r698 - trunk
lordhavoc at icculus.org
lordhavoc at icculus.org
Sat Apr 8 23:55:57 EDT 2006
Author: lordhavoc
Date: 2006-04-08 23:55:57 -0400 (Sat, 08 Apr 2006)
New Revision: 698
Modified:
trunk/model.c
trunk/model.h
Log:
no longer stores skeletal data about md5mesh files that contain only one
bone, this saves a bit of memory
Modified: trunk/model.c
===================================================================
--- trunk/model.c 2006-04-09 03:10:04 UTC (rev 697)
+++ trunk/model.c 2006-04-09 03:55:57 UTC (rev 698)
@@ -215,11 +215,12 @@
void Model_Load(ResourceEntry *r)
{
Util_ParseC_Thread thread;
- NUint32 meshnum, version;
+ NUint32 meshnum, version, numjoints = 0;
Nbool error;
Nsize filesize;
Model *model;
char *filedata;
+ Nbool isskeletal = false;
model = Mem_Alloc(r->memzone, sizeof(Model));
@@ -275,14 +276,19 @@
//numJoints 3
else if (Util_ParseC_MatchKeyword(&thread, "numJoints"))
{
- LoadInt(model->num_transforms, "after 'numJoints'");
- if (model->num_transforms < 1)
+ LoadInt(numjoints, "after 'numJoints'");
+ if (numjoints < 1)
{
- Console_Printf("Model_Load: numJoints %i < 1\n", model->num_transforms);
+ Console_Printf("Model_Load: numJoints %i < 1\n", numjoints);
Abort();
}
- model->max_transforms = model->num_transforms;
- model->data_transforminfo = Mem_Alloc(r->memzone, model->max_transforms * sizeof(*model->data_transforminfo));
+ if (numjoints > 1)
+ {
+ isskeletal = true;
+ model->num_transforms = numjoints;
+ model->max_transforms = model->num_transforms;
+ model->data_transforminfo = Mem_Alloc(r->memzone, model->max_transforms * sizeof(*model->data_transforminfo));
+ }
}
//numMeshes 1
else if (Util_ParseC_MatchKeyword(&thread, "numMeshes"))
@@ -303,35 +309,44 @@
//}
else if (Util_ParseC_MatchKeyword(&thread, "joints"))
{
+ char *name = NULL;
NUint32 jointnum;
ExpectKeyword("{", "after 'joints'");
for (jointnum = 0; !Util_ParseC_MatchKeyword(&thread, "}");jointnum++)
{
NSint32 parent;
+ Nfloat pose[6];
// "root" -1 ( 0.000000 0.000000 0.000000 ) ( -0.707107 -0.000000 -0.000000 )
- LoadString(model->data_transforminfo[jointnum].name, "for joint name");
+ LoadString(name, "for joint name");
LoadInt(parent, "as parent");
ExpectKeyword("(", "before first joint data list");
- LoadValue(model->data_transforminfo[jointnum].basepose[0], "(joint 0)");
- LoadValue(model->data_transforminfo[jointnum].basepose[1], "(joint 1)");
- LoadValue(model->data_transforminfo[jointnum].basepose[2], "(joint 2)");
+ LoadValue(pose[0], "(joint 0)");
+ LoadValue(pose[1], "(joint 1)");
+ LoadValue(pose[2], "(joint 2)");
ExpectKeyword(")", "after first joint data list");
ExpectKeyword("(", "before second joint data list");
- LoadValue(model->data_transforminfo[jointnum].basepose[3], "(joint 3)");
- LoadValue(model->data_transforminfo[jointnum].basepose[4], "(joint 4)");
- LoadValue(model->data_transforminfo[jointnum].basepose[5], "(joint 5)");
+ LoadValue(pose[3], "(joint 3)");
+ LoadValue(pose[4], "(joint 4)");
+ LoadValue(pose[5], "(joint 5)");
ExpectKeyword(")", "after second joint data list");
- Matrix4x4_CreateFromDoom3Joint(&model->data_transforminfo[jointnum].basematrix, model->data_transforminfo[jointnum].basepose[0], model->data_transforminfo[jointnum].basepose[1], model->data_transforminfo[jointnum].basepose[2], model->data_transforminfo[jointnum].basepose[3], model->data_transforminfo[jointnum].basepose[4], model->data_transforminfo[jointnum].basepose[5]);
- Matrix4x4_Invert_Simple(&model->data_transforminfo[jointnum].baseinversematrix, &model->data_transforminfo[jointnum].basematrix);
if (parent >= (NSint32)jointnum)
{
+ String_Free(&name);
Console_Printf("Model_Load: joint.parent (%i) >= joint (%i)\n", parent, jointnum);
Abort();
}
+ if (isskeletal)
+ {
+ Matrix4x4_CreateFromDoom3Joint(&model->data_transforminfo[jointnum].basematrix, pose[0], pose[1], pose[2], pose[3], pose[4], pose[5]);
+ Matrix4x4_Invert_Simple(&model->data_transforminfo[jointnum].baseinversematrix, &model->data_transforminfo[jointnum].basematrix);
+ model->data_transforminfo[jointnum].name = name;
+ name = NULL;
+ }
}
- if (jointnum != model->num_transforms)
+ String_Free(&name);
+ if (jointnum != numjoints)
{
- Console_Printf("Model_Load: final jointnum (%i) != numJoints (%i)\n", jointnum, model->num_transforms);
+ Console_Printf("Model_Load: final jointnum (%i) != numJoints (%i)\n", jointnum, numjoints);
Abort();
}
}
@@ -377,8 +392,11 @@
mesh->data_normal3f = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(float[3]));
mesh->data_texcoord2f = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(float[2]));
mesh->data_lightmaptexcoord2f = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(float[2]));
- mesh->data_weightindex4b = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(NUint8[4]));
- mesh->data_weightvalue4b = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(NUint8[4]));
+ if (isskeletal)
+ {
+ mesh->data_weightindex4b = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(NUint8[4]));
+ mesh->data_weightvalue4b = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(NUint8[4]));
+ }
md5weightrange = Mem_Alloc(Global_Zone, mesh->max_vertices * sizeof(NUint32[2]));
}
// vert 0 ( 0.142532 0.983877 ) 0 1
@@ -469,9 +487,9 @@
md5weight = md5weights + weightnum;
// 2
LoadInt(md5weight->jointnum, "(weight jointnum)");
- if (md5weight->jointnum >= model->num_transforms)
+ if (md5weight->jointnum >= numjoints)
{
- Console_Printf("Model_Load: joint (%i) >= num_transforms (%i)\n", md5weight->jointnum, model->num_transforms);
+ Console_Printf("Model_Load: joint (%i) >= numjoints (%i)\n", md5weight->jointnum, numjoints);
Abort();
}
// 1.000000
@@ -497,57 +515,68 @@
}
}
memset(mesh->data_vertex3f, 0, mesh->num_vertices * sizeof(float[3]));
- for (i = 0;i < mesh->num_vertices;i++)
+ if (isskeletal)
{
- Ndouble sum = 0;
- NUint32 k;
- NUint32 wi[4];
- Nfloat wf[4];
- Vector4Clear(wi);
- Vector4Clear(wf);
- for (j = 0, md5weight = md5weights + md5weightrange[i*2+0];j < md5weightrange[i*2+1];j++, md5weight++)
+ // convert the skeletal data from doom3 vertex weights to
+ // matrix palette weights (usable by a vertex shader)
+ for (i = 0;i < mesh->num_vertices;i++)
{
- matrix = &model->data_transforminfo[md5weight->jointnum].basematrix;
- mesh->data_vertex3f[i*3+0] += DotProduct4(md5weight->vertex, matrix->m[0]);
- mesh->data_vertex3f[i*3+1] += DotProduct4(md5weight->vertex, matrix->m[1]);
- mesh->data_vertex3f[i*3+2] += DotProduct4(md5weight->vertex, matrix->m[2]);
- // store the best weights in the vertex's limited number of blend weights
- for (k = 4;k >= 1 && mesh->data_weightvalue4b[i*4+k-1] < md5weight->vertex[3];k--)
+ Ndouble sum = 0;
+ NUint32 k;
+ NUint32 wi[4];
+ Nfloat wf[4];
+ Vector4Clear(wi);
+ Vector4Clear(wf);
+ for (j = 0, md5weight = md5weights + md5weightrange[i*2+0];j < md5weightrange[i*2+1];j++, md5weight++)
{
+ matrix = &model->data_transforminfo[md5weight->jointnum].basematrix;
+ mesh->data_vertex3f[i*3+0] += DotProduct4(md5weight->vertex, matrix->m[0]);
+ mesh->data_vertex3f[i*3+1] += DotProduct4(md5weight->vertex, matrix->m[1]);
+ mesh->data_vertex3f[i*3+2] += DotProduct4(md5weight->vertex, matrix->m[2]);
+ // store the best weights in the vertex's limited number of blend weights
+ for (k = 4;k >= 1 && mesh->data_weightvalue4b[i*4+k-1] < md5weight->vertex[3];k--)
+ {
+ if (k < 4)
+ {
+ wi[k] = wi[k-1];
+ wf[k] = wf[k-1];
+ }
+ }
if (k < 4)
{
- wi[k] = wi[k-1];
- wf[k] = wf[k-1];
+ wi[k] = md5weight->jointnum;
+ wf[k] = md5weight->vertex[3];
}
+ sum += md5weight->vertex[3];
}
- if (k < 4)
+ if (fabs(sum - 1) > 0.001)
+ Console_Printf("vertex #%i (weights %i-%i) does not sum to 1! (sum = %f)\n", i, md5weightrange[i*2+0], md5weightrange[i*2+0]+md5weightrange[i*2+1], sum);
+ if (wf[3] > wf[2] || wf[2] > wf[1] || wf[1] > wf[0])
+ Console_Printf("vertex sorting error! vertex #%i has weights %i:%f %i:%f %i:%f %i:%f\n", i, wi[0], wf[0], wi[1], wf[1], wi[2], wf[2], wi[3], wf[3]);
+ // renormalize the array of strongest weights on this vertex
+ sum = 0;
+ for (k = 0;k < 4;k++)
+ sum += wf[k];
+ if (sum)
{
- wi[k] = md5weight->jointnum;
- wf[k] = md5weight->vertex[3];
+ sum = 1.0f / sum;
+ for (k = 0;k < 4;k++)
+ wf[k] *= sum;
}
- sum += md5weight->vertex[3];
- }
- if (fabs(sum - 1) > 0.001)
- Console_Printf("vertex #%i (weights %i-%i) does not sum to 1! (sum = %f)\n", i, md5weightrange[i*2+0], md5weightrange[i*2+0]+md5weightrange[i*2+1], sum);
- if (wf[3] > wf[2] || wf[2] > wf[1] || wf[1] > wf[0])
- Console_Printf("vertex sorting error! vertex #%i has weights %i:%f %i:%f %i:%f %i:%f\n", i, wi[0], wf[0], wi[1], wf[1], wi[2], wf[2], wi[3], wf[3]);
- // renormalize the array of strongest weights on this vertex
- sum = 0;
- for (k = 0;k < 4;k++)
- sum += wf[k];
- if (sum)
- {
- sum = 1.0f / sum;
+ // now convert to the compact format used for longterm storage
for (k = 0;k < 4;k++)
- wf[k] *= sum;
+ {
+ mesh->data_weightindex4b[i*4+k] = (NUint8)wi[k];
+ mesh->data_weightvalue4b[i*4+k] = (NUint8)(wf[k] * 255.0f);
+ }
}
- // now convert to the compact format used for longterm storage
- for (k = 0;k < 4;k++)
- {
- mesh->data_weightindex4b[i*4+k] = (NUint8)wi[k];
- mesh->data_weightvalue4b[i*4+k] = (NUint8)(wf[k] * 255.0f);
- }
}
+ else
+ {
+ // non-skeletal
+ for (i = 0;i < mesh->num_vertices;i++)
+ VectorCopy(md5weights[md5weightrange[i*2+0]].vertex, mesh->data_vertex3f + i*3);
+ }
// compile the base frame of the mesh for static uses
Model_MeshVectors(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_svector3f, mesh->data_tvector3f, mesh->data_normal3f);
Model_MeshNeighbors(mesh->num_triangles, mesh->data_element3i, mesh->data_neighbor3i, mesh->num_vertices);
@@ -590,15 +619,18 @@
mesh->basecullmaxs[1] = Max(mesh->basecullmaxs[1], mesh->data_vertex3f[i * 3 + 1]);
mesh->basecullmaxs[2] = Max(mesh->basecullmaxs[2], mesh->data_vertex3f[i * 3 + 2]);
}
- for (k = 0;k < 4 && mesh->data_weightvalue4b[i*4+k] > 0;k++)
+ if (isskeletal)
{
- NUint32 index = mesh->data_weightindex4b[i*4+k];
- Nvec3 v1, v;
- Nvec r;
- VectorCopy(mesh->data_vertex3f + i * 3, v1);
- Matrix4x4_Transform(&model->data_transforminfo[index].baseinversematrix, v1, v);
- r = VectorLength(v);
- model->data_transforminfo[index].radius = Max(model->data_transforminfo[index].radius, r);
+ for (k = 0;k < 4 && mesh->data_weightvalue4b[i*4+k] > 0;k++)
+ {
+ NUint32 index = mesh->data_weightindex4b[i*4+k];
+ Nvec3 v1, v;
+ Nvec r;
+ VectorCopy(mesh->data_vertex3f + i * 3, v1);
+ Matrix4x4_Transform(&model->data_transforminfo[index].baseinversematrix, v1, v);
+ r = VectorLength(v);
+ model->data_transforminfo[index].radius = Max(model->data_transforminfo[index].radius, r);
+ }
}
}
Mem_Free(&md5weights);
@@ -653,7 +685,9 @@
if (meshindex >= model->num_meshes)
return; // invalid mesh index
mesh = model->data_meshes + meshindex;
- if (!transforms)
+ // if the caller is not requesting skeletal animation or if the model
+ // doesn't even support animation, just return the undeformed arrays
+ if (!transforms || !mesh->data_weightvalue4b)
{
if (outvertex3f)
{
Modified: trunk/model.h
===================================================================
--- trunk/model.h 2006-04-09 03:10:04 UTC (rev 697)
+++ trunk/model.h 2006-04-09 03:55:57 UTC (rev 698)
@@ -47,6 +47,8 @@
// (aka bumpmapped) lighting.
// location of vertex
float *data_vertex3f;
+ // TODO: these should be used only in the vertex shader
+ // TODO: when vertex shader is used, replace svector tvector normal with a 4 byte quaternion to save memory
// direction of S texcoord
float *data_svector3f;
// direction of T texcoord
@@ -57,6 +59,7 @@
float *data_texcoord2f;
// lightmap texture coordinates for vertices in this mesh
float *data_lightmaptexcoord2f;
+ // NOTE: on non-skeletal models all weight stuff is NULL!
// indices of up to 4 transforms per vertex
NUint8 *data_weightindex4b;
// blending influence values of up to 4 transforms per vertex
@@ -81,6 +84,7 @@
NUint32 max_meshes;
Model_Mesh *data_meshes;
+ // NOTE: on non-skeletal models all transform stuff is 0 or NULL!
NUint32 num_transforms;
NUint32 max_transforms;
Model_TransformInfo *data_transforminfo;
More information about the neither-commits
mailing list