From 7c13efdc924ff136b267beb8823f7ba71b21c394 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Fri, 20 Dec 2013 13:43:12 +0000 Subject: [PATCH] Improved handling of transparent materials (still needs work) --- .../include/renderwure/engine/GTAData.hpp | 14 +- .../include/renderwure/render/GTARenderer.hpp | 17 +++ framework2/src/loaders/TextureLoader.cpp | 26 +++- framework2/src/render/GTARenderer.cpp | 135 +++++++++++------- 4 files changed, 125 insertions(+), 67 deletions(-) diff --git a/framework2/include/renderwure/engine/GTAData.hpp b/framework2/include/renderwure/engine/GTAData.hpp index 23e65676..7555e9a8 100644 --- a/framework2/include/renderwure/engine/GTAData.hpp +++ b/framework2/include/renderwure/engine/GTAData.hpp @@ -25,16 +25,14 @@ struct TextureInfo { /// Texture Name GLuint texName; - /// Atlas (if applicable) - TextureAtlas* atlas; - glm::vec4 rect; /// X/Y base coord, Z/W UV scale. + + /// Transparent flag. + bool transparent; - TextureInfo(GLuint tex) - : texName(tex), atlas(nullptr), rect(0.f, 0.f, 1.f, 1.f) {} - TextureInfo(TextureAtlas* a, const glm::vec4&r) - : texName(0), atlas(a), rect(r) {} + TextureInfo(GLuint tex, bool t) + : texName(tex), transparent(t) {} TextureInfo() - : texName(0), atlas(nullptr) {} + : texName(0), transparent(false) {} }; /** diff --git a/framework2/include/renderwure/render/GTARenderer.hpp b/framework2/include/renderwure/render/GTARenderer.hpp index b652a0e4..a71f8a03 100644 --- a/framework2/include/renderwure/render/GTARenderer.hpp +++ b/framework2/include/renderwure/render/GTARenderer.hpp @@ -4,6 +4,7 @@ #define GLEW_STATIC #include #include +#include #include @@ -15,6 +16,22 @@ class Animator; class GTARenderer { GTAEngine* engine; + + struct RQueueEntry { + Model* model; + size_t g; + size_t sg; + glm::mat4 matrix; + GTAObject* object; + }; + + // Internal method for processing sub-geometry + bool renderSubgeometry(Model* model, size_t g, size_t sg, const glm::mat4& matrix, GTAObject* object, bool queueTransparent = true); + + /// Queue of sub-geometry to post-render + /// With a faster occulusion culling stage + /// This could be replaced with a 2nd draw pass. + std::vector transparentDrawQueue; public: diff --git a/framework2/src/loaders/TextureLoader.cpp b/framework2/src/loaders/TextureLoader.cpp index dd1a6e87..02524f53 100644 --- a/framework2/src/loaders/TextureLoader.cpp +++ b/framework2/src/loaders/TextureLoader.cpp @@ -23,6 +23,7 @@ bool TextureLoader::loadFromFile(std::string filename, GTAData* gameData) } GLuint gErrorTextureData[] = { 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFF0000 }; +GLuint gDebugTextureData[] = {0xFF0000FF, 0xFF00FF00}; GLuint getErrorTexture() { @@ -56,7 +57,7 @@ void processPalette(uint32_t* fullColor, RW::BSTextureNative& texNative, RW::Bin } -GLuint createTexture(RW::BSTextureNative& texNative, RW::BinaryStreamSection& rootSection) +GLuint createTexture(RW::BSTextureNative& texNative, RW::BinaryStreamSection& rootSection, bool* transparent) { // TODO: Exception handling. if(texNative.platform != 8) { @@ -68,13 +69,29 @@ GLuint createTexture(RW::BSTextureNative& texNative, RW::BinaryStreamSection& ro bool isFulc = texNative.rasterformat == RW::BSTextureNative::FORMAT_1555 || texNative.rasterformat == RW::BSTextureNative::FORMAT_8888 || texNative.rasterformat == RW::BSTextureNative::FORMAT_888; + // Export this value + *transparent = !((texNative.rasterformat&RW::BSTextureNative::FORMAT_888) == RW::BSTextureNative::FORMAT_888); + if(! (isPal8 || isFulc)) { std::cerr << "Unsuported raster format " << std::dec << texNative.rasterformat << std::endl; return getErrorTexture(); } GLuint textureName = 0; - + +#if ENABLE_ABHORENT_DEBUGGING + if(true) + { + glGenTextures(1, &textureName); + glBindTexture(GL_TEXTURE_2D, textureName); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA, + 1, 1, 0, + GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)(gDebugTextureData) + (*transparent ? 0 : 4) + ); + } + else +#endif if(isPal8) { uint32_t fullColor[texNative.width * texNative.height]; @@ -182,9 +199,10 @@ bool TextureLoader::loadFromMemory(char *data, GTAData *gameData) RW::BSTextureNative texNative = rootSection.readStructure(); std::string name = std::string(texNative.diffuseName); - GLuint id = createTexture(texNative, rootSection); + bool transparent = false; + GLuint id = createTexture(texNative, rootSection, &transparent); - gameData->textures.insert({name, {id}}); + gameData->textures.insert({name, {id, transparent}}); } return true; diff --git a/framework2/src/render/GTARenderer.cpp b/framework2/src/render/GTARenderer.cpp index 6d0b46da..47cc1a16 100644 --- a/framework2/src/render/GTARenderer.cpp +++ b/framework2/src/render/GTARenderer.cpp @@ -370,6 +370,18 @@ void GTARenderer::renderWorld() } } + // Draw anything that got queued. + for(auto it = transparentDrawQueue.begin(); + it != transparentDrawQueue.end(); + ++it) + { + glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(it->matrix)); + glUniform4f(uniCol, 1.f, 1.f, 1.f, 1.f); + + renderSubgeometry(it->model, it->g, it->sg, it->matrix, it->object, false); + } + transparentDrawQueue.clear(); + glUseProgram(skyProgram); glBindBuffer(GL_ARRAY_BUFFER, skydomeVBO); @@ -421,71 +433,84 @@ void GTARenderer::renderGeometry(Model* model, size_t g, const glm::mat4& modelM glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(modelMatrix)); glUniform4f(uniCol, 1.f, 1.f, 1.f, 1.f); - glBindBuffer(GL_ARRAY_BUFFER, model->geometries[g]->VBO); - - glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)model->geometries[g]->offsVert); - glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)model->geometries[g]->offsTexCoords); - glVertexAttribPointer(normalAttrib, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)model->geometries[g]->offsNormals); - glVertexAttribPointer(colourAttrib, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*)model->geometries[g]->offsColours); - glEnableVertexAttribArray(posAttrib); - glEnableVertexAttribArray(texAttrib); - glEnableVertexAttribArray(normalAttrib); - glEnableVertexAttribArray(colourAttrib); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->geometries[g]->EBO); - for(size_t sg = 0; sg < model->geometries[g]->subgeom.size(); ++sg) { - auto& subgeom = model->geometries[g]->subgeom[sg]; + if(! renderSubgeometry(model, g, sg, modelMatrix, object)) { + // If rendering was rejected, queue for later. + transparentDrawQueue.push_back( + {model, g, sg, modelMatrix, object} + ); + } + } +} - if (model->geometries[g]->materials.size() > subgeom.material) { - Model::Material& mat = model->geometries[g]->materials[subgeom.material]; +static GLuint currentVBO = 0; - if(mat.textures.size() > 0 ) { - TextureInfo& tex = engine->gameData.textures[mat.textures[0].name]; - if(tex.atlas) { - if(! tex.atlas->isFinalized()) { - tex.atlas->finalize(); - } - glBindTexture(GL_TEXTURE_2D, tex.atlas->getName()); +bool GTARenderer::renderSubgeometry(Model* model, size_t g, size_t sg, const glm::mat4& matrix, GTAObject* object, bool queueTransparent) +{ + if(currentVBO != model->geometries[g]->VBO) { + glBindBuffer(GL_ARRAY_BUFFER, model->geometries[g]->VBO); + + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)model->geometries[g]->offsVert); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)model->geometries[g]->offsTexCoords); + glVertexAttribPointer(normalAttrib, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)model->geometries[g]->offsNormals); + glVertexAttribPointer(colourAttrib, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*)model->geometries[g]->offsColours); + glEnableVertexAttribArray(posAttrib); + glEnableVertexAttribArray(texAttrib); + glEnableVertexAttribArray(normalAttrib); + glEnableVertexAttribArray(colourAttrib); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->geometries[g]->EBO); + + currentVBO = model->geometries[g]->VBO; + } + + auto& subgeom = model->geometries[g]->subgeom[sg]; + + if (model->geometries[g]->materials.size() > subgeom.material) { + Model::Material& mat = model->geometries[g]->materials[subgeom.material]; + + if(mat.textures.size() > 0 ) { + TextureInfo& tex = engine->gameData.textures[mat.textures[0].name]; + if(tex.transparent && queueTransparent) { + return false; + } + glBindTexture(GL_TEXTURE_2D, tex.texName); + } + + if( (model->geometries[g]->flags & RW::BSGeometry::ModuleMaterialColor) == RW::BSGeometry::ModuleMaterialColor) { + auto colmasked = mat.colour; + size_t R = colmasked % 256; colmasked /= 256; + size_t G = colmasked % 256; colmasked /= 256; + size_t B = colmasked % 256; colmasked /= 256; + if( object && object->type() == GTAObject::Vehicle ) { + auto vehicle = static_cast(object); + if( R == 60 && G == 255 && B == 0 ) { + glUniform4f(uniCol, vehicle->colourPrimary.r, vehicle->colourPrimary.g, vehicle->colourPrimary.b, 1.f); + } + else if( R == 255 && G == 0 && B == 175 ) { + glUniform4f(uniCol, vehicle->colourSecondary.r, vehicle->colourSecondary.g, vehicle->colourSecondary.b, 1.f); } else { - glBindTexture(GL_TEXTURE_2D, tex.texName); + glUniform4f(uniCol, R/255.f, G/255.f, B/255.f, 1.f); } - } + } + else { + glUniform4f(uniCol, R/255.f, G/255.f, B/255.f, 1.f); + } + } - if( (model->geometries[g]->flags & RW::BSGeometry::ModuleMaterialColor) == RW::BSGeometry::ModuleMaterialColor) { - auto colmasked = mat.colour; - size_t R = colmasked % 256; colmasked /= 256; - size_t G = colmasked % 256; colmasked /= 256; - size_t B = colmasked % 256; colmasked /= 256; - if( object && object->type() == GTAObject::Vehicle ) { - auto vehicle = static_cast(object); - if( R == 60 && G == 255 && B == 0 ) { - glUniform4f(uniCol, vehicle->colourPrimary.r, vehicle->colourPrimary.g, vehicle->colourPrimary.b, 1.f); - } - else if( R == 255 && G == 0 && B == 175 ) { - glUniform4f(uniCol, vehicle->colourSecondary.r, vehicle->colourSecondary.g, vehicle->colourSecondary.b, 1.f); - } - else { - glUniform4f(uniCol, R/255.f, G/255.f, B/255.f, 1.f); - } - } - else { - glUniform4f(uniCol, R/255.f, G/255.f, B/255.f, 1.f); - } - } + glUniform1f(uniMatDiffuse, mat.diffuseIntensity); + glUniform1f(uniMatAmbient, mat.ambientIntensity); + } - glUniform1f(uniMatDiffuse, mat.diffuseIntensity); - glUniform1f(uniMatAmbient, mat.ambientIntensity); - } + rendered++; - rendered++; - - glDrawElements((model->geometries[g]->facetype == Model::Triangles ? - GL_TRIANGLES : GL_TRIANGLE_STRIP), - subgeom.numIndices, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * subgeom.start)); - } + glDrawElements((model->geometries[g]->facetype == Model::Triangles ? + GL_TRIANGLES : GL_TRIANGLE_STRIP), + subgeom.numIndices, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * subgeom.start)); + + return true; } void GTARenderer::renderModel(Model* model, const glm::mat4& modelMatrix, GTAObject* object, Animator *animator)