X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=model_alias.c;h=df2d5c03cb4f067d235597b79cbd23092d6186e2;hb=6083bf03e54784cb921a0ed5cbddaca25c65d83f;hp=4377c021578e248a59540ccaf0a1935083916cdc;hpb=1c341aa1923856369c95aa2be1268f71e4ff65b4;p=xonotic%2Fdarkplaces.git diff --git a/model_alias.c b/model_alias.c index 4377c021..df2d5c03 100644 --- a/model_alias.c +++ b/model_alias.c @@ -29,24 +29,42 @@ cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "deve cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"}; cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"}; +float mod_md3_sin[320]; + void Mod_AliasInit (void) { + int i; Cvar_RegisterVariable(&r_skeletal_debugbone); Cvar_RegisterVariable(&r_skeletal_debugbonecomponent); Cvar_RegisterVariable(&r_skeletal_debugbonevalue); Cvar_RegisterVariable(&r_skeletal_debugtranslatex); Cvar_RegisterVariable(&r_skeletal_debugtranslatey); Cvar_RegisterVariable(&r_skeletal_debugtranslatez); + for (i = 0;i < 320;i++) + mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0); } -void Mod_Alias_GetMesh_Vertex3f(const model_t *model, const frameblend_t *frameblend, float *out3f) +void Mod_Alias_GetMesh_Vertices(const model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f) { - if (model->surfmesh.num_vertexboneweights) + if (model->surfmesh.data_vertexweightindex4i) { int i, k, blends; - surfmeshvertexboneweight_t *v; - float *out, *matrix, m[12], bonepose[256][12]; + const float *v = model->surfmesh.data_vertex3f; + const float *n = model->surfmesh.data_normal3f; + const float *sv = model->surfmesh.data_svector3f; + const float *tv = model->surfmesh.data_tvector3f; + const int *wi = model->surfmesh.data_vertexweightindex4i; + const float *wf = model->surfmesh.data_vertexweightinfluence4f; + float *matrix, m[12], bonepose[256][12], boneposerelative[256][12]; // vertex weighted skeletal + memset(vertex3f, 0, model->surfmesh.num_vertices * sizeof(float[3])); + if (normal3f) + memset(normal3f, 0, model->surfmesh.num_vertices * sizeof(float[3])); + if (svector3f) + { + memset(svector3f, 0, model->surfmesh.num_vertices * sizeof(float[3])); + memset(tvector3f, 0, model->surfmesh.num_vertices * sizeof(float[3])); + } // interpolate matrices and concatenate them to their parents for (i = 0;i < model->num_bones;i++) { @@ -68,56 +86,168 @@ void Mod_Alias_GetMesh_Vertex3f(const model_t *model, const frameblend_t *frameb else for (k = 0;k < 12;k++) bonepose[i][k] = m[k]; + // create a relative deformation matrix to describe displacement + // from the base mesh, which is used by the actual weighting + R_ConcatTransforms(bonepose[i], model->data_baseboneposeinverse + i * 12, boneposerelative[i]); } // blend the vertex bone weights - memset(out3f, 0, model->surfmesh.num_vertices * sizeof(float[3])); - v = model->surfmesh.data_vertexboneweights; - for (i = 0;i < model->surfmesh.num_vertexboneweights;i++, v++) + if (svector3f) + { + for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, n += 3, sv += 3, tv += 3, wi += 4, wf += 4, vertex3f += 3, normal3f += 3, svector3f += 3, tvector3f += 3) + { + for (k = 0;k < 4 && wf[k];k++) + { + const float *m = boneposerelative[wi[k]]; + float f = wf[k]; + vertex3f[0] += f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]); + vertex3f[1] += f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]); + vertex3f[2] += f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]); + normal3f[0] += f * (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]); + normal3f[1] += f * (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]); + normal3f[2] += f * (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]); + svector3f[0] += f * (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]); + svector3f[1] += f * (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]); + svector3f[2] += f * (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]); + tvector3f[0] += f * (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]); + tvector3f[1] += f * (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]); + tvector3f[2] += f * (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]); + } + } + } + else if (normal3f) + { + for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, n += 3, wi += 4, wf += 4, vertex3f += 3, normal3f += 3) + { + for (k = 0;k < 4 && wf[k];k++) + { + const float *m = boneposerelative[wi[k]]; + float f = wf[k]; + vertex3f[0] += f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]); + vertex3f[1] += f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]); + vertex3f[2] += f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]); + normal3f[0] += f * (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]); + normal3f[1] += f * (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]); + normal3f[2] += f * (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]); + } + } + } + else { - out = out3f + v->vertexindex * 3; - matrix = bonepose[v->boneindex]; - // FIXME: this can very easily be optimized with SSE or 3DNow - out[0] += v->origin[0] * matrix[0] + v->origin[1] * matrix[1] + v->origin[2] * matrix[ 2] + v->origin[3] * matrix[ 3]; - out[1] += v->origin[0] * matrix[4] + v->origin[1] * matrix[5] + v->origin[2] * matrix[ 6] + v->origin[3] * matrix[ 7]; - out[2] += v->origin[0] * matrix[8] + v->origin[1] * matrix[9] + v->origin[2] * matrix[10] + v->origin[3] * matrix[11]; + for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, wi += 4, wf += 4, vertex3f += 3) + { + for (k = 0;k < 4 && wf[k];k++) + { + const float *m = boneposerelative[wi[k]]; + float f = wf[k]; + vertex3f[0] += f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]); + vertex3f[1] += f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]); + vertex3f[2] += f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]); + } + } } } - else if (!model->surfmesh.data_morphvertex3f) - Host_Error("model %s has no skeletal or vertex morph animation data", model->name); - else + else if (model->surfmesh.data_morphmd3vertex) { // vertex morph + int i, numblends, blendnum; int numverts = model->surfmesh.num_vertices; - const float *vertsbase = model->surfmesh.data_morphvertex3f; - const float *verts1 = vertsbase + numverts * 3 * frameblend[0].frame; - if (frameblend[1].lerp) + numblends = 0; + for (blendnum = 0;blendnum < 4;blendnum++) + { + //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate); + if (frameblend[blendnum].lerp > 0) + numblends = blendnum + 1; + } + memset(vertex3f, 0, numverts * sizeof(float[3])); + if (normal3f) + for (i = 0;i < numverts;i++) + VectorClear(normal3f + i * 3); + for (blendnum = 0;blendnum < numblends;blendnum++) { - int i; - float lerp1 = frameblend[0].lerp; - const float *verts2 = vertsbase + numverts * 3 * frameblend[1].frame; - float lerp2 = frameblend[1].lerp; - if (frameblend[2].lerp) + const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].frame; + float scale = frameblend[blendnum].lerp * (1.0f / 64.0f); + for (i = 0;i < numverts;i++) { - const float *verts3 = vertsbase + numverts * 3 * frameblend[2].frame; - float lerp3 = frameblend[2].lerp; - if (frameblend[3].lerp) + vertex3f[i * 3 + 0] += verts[i].origin[0] * scale; + vertex3f[i * 3 + 1] += verts[i].origin[1] * scale; + vertex3f[i * 3 + 2] += verts[i].origin[2] * scale; + } + // the yaw and pitch stored in md3 models are 8bit quantized angles + // (0-255), and as such a lookup table is very well suited to + // decoding them, and since cosine is equivilant to sine with an + // extra 45 degree rotation, this uses one lookup table for both + // sine and cosine with a +64 bias to get cosine. + if (normal3f) + { + float lerp = frameblend[blendnum].lerp; + for (i = 0;i < numverts;i++) { - const float *verts4 = vertsbase + numverts * 3 * frameblend[3].frame; - float lerp4 = frameblend[3].lerp; - for (i = 0;i < numverts * 3;i++) - out3f[i] = lerp1 * verts1[i] + lerp2 * verts2[i] + lerp3 * verts3[i] + lerp4 * verts4[i]; + normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp; + normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp; + normal3f[i * 3 + 2] += mod_md3_sin[verts[i].pitch + 64] * lerp; } - else - for (i = 0;i < numverts * 3;i++) - out3f[i] = lerp1 * verts1[i] + lerp2 * verts2[i] + lerp3 * verts3[i]; } + } + if (normal3f) + if (svector3f) + Mod_BuildTextureVectorsFromNormals(0, model->surfmesh.num_vertices, model->surfmesh.num_triangles, vertex3f, model->surfmesh.data_texcoordtexture2f, normal3f, model->surfmesh.data_element3i, svector3f, tvector3f, r_smoothnormals_areaweighting.integer); + } + else if (model->surfmesh.data_morphmdlvertex) + { + // vertex morph + int i, numblends, blendnum; + int numverts = model->surfmesh.num_vertices; + float translate[3]; + VectorClear(translate); + numblends = 0; + for (blendnum = 0;blendnum < 4;blendnum++) + { + if (model->surfmesh.data_morphmd2framesize6f) + VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6 + 3, translate); else - for (i = 0;i < numverts * 3;i++) - out3f[i] = lerp1 * verts1[i] + lerp2 * verts2[i]; + VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate); + if (frameblend[blendnum].lerp > 0) + numblends = blendnum + 1; } - else - memcpy(out3f, verts1, numverts * 3 * sizeof(float)); + for (i = 0;i < numverts;i++) + VectorCopy(translate, vertex3f + i * 3); + if (normal3f) + for (i = 0;i < numverts;i++) + VectorClear(normal3f + i * 3); + for (blendnum = 0;blendnum < numblends;blendnum++) + { + const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].frame; + float scale[3]; + if (model->surfmesh.data_morphmd2framesize6f) + VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6, frameblend[blendnum].lerp, scale); + else + VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale); + for (i = 0;i < numverts;i++) + { + vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0]; + vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1]; + vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2]; + } + // the vertex normals in mdl models are an index into a table of + // 162 unique values, this very crude quantization reduces the + // vertex normal to only one byte, which saves a lot of space but + // also makes lighting pretty coarse + if (normal3f) + { + float lerp = frameblend[blendnum].lerp; + for (i = 0;i < numverts;i++) + { + const float *vn = m_bytenormals[verts[i].lightnormalindex]; + VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3); + } + } + } + if (normal3f) + if (svector3f) + Mod_BuildTextureVectorsFromNormals(0, model->surfmesh.num_vertices, model->surfmesh.num_triangles, vertex3f, model->surfmesh.data_texcoordtexture2f, normal3f, model->surfmesh.data_element3i, svector3f, tvector3f, r_smoothnormals_areaweighting.integer); } + else + Host_Error("model %s has no skeletal or vertex morph animation data", model->name); } int Mod_Alias_GetTagMatrix(const model_t *model, int poseframe, int tagindex, matrix4x4_t *outmatrix) @@ -185,6 +315,108 @@ int Mod_Alias_GetTagIndexForName(const model_t *model, unsigned int skin, const return 0; } +static void Mod_BuildBaseBonePoses(void) +{ + int i, k; + double scale; + float *in12f = loadmodel->data_poses; + float *out12f = loadmodel->data_basebonepose; + float *outinv12f = loadmodel->data_baseboneposeinverse; + for (i = 0;i < loadmodel->num_bones;i++, in12f += 12, out12f += 12, outinv12f += 12) + { + if (loadmodel->data_bones[i].parent >= 0) + R_ConcatTransforms(loadmodel->data_basebonepose + 12 * loadmodel->data_bones[i].parent, in12f, out12f); + else + for (k = 0;k < 12;k++) + out12f[k] = in12f[k]; + + // invert The Matrix + + // we only support uniform scaling, so assume the first row is enough + // (note the lack of sqrt here, because we're trying to undo the scaling, + // this means multiplying by the inverse scale twice - squaring it, which + // makes the sqrt a waste of time) + scale = 1.0 / (out12f[ 0] * out12f[ 0] + out12f[ 1] * out12f[ 1] + out12f[ 2] * out12f[ 2]); + + // invert the rotation by transposing and multiplying by the squared + // recipricol of the input matrix scale as described above + outinv12f[ 0] = (float)(out12f[ 0] * scale); + outinv12f[ 1] = (float)(out12f[ 4] * scale); + outinv12f[ 2] = (float)(out12f[ 8] * scale); + outinv12f[ 4] = (float)(out12f[ 1] * scale); + outinv12f[ 5] = (float)(out12f[ 5] * scale); + outinv12f[ 6] = (float)(out12f[ 9] * scale); + outinv12f[ 8] = (float)(out12f[ 2] * scale); + outinv12f[ 9] = (float)(out12f[ 6] * scale); + outinv12f[10] = (float)(out12f[10] * scale); + + // invert the translate + outinv12f[ 3] = -(out12f[ 3] * outinv12f[ 0] + out12f[ 7] * outinv12f[ 1] + out12f[11] * outinv12f[ 2]); + outinv12f[ 7] = -(out12f[ 3] * outinv12f[ 4] + out12f[ 7] * outinv12f[ 5] + out12f[11] * outinv12f[ 6]); + outinv12f[11] = -(out12f[ 3] * outinv12f[ 8] + out12f[ 7] * outinv12f[ 9] + out12f[11] * outinv12f[10]); + } +} + +static void Mod_Alias_CalculateBoundingBox(void) +{ + int i, j; + int vnum; + qboolean firstvertex = true; + float dist, yawradius, radius; + float *v; + float *vertex3f; + frameblend_t frameblend[4]; + memset(frameblend, 0, sizeof(frameblend)); + frameblend[0].lerp = 1; + vertex3f = Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3])); + VectorClear(loadmodel->normalmins); + VectorClear(loadmodel->normalmaxs); + yawradius = 0; + radius = 0; + for (i = 0;i < loadmodel->numframes;i++) + { + for (j = 0, frameblend[0].frame = loadmodel->animscenes[i].firstframe;j < loadmodel->animscenes[i].framecount;j++, frameblend[0].frame++) + { + Mod_Alias_GetMesh_Vertices(loadmodel, frameblend, vertex3f, NULL, NULL, NULL); + for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3) + { + if (firstvertex) + { + firstvertex = false; + VectorCopy(v, loadmodel->normalmins); + VectorCopy(v, loadmodel->normalmaxs); + } + else + { + if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0]; + if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1]; + if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2]; + if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0]; + if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1]; + if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2]; + } + dist = v[0] * v[0] + v[1] * v[1]; + if (yawradius < dist) + yawradius = dist; + dist += v[2] * v[2]; + if (radius < dist) + radius = dist; + } + } + } + Mem_Free(vertex3f); + radius = sqrt(radius); + yawradius = sqrt(yawradius); + loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius; + loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius; + loadmodel->yawmins[2] = loadmodel->normalmins[2]; + loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2]; + loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius; + loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius; + loadmodel->radius = radius; + loadmodel->radius2 = radius * radius; +} + static void Mod_Alias_Mesh_CompileFrameZero(void) { frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}}; @@ -192,8 +424,9 @@ static void Mod_Alias_Mesh_CompileFrameZero(void) loadmodel->surfmesh.data_svector3f = loadmodel->surfmesh.data_vertex3f + loadmodel->surfmesh.num_vertices * 3; loadmodel->surfmesh.data_tvector3f = loadmodel->surfmesh.data_vertex3f + loadmodel->surfmesh.num_vertices * 6; loadmodel->surfmesh.data_normal3f = loadmodel->surfmesh.data_vertex3f + loadmodel->surfmesh.num_vertices * 9; - Mod_Alias_GetMesh_Vertex3f(loadmodel, frameblend, loadmodel->surfmesh.data_vertex3f); - Mod_BuildTextureVectorsAndNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, loadmodel->surfmesh.data_normal3f, true); + Mod_Alias_GetMesh_Vertices(loadmodel, frameblend, loadmodel->surfmesh.data_vertex3f, NULL, NULL, NULL); + Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true); + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true); } static void Mod_MDLMD2MD3_TraceBox(model_t *model, int frame, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask) @@ -229,7 +462,7 @@ static void Mod_MDLMD2MD3_TraceBox(model_t *model, int frame, trace_t *trace, co segmentmaxs[2] = max(start[2], end[2]) + 1; for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++) { - Mod_Alias_GetMesh_Vertex3f(model, frameblend, vertex3f); + Mod_Alias_GetMesh_Vertices(model, frameblend, vertex3f, NULL, NULL, NULL); Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs); } } @@ -259,69 +492,29 @@ static void Mod_MDLMD2MD3_TraceBox(model_t *model, int frame, trace_t *trace, co maxvertices = (model->surfmesh.num_vertices + 255) & ~255; vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3])); } - Mod_Alias_GetMesh_Vertex3f(model, frameblend, vertex3f); + Mod_Alias_GetMesh_Vertices(model, frameblend, vertex3f, NULL, NULL, NULL); Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs); } } } -static void Mod_CalcAliasModelBBoxes (void) -{ - int vnum; - float dist, yawradius, radius; - float *v; - VectorClear(loadmodel->normalmins); - VectorClear(loadmodel->normalmaxs); - yawradius = 0; - radius = 0; - for (vnum = 0, v = loadmodel->surfmesh.data_morphvertex3f;vnum < loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes;vnum++, v += 3) - { - if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0]; - if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1]; - if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2]; - if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0]; - if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1]; - if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2]; - dist = v[0] * v[0] + v[1] * v[1]; - if (yawradius < dist) - yawradius = dist; - dist += v[2] * v[2]; - if (radius < dist) - radius = dist; - } - radius = sqrt(radius); - yawradius = sqrt(yawradius); - loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius; - loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius; - loadmodel->yawmins[2] = loadmodel->normalmins[2]; - loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2]; - loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius; - loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius; - loadmodel->radius = radius; - loadmodel->radius2 = radius * radius; -} - -static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, trivertx_t *v, float *out3f, int *vertremap) +static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap) { int i, j; - vec3_t temp; for (i = 0;i < inverts;i++) { if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply... continue; - temp[0] = v[i].v[0] * scale[0] + translate[0]; - temp[1] = v[i].v[1] * scale[1] + translate[1]; - temp[2] = v[i].v[2] * scale[2] + translate[2]; j = vertremap[i]; // not onseam if (j >= 0) - VectorCopy(temp, out3f + j * 3); + out[j] = v[i]; j = vertremap[i+inverts]; // onseam if (j >= 0) - VectorCopy(temp, out3f + j * 3); + out[j] = v[i]; } } -static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, vec3_t scale, vec3_t translate, int *vertremap) +static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap) { int i, f, pose, groupframes; float interval; @@ -376,7 +569,7 @@ static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, vec3_t { pinframe = (daliasframe_t *)datapointer; datapointer += sizeof(daliasframe_t); - Mod_ConvertAliasVerts(inverts, scale, translate, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphvertex3f + pose * loadmodel->surfmesh.num_vertices * 3, vertremap); + Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap); datapointer += sizeof(trivertx_t) * inverts; pose++; } @@ -398,7 +591,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *skin, skinframe_t *skinfr skin->currentframe = skin; skin->basematerialflags = MATERIALFLAG_WALL; if (skin->skin.fog) - skin->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT; + skin->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT; skin->currentmaterialflags = skin->basematerialflags; } @@ -457,7 +650,7 @@ static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfi void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend) { int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts; - float scales, scalet, scale[3], translate[3], interval; + float scales, scalet, interval; msurface_t *surface; unsigned char *data; mdl_t *pinmodel; @@ -519,8 +712,8 @@ void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend) for (i = 0;i < 3;i++) { - scale[i] = LittleFloat (pinmodel->scale[i]); - translate[i] = LittleFloat (pinmodel->scale_origin[i]); + loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]); + loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]); } startskins = datapointer; @@ -642,11 +835,11 @@ void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend) // load the frames loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); - loadmodel->surfmesh.data_morphvertex3f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices); + loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices); loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3])); - Mod_MDL_LoadFrames (startframes, numverts, scale, translate, vertremap); + Mod_MDL_LoadFrames (startframes, numverts, vertremap); Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); - Mod_CalcAliasModelBBoxes(); + Mod_Alias_CalculateBoundingBox(); Mod_Alias_Mesh_CompileFrameZero(); Mem_Free(vertst); @@ -755,25 +948,14 @@ void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend) surface->num_triangles = loadmodel->surfmesh.num_triangles; surface->num_firstvertex = 0; surface->num_vertices = loadmodel->surfmesh.num_vertices; -} -static void Mod_MD2_ConvertVerts (vec3_t scale, vec3_t translate, trivertx_t *v, float *out3f, int numverts, int *vertremap) -{ - int i; - trivertx_t *in; - for (i = 0;i < numverts;i++, out3f += 3) - { - in = v + vertremap[i]; - out3f[0] = in->v[0] * scale[0] + translate[0]; - out3f[1] = in->v[1] * scale[1] + translate[1]; - out3f[2] = in->v[2] * scale[2] + translate[2]; - } + loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; } void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend) { - int i, j, k, hashindex, num, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end, numverts; - float *stverts, s, t, scale[3], translate[3]; + int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end; + float iskinwidth, iskinheight; unsigned char *data; msurface_t *surface; md2_t *pinmodel; @@ -785,8 +967,8 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend) struct md2verthash_s { struct md2verthash_s *next; - int xyz; - float st[2]; + unsigned short xyz; + unsigned short st; } *hash, **md2verthash, *md2verthashdata; skinframe_t tempskinframe; @@ -829,20 +1011,27 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend) if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end) Host_Error ("%s is not a valid model", loadmodel->name); - loadmodel->num_surfaces = 1; - loadmodel->nummodelsurfaces = loadmodel->num_surfaces; - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int)); - loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); - loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); - loadmodel->surfacelist[0] = 0; - loadmodel->numskins = LittleLong(pinmodel->num_skins); numxyz = LittleLong(pinmodel->num_xyz); numst = LittleLong(pinmodel->num_st); loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris); loadmodel->numframes = LittleLong(pinmodel->num_frames); loadmodel->surfmesh.num_morphframes = loadmodel->numframes; - loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t)); + skinwidth = LittleLong(pinmodel->skinwidth); + skinheight = LittleLong(pinmodel->skinheight); + iskinwidth = 1.0f / skinwidth; + iskinheight = 1.0f / skinheight; + + loadmodel->num_surfaces = 1; + loadmodel->nummodelsurfaces = loadmodel->num_surfaces; + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3])); + loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); + loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->surfacelist[0] = 0; + loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); + loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]); + loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); loadmodel->flags = 0; // there are no MD2 flags loadmodel->synctype = ST_RAND; @@ -894,31 +1083,10 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend) // load the triangles and stvert data inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st)); intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris)); - skinwidth = LittleLong(pinmodel->skinwidth); - skinheight = LittleLong(pinmodel->skinheight); - - stverts = (float *)Mem_Alloc(tempmempool, numst * sizeof(float[2])); - s = 1.0f / skinwidth; - t = 1.0f / skinheight; - for (i = 0;i < numst;i++) - { - j = (unsigned short) LittleShort(inst[i*2+0]); - k = (unsigned short) LittleShort(inst[i*2+1]); - if (j >= skinwidth || k >= skinheight) - { - Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, j, k, i); - j = 0; - k = 0; - } - stverts[i*2+0] = j * s; - stverts[i*2+1] = k * t; - } - - md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 256 * sizeof(hash)); + md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash)); md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash)); // swap the triangle list - num = 0; - loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3])); + loadmodel->surfmesh.num_vertices = 0; for (i = 0;i < loadmodel->surfmesh.num_triangles;i++) { for (j = 0;j < 3;j++) @@ -935,18 +1103,15 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend) Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i); st = 0; } - s = stverts[st*2+0]; - t = stverts[st*2+1]; - hashindex = (xyz * 17 + st) & 255; + hashindex = (xyz * 256 + st) & 65535; for (hash = md2verthash[hashindex];hash;hash = hash->next) - if (hash->xyz == xyz && hash->st[0] == s && hash->st[1] == t) + if (hash->xyz == xyz && hash->st == st) break; if (hash == NULL) { - hash = md2verthashdata + num++; + hash = md2verthashdata + loadmodel->surfmesh.num_vertices++; hash->xyz = xyz; - hash->st[0] = s; - hash->st[1] = t; + hash->st = st; hash->next = md2verthash[hashindex]; md2verthash[hashindex] = hash; } @@ -954,18 +1119,25 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend) } } - Mem_Free(stverts); - - numverts = num; - loadmodel->surfmesh.num_vertices = numverts; - vertremap = (int *)Mem_Alloc(loadmodel->mempool, num * sizeof(int)); - loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, num * sizeof(float[2])); - for (i = 0;i < num;i++) + vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int)); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t)); + loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]); + loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t); + for (i = 0;i < loadmodel->surfmesh.num_vertices;i++) { + int sts, stt; hash = md2verthashdata + i; vertremap[i] = hash->xyz; - loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = hash->st[0]; - loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = hash->st[1]; + sts = LittleShort(inst[hash->st*2+0]); + stt = LittleShort(inst[hash->st*2+1]); + if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight) + { + Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i); + sts = 0; + stt = 0; + } + loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth; + loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight; } Mem_Free(md2verthash); @@ -973,17 +1145,24 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend) // load the frames datapointer = (base + LittleLong(pinmodel->ofs_frames)); - loadmodel->surfmesh.data_morphvertex3f = (float *)Mem_Alloc(loadmodel->mempool, numverts * loadmodel->surfmesh.num_morphframes * sizeof(float[3])); for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++) { + int k; + trivertx_t *v; + trivertx_t *out; pinframe = (md2frame_t *)datapointer; datapointer += sizeof(md2frame_t); + // store the frame scale/translate into the appropriate array for (j = 0;j < 3;j++) { - scale[j] = LittleFloat(pinframe->scale[j]); - translate[j] = LittleFloat(pinframe->translate[j]); + loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]); + loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]); } - Mod_MD2_ConvertVerts(scale, translate, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphvertex3f + i * numverts * 3, numverts, vertremap); + // convert the vertices + v = (trivertx_t *)datapointer; + out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices; + for (k = 0;k < loadmodel->surfmesh.num_vertices;k++) + out[k] = v[vertremap[k]]; datapointer += numxyz * sizeof(trivertx_t); strcpy(loadmodel->animscenes[i].name, pinframe->name); @@ -995,9 +1174,8 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend) Mem_Free(vertremap); - loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3])); Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); - Mod_CalcAliasModelBBoxes(); + Mod_Alias_CalculateBoundingBox(); Mod_Alias_Mesh_CompileFrameZero(); surface = loadmodel->data_surfaces; @@ -1006,6 +1184,8 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend) surface->num_triangles = loadmodel->surfmesh.num_triangles; surface->num_firstvertex = 0; surface->num_vertices = loadmodel->surfmesh.num_vertices; + + loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; } void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend) @@ -1099,7 +1279,7 @@ void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend) loadmodel->nummodelsurfaces = loadmodel->num_surfaces; loadmodel->num_textures = loadmodel->num_surfaces; - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(float[3])); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t)); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); @@ -1109,7 +1289,7 @@ void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend) loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]); loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]); loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]); - loadmodel->surfmesh.data_morphvertex3f = (float *)data;data += meshvertices * loadmodel->numframes * sizeof(float[3]); + loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t); meshvertices = 0; meshtriangles = 0; @@ -1136,13 +1316,15 @@ void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend) } for (j = 0;j < loadmodel->numframes;j++) { - const short *in4s = (short *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices * 4; - float *out3f = loadmodel->surfmesh.data_morphvertex3f + 3 * (j * loadmodel->surfmesh.num_vertices + surface->num_firstvertex); - for (k = 0;k < surface->num_vertices;k++, in4s += 4, out3f += 3) + const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices; + md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices; + for (k = 0;k < surface->num_vertices;k++, in++, out++) { - out3f[0] = LittleShort(in4s[0]) * (1.0f / 64.0f); - out3f[1] = LittleShort(in4s[1]) * (1.0f / 64.0f); - out3f[2] = LittleShort(in4s[2]) * (1.0f / 64.0f); + out->origin[0] = LittleShort(in->origin[0]); + out->origin[1] = LittleShort(in->origin[1]); + out->origin[2] = LittleShort(in->origin[2]); + out->pitch = in->pitch; + out->yaw = in->yaw; } } @@ -1156,16 +1338,18 @@ void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend) } Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); Mod_Alias_Mesh_CompileFrameZero(); - Mod_CalcAliasModelBBoxes(); + Mod_Alias_CalculateBoundingBox(); Mod_FreeSkinFiles(skinfiles); + + loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; } void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend) { zymtype1header_t *pinmodel, *pheader; unsigned char *pbase; - int i, j, k, l, numposes, meshvertices, meshtriangles, numvertexboneweights, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements; - float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f; + int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements; + float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose; zymvertex_t *verts, *vertdata; zymscene_t *scene; zymbone_t *bone; @@ -1316,30 +1500,35 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend) for (i = 0;i < pheader->numverts;i++) { vertbonecounts[i] = BigLong(bonecount[i]); - if (vertbonecounts[i] < 1) - Host_Error("%s bonecount[%i] < 1", loadmodel->name, i); + if (vertbonecounts[i] != 1) + Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i); } loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]); meshvertices = pheader->numverts; meshtriangles = pheader->numtris; - numvertexboneweights = pheader->lump_verts.length / sizeof(zymvertex_t); loadmodel->nummodelsurfaces = loadmodel->num_surfaces; loadmodel->num_textures = loadmodel->num_surfaces; - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * sizeof(float[2]) + numvertexboneweights * sizeof(surfmeshvertexboneweight_t) + loadmodel->num_poses * sizeof(float[3][4])); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * sizeof(float[14]) + meshvertices * sizeof(int[4]) + meshvertices * sizeof(float[4]) + loadmodel->num_poses * sizeof(float[36])); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); loadmodel->surfmesh.num_vertices = meshvertices; loadmodel->surfmesh.num_triangles = meshtriangles; - loadmodel->surfmesh.num_vertexboneweights = numvertexboneweights; loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]); loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]); + loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]); loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]); - loadmodel->surfmesh.data_vertexboneweights = (surfmeshvertexboneweight_t *)data;data += numvertexboneweights * sizeof(surfmeshvertexboneweight_t); - loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[3][4]); + loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]); + loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]); + loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]); + loadmodel->data_basebonepose = (float *)data;data += loadmodel->num_poses * sizeof(float[12]); + loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_poses * sizeof(float[12]); //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data poses = (float *) (pheader->lump_poses.start + pbase); @@ -1349,21 +1538,40 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend) //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length); vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase); - l = 0; - for (j = 0;j < pheader->numverts;j++) + // reconstruct frame 0 matrices to allow reconstruction of the base mesh + // (converting from weight-blending skeletal animation to + // deformation-based skeletal animation) + bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12])); + for (i = 0;i < loadmodel->num_bones;i++) { - for (k = 0;k < vertbonecounts[j];k++, l++) - { - // this format really should have had a per vertexweight weight value... - float influence = 1.0f / vertbonecounts[j]; - loadmodel->surfmesh.data_vertexboneweights[l].vertexindex = j; - loadmodel->surfmesh.data_vertexboneweights[l].boneindex = BigLong(vertdata[l].bonenum); - loadmodel->surfmesh.data_vertexboneweights[l].origin[0] = BigFloat(vertdata[l].origin[0]) * influence; - loadmodel->surfmesh.data_vertexboneweights[l].origin[1] = BigFloat(vertdata[l].origin[1]) * influence; - loadmodel->surfmesh.data_vertexboneweights[l].origin[2] = BigFloat(vertdata[l].origin[2]) * influence; - loadmodel->surfmesh.data_vertexboneweights[l].origin[3] = influence; - } + const float *m = loadmodel->data_poses + i * 12; + if (loadmodel->data_bones[i].parent >= 0) + R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i); + else + for (k = 0;k < 12;k++) + bonepose[12*i+k] = m[k]; } + for (j = 0;j < pheader->numverts;j++) + { + // this format really should have had a per vertexweight weight value... + // but since it does not, the weighting is completely ignored and + // only one weight is allowed per vertex + int boneindex = BigLong(vertdata[j].bonenum); + const float *m = bonepose + 12 * boneindex; + float relativeorigin[3]; + relativeorigin[0] = BigFloat(vertdata[j].origin[0]); + relativeorigin[1] = BigFloat(vertdata[j].origin[1]); + relativeorigin[2] = BigFloat(vertdata[j].origin[2]); + // transform the vertex bone weight into the base mesh + loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3]; + loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7]; + loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11]; + // store the weight as the primary weight on this vertex + loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex; + loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = 1; + } + Z_Free(bonepose); + // normals and tangents are calculated after elements are loaded //zymlump_t lump_texcoords; // float texcoords[numvertices][2]; outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f; @@ -1390,7 +1598,7 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend) meshtriangles = 0; for (i = 0;i < loadmodel->num_surfaces;i++) { - int lastvertex; + int firstvertex, lastvertex; if (renderlist >= renderlistend) Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name); count = BigLong(*renderlist);renderlist++; @@ -1402,33 +1610,28 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend) surface->texture = loadmodel->data_textures + i; surface->num_firsttriangle = meshtriangles; surface->num_triangles = count; - surface->num_firstvertex = meshvertices; - surface->num_vertices = meshvertices; + meshtriangles += surface->num_triangles; - // load the elements and find the used vertex range - lastvertex = 0; + // load the elements outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3; - for (j = 0;j < surface->num_triangles;j++) + for (j = 0;j < surface->num_triangles;j++, renderlist += 3) + { + outelements[j*3+2] = BigLong(renderlist[0]); + outelements[j*3+1] = BigLong(renderlist[1]); + outelements[j*3+0] = BigLong(renderlist[2]); + } + // validate the elements and find the used vertex range + firstvertex = meshvertices; + lastvertex = 0; + for (j = 0;j < surface->num_triangles * 3;j++) { - outelements[2] = BigLong(renderlist[0]); - outelements[1] = BigLong(renderlist[1]); - outelements[0] = BigLong(renderlist[2]); - if ((unsigned int)outelements[0] >= (unsigned int)pheader->numverts - || (unsigned int)outelements[1] >= (unsigned int)pheader->numverts - || (unsigned int)outelements[2] >= (unsigned int)pheader->numverts) + if ((unsigned int)outelements[j] >= (unsigned int)meshvertices) Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name); - if (vertbonecounts[outelements[0]] == 0 || vertbonecounts[outelements[1]] == 0 || vertbonecounts[outelements[2]] == 0) - Host_Error("%s corrupt renderlist (references vertex with no bone weights", loadmodel->name); - surface->num_firstvertex = min(surface->num_firstvertex, outelements[0]); - surface->num_firstvertex = min(surface->num_firstvertex, outelements[1]); - surface->num_firstvertex = min(surface->num_firstvertex, outelements[2]); - lastvertex = max(lastvertex, outelements[0]); - lastvertex = max(lastvertex, outelements[1]); - lastvertex = max(lastvertex, outelements[2]); - renderlist += 3; - outelements += 3; + firstvertex = min(firstvertex, outelements[j]); + lastvertex = max(lastvertex, outelements[j]); } - surface->num_vertices = lastvertex + 1 - surface->num_firstvertex; + surface->num_firstvertex = firstvertex; + surface->num_vertices = lastvertex + 1 - firstvertex; // since zym models do not have named sections, reuse their shader // name as the section name @@ -1438,14 +1641,19 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend) else for (j = 0;j < loadmodel->numskins;j++) Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + i + j * loadmodel->num_surfaces, NULL); - - Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__); } - Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); - Mod_Alias_Mesh_CompileFrameZero(); Mod_FreeSkinFiles(skinfiles); Mem_Free(vertbonecounts); Mem_Free(verts); + + // compute all the mesh information that was not loaded from the file + Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__); + Mod_BuildBaseBonePoses(); + Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true); + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true); + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + + loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; } void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend) @@ -1455,9 +1663,10 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend) dpmbone_t *bone; dpmmesh_t *dpmmesh; unsigned char *pbase; - int i, j, k, meshvertices, meshtriangles, numvertexboneweights; + int i, j, k, meshvertices, meshtriangles; skinfile_t *skinfiles; unsigned char *data; + float *bonepose; pheader = (dpmheader_t *)buffer; pbase = (unsigned char *)buffer; @@ -1526,25 +1735,14 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend) meshvertices = 0; meshtriangles = 0; - numvertexboneweights = 0; - // load the meshes now + // gather combined statistics from the meshes dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs); - for (i = 0;i < loadmodel->num_surfaces;i++) + for (i = 0;i < (int)pheader->num_meshs;i++) { int numverts = BigLong(dpmmesh->num_verts); meshvertices += numverts;; meshtriangles += BigLong(dpmmesh->num_tris); - - // to find out how many weights exist we two a two-stage load... - data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts)); - for (j = 0;j < numverts;j++) - { - int numweights = BigLong(((dpmvertex_t *)data)->numbones); - numvertexboneweights += numweights; - data += sizeof(dpmvertex_t); - data += numweights * sizeof(dpmbonevert_t); - } dpmmesh++; } @@ -1553,18 +1751,24 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend) loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes; loadmodel->num_textures = loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs; // do most allocations as one merged chunk - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * sizeof(float[2]) + numvertexboneweights * sizeof(surfmeshvertexboneweight_t) + loadmodel->num_poses * sizeof(float[3][4]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * (sizeof(float[14]) + sizeof(int[4]) + sizeof(float[4])) + loadmodel->num_poses * sizeof(float[36]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); loadmodel->surfmesh.num_vertices = meshvertices; loadmodel->surfmesh.num_triangles = meshtriangles; - loadmodel->surfmesh.num_vertexboneweights = numvertexboneweights; loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]); loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]); + loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]); loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]); - loadmodel->surfmesh.data_vertexboneweights = (surfmeshvertexboneweight_t *)data;data += numvertexboneweights * sizeof(surfmeshvertexboneweight_t); - loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[3][4]); + loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]); + loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]); + loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]); + loadmodel->data_basebonepose = (float *)data;data += loadmodel->num_poses * sizeof(float[12]); + loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_poses * sizeof(float[12]); loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t); loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t); loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); @@ -1610,7 +1814,19 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend) dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs); meshvertices = 0; meshtriangles = 0; - numvertexboneweights = 0; + // reconstruct frame 0 matrices to allow reconstruction of the base mesh + // (converting from weight-blending skeletal animation to + // deformation-based skeletal animation) + bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12])); + for (i = 0;i < loadmodel->num_bones;i++) + { + const float *m = loadmodel->data_poses + i * 12; + if (loadmodel->data_bones[i].parent >= 0) + R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i); + else + for (k = 0;k < 12;k++) + bonepose[12*i+k] = m[k]; + } for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++) { const int *inelements; @@ -1645,23 +1861,71 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend) loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]); data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts)); - for (j = 0;j < surface->num_vertices;j++) + for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++) { + float sum; + int l; int numweights = BigLong(((dpmvertex_t *)data)->numbones); data += sizeof(dpmvertex_t); for (k = 0;k < numweights;k++) { const dpmbonevert_t *vert = (dpmbonevert_t *) data; - // stuff not processed here: normal - loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].vertexindex = j; - loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].boneindex = BigLong(vert->bonenum); - loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin[0] = BigFloat(vert->origin[0]); - loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin[1] = BigFloat(vert->origin[1]); - loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin[2] = BigFloat(vert->origin[2]); - loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin[3] = BigFloat(vert->influence); - numvertexboneweights++; + int boneindex = BigLong(vert->bonenum); + const float *m = bonepose + 12 * boneindex; + float influence = BigFloat(vert->influence); + float relativeorigin[3], relativenormal[3]; + relativeorigin[0] = BigFloat(vert->origin[0]); + relativeorigin[1] = BigFloat(vert->origin[1]); + relativeorigin[2] = BigFloat(vert->origin[2]); + relativenormal[0] = BigFloat(vert->normal[0]); + relativenormal[1] = BigFloat(vert->normal[1]); + relativenormal[2] = BigFloat(vert->normal[2]); + // blend the vertex bone weights into the base mesh + loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3]; + loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7]; + loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11]; + loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2]; + loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6]; + loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10]; + if (!k) + { + // store the first (and often only) weight + loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = influence; + loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex; + } + else + { + // sort the new weight into this vertex's weight table + // (which only accepts up to 4 bones per vertex) + for (l = 0;l < 4;l++) + { + if (loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] < influence) + { + // move weaker influence weights out of the way first + int l2; + for (l2 = 3;l2 > l;l2--) + { + loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2-1]; + loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2-1]; + } + // store the new weight + loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] = influence; + loadmodel->surfmesh.data_vertexweightindex4i[j*4+l] = boneindex; + break; + } + } + } data += sizeof(dpmbonevert_t); } + sum = 0; + for (l = 0;l < 4;l++) + sum += loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l]; + if (sum && fabs(sum - 1) > (1.0f / 256.0f)) + { + float f = 1.0f / sum; + for (l = 0;l < 4;l++) + loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] *= f; + } } // since dpm models do not have named sections, reuse their shader name as the section name @@ -1673,9 +1937,15 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend) Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__); } - Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); - Mod_Alias_Mesh_CompileFrameZero(); + Z_Free(bonepose); Mod_FreeSkinFiles(skinfiles); + + // compute all the mesh information that was not loaded from the file + Mod_BuildBaseBonePoses(); + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true); + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + + loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; } static void Mod_PSKMODEL_AnimKeyToMatrix(float *origin, float *quat, matrix4x4_t *m) @@ -1691,7 +1961,7 @@ static void Mod_PSKMODEL_AnimKeyToMatrix(float *origin, float *quat, matrix4x4_t #define PSKQUATNEGATIONS void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend) { - int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles, numvertexboneweights; + int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles; int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys; fs_offset_t filesize; pskpnts_t *pnts; @@ -1841,6 +2111,7 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend) matts = (pskmatt_t *)buffer; for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++) { + // nothing to do } buffer = p; } @@ -2002,9 +2273,7 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend) p->firstframe = LittleLong(p->firstframe); p->numframes = LittleLong(p->numframes); if (p->numbones != numbones) - { Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname); - } } animbuffer = p; } @@ -2050,20 +2319,6 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend) if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights || !numanims || !anims || !numanimkeys || !animkeys) Host_Error("%s: missing required chunks", loadmodel->name); - // FIXME: model bbox - // model bbox - for (i = 0;i < 3;i++) - { - loadmodel->normalmins[i] = -128; - loadmodel->normalmaxs[i] = 128; - loadmodel->yawmins[i] = -128; - loadmodel->yawmaxs[i] = 128; - loadmodel->rotatedmins[i] = -128; - loadmodel->rotatedmaxs[i] = 128; - } - loadmodel->radius = 128; - loadmodel->radius2 = loadmodel->radius * loadmodel->radius; - loadmodel->numframes = 0; for (index = 0;index < numanims;index++) loadmodel->numframes += anims[index].numframes; @@ -2073,11 +2328,6 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend) meshvertices = numvtxw; meshtriangles = numfaces; - numvertexboneweights = 0; - for (index = 0;index < numvtxw;index++) - for (j = 0;j < numrawweights;j++) - if (rawweights[j].pntsindex == vtxw[index].pntsindex) - numvertexboneweights++; // load external .skin files if present skinfiles = Mod_LoadSkinFiles(); @@ -2087,18 +2337,24 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend) loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes; loadmodel->num_textures = loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts; // do most allocations as one merged chunk - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * sizeof(float[2]) + numvertexboneweights * sizeof(surfmeshvertexboneweight_t) + loadmodel->num_poses * sizeof(float[3][4]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * (sizeof(float[14]) + sizeof(int[4]) + sizeof(float[4])) + loadmodel->num_poses * sizeof(float[36]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); loadmodel->surfmesh.num_vertices = meshvertices; loadmodel->surfmesh.num_triangles = meshtriangles; - loadmodel->surfmesh.num_vertexboneweights = numvertexboneweights; loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]); loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]); + loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]); loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]); - loadmodel->surfmesh.data_vertexboneweights = (surfmeshvertexboneweight_t *)data;data += numvertexboneweights * sizeof(surfmeshvertexboneweight_t); - loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[3][4]); + loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]); + loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]); + loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]); + loadmodel->data_basebonepose = (float *)data;data += loadmodel->num_poses * sizeof(float[12]); + loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_poses * sizeof(float[12]); loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t); loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t); loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); @@ -2126,9 +2382,12 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend) loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices; } - // copy over the texcoords + // copy over the vertex locations and texcoords for (index = 0;index < numvtxw;index++) { + loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0]; + loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1]; + loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2]; loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0]; loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1]; } @@ -2159,32 +2418,46 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend) Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index); } - // build bone-relative vertex weights from the psk point weights - numvertexboneweights = 0; + // sort the psk point weights into the vertex weight tables + // (which only accept up to 4 bones per vertex) for (index = 0;index < numvtxw;index++) { + int l; + float sum; for (j = 0;j < numrawweights;j++) { if (rawweights[j].pntsindex == vtxw[index].pntsindex) { - matrix4x4_t matrix, inversematrix; - loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].vertexindex = index; - loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].boneindex = rawweights[j].boneindex; - loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].weight = rawweights[j].weight; - matrix = identitymatrix; - for (i = rawweights[j].boneindex;i >= 0;i = loadmodel->data_bones[i].parent) + int boneindex = rawweights[j].boneindex; + float influence = rawweights[j].weight; + for (l = 0;l < 4;l++) { - matrix4x4_t childmatrix, tempmatrix; - Mod_PSKMODEL_AnimKeyToMatrix(bones[i].basepose.origin, bones[i].basepose.quat, &tempmatrix); - childmatrix = matrix; - Matrix4x4_Concat(&matrix, &tempmatrix, &childmatrix); + if (loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] < influence) + { + // move lower influence weights out of the way first + int l2; + for (l2 = 3;l2 > l;l2--) + { + loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2-1]; + loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2-1]; + } + // store the new weight + loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] = influence; + loadmodel->surfmesh.data_vertexweightindex4i[index*4+l] = boneindex; + break; + } } - Matrix4x4_Invert_Simple(&inversematrix, &matrix); - Matrix4x4_Transform(&inversematrix, pnts[rawweights[j].pntsindex].origin, loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin); - VectorScale(loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin, loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].weight, loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin); - numvertexboneweights++; } } + sum = 0; + for (l = 0;l < 4;l++) + sum += loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l]; + if (sum && fabs(sum - 1) > (1.0f / 256.0f)) + { + float f = 1.0f / sum; + for (l = 0;l < 4;l++) + loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] *= f; + } } // set up the animscenes based on the anims @@ -2218,13 +2491,18 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend) loadmodel->data_poses[index*12+10] = matrix.m[2][2]; loadmodel->data_poses[index*12+11] = matrix.m[2][3]; } + Mod_FreeSkinFiles(skinfiles); + Mem_Free(animfilebuffer); - // compile extra data we want + // compute all the mesh information that was not loaded from the file + // TODO: honor smoothing groups somehow? Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__); + Mod_BuildBaseBonePoses(); + Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true); + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true); Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); - Mod_Alias_Mesh_CompileFrameZero(); - Mod_FreeSkinFiles(skinfiles); + Mod_Alias_CalculateBoundingBox(); - Mem_Free(animfilebuffer); + loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; }