Merge branch 'ogl-model-uv-adjust' into 'next'

Re-adjust model UVs when sprite texture dimensions change

See merge request STJr/SRB2!1068
This commit is contained in:
SteelT 2020-09-25 21:19:59 -04:00
commit 060f46653d
4 changed files with 100 additions and 29 deletions

View File

@ -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,35 @@ 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)
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 +1238,10 @@ boolean HWR_DrawModel(gl_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
@ -1330,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
@ -1344,10 +1363,6 @@ boolean HWR_DrawModel(gl_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,14 @@ boolean HWR_DrawModel(gl_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.
// Comparing floats with the != operator here should be okay because they
// are just copies of glpatches' max_s and max_t values.
// 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);
}

View File

@ -221,6 +221,15 @@ 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;
model->max_s = 1.0;
model->max_t = 1.0;
model->vbo_max_s = 1.0;
model->vbo_max_t = 1.0;
return model;
}

View File

@ -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,15 @@ 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;
// 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;

View File

@ -2535,6 +2535,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
@ -2678,6 +2680,15 @@ 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.
// 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);
for (i = 0; i < model->numMeshes; i++)
@ -2694,13 +2705,23 @@ 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
{
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
{
@ -2736,21 +2757,25 @@ 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
{
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
{