1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-15 06:52:34 +02:00

Improved handling of transparent materials (still needs work)

This commit is contained in:
Daniel Evans 2013-12-20 13:43:12 +00:00
parent ece92d30f0
commit 7c13efdc92
4 changed files with 125 additions and 67 deletions

View File

@ -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) {}
};
/**

View File

@ -4,6 +4,7 @@
#define GLEW_STATIC
#include <GL/glew.h>
#include <memory>
#include <vector>
#include <renderwure/render/ViewCamera.hpp>
@ -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<RQueueEntry> transparentDrawQueue;
public:

View File

@ -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<RW::BSTextureNative>();
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;

View File

@ -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<GTAVehicle*>(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<GTAVehicle*>(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)