summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2013-03-22 13:43:06 +0400
committerAndrey Nazarov <skuller@skuller.net>2013-03-22 13:51:50 +0400
commit8afc649d1f53606a4bd1c46dd6f8f9ab165b8303 (patch)
tree6ca81f90e8f84ccd699e5a0176124dbe46bd18b3 /src
parent376bef83ff1fef84baa45631038a9bd9df46e2e8 (diff)
Clean up and fix MD2 model loading code.
Bump maximum number of vertices MD2 model can have to 4096 from original limit of 2048. Some semi-broken models exist that have triangles with indices set to -1. Simply skip such bad triangles and make GL renderer load the model anyway. Correctly cap total number of vertices after remapping. Ignore invalid light normal indices instead of exiting with error.
Diffstat (limited to 'src')
-rw-r--r--src/refresh/gl/gl.h3
-rw-r--r--src/refresh/gl/mesh.c2
-rw-r--r--src/refresh/gl/models.c169
-rw-r--r--src/refresh/models.c4
-rw-r--r--src/refresh/sw/alias.c2
-rw-r--r--src/refresh/sw/sw.h1
6 files changed, 103 insertions, 78 deletions
diff --git a/src/refresh/gl/gl.h b/src/refresh/gl/gl.h
index 3064967..5e644e6 100644
--- a/src/refresh/gl/gl.h
+++ b/src/refresh/gl/gl.h
@@ -423,8 +423,7 @@ void GL_ShutdownImages(void);
* gl_tess.c
*
*/
-#define TESS_MAX_FACES 256
-#define TESS_MAX_VERTICES (16 * TESS_MAX_FACES)
+#define TESS_MAX_VERTICES 4096
#define TESS_MAX_INDICES (3 * TESS_MAX_VERTICES)
typedef struct {
diff --git a/src/refresh/gl/mesh.c b/src/refresh/gl/mesh.c
index e469339..490a64e 100644
--- a/src/refresh/gl/mesh.c
+++ b/src/refresh/gl/mesh.c
@@ -591,7 +591,7 @@ static void draw_alias_mesh(maliasmesh_t *mesh)
GL_BindTexture(0, texnum_for_mesh(mesh));
(*tessfunc)(mesh);
- c.trisDrawn += mesh->numverts;
+ c.trisDrawn += mesh->numtris;
if (shadelight) {
GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR);
diff --git a/src/refresh/gl/models.c b/src/refresh/gl/models.c
index b9fc8e2..22119cd 100644
--- a/src/refresh/gl/models.c
+++ b/src/refresh/gl/models.c
@@ -21,29 +21,36 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "format/md3.h"
#include "format/sp2.h"
+#if MAX_ALIAS_VERTS > TESS_MAX_VERTICES
+#error TESS_MAX_VERTICES
+#endif
+
+#if MD2_MAX_TRIANGLES > TESS_MAX_INDICES / 3
+#error TESS_MAX_INDICES
+#endif
+
qerror_t MOD_LoadMD2(model_t *model, const void *rawdata, size_t length)
{
- dmd2header_t header;
- dmd2frame_t *src_frame;
- dmd2trivertx_t *src_vert;
- dmd2triangle_t *src_tri;
- dmd2stvert_t *src_tc;
- maliasframe_t *dst_frame;
- maliasvert_t *dst_vert;
- maliasmesh_t *dst_mesh;
- QGL_INDEX_TYPE *finalIndices;
- maliastc_t *dst_tc;
- int i, j, k;
- uint16_t remap[MD2_MAX_TRIANGLES * 3];
- uint16_t vertIndices[MD2_MAX_TRIANGLES * 3];
- uint16_t tcIndices[MD2_MAX_TRIANGLES * 3];
- int numverts, numindices;
- char skinname[MAX_QPATH];
- char *src_skin;
- vec_t scaleS, scaleT;
- int val;
- vec3_t mins, maxs;
- qerror_t ret;
+ dmd2header_t header;
+ dmd2frame_t *src_frame;
+ dmd2trivertx_t *src_vert;
+ dmd2triangle_t *src_tri;
+ dmd2stvert_t *src_tc;
+ char *src_skin;
+ maliasframe_t *dst_frame;
+ maliasvert_t *dst_vert;
+ maliasmesh_t *dst_mesh;
+ maliastc_t *dst_tc;
+ int i, j, k, val;
+ uint16_t remap[TESS_MAX_INDICES];
+ uint16_t vertIndices[TESS_MAX_INDICES];
+ uint16_t tcIndices[TESS_MAX_INDICES];
+ uint16_t finalIndices[TESS_MAX_INDICES];
+ int numverts, numindices;
+ char skinname[MAX_QPATH];
+ vec_t scale_s, scale_t;
+ vec3_t mins, maxs;
+ qerror_t ret;
if (length < sizeof(header)) {
return Q_ERR_FILE_TOO_SMALL;
@@ -66,44 +73,40 @@ qerror_t MOD_LoadMD2(model_t *model, const void *rawdata, size_t length)
return ret;
}
- Hunk_Begin(&model->hunk, 0x400000);
- model->type = MOD_ALIAS;
-
// load all triangle indices
+ numindices = 0;
src_tri = (dmd2triangle_t *)((byte *)rawdata + header.ofs_tris);
for (i = 0; i < header.num_tris; i++) {
for (j = 0; j < 3; j++) {
uint16_t idx_xyz = LittleShort(src_tri->index_xyz[j]);
uint16_t idx_st = LittleShort(src_tri->index_st[j]);
+ // some broken models have 0xFFFF indices
if (idx_xyz >= header.num_xyz || idx_st >= header.num_st) {
- ret = Q_ERR_BAD_INDEX;
- goto fail;
+ break;
}
- vertIndices[i * 3 + j] = idx_xyz;
- tcIndices[i * 3 + j] = idx_st;
+ vertIndices[numindices + j] = idx_xyz;
+ tcIndices[numindices + j] = idx_st;
+ }
+ if (j == 3) {
+ // only count good triangles
+ numindices += 3;
}
src_tri++;
}
- numindices = header.num_tris * 3;
-
- model->meshes = MOD_Malloc(sizeof(maliasmesh_t));
- model->nummeshes = 1;
-
- dst_mesh = model->meshes;
- dst_mesh->indices = MOD_Malloc(numindices * sizeof(QGL_INDEX_TYPE));
- dst_mesh->numtris = header.num_tris;
- dst_mesh->numindices = numindices;
+ if (numindices < 3) {
+ return Q_ERR_TOO_FEW;
+ }
for (i = 0; i < numindices; i++) {
remap[i] = 0xFFFF;
}
+ // remap all triangle indices
numverts = 0;
src_tc = (dmd2stvert_t *)((byte *)rawdata + header.ofs_st);
- finalIndices = dst_mesh->indices;
for (i = 0; i < numindices; i++) {
if (remap[i] != 0xFFFF) {
continue; // already remapped
@@ -124,9 +127,34 @@ qerror_t MOD_LoadMD2(model_t *model, const void *rawdata, size_t length)
finalIndices[i] = numverts++;
}
+ if (numverts > TESS_MAX_VERTICES) {
+ return Q_ERR_TOO_MANY;
+ }
+
+ Hunk_Begin(&model->hunk, 0x400000);
+ model->type = MOD_ALIAS;
+ model->nummeshes = 1;
+ model->numframes = header.num_frames;
+ model->meshes = MOD_Malloc(sizeof(maliasmesh_t));
+ model->frames = MOD_Malloc(header.num_frames * sizeof(maliasframe_t));
+
+ dst_mesh = model->meshes;
+ dst_mesh->numtris = numindices / 3;
+ dst_mesh->numindices = numindices;
+ dst_mesh->numverts = numverts;
+ dst_mesh->numskins = header.num_skins;
dst_mesh->verts = MOD_Malloc(numverts * header.num_frames * sizeof(maliasvert_t));
dst_mesh->tcoords = MOD_Malloc(numverts * sizeof(maliastc_t));
- dst_mesh->numverts = numverts;
+ dst_mesh->indices = MOD_Malloc(numindices * sizeof(QGL_INDEX_TYPE));
+
+ if (dst_mesh->numtris != header.num_tris) {
+ Com_DPrintf("%s has %d bad triangles\n", model->name, header.num_tris - dst_mesh->numtris);
+ }
+
+ // store final triangle indices
+ for (i = 0; i < numindices; i++) {
+ dst_mesh->indices[i] = finalIndices[i];
+ }
// load all skins
src_skin = (char *)rawdata + header.ofs_skins;
@@ -139,27 +167,23 @@ qerror_t MOD_LoadMD2(model_t *model, const void *rawdata, size_t length)
dst_mesh->skins[i] = IMG_Find(skinname, IT_SKIN, IF_NONE);
src_skin += MD2_MAX_SKINNAME;
}
- dst_mesh->numskins = header.num_skins;
// load all tcoords
src_tc = (dmd2stvert_t *)((byte *)rawdata + header.ofs_st);
dst_tc = dst_mesh->tcoords;
- scaleS = 1.0f / header.skinwidth;
- scaleT = 1.0f / header.skinheight;
+ scale_s = 1.0f / header.skinwidth;
+ scale_t = 1.0f / header.skinheight;
for (i = 0; i < numindices; i++) {
- if (remap[i] == i) {
- float s = (int16_t)LittleShort(src_tc[tcIndices[i]].s);
- float t = (int16_t)LittleShort(src_tc[tcIndices[i]].t);
-
- dst_tc[finalIndices[i]].st[0] = s * scaleS;
- dst_tc[finalIndices[i]].st[1] = t * scaleT;
+ if (remap[i] != i) {
+ continue;
}
+ dst_tc[finalIndices[i]].st[0] =
+ (int16_t)LittleShort(src_tc[tcIndices[i]].s) * scale_s;
+ dst_tc[finalIndices[i]].st[1] =
+ (int16_t)LittleShort(src_tc[tcIndices[i]].t) * scale_t;
}
// load all frames
- model->frames = MOD_Malloc(header.num_frames * sizeof(maliasframe_t));
- model->numframes = header.num_frames;
-
src_frame = (dmd2frame_t *)((byte *)rawdata + header.ofs_frames);
dst_frame = model->frames;
for (j = 0; j < header.num_frames; j++) {
@@ -169,28 +193,31 @@ qerror_t MOD_LoadMD2(model_t *model, const void *rawdata, size_t length)
// load frame vertices
ClearBounds(mins, maxs);
for (i = 0; i < numindices; i++) {
- if (remap[i] == i) {
- src_vert = &src_frame->verts[vertIndices[i]];
- dst_vert = &dst_mesh->verts[j * numverts + finalIndices[i]];
+ if (remap[i] != i) {
+ continue;
+ }
+ src_vert = &src_frame->verts[vertIndices[i]];
+ dst_vert = &dst_mesh->verts[j * numverts + finalIndices[i]];
+
+ dst_vert->pos[0] = src_vert->v[0];
+ dst_vert->pos[1] = src_vert->v[1];
+ dst_vert->pos[2] = src_vert->v[2];
- dst_vert->pos[0] = src_vert->v[0];
- dst_vert->pos[1] = src_vert->v[1];
- dst_vert->pos[2] = src_vert->v[2];
- k = src_vert->lightnormalindex;
- if (k >= NUMVERTEXNORMALS) {
- ret = Q_ERR_BAD_INDEX;
- goto fail;
- }
- dst_vert->norm[0] = gl_static.latlngtab[k][0];
- dst_vert->norm[1] = gl_static.latlngtab[k][1];
+ val = src_vert->lightnormalindex;
+ if (val >= NUMVERTEXNORMALS) {
+ dst_vert->norm[0] = 0;
+ dst_vert->norm[1] = 0;
+ } else {
+ dst_vert->norm[0] = gl_static.latlngtab[val][0];
+ dst_vert->norm[1] = gl_static.latlngtab[val][1];
+ }
- for (k = 0; k < 3; k++) {
- val = dst_vert->pos[k];
- if (val < mins[k])
- mins[k] = val;
- if (val > maxs[k])
- maxs[k] = val;
- }
+ for (k = 0; k < 3; k++) {
+ val = dst_vert->pos[k];
+ if (val < mins[k])
+ mins[k] = val;
+ if (val > maxs[k])
+ maxs[k] = val;
}
}
diff --git a/src/refresh/models.c b/src/refresh/models.c
index fc11d8b..e11cb59 100644
--- a/src/refresh/models.c
+++ b/src/refresh/models.c
@@ -159,7 +159,7 @@ qerror_t MOD_ValidateMD2(dmd2header_t *header, size_t length)
// check st
if (header->num_st < 3)
return Q_ERR_TOO_FEW;
- if (header->num_st > MD2_MAX_VERTS)
+ if (header->num_st > MAX_ALIAS_VERTS)
return Q_ERR_TOO_MANY;
end = header->ofs_st + sizeof(dmd2stvert_t) * header->num_st;
@@ -169,7 +169,7 @@ qerror_t MOD_ValidateMD2(dmd2header_t *header, size_t length)
// check xyz and frames
if (header->num_xyz < 3)
return Q_ERR_TOO_FEW;
- if (header->num_xyz > MD2_MAX_VERTS)
+ if (header->num_xyz > MAX_ALIAS_VERTS)
return Q_ERR_TOO_MANY;
if (header->num_frames < 1)
return Q_ERR_TOO_FEW;
diff --git a/src/refresh/sw/alias.c b/src/refresh/sw/alias.c
index 5d2c2e0..9d7e402 100644
--- a/src/refresh/sw/alias.c
+++ b/src/refresh/sw/alias.c
@@ -277,7 +277,7 @@ static void R_AliasPreparePoints(void)
maliasst_t *pstverts;
maliastri_t *ptri;
finalvert_t *pfv[3];
- finalvert_t finalverts[MAXALIASVERTS +
+ finalvert_t finalverts[MAX_ALIAS_VERTS +
((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 3];
finalvert_t *pfinalverts;
diff --git a/src/refresh/sw/sw.h b/src/refresh/sw/sw.h
index 1fea7ee..d00681a 100644
--- a/src/refresh/sw/sw.h
+++ b/src/refresh/sw/sw.h
@@ -102,7 +102,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define NEAR_CLIP 0.01
-#define MAXALIASVERTS 2048 // MD2_MAX_VERTS
#define ALIAS_Z_CLIP_PLANE 4
// turbulence stuff