diff --git a/assets/shaders/alphamask.common.frag.glsl b/assets/shaders/alphamask.common.frag.glsl new file mode 100644 index 0000000000..0f10d993d5 --- /dev/null +++ b/assets/shaders/alphamask.common.frag.glsl @@ -0,0 +1,39 @@ +#version 120 + +//alpha masking shader +// +//applies an alpha mask texture to a base texture, +//then draws the masked texture. + +//the base and mask texture, base is the plain terrain tile +uniform sampler2D texture; +uniform sampler2D mask_texture; + +//disable blending and show the mask instead +uniform bool show_mask; + +//get those interpolated texture position from vertexshader +varying vec2 base_tex_position; +varying vec2 mask_tex_position; + + +void main() +{ + //get the texel from the uniform texture. + vec4 base_pixel = texture2D(texture, base_tex_position); + vec4 mask_pixel = texture2D(mask_texture, mask_tex_position); + + float factor = 1.0 - mask_pixel.x; + + vec4 blended_pixel = vec4(base_pixel.r, base_pixel.g, base_pixel.b, base_pixel.a - factor); + + //force to pink + //blended_pixel = vec4(255.0/255.0, 20.0/255.0, 147.0/255.0, 1.0); + if (show_mask) { + gl_FragColor = mask_pixel; + } else { + gl_FragColor = blended_pixel; + } + + gl_FragDepth = 0; +} diff --git a/assets/shaders/alphamask.common.vert.glsl b/assets/shaders/alphamask.common.vert.glsl new file mode 100644 index 0000000000..6bd0e4e4a3 --- /dev/null +++ b/assets/shaders/alphamask.common.vert.glsl @@ -0,0 +1,25 @@ +//vertex shader for applying an alpha mask to a texture +#version 120 + +//modelview*projection matrix +uniform mat4 mvp_matrix; + +//the position of this vertex +attribute vec4 vertex_position; + +//send the texture coordinates to the fragmentshader +attribute vec2 tex_coordinates; +attribute vec2 mask_tex_coordinates; + +//send the texture coordinates to the fragmentshader +varying vec2 base_tex_position; +varying vec2 mask_tex_position; + +void main(void) { + //transform the position with the mvp matrix + gl_Position = gl_ModelViewProjectionMatrix * vertex_position; + + //set the fixpoints for the tex coordinates at this vertex + mask_tex_position = mask_tex_coordinates; + base_tex_position = tex_coordinates; +} diff --git a/assets/shaders/maptexture.frag.glsl b/assets/shaders/maptexture.frag.glsl index 78185f9715..3d2e7421cc 100644 --- a/assets/shaders/maptexture.frag.glsl +++ b/assets/shaders/maptexture.frag.glsl @@ -11,4 +11,5 @@ varying vec2 tex_position; void main (void) { //this sets the fragment color to the corresponding texel. gl_FragColor = texture2D(texture, tex_position); + gl_FragDepth = 0; } diff --git a/assets/shaders/maptexture.vert.glsl b/assets/shaders/maptexture.vert.glsl index b1391a8869..607a7ef788 100644 --- a/assets/shaders/maptexture.vert.glsl +++ b/assets/shaders/maptexture.vert.glsl @@ -10,8 +10,11 @@ attribute vec4 vertex_position; //the texture coordinates assigned to this vertex attribute vec2 tex_coordinates; +attribute float player_number; + //interpolated texture coordinates sent to fragment shader varying vec2 tex_position; +varying float vplayer_number; void main(void) { //transform the vertex coordinates @@ -19,4 +22,5 @@ void main(void) { //pass the fix points for texture coordinates set at this vertex tex_position = tex_coordinates; + vplayer_number = player_number; } diff --git a/assets/shaders/teamcolors.frag.glsl b/assets/shaders/teamcolors.frag.glsl index fe411ebb22..8c851ff031 100644 --- a/assets/shaders/teamcolors.frag.glsl +++ b/assets/shaders/teamcolors.frag.glsl @@ -9,9 +9,6 @@ //the unmodified texture itself uniform sampler2D texture; -//the desired player number the final resulting colors -uniform int player_number; - //the alpha value which marks colors to be replaced uniform float alpha_marker; @@ -21,59 +18,33 @@ uniform vec4 player_color[64]; //interpolated texture coordinates sent from vertex shader varying vec2 tex_position; +//the desired player number the final resulting colors +varying float vplayer_number; +varying float vz_order; + //create epsilon environment for float comparison const float epsilon = 0.001; - -//do the lookup in the player color table -//for a playernumber (red, blue, etc) -//get the subcolor (brightness variations) -vec4 get_color(int playernum, int subcolor) { - return player_color[((playernum-1) * 8) + subcolor]; -} - -//compare color c1 to a reference color -bool is_color(vec4 c1, vec4 reference) { - if (all(greaterThanEqual(c1, reference - epsilon)) && all(lessThanEqual(c1, reference + epsilon))) { - return true; - } - else { - return false; - } -} +const vec3 vepsilon = vec3(epsilon, epsilon, epsilon); void main() { //get the texel from the uniform texture. vec4 pixel = texture2D(texture, tex_position); - //check if this texel has an alpha marker, so we can replace it's rgb values. - if (pixel[3] >= alpha_marker - epsilon && pixel[3] <= alpha_marker + epsilon) { - - //set alpha to 1 for the comparison - pixel[3] = 1.0; - - //don't replace the colors if it's already player 1 (blue) - //as the media convert scripts generates blue-player sprites - if (player_number != 1) { - bool found = false; - - //try to find the base color, there are 8 of them. - for(int i = 0; i <= 7; i++) { - if (is_color(pixel, player_color[i])) { - //base color found, now replace it with the same color - //but player_number tinted. - pixel = get_color(player_number, i); - found = true; - break; - } - } - if (!found) { - //unknown base color gets pink muhahaha - pixel = vec4(255.0/255.0, 20.0/255.0, 147.0/255.0, 1.0); - } + if ( abs(pixel.a - alpha_marker) > epsilon ) + { + //Even replace player 1's colours as we then remove a branch + for(int i = 0; i <= 7; i++) { + if ( all(lessThanEqual(abs(pixel.rgb - player_color[i].rgb), vepsilon)) ) + { + pixel = player_color[int( ((vplayer_number-1) * 8) + i )]; + //pixel = vec4(1, 1, 1, 1); + break; + } } } - //else the texel had no marker so we can just draw it without player coloring gl_FragColor = pixel; -} + gl_FragDepth = 0.2; + //gl_FragDepth = floor(gl_FragColor.a) * 0.2; +} \ No newline at end of file diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index c0c3000d4a..a8b717e620 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -33,6 +33,7 @@ add_subdirectory("console") add_subdirectory("coord") add_subdirectory("job") add_subdirectory("pathfinding") +add_subdirectory("renderer") add_subdirectory("shader") add_subdirectory("util") add_subdirectory("datastructure") diff --git a/cpp/game_main.cpp b/cpp/game_main.cpp index 969917c342..e96bbd670f 100644 --- a/cpp/game_main.cpp +++ b/cpp/game_main.cpp @@ -20,6 +20,8 @@ #include "util/strings.h" #include "util/timer.h" +#include "renderer/renderer.h" + namespace openage { /* @@ -235,6 +237,8 @@ GameMain::GameMain(Engine *engine) // shader initialisation // read shader source codes and create shader objects for wrapping them. + graphics::Renderer::create(data_dir, &asset_dir); + char *texture_vert_code; util::read_whole_file(&texture_vert_code, data_dir->join("shaders/maptexture.vert.glsl")); auto plaintexture_vert = new shader::Shader(GL_VERTEX_SHADER, texture_vert_code); @@ -551,11 +555,13 @@ bool GameMain::on_draw() { Engine &engine = Engine::get(); // draw gaben, our great and holy protector, bringer of the half-life 3. - gaben->draw(coord::camgame {0, 0}); + //gaben->draw(coord::camgame {0, 0}); // draw terrain terrain->draw(&engine); + graphics::Renderer::get().render(); + return true; } diff --git a/cpp/renderer/CMakeLists.txt b/cpp/renderer/CMakeLists.txt new file mode 100644 index 0000000000..89aa44b6e7 --- /dev/null +++ b/cpp/renderer/CMakeLists.txt @@ -0,0 +1,3 @@ +add_sources(${PROJECT_NAME} + renderer.cpp +) diff --git a/cpp/renderer/renderer.cpp b/cpp/renderer/renderer.cpp new file mode 100644 index 0000000000..7684dfb35d --- /dev/null +++ b/cpp/renderer/renderer.cpp @@ -0,0 +1,370 @@ +#include "renderer.h" + +#include "../shader/program.h" +#include "../shader/shader.h" + +#include "../util/file.h" +#include "../util/dir.h" +#include "../gamedata/color.gen.h" + +#include +#include + +namespace openage { +namespace graphics { + +Renderer *Renderer::instance = NULL; + +//Local for now +GLuint vertbuf; + + +bool Renderer::create(util::Dir const *data_dir, util::Dir const *asset_dir) { + //Idempotent + if ( instance != NULL ) return true; + + Renderer *nRenderer = new Renderer(); + + if ( nRenderer->init(data_dir, asset_dir) ) { + instance = nRenderer; + return true; + } + + delete nRenderer; + return false; +} + +Renderer &Renderer::get() { + //TODO: Should assert here if instance == NULL + + return *instance; +} + + +Renderer::Renderer() { + //Constructor +} + +bool Renderer::init(util::Dir const *data_dir, util::Dir const *asset_dir) { + const char *shader_file_names[][2] = { + {"shaders/maptexture.vert.glsl", "shaders/maptexture.frag.glsl"}, + {"shaders/maptexture.vert.glsl", "shaders/teamcolors.frag.glsl"}, + {"shaders/alphamask.common.vert.glsl", "shaders/alphamask.common.frag.glsl"}, + {NULL} + }; + + + + for ( int cmaterial_idx = 0; cmaterial_idx < eMaterialType::keCount; cmaterial_idx++) + { + char const **cshader_file = shader_file_names[cmaterial_idx]; + + printf ("Loading shaders: %s %s\n", cshader_file[0], cshader_file[1]); + + char *texture_vert_code; + util::read_whole_file(&texture_vert_code, data_dir->join(cshader_file[0])); + auto vert_shader = new shader::Shader(GL_VERTEX_SHADER, texture_vert_code); + + char *texture_frag_code; + util::read_whole_file(&texture_frag_code, data_dir->join(cshader_file[1])); + auto frag_shader = new shader::Shader(GL_FRAGMENT_SHADER, texture_frag_code); + + material &cMaterial = materials[cmaterial_idx]; + + cMaterial.program = new shader::Program(vert_shader, frag_shader); + cMaterial.program->link(); + + cMaterial.uniformNormalTexture = cMaterial.program->get_uniform_id("texture"); + cMaterial.uniformMasktexture = cMaterial.program->get_uniform_id("mask_texture"); + cMaterial.uniformPlayerColors = cMaterial.program->get_uniform_id("player_color"); + + //Needs to be an attribute + cMaterial.attributeMaskUV = (cMaterial.program->has_attribute("mask_tex_coordinates")) ? + cMaterial.program->get_attribute_id("mask_tex_coordinates") + : -1; + + cMaterial.attributeUV = (cMaterial.program->has_attribute("tex_coordinates")) ? + cMaterial.program->get_attribute_id("tex_coordinates") + : -1; + + cMaterial.attributePlayerCol = (cMaterial.program->has_attribute("player_number")) ? + cMaterial.program->get_attribute_id("player_number") + : -1; + + cMaterial.attributeZOrder = (cMaterial.program->has_attribute("z_order")) ? + cMaterial.program->get_attribute_id("z_order") + : -1; + + //Fixup material specific + + cMaterial.program->use(); + glUniform1i(cMaterial.uniformNormalTexture, 0); + glUniform1i(cMaterial.uniformMasktexture, 1); + cMaterial.program->stopusing(); + + delete[] texture_vert_code; + delete[] texture_frag_code; + } + + { + //fixup material specific normals + auto player_color_lines = util::read_csv_file(asset_dir->join("player_palette_50500.docx")); + + GLfloat *playercolors = new GLfloat[player_color_lines.size() * 4]; + for (size_t i = 0; i < player_color_lines.size(); i++) { + auto line = &player_color_lines[i]; + playercolors[i*4] = line->r / 255.0; + playercolors[i*4 + 1] = line->g / 255.0; + playercolors[i*4 + 2] = line->b / 255.0; + playercolors[i*4 + 3] = line->a / 255.0; + } + + + // + // TODO: Update these to a 1D texture + // + materials[eMaterialType::keColorReplace].program->use(); + glUniform4fv(materials[eMaterialType::keColorReplace].uniformPlayerColors, 64, playercolors); + materials[eMaterialType::keColorReplace].program->stopusing(); + } + glGenBuffers(1, &vertbuf); + + return true; +} + +void Renderer::submit_quad(render_quad const & quad, + GLint diffuse, + GLint mask, + unsigned char layer, + eMaterialType::Enum material_type) { + + //Generate a renderer key from + // MaterialType(16bit) | {textureHandle(16bit) | maskHandle(16bit)} | QuadIdx (16bit) + + int cIndex = render_queue.size(); + + render_token_struct pData = { + (short)cIndex, + (short)mask, + (short)diffuse, + (unsigned char)material_type, + layer, + }; + + //Pack this into a 64bit unsigned long + render_token nToken = *((render_token*)&pData); + render_queue.push_back(nToken); + render_buffer.push_back(quad); + + //Render immediately for testing purposes + //render(); + +} + +void Renderer::apply_material (eMaterialType::Enum material_type) { + material current_material = materials[material_type]; + + //if (material_type == eMaterialType::keNormal) continue; + + current_material.program->use(); + + // Need to retrieve the attributes from the shaders before we can use them here + glEnableVertexAttribArray(current_material.program->pos_id); + glEnableVertexAttribArray(current_material.attributeUV); + + //set data types, offsets in the vdata array + glVertexAttribPointer(current_material.program->pos_id, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(render_quad::quad_vertex), + (void*)offsetof(render_quad::quad_vertex, pos)); + + glVertexAttribPointer(current_material.attributeUV, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(render_quad::quad_vertex), + (void*)offsetof(render_quad::quad_vertex, uv)); + + if ( material_type == eMaterialType::keAlphaMask ) { + glEnableVertexAttribArray(current_material.attributeMaskUV); + glVertexAttribPointer(current_material.attributeMaskUV, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(render_quad::quad_vertex), + (void*)offsetof(render_quad::quad_vertex, maskUV)); + + glActiveTexture(GL_TEXTURE1); + glEnable(GL_TEXTURE_2D); + } + + //These checks are temporary + if ( current_material.attributePlayerCol != -1 ) + { + glEnableVertexAttribArray(current_material.attributePlayerCol); + glVertexAttribPointer(current_material.attributePlayerCol, + 1, + GL_UNSIGNED_INT, + GL_FALSE, + sizeof(render_quad::quad_vertex), + (void*)offsetof(render_quad::quad_vertex, playerID)); + } + if ( current_material.attributeZOrder != -1 ) + { + glEnableVertexAttribArray(current_material.attributeZOrder); + glVertexAttribPointer(current_material.attributeZOrder, + 1, + GL_FLOAT, + GL_FALSE, + sizeof(render_quad::quad_vertex), + (void*)offsetof(render_quad::quad_vertex, zValue)); + } +} + +void Renderer::disable_material (eMaterialType::Enum material_type){ + material current_material = materials[material_type]; + + glDisableVertexAttribArray(current_material.program->pos_id); + glDisableVertexAttribArray(current_material.attributeUV); + + //These checks are temporary + if ( current_material.attributePlayerCol != -1 ) + { + glDisableVertexAttribArray(current_material.attributePlayerCol); + } + if ( current_material.attributeZOrder != -1 ) + { + glDisableVertexAttribArray(current_material.attributeZOrder); + } + + if ( material_type == eMaterialType::keAlphaMask) { + glDisableVertexAttribArray(current_material.attributeMaskUV); + glActiveTexture(GL_TEXTURE1); + glDisable(GL_TEXTURE_2D); + } + + current_material.program->stopusing(); +} + +void renderBuffer (std::vector &idxBuffer, + eMaterialType::Enum material_type, + GLint diffuse, + GLint mask) +{ + //Render out + if ( material_type == eMaterialType::keAlphaMask ) + { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, mask); + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, diffuse); + + //draw the vertex array + glDrawElements(GL_QUADS, idxBuffer.size(), GL_UNSIGNED_SHORT, &idxBuffer[0]); + //glDrawArrays(GL_QUADS, renderCommand.idx * 4, 4); + + idxBuffer.clear(); +} + +void Renderer::render() { + int quadCount = render_queue.size(); + int bufferSize = sizeof(render_quad) * quadCount; + + glClearDepth(0); + glDepthMask(true); + + + glEnable (GL_DEPTH_TEST); + glDepthFunc(GL_GEQUAL); + + glBindBuffer(GL_ARRAY_BUFFER, vertbuf); + glBufferData(GL_ARRAY_BUFFER, bufferSize, &render_buffer[0].vertices, GL_STREAM_DRAW); + + //Sort the draw calls + std::sort(render_queue.begin(), render_queue.end()); + + render_token_struct lastCommand = *((render_token_struct*)&render_queue[render_queue.size()-1]); + unsigned char maxLayer = lastCommand.layer; + + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_2D); + + std::vector indexBuffer; + + int cQuad = 0; + for ( int cLayer = 0; cLayer <= maxLayer; cLayer++) + { + glClear(GL_DEPTH_BUFFER_BIT); + + for ( int cMaterial = 0; cMaterial < eMaterialType::keCount; cMaterial++) + { + eMaterialType::Enum material_type = (eMaterialType::Enum)cMaterial; + apply_material(material_type); + + //Render all the quads for this material + while ( true ) + { + render_token_struct renderCommand = *((render_token_struct*)&render_queue[cQuad]); + GLint textureCombo = *((GLint*)&renderCommand.diffuse); + + if ( (eMaterialType::Enum)renderCommand.matType != material_type ) + { + //printf ("Batching %lu on material change\n", indexBuffer.size()); + renderBuffer(indexBuffer, material_type, renderCommand.diffuse, renderCommand.mask); + break; + } + + indexBuffer.push_back((renderCommand.idx * 4)); + indexBuffer.push_back((renderCommand.idx * 4) +1); + indexBuffer.push_back((renderCommand.idx * 4) +2); + indexBuffer.push_back((renderCommand.idx * 4) +3); + + + cQuad++; + if ( cQuad >= quadCount) + { + //printf ("Completing render %lu\n", indexBuffer.size()); + renderBuffer(indexBuffer, material_type, renderCommand.diffuse, renderCommand.mask); + break; + } + + render_token_struct nextRenderCommand = *((render_token_struct*)&render_queue[cQuad]); + GLint nextTextureCombo = *((GLint*)&nextRenderCommand.diffuse); + + //Check for texture change + if ((eMaterialType::Enum)nextRenderCommand.matType != material_type + || nextTextureCombo != textureCombo) + { + //printf ("Batching %lu on texture change\n", indexBuffer.size()); + renderBuffer(indexBuffer, material_type, renderCommand.diffuse, renderCommand.mask); + //renderBuffer(indexBuffer, material_type, renderCommand.diffuse, renderCommand.diffuse); + } + } + + //Render + + disable_material(material_type); + } + + } + + //unbind the current buffer + glBindBuffer(GL_ARRAY_BUFFER, 0); + glActiveTexture(GL_TEXTURE0); + glDisable(GL_TEXTURE_2D); + + glDisable (GL_DEPTH_TEST); + glDepthMask(false); + + glClear(GL_DEPTH_BUFFER_BIT); + + render_queue.clear(); + render_buffer.clear(); +} + +} +} \ No newline at end of file diff --git a/cpp/renderer/renderer.h b/cpp/renderer/renderer.h new file mode 100644 index 0000000000..234ae5add3 --- /dev/null +++ b/cpp/renderer/renderer.h @@ -0,0 +1,169 @@ +#ifndef _RENDERER_H_ +#define _RENDERER_H_ + +#include + +#include + + +namespace openage { + +namespace shader { + class Program; +} +namespace util { + class Dir; +} + +namespace graphics { + +struct vertex2 { + float x; + float y; + + static vertex2 Create (float _x, float _y) { + vertex2 nVertex2; + nVertex2.x = _x; + nVertex2.y = _y; + + return nVertex2; + } +}; + + +struct rect { + vertex2 topLeft; + vertex2 bottomRight; + + static rect Create( vertex2 _topLeft, + vertex2 _bottomRight ) { + rect nRect; + nRect.topLeft = _topLeft; + nRect.bottomRight = _bottomRight; + + return nRect; + } +}; + +struct render_quad { + struct quad_vertex { + vertex2 pos; + vertex2 uv; + vertex2 maskUV; + float zValue; + unsigned playerID; + }; + + quad_vertex vertices[4]; + + static render_quad Create ( rect const & _pos, + rect const & _uv, + rect const & _maskUV, + float _zValue, + unsigned _playerID ) { + render_quad nQuad; + + nQuad.vertices[0].pos = _pos.topLeft; + nQuad.vertices[0].uv = _uv.topLeft; + nQuad.vertices[0].maskUV = _maskUV.topLeft; + nQuad.vertices[0].zValue = _zValue; + nQuad.vertices[0].playerID = _playerID; + + nQuad.vertices[1].pos = vertex2::Create(_pos.topLeft.x, _pos.bottomRight.y); + nQuad.vertices[1].uv = vertex2::Create(_uv.topLeft.x, _uv.bottomRight.y); + nQuad.vertices[1].maskUV = vertex2::Create(_maskUV.topLeft.x, _maskUV.bottomRight.y); + nQuad.vertices[1].zValue = _zValue; + nQuad.vertices[1].playerID = _playerID; + + nQuad.vertices[2].pos = _pos.bottomRight; + nQuad.vertices[2].uv = _uv.bottomRight; + nQuad.vertices[2].maskUV = _maskUV.bottomRight; + nQuad.vertices[2].zValue = _zValue; + nQuad.vertices[2].playerID = _playerID; + + nQuad.vertices[3].pos = vertex2::Create(_pos.bottomRight.x, _pos.topLeft.y); + nQuad.vertices[3].uv = vertex2::Create(_uv.bottomRight.x, _uv.topLeft.y); + nQuad.vertices[3].maskUV = vertex2::Create(_maskUV.bottomRight.x, _maskUV.topLeft.y); + nQuad.vertices[3].zValue = _zValue; + nQuad.vertices[3].playerID = _playerID; + + return nQuad; + } +}; + +struct eMaterialType { + enum Enum { + keNormal, + keColorReplace, + keAlphaMask, + + keCount + }; +}; + +struct material { + shader::Program *program; + GLint uniformNormalTexture; + GLint uniformMasktexture; + GLint uniformPlayerColors; + + GLint attributeUV; + GLint attributeMaskUV; + + GLint attributePlayerCol; + GLint attributeZOrder; +}; + + + +class Renderer { +public: + void submit_quad (render_quad const & quad, + GLint diffuse, + GLint mask, + unsigned char layer, + eMaterialType::Enum material_type); + + void render (); + + static bool create (util::Dir const *data_dir, util::Dir const *asset_dir); + static Renderer &get(); + +private: + + Renderer (); + bool init (util::Dir const *data_dir, util::Dir const *asset_dir); + + void apply_material (eMaterialType::Enum material_type); + void disable_material (eMaterialType::Enum material_type); + + Renderer(const Renderer ©) = delete; + Renderer &operator=(const Renderer ©) = delete; + Renderer(Renderer &&other) = delete; + Renderer &operator=(Renderer &&other) = delete; + +private: + struct render_token_struct { + short idx; + short mask; + short diffuse; + unsigned char matType; + unsigned char layer; + } ; + + typedef unsigned long long render_token; + + typedef std::vector render_quad_list; + typedef std::vector render_queue_list; + render_quad_list render_buffer; + render_queue_list render_queue; + + material materials[eMaterialType::keCount]; + + static Renderer *instance; +}; + +} +} + +#endif \ No newline at end of file diff --git a/cpp/shader/program.cpp b/cpp/shader/program.cpp index 9437230a9e..80743a7a1f 100644 --- a/cpp/shader/program.cpp +++ b/cpp/shader/program.cpp @@ -108,6 +108,16 @@ GLint Program::get_uniform_id(const char *name) { return glGetUniformLocation(this->id, name); } +bool Program::has_attribute(const char *name) { + if (this->is_linked) { + GLint aid = glGetAttribLocation(this->id, name); + return aid != -1; + } + else { + throw util::Error("queried attribute '%s' id before program was linked.", name); + } +} + GLint Program::get_attribute_id(const char *name) { if (this->is_linked) { GLint aid = glGetAttribLocation(this->id, name); diff --git a/cpp/shader/program.h b/cpp/shader/program.h index f38b5068ed..c93af74acb 100644 --- a/cpp/shader/program.h +++ b/cpp/shader/program.h @@ -25,6 +25,8 @@ class Program { void use(); void stopusing(); + bool has_attribute(const char *name); + GLint get_uniform_id(const char *name); GLint get_attribute_id(const char *name); diff --git a/cpp/texture.cpp b/cpp/texture.cpp index 6452211596..159bfd0556 100644 --- a/cpp/texture.cpp +++ b/cpp/texture.cpp @@ -10,6 +10,10 @@ #include "util/error.h" #include "util/file.h" +#include "renderer/renderer.h" + +using namespace openage::graphics; + namespace openage { //real definition of the shaders, @@ -147,67 +151,42 @@ void Texture::draw(coord::tile pos, int subid, Texture *alpha_texture, int alpha } void Texture::draw(coord::pixel_t x, coord::pixel_t y, bool mirrored, int subid, unsigned player, Texture *alpha_texture, int alpha_subid) { - glColor4f(1, 1, 1, 1); - //log::dbg("drawing texture at %hd, %hd", x, y); - - bool use_playercolors = false; - bool use_alphashader = false; + eMaterialType::Enum cType; //Use this to help transition to new renderer struct gamedata::subtexture *mtx; - - int *pos_id, *texcoord_id, *masktexcoord_id; - + struct gamedata::subtexture *tx = this->get_subtexture(subid); + + int cLayer = 0; + //is this texture drawn with an alpha mask? if (this->use_alpha_masking && alpha_subid >= 0 && alpha_texture != nullptr) { - alphamask_shader::program->use(); - - //bind the alpha mask texture to slot 1 - glActiveTexture(GL_TEXTURE1); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, alpha_texture->get_texture_id()); - - //get the alphamask subtexture (the blend mask!) + cLayer = 0; mtx = alpha_texture->get_subtexture(alpha_subid); - pos_id = &alphamask_shader::program->pos_id; - texcoord_id = &alphamask_shader::base_coord; - masktexcoord_id = &alphamask_shader::mask_coord; - use_alphashader = true; + cType = eMaterialType::keAlphaMask; } //is this texure drawn with replaced pixels for team coloring? else if (this->use_player_color_tinting) { - teamcolor_shader::program->use(); - - //set the desired player id in the shader - glUniform1i(teamcolor_shader::player_id_var, player); - pos_id = &teamcolor_shader::program->pos_id; - texcoord_id = &teamcolor_shader::tex_coord; - use_playercolors = true; + cLayer = 1; + cType = eMaterialType::keColorReplace; } //mkay, we just draw the plain texture otherwise. else { - texture_shader::program->use(); - pos_id = &texture_shader::program->pos_id; - texcoord_id = &texture_shader::tex_coord; + cLayer = 0; + cType = eMaterialType::keNormal; } - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, this->id); - - struct gamedata::subtexture *tx = this->get_subtexture(subid); - int left, right, top, bottom; //coordinates where the texture will be drawn on screen. bottom = y - (tx->h - tx->cy); top = bottom + tx->h; - if (not mirrored) { - left = x - tx->cx; - right = left + tx->w; - } else { + if (mirrored) { left = x + tx->cx; right = left - tx->w; + } else { + left = x - tx->cx; + right = left + tx->w; } //convert the texture boundaries to float @@ -225,71 +204,28 @@ void Texture::draw(coord::pixel_t x, coord::pixel_t y, bool mirrored, int subid, this->get_subtexture_coordinates(tx, &txl, &txr, &txt, &txb); float mtxl=0, mtxr=0, mtxt=0, mtxb=0; - if (use_alphashader) { + if (cType == eMaterialType::keAlphaMask) { alpha_texture->get_subtexture_coordinates(mtx, &mtxl, &mtxr, &mtxt, &mtxb); } - - //this array will be uploaded to the GPU. - //it contains all dynamic vertex data (position, tex coordinates, mask coordinates) - float vdata[] { - leftf, topf, - leftf, bottomf, - rightf, bottomf, - rightf, topf, - txl, txt, - txl, txb, - txr, txb, - txr, txt, - mtxl, mtxt, - mtxl, mtxb, - mtxr, mtxb, - mtxr, mtxt - }; - - - //store vertex buffer data, TODO: prepare this sometime earlier. - glBindBuffer(GL_ARRAY_BUFFER, this->vertbuf); - glBufferData(GL_ARRAY_BUFFER, sizeof(vdata), vdata, GL_STREAM_DRAW); - - //enable vertex buffer and bind it to the vertex attribute - glEnableVertexAttribArray(*pos_id); - glEnableVertexAttribArray(*texcoord_id); - if (use_alphashader) { - glEnableVertexAttribArray(*masktexcoord_id); - } - - //set data types, offsets in the vdata array - glVertexAttribPointer(*pos_id, 2, GL_FLOAT, GL_FALSE, 0, (void *)(0)); - glVertexAttribPointer(*texcoord_id, 2, GL_FLOAT, GL_FALSE, 0, (void *)(sizeof(float) * 8)); - if (use_alphashader) { - glVertexAttribPointer(*masktexcoord_id, 2, GL_FLOAT, GL_FALSE, 0, (void *)(sizeof(float) * 8 * 2)); - } - - //draw the vertex array - glDrawArrays(GL_QUADS, 0, 4); - - //unbind the current buffer - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glDisableVertexAttribArray(*pos_id); - glDisableVertexAttribArray(*texcoord_id); - if (use_alphashader) { - glDisableVertexAttribArray(*masktexcoord_id); - } - - //disable the shaders. - if (use_playercolors) { - teamcolor_shader::program->stopusing(); - } else if (use_alphashader) { - alphamask_shader::program->stopusing(); - glActiveTexture(GL_TEXTURE1); - glDisable(GL_TEXTURE_2D); - } else { - texture_shader::program->stopusing(); - } - - glActiveTexture(GL_TEXTURE0); - glDisable(GL_TEXTURE_2D); + + GLint maskID = (cType == eMaterialType::keAlphaMask) ? alpha_texture->get_texture_id() : -1; + + Renderer::get().submit_quad(render_quad::Create( + //Position to render to + rect::Create(vertex2::Create(leftf, topf), + vertex2::Create(rightf, bottomf)), + //UV coords for texture + rect::Create(vertex2::Create(txl, txt), + vertex2::Create(txr, txb)), + //UV coords for mask texture + rect::Create(vertex2::Create(mtxl, mtxt), + vertex2::Create(mtxr, mtxb)), + 0, //z-value + 6), //playerID + this->id, //diffuse + maskID, //Mask + cLayer, //Layer + cType); } diff --git a/cpp/util/dir.cpp b/cpp/util/dir.cpp index 3f1fde1625..c957c7301d 100644 --- a/cpp/util/dir.cpp +++ b/cpp/util/dir.cpp @@ -11,11 +11,11 @@ Dir::Dir(std::string basedir) { Dir::~Dir() {} -std::string Dir::join(const std::string &fname) { +std::string Dir::join(const std::string &fname) const { return this->basedir + PATHSEP + fname; } -Dir Dir::append(const std::string &suffix) { +Dir Dir::append(const std::string &suffix) const { if (suffix.length() == 0) { return Dir{this->basedir}; } else { diff --git a/cpp/util/dir.h b/cpp/util/dir.h index 4ea3533986..a10768835e 100644 --- a/cpp/util/dir.h +++ b/cpp/util/dir.h @@ -18,8 +18,8 @@ class Dir { Dir(std::string basedir); ~Dir(); - std::string join(const std::string &fname); - Dir append(const std::string &suffix); + std::string join(const std::string &fname) const; + Dir append(const std::string &suffix) const; std::string basedir; };