From ec13272d8ca487d2a3695d12c5779937dd685e90 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sun, 12 Jul 2020 18:04:56 +0300 Subject: [PATCH 1/4] Adjust model uvs when used sprite texture changes --- src/hardware/hw_md2.c | 42 +++++++++++++++++++++++++++++++++-------- src/hardware/hw_model.c | 8 ++++++++ src/hardware/hw_model.h | 10 ++++++++++ 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 80c01f98c..05a70f6e8 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1177,6 +1177,7 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t return spr2; } +// Adjust texture coords of model to fit into a patch's max_s and max_t static void adjustTextureCoords(model_t *model, GLPatch_t *gpatch) { int i; @@ -1185,24 +1186,38 @@ static void adjustTextureCoords(model_t *model, GLPatch_t *gpatch) int j; mesh_t *mesh = &model->meshes[i]; int numVertices; - float *uvPtr = mesh->uvs; + float *uvReadPtr = mesh->originaluvs; + float *uvWritePtr; // i dont know if this is actually possible, just logical conclusion of structure in CreateModelVBOs - if (!mesh->frames && !mesh->tinyframes) return; + if (!mesh->frames && !mesh->tinyframes) continue; if (mesh->frames) // again CreateModelVBO and CreateModelVBOTiny iterate like this so I'm gonna do that too numVertices = mesh->numTriangles * 3; else numVertices = mesh->numVertices; + // if originaluvs points to uvs, we need to allocate new memory for adjusted uvs + // the old uvs are kept around for use in possible readjustments + if (mesh->uvs == mesh->originaluvs) + { + CONS_Printf("Debug: allocating memory for adjusted uvs\n"); + mesh->uvs = Z_Malloc(numVertices * 2 * sizeof(float), PU_STATIC, NULL); + } + + uvWritePtr = mesh->uvs; + // fix uvs (texture coordinates) to take into account that the actual texture // has empty space added until the next power of two for (j = 0; j < numVertices; j++) { - *uvPtr++ *= gpatch->max_s; - *uvPtr++ *= gpatch->max_t; + *uvWritePtr++ = *uvReadPtr++ * gpatch->max_s; + *uvWritePtr++ = *uvReadPtr++ * gpatch->max_t; } } + // Save the values we adjusted the uvs for + model->max_s = gpatch->max_s; + model->max_t = gpatch->max_t; } // @@ -1226,6 +1241,10 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) if (spr->precip) return false; + // Lactozilla: Disallow certain models from rendering + if (!HWR_AllowModel(spr->mobj)) + return false; + memset(&p, 0x00, sizeof(FTransform)); // MD2 colormap fix @@ -1344,10 +1363,6 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) } } - // Lactozilla: Disallow certain models from rendering - if (!HWR_AllowModel(spr->mobj)) - return false; - //HWD.pfnSetBlend(blend); // This seems to actually break translucency? finalscale = md2->scale; //Hurdler: arf, I don't like that implementation at all... too much crappy @@ -1391,6 +1406,17 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) { // Sprite gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); + // Check if sprite dimensions are different from previously used sprite. + // If so, uvs need to be readjusted. + if (gpatch->max_s != md2->model->max_s || gpatch->max_t != md2->model->max_t) + { + CONS_Printf("Debug: Readjusting uvs!\n"); + adjustTextureCoords(md2->model, gpatch); + // The vbo(s) are now wrong, so recreate them. + // If this turns out to be slow, then could try updating the vbos instead of + // deleting and creating new ones. + HWD.pfnCreateModelVBOs(md2->model); + } HWR_GetMappedPatch(gpatch, spr->colormap); } diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index ac73f8aca..cb22a2ec4 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -221,6 +221,14 @@ model_t *LoadModel(const char *filename, int ztag) material->shininess = 25.0f; } + // Set originaluvs to point to uvs + for (i = 0; i < model->numMeshes; i++) + model->meshes[i].originaluvs = model->meshes[i].uvs; + + // Set initial values to max_s and max_t + model->max_s = 1.0; + model->max_t = 1.0; + return model; } diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h index 2a5240bde..0b1834b52 100644 --- a/src/hardware/hw_model.h +++ b/src/hardware/hw_model.h @@ -59,6 +59,11 @@ typedef struct mesh_s int numTriangles; float *uvs; + // if uv adjustment is needed, uvs is changed to point to adjusted ones and + // this one retains the originals + // note: this member has been added with the assumption that models are never freed. + // (UnloadModel is called by nobody at the time of writing.) + float *originaluvs; float *lightuvs; int numFrames; @@ -99,6 +104,11 @@ typedef struct model_s char *framenames; boolean interpolate[256]; modelspr2frames_t *spr2frames; + + // the max_s and max_t values that the uvs are currently adjusted to + // (if a sprite is used as a texture) + float max_s; + float max_t; } model_t; extern int numModels; From afd0858b4d3a024b65fad944b1d20083018a6492 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Thu, 16 Jul 2020 22:11:36 +0300 Subject: [PATCH 2/4] More work on sprite-texture model uv adjustment --- src/hardware/hw_md2.c | 17 +++------ src/hardware/hw_model.h | 4 ++ src/hardware/r_opengl/r_opengl.c | 65 ++++++++++++++++++++++---------- 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index abb5267a9..05afff37f 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1200,10 +1200,7 @@ static void adjustTextureCoords(model_t *model, GLPatch_t *gpatch) // if originaluvs points to uvs, we need to allocate new memory for adjusted uvs // the old uvs are kept around for use in possible readjustments if (mesh->uvs == mesh->originaluvs) - { - CONS_Printf("Debug: allocating memory for adjusted uvs\n"); mesh->uvs = Z_Malloc(numVertices * 2 * sizeof(float), PU_STATIC, NULL); - } uvWritePtr = mesh->uvs; @@ -1349,10 +1346,13 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) if (md2->model) { md2_printModelInfo(md2->model); - // if model uses sprite patch as texture, then + // If model uses sprite patch as texture, then // adjust texture coordinates to take power of two textures into account if (!gpatch || !gpatch->mipmap->format) adjustTextureCoords(md2->model, spr->gpatch); + // note down the max_s and max_t that end up in the VBO + md2->model->vbo_max_s = md2->model->max_s; + md2->model->vbo_max_t = md2->model->max_t; HWD.pfnCreateModelVBOs(md2->model); } else @@ -1408,15 +1408,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); // Check if sprite dimensions are different from previously used sprite. // If so, uvs need to be readjusted. + // Comparing floats with the != operator here should be okay because they + // are just copies of glpatches' max_s and max_t values. if (gpatch->max_s != md2->model->max_s || gpatch->max_t != md2->model->max_t) - { - CONS_Printf("Debug: Readjusting uvs!\n"); adjustTextureCoords(md2->model, gpatch); - // The vbo(s) are now wrong, so recreate them. - // If this turns out to be slow, then could try updating the vbos instead of - // deleting and creating new ones. - HWD.pfnCreateModelVBOs(md2->model); - } HWR_GetMappedPatch(gpatch, spr->colormap); } diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h index 0b1834b52..6b39eb24d 100644 --- a/src/hardware/hw_model.h +++ b/src/hardware/hw_model.h @@ -109,6 +109,10 @@ typedef struct model_s // (if a sprite is used as a texture) float max_s; float max_t; + // These are the values that the uvs in the VBO have been adjusted to. + // If they are not same as max_s and max_t, then the VBO won't be used. + float vbo_max_s; + float vbo_max_t; } model_t; extern int numModels; diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 08d688e1d..a837b5e03 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2626,6 +2626,8 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 boolean useTinyFrames; + boolean useVBO = true; + int i; // Because otherwise, scaling the screen negatively vertically breaks the lighting @@ -2766,6 +2768,13 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 if (useTinyFrames) pglScalef(1 / 64.0f, 1 / 64.0f, 1 / 64.0f); + // Don't use the VBO if it does not have the correct texture coordinates. + // (Can happen when model uses a sprite as a texture and the sprite changes) + // Comparing floats with the != operator here should be okay because they + // are just copies of glpatches' max_s and max_t values. + if (model->vbo_max_s != model->max_s || model->vbo_max_t != model->max_t) + useVBO = false; + pglEnableClientState(GL_NORMAL_ARRAY); for (i = 0; i < model->numMeshes; i++) @@ -2782,13 +2791,24 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 if (!nextframe || fpclassify(pol) == FP_ZERO) { - pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID); - pglVertexPointer(3, GL_SHORT, sizeof(vbotiny_t), BUFFER_OFFSET(0)); - pglNormalPointer(GL_BYTE, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short)*3)); - pglTexCoordPointer(2, GL_FLOAT, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short) * 3 + sizeof(char) * 6)); + if (useVBO) + { + pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID); + pglVertexPointer(3, GL_SHORT, sizeof(vbotiny_t), BUFFER_OFFSET(0)); + pglNormalPointer(GL_BYTE, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short)*3)); + pglTexCoordPointer(2, GL_FLOAT, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short) * 3 + sizeof(char) * 6)); - pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices); - pglBindBuffer(GL_ARRAY_BUFFER, 0); + pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices); + pglBindBuffer(GL_ARRAY_BUFFER, 0); + } + else + { + //CONS_Printf("non-vbo tinyframe\n"); + pglVertexPointer(3, GL_SHORT, 0, frame->vertices); + pglNormalPointer(GL_BYTE, 0, frame->normals); + pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs); + pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices); + } } else { @@ -2824,21 +2844,26 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 if (!nextframe || fpclassify(pol) == FP_ZERO) { - // Zoom! Take advantage of just shoving the entire arrays to the GPU. -/* pglVertexPointer(3, GL_FLOAT, 0, frame->vertices); - pglNormalPointer(GL_FLOAT, 0, frame->normals); - pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs); - pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3);*/ + if (useVBO) + { + pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID); + pglVertexPointer(3, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(0)); + pglNormalPointer(GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 3)); + pglTexCoordPointer(2, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 6)); - pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID); - pglVertexPointer(3, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(0)); - pglNormalPointer(GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 3)); - pglTexCoordPointer(2, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 6)); - - pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3); - // No tinyframes, no mesh indices - //pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices); - pglBindBuffer(GL_ARRAY_BUFFER, 0); + pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3); + // No tinyframes, no mesh indices + //pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices); + pglBindBuffer(GL_ARRAY_BUFFER, 0); + } + else + { + //CONS_Printf("non-vbo frame\n"); + pglVertexPointer(3, GL_FLOAT, 0, frame->vertices); + pglNormalPointer(GL_FLOAT, 0, frame->normals); + pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs); + pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3); + } } else { From 0e5631fe667ccf6ff5b67c466ca12e84195410a0 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Thu, 16 Jul 2020 22:39:44 +0300 Subject: [PATCH 3/4] More work on sprite-texture model uv adjustment 2 --- src/hardware/hw_model.c | 3 ++- src/hardware/r_opengl/r_opengl.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index cb22a2ec4..4ed03744b 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -225,9 +225,10 @@ model_t *LoadModel(const char *filename, int ztag) for (i = 0; i < model->numMeshes; i++) model->meshes[i].originaluvs = model->meshes[i].uvs; - // Set initial values to max_s and max_t model->max_s = 1.0; model->max_t = 1.0; + model->vbo_max_s = 1.0; + model->vbo_max_t = 1.0; return model; } diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index a837b5e03..195f3d6f7 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2803,7 +2803,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 } else { - //CONS_Printf("non-vbo tinyframe\n"); pglVertexPointer(3, GL_SHORT, 0, frame->vertices); pglNormalPointer(GL_BYTE, 0, frame->normals); pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs); @@ -2858,7 +2857,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 } else { - //CONS_Printf("non-vbo frame\n"); pglVertexPointer(3, GL_FLOAT, 0, frame->vertices); pglNormalPointer(GL_FLOAT, 0, frame->normals); pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs); From bda1d1e725de9b7a857bdb800e07b23c002a7097 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 18 Aug 2020 23:21:26 +0300 Subject: [PATCH 4/4] Convince the compiler that I know what I'm doing, I think --- src/hardware/hw_md2.c | 4 +++- src/hardware/r_opengl/r_opengl.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 05afff37f..5f5130896 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1410,7 +1410,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // If so, uvs need to be readjusted. // Comparing floats with the != operator here should be okay because they // are just copies of glpatches' max_s and max_t values. - if (gpatch->max_s != md2->model->max_s || gpatch->max_t != md2->model->max_t) + // Instead of the != operator, memcmp is used to avoid a compiler warning. + if (memcmp(&(gpatch->max_s), &(md2->model->max_s), sizeof(md2->model->max_s)) != 0 || + memcmp(&(gpatch->max_t), &(md2->model->max_t), sizeof(md2->model->max_t)) != 0) adjustTextureCoords(md2->model, gpatch); HWR_GetMappedPatch(gpatch, spr->colormap); } diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 195f3d6f7..da86dc0fd 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2772,7 +2772,9 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 // (Can happen when model uses a sprite as a texture and the sprite changes) // Comparing floats with the != operator here should be okay because they // are just copies of glpatches' max_s and max_t values. - if (model->vbo_max_s != model->max_s || model->vbo_max_t != model->max_t) + // Instead of the != operator, memcmp is used to avoid a compiler warning. + if (memcmp(&(model->vbo_max_s), &(model->max_s), sizeof(model->max_s)) != 0 || + memcmp(&(model->vbo_max_t), &(model->max_t), sizeof(model->max_t)) != 0) useVBO = false; pglEnableClientState(GL_NORMAL_ARRAY);