X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=model_alias.c;h=f394a71b7af8b93022504f795df2fa10ecaf81c6;hb=018f5c7c845311a157da255d819683770c6543c4;hp=ad912f96f658c2a156be83c65f099e03941f2e38;hpb=7a001bd650455489c03aa3ec81471774a36ab4fb;p=xonotic%2Fdarkplaces.git diff --git a/model_alias.c b/model_alias.c index ad912f96..f394a71b 100644 --- a/model_alias.c +++ b/model_alias.c @@ -21,7 +21,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #include "image.h" #include "r_shadow.h" +#include "mod_skeletal_animatevertices_generic.h" +#ifdef SSE_POSSIBLE +#include "mod_skeletal_animatevertices_sse.h" +#endif +#ifdef SSE_POSSIBLE +static qboolean r_skeletal_use_sse_defined = false; +cvar_t r_skeletal_use_sse = {0, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"}; +#endif cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"}; cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"}; cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"}; @@ -32,6 +40,89 @@ cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "suppor float mod_md3_sin[320]; +static size_t Mod_Skeltal_AnimateVertices_maxbonepose = 0; +static void *Mod_Skeltal_AnimateVertices_bonepose = NULL; +void Mod_Skeletal_FreeBuffers(void) +{ + if(Mod_Skeltal_AnimateVertices_bonepose) + Mem_Free(Mod_Skeltal_AnimateVertices_bonepose); + Mod_Skeltal_AnimateVertices_maxbonepose = 0; + Mod_Skeltal_AnimateVertices_bonepose = NULL; +} +void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes) +{ + if(Mod_Skeltal_AnimateVertices_maxbonepose < nbytes) + { + if(Mod_Skeltal_AnimateVertices_bonepose) + Mem_Free(Mod_Skeltal_AnimateVertices_bonepose); + Mod_Skeltal_AnimateVertices_bonepose = Z_Malloc(nbytes); + Mod_Skeltal_AnimateVertices_maxbonepose = nbytes; + } + return Mod_Skeltal_AnimateVertices_bonepose; +} + +void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f) +{ +#ifdef SSE_POSSIBLE + if(r_skeletal_use_sse_defined) + if(r_skeletal_use_sse.integer) + { + Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f); + return; + } +#endif + Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f); +} + +#ifdef SSE_POSSIBLE +#ifndef SSE_PRESENT +// code from SDL, shortened as we can expect CPUID to work +static int CPUID_Features(void) +{ + int features = 0; +# if defined(__GNUC__) && defined(__i386__) + __asm__ ( +" movl %%ebx,%%edi\n" +" xorl %%eax,%%eax \n" +" incl %%eax \n" +" cpuid # Get family/model/stepping/features\n" +" movl %%edx,%0 \n" +" movl %%edi,%%ebx\n" + : "=m" (features) + : + : "%eax", "%ecx", "%edx", "%edi" + ); +# elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + __asm { + xor eax, eax + inc eax + cpuid ; Get family/model/stepping/features + mov features, edx + } +# else +# error SSE_POSSIBLE set but no CPUID implementation +# endif + return features; +} +#endif +static qboolean Have_SSE(void) +{ + // COMMANDLINEOPTION: SSE: -nosse disables SSE support and detection + if(COM_CheckParm("-nosse")) + return false; + // COMMANDLINEOPTION: SSE: -forcesse enables SSE support and disables detection +#ifdef SSE_PRESENT + return true; +#else + if(COM_CheckParm("-forcesse")) + return true; + if(CPUID_Features() & (1 << 25)) + return true; + return false; +#endif +} +#endif + void Mod_AliasInit (void) { int i; @@ -44,196 +135,89 @@ void Mod_AliasInit (void) Cvar_RegisterVariable(&mod_alias_supporttagscale); for (i = 0;i < 320;i++) mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0); -} - -void Mod_Skeletal_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f) -{ -#define MAX_BONES 256 - // vertex weighted skeletal - int i, k; - int blends; - float desiredscale[3]; - float boneposerelative[MAX_BONES][12]; - float *matrix, m[12], bonepose[MAX_BONES][12]; - - // interpolate matrices and concatenate them to their parents - for (i = 0;i < model->num_bones;i++) +#ifdef SSE_POSSIBLE { - for (k = 0;k < 12;k++) - m[k] = 0; - VectorClear(desiredscale); - for (blends = 0;blends < 4 && frameblend[blends].lerp > 0;blends++) + if(Have_SSE()) { - matrix = model->data_poses + (frameblend[blends].frame * model->num_bones + i) * 12; - for (k = 0;k < 12;k++) - m[k] += matrix[k] * frameblend[blends].lerp; - desiredscale[0] += frameblend[blends].lerp * VectorLength(matrix ); - desiredscale[1] += frameblend[blends].lerp * VectorLength(matrix + 4); - desiredscale[2] += frameblend[blends].lerp * VectorLength(matrix + 8); + Con_Printf("Skeletal animation uses SSE code path\n"); + r_skeletal_use_sse_defined = true; + Cvar_RegisterVariable(&r_skeletal_use_sse); } - VectorNormalize(m ); - VectorNormalize(m + 4); - VectorNormalize(m + 8); - VectorScale(m , desiredscale[0], m ); - VectorScale(m + 4, desiredscale[1], m + 4); - VectorScale(m + 8, desiredscale[2], m + 8); - if (i == r_skeletal_debugbone.integer) - m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value; - m[3] *= r_skeletal_debugtranslatex.value; - m[7] *= r_skeletal_debugtranslatey.value; - m[11] *= r_skeletal_debugtranslatez.value; - if (model->data_bones[i].parent >= 0) - R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]); 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 - // special case for the extremely common wf[0] == 1 because it saves 3 multiplies per array when compared to the other case (w[0] is always 1 if only one bone controls this vertex, artists only use multiple bones for certain special cases) - // special case for the first bone because it avoids the need to memset the arrays before filling - { - const float *v = model->surfmesh.data_vertex3f; - const int *wi = model->surfmesh.data_vertexweightindex4i; - const float *wf = model->surfmesh.data_vertexweightinfluence4f; - memset(vertex3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices); - for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, wi += 4, wf += 4, vertex3f += 3) - { - if (wf[0] == 1) - { - const float *m = boneposerelative[wi[0]]; - vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]); - vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]); - vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]); - } - else - { - const float *m = boneposerelative[wi[0]]; - float f = wf[0]; - 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]); - for (k = 1;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]); - } - } - } - } - if (normal3f) - { - const float *n = model->surfmesh.data_normal3f; - const int *wi = model->surfmesh.data_vertexweightindex4i; - const float *wf = model->surfmesh.data_vertexweightinfluence4f; - memset(normal3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices); - for (i = 0;i < model->surfmesh.num_vertices;i++, n += 3, wi += 4, wf += 4, normal3f += 3) - { - if (wf[0] == 1) - { - const float *m = boneposerelative[wi[0]]; - normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]); - normal3f[1] = (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]); - normal3f[2] = (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]); - } - else - { - const float *m = boneposerelative[wi[0]]; - float f = wf[0]; - 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]); - for (k = 1;k < 4 && wf[k];k++) - { - const float *m = boneposerelative[wi[k]]; - float f = wf[k]; - 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]); - } - } - } + Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n"); } - if (svector3f) - { - const float *sv = model->surfmesh.data_svector3f; - const int *wi = model->surfmesh.data_vertexweightindex4i; - const float *wf = model->surfmesh.data_vertexweightinfluence4f; - memset(svector3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices); - for (i = 0;i < model->surfmesh.num_vertices;i++, sv += 3, wi += 4, wf += 4, svector3f += 3) +#else + Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n"); +#endif +} + +int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights) +{ + int i; + blendweights_t *weights; + if(!newweights->influence[1]) + return newweights->index[0]; + weights = model->surfmesh.data_blendweights; + for (i = 0;i < model->surfmesh.num_blends;i++, weights++) + { + if (!memcmp(weights, newweights, sizeof(blendweights_t))) + return model->num_bones + i; + } + model->surfmesh.num_blends++; + memcpy(weights, newweights, sizeof(blendweights_t)); + return model->num_bones + i; +} + +int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const float *newinfluence) +{ + int i, total; + float scale; + blendweights_t newweights; + if(!newinfluence[1]) + return newindex[0]; + scale = 0; + for (i = 0;i < 4;i++) + scale += newinfluence[i]; + scale = 255.0f / scale; + total = 0; + for (i = 0;i < 4;i++) + { + newweights.index[i] = newindex[i]; + newweights.influence[i] = (unsigned char)(newinfluence[i] * scale); + total += newweights.influence[i]; + } + while (total > 255) + { + for (i = 0;i < 4;i++) { - if (wf[0] == 1) - { - const float *m = boneposerelative[wi[0]]; - svector3f[0] = (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]); - svector3f[1] = (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]); - svector3f[2] = (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]); - } - else - { - const float *m = boneposerelative[wi[0]]; - float f = wf[0]; - 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]); - for (k = 1;k < 4 && wf[k];k++) - { - const float *m = boneposerelative[wi[k]]; - float f = wf[k]; - 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]); - } + if(newweights.influence[i] > 0 && total > 255) + { + newweights.influence[i]--; + total--; } } } - if (tvector3f) + while (total < 255) { - const float *tv = model->surfmesh.data_tvector3f; - const int *wi = model->surfmesh.data_vertexweightindex4i; - const float *wf = model->surfmesh.data_vertexweightinfluence4f; - memset(tvector3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices); - for (i = 0;i < model->surfmesh.num_vertices;i++, tv += 3, wi += 4, wf += 4, tvector3f += 3) + for (i = 0; i < 4;i++) { - if (wf[0] == 1) - { - const float *m = boneposerelative[wi[0]]; - tvector3f[0] = (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]); - tvector3f[1] = (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]); - tvector3f[2] = (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]); - } - else - { - const float *m = boneposerelative[wi[0]]; - float f = wf[0]; - 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]); - for (k = 1;k < 4 && wf[k];k++) - { - const float *m = boneposerelative[wi[k]]; - float f = wf[k]; - 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]); - } + if(newweights.influence[i] < 255 && total < 255) + { + newweights.influence[i]++; + total++; } } } + return Mod_Skeletal_AddBlend(model, &newweights); } -void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f) +void Mod_MD3_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f) { // vertex morph int i, numblends, blendnum; int numverts = model->surfmesh.num_vertices; numblends = 0; - for (blendnum = 0;blendnum < 4;blendnum++) + for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++) { //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate); if (frameblend[blendnum].lerp > 0) @@ -242,24 +226,27 @@ void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb // special case for the first blend because it avoids some adds and the need to memset the arrays first for (blendnum = 0;blendnum < numblends;blendnum++) { - const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].frame; - float scale = frameblend[blendnum].lerp * (1.0f / 64.0f); - if (blendnum == 0) + const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe; + if (vertex3f) { - for (i = 0;i < numverts;i++) + float scale = frameblend[blendnum].lerp * (1.0f / 64.0f); + if (blendnum == 0) { - 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; + for (i = 0;i < numverts;i++) + { + 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; + } } - } - else - { - for (i = 0;i < numverts;i++) + else { - 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; + for (i = 0;i < numverts;i++) + { + 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 @@ -291,7 +278,7 @@ void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb } if (svector3f) { - const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame; + const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe; float f = frameblend[blendnum].lerp * (1.0f / 127.0f); if (blendnum == 0) { @@ -312,8 +299,7 @@ void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb } } } - -void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f) +void Mod_MDL_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f) { // vertex morph int i, numblends, blendnum; @@ -323,10 +309,10 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb numblends = 0; // blend the frame translates to avoid redundantly doing so on each vertex // (a bit of a brain twister but it works) - for (blendnum = 0;blendnum < 4;blendnum++) + for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++) { if (model->surfmesh.data_morphmd2framesize6f) - VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6 + 3, translate); + VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate); else VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate); if (frameblend[blendnum].lerp > 0) @@ -335,28 +321,31 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb // special case for the first blend because it avoids some adds and the need to memset the arrays first 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); - if (blendnum == 0) + const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe; + if (vertex3f) { - for (i = 0;i < numverts;i++) + float scale[3]; + if (model->surfmesh.data_morphmd2framesize6f) + VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale); + else + VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale); + if (blendnum == 0) { - vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0]; - vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1]; - vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2]; + for (i = 0;i < numverts;i++) + { + vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0]; + vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1]; + vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2]; + } } - } - else - { - for (i = 0;i < numverts;i++) + else { - 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]; + 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 @@ -385,7 +374,7 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb } if (svector3f) { - const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame; + const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe; float f = frameblend[blendnum].lerp * (1.0f / 127.0f); if (blendnum == 0) { @@ -407,34 +396,65 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb } } -int Mod_Alias_GetTagMatrix(const dp_model_t *model, int poseframe, int tagindex, matrix4x4_t *outmatrix) +int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix) { - const float *boneframe; - float tempbonematrix[12], bonematrix[12]; + matrix4x4_t temp; + matrix4x4_t parentbonematrix; + matrix4x4_t tempbonematrix; + matrix4x4_t bonematrix; + matrix4x4_t blendmatrix; + int blendindex; + int parenttagindex; + int k; + float lerp; + const float *input; + float blendtag[12]; *outmatrix = identitymatrix; - if (model->num_bones) + if (skeleton && skeleton->relativetransforms) + { + if (tagindex < 0 || tagindex >= skeleton->model->num_bones) + return 4; + *outmatrix = skeleton->relativetransforms[tagindex]; + while ((tagindex = model->data_bones[tagindex].parent) >= 0) + { + temp = *outmatrix; + Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp); + } + } + else if (model->num_bones) { if (tagindex < 0 || tagindex >= model->num_bones) return 4; - if (poseframe >= model->num_poses) - return 6; - boneframe = model->data_poses + poseframe * model->num_bones * 12; - memcpy(bonematrix, boneframe + tagindex * 12, sizeof(float[12])); - while (model->data_bones[tagindex].parent >= 0) + Matrix4x4_Clear(&blendmatrix); + for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++) { - memcpy(tempbonematrix, bonematrix, sizeof(float[12])); - R_ConcatTransforms(boneframe + model->data_bones[tagindex].parent * 12, tempbonematrix, bonematrix); - tagindex = model->data_bones[tagindex].parent; + lerp = frameblend[blendindex].lerp; + Matrix4x4_FromBonePose6s(&bonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + tagindex)); + parenttagindex = tagindex; + while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0) + { + Matrix4x4_FromBonePose6s(&parentbonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex)); + tempbonematrix = bonematrix; + Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix); + } + Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp); } - Matrix4x4_FromArray12FloatD3D(outmatrix, bonematrix); + *outmatrix = blendmatrix; } else if (model->num_tags) { if (tagindex < 0 || tagindex >= model->num_tags) return 4; - if (poseframe >= model->num_tagframes) - return 6; - Matrix4x4_FromArray12FloatGL(outmatrix, model->data_tags[poseframe * model->num_tags + tagindex].matrixgl); + for (k = 0;k < 12;k++) + blendtag[k] = 0; + for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++) + { + lerp = frameblend[blendindex].lerp; + input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl; + for (k = 0;k < 12;k++) + blendtag[k] += input[k] * lerp; + } + Matrix4x4_FromArray12FloatGL(outmatrix, blendtag); } if(!mod_alias_supporttagscale.integer) @@ -443,35 +463,57 @@ int Mod_Alias_GetTagMatrix(const dp_model_t *model, int poseframe, int tagindex, return 0; } -int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, int poseframe, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix) +int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix) { - const float *boneframe; - - if(skin >= (unsigned int)model->numskins) - skin = 0; + int blendindex; + int k; + float lerp; + matrix4x4_t bonematrix; + matrix4x4_t blendmatrix; + const float *input; + float blendtag[12]; - if (model->num_bones) + if (skeleton && skeleton->relativetransforms) { - if(tagindex >= model->num_bones || tagindex < 0) + if (tagindex < 0 || tagindex >= skeleton->model->num_bones) + return 1; + *parentindex = skeleton->model->data_bones[tagindex].parent; + *tagname = skeleton->model->data_bones[tagindex].name; + *tag_localmatrix = skeleton->relativetransforms[tagindex]; + return 0; + } + else if (model->num_bones) + { + if (tagindex < 0 || tagindex >= model->num_bones) return 1; - if (poseframe >= model->num_poses) - return 2; - - boneframe = model->data_poses + poseframe * model->num_bones * 12; *parentindex = model->data_bones[tagindex].parent; *tagname = model->data_bones[tagindex].name; - Matrix4x4_FromArray12FloatD3D(tag_localmatrix, boneframe + tagindex * 12); + Matrix4x4_Clear(&blendmatrix); + for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++) + { + lerp = frameblend[blendindex].lerp; + Matrix4x4_FromBonePose6s(&bonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + tagindex)); + Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp); + } + *tag_localmatrix = blendmatrix; return 0; } - - if (model->num_tags) + else if (model->num_tags) { - if(tagindex >= model->num_tags || tagindex < 0) + if (tagindex < 0 || tagindex >= model->num_tags) return 1; - if (poseframe >= model->num_tagframes) - return 2; + *parentindex = -1; *tagname = model->data_tags[tagindex].name; - Matrix4x4_FromArray12FloatGL(tag_localmatrix, model->data_tags[poseframe * model->num_tags + tagindex].matrixgl); + for (k = 0;k < 12;k++) + blendtag[k] = 0; + for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++) + { + lerp = frameblend[blendindex].lerp; + input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl; + for (k = 0;k < 12;k++) + blendtag[k] += input[k] * lerp; + } + Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag); return 0; } @@ -496,44 +538,25 @@ int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, con static void Mod_BuildBaseBonePoses(void) { - int i, k; - double scale; - float *basebonepose = (float *) Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(float[12])); - float *in12f = loadmodel->data_poses; - float *out12f = basebonepose; - float *outinv12f = loadmodel->data_baseboneposeinverse; - for (i = 0;i < loadmodel->num_bones;i++, in12f += 12, out12f += 12, outinv12f += 12) + int boneindex; + matrix4x4_t *basebonepose; + float *outinvmatrix = loadmodel->data_baseboneposeinverse; + matrix4x4_t bonematrix; + matrix4x4_t tempbonematrix; + if (!loadmodel->num_bones) + return; + basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t)); + for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++) { - if (loadmodel->data_bones[i].parent >= 0) - R_ConcatTransforms(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]); + Matrix4x4_FromBonePose6s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses6s + 6 * boneindex); + if (loadmodel->data_bones[boneindex].parent >= 0) + { + tempbonematrix = bonematrix; + Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix); + } + basebonepose[boneindex] = bonematrix; + Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex); + Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex); } Mem_Free(basebonepose); } @@ -545,7 +568,7 @@ static void Mod_Alias_CalculateBoundingBox(void) float dist, yawradius, radius; float *v; float *vertex3f; - frameblend_t frameblend[4]; + frameblend_t frameblend[MAX_FRAMEBLENDS]; memset(frameblend, 0, sizeof(frameblend)); frameblend[0].lerp = 1; vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3])); @@ -553,9 +576,9 @@ static void Mod_Alias_CalculateBoundingBox(void) VectorClear(loadmodel->normalmaxs); yawradius = 0; radius = 0; - for (frameblend[0].frame = 0;frameblend[0].frame < loadmodel->num_poses;frameblend[0].frame++) + for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++) { - loadmodel->AnimateVertices(loadmodel, frameblend, vertex3f, NULL, NULL, NULL); + loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL); for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3) { if (firstvertex) @@ -581,7 +604,8 @@ static void Mod_Alias_CalculateBoundingBox(void) radius = dist; } } - Mem_Free(vertex3f); + if (vertex3f) + Mem_Free(vertex3f); radius = sqrt(radius); yawradius = sqrt(yawradius); loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius; @@ -597,8 +621,10 @@ static void Mod_Alias_CalculateBoundingBox(void) static void Mod_Alias_MorphMesh_CompileFrames(void) { int i, j; - frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}}; + frameblend_t frameblend[MAX_FRAMEBLENDS]; unsigned char *datapointer; + memset(frameblend, 0, sizeof(frameblend)); + frameblend[0].lerp = 1; datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t))); loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]); loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]); @@ -608,9 +634,9 @@ static void Mod_Alias_MorphMesh_CompileFrames(void) // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there) for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--) { - frameblend[0].frame = i; - loadmodel->AnimateVertices(loadmodel, frameblend, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL); - 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, r_smoothnormals_areaweighting.integer); + frameblend[0].subframe = i; + loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL); + 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, r_smoothnormals_areaweighting.integer != 0); // encode the svector and tvector in 3 byte format for permanent storage for (j = 0;j < loadmodel->surfmesh.num_vertices;j++) { @@ -620,11 +646,10 @@ static void Mod_Alias_MorphMesh_CompileFrames(void) } } -static void Mod_MDLMD2MD3_TraceBox(dp_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) +static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask) { int i; float segmentmins[3], segmentmaxs[3]; - frameblend_t frameblend[4]; msurface_t *surface; static int maxvertices = 0; static float *vertex3f = NULL; @@ -632,9 +657,6 @@ static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, int frame, trace_t *trace, trace->fraction = 1; trace->realfraction = 1; trace->hitsupercontentsmask = hitsupercontentsmask; - memset(frameblend, 0, sizeof(frameblend)); - frameblend[0].frame = frame; - frameblend[0].lerp = 1; if (maxvertices < model->surfmesh.num_vertices) { if (vertex3f) @@ -642,51 +664,72 @@ static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, int frame, trace_t *trace, maxvertices = (model->surfmesh.num_vertices + 255) & ~255; vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3])); } - if (VectorLength2(boxmins) + VectorLength2(boxmaxs) == 0) + segmentmins[0] = min(start[0], end[0]) - 1; + segmentmins[1] = min(start[1], end[1]) - 1; + segmentmins[2] = min(start[2], end[2]) - 1; + segmentmaxs[0] = max(start[0], end[0]) + 1; + segmentmaxs[1] = max(start[1], end[1]) + 1; + segmentmaxs[2] = max(start[2], end[2]) + 1; + model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL); + for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++) + Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs); +} + +static int maxvertices = 0; +static float *vertex3f = NULL; + +static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask) +{ + int i; + vec3_t shiftstart, shiftend; + float segmentmins[3], segmentmaxs[3]; + msurface_t *surface; + colboxbrushf_t thisbrush_start, thisbrush_end; + vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs; + + if (VectorCompare(boxmins, boxmaxs)) { - // line trace - segmentmins[0] = min(start[0], end[0]) - 1; - segmentmins[1] = min(start[1], end[1]) - 1; - segmentmins[2] = min(start[2], end[2]) - 1; - segmentmaxs[0] = max(start[0], end[0]) + 1; - segmentmaxs[1] = max(start[1], end[1]) + 1; - segmentmaxs[2] = max(start[2], end[2]) + 1; - for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++) - { - model->AnimateVertices(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); - } + VectorAdd(start, boxmins, shiftstart); + VectorAdd(end, boxmins, shiftend); + Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask); + VectorSubtract(trace->endpos, boxmins, trace->endpos); + return; } - else + + // box trace, performed as brush trace + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + if (maxvertices < model->surfmesh.num_vertices) { - // box trace, performed as brush trace - colbrushf_t *thisbrush_start, *thisbrush_end; - vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs; - segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1; - segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1; - segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1; - segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1; - segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1; - segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1; - VectorAdd(start, boxmins, boxstartmins); - VectorAdd(start, boxmaxs, boxstartmaxs); - VectorAdd(end, boxmins, boxendmins); - VectorAdd(end, boxmaxs, boxendmaxs); - thisbrush_start = Collision_BrushForBox(&identitymatrix, boxstartmins, boxstartmaxs, 0, 0, NULL); - thisbrush_end = Collision_BrushForBox(&identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL); - for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++) - { - if (maxvertices < model->surfmesh.num_vertices) - { - if (vertex3f) - Z_Free(vertex3f); - maxvertices = (model->surfmesh.num_vertices + 255) & ~255; - vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3])); - } - model->AnimateVertices(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); - } + if (vertex3f) + Z_Free(vertex3f); + maxvertices = (model->surfmesh.num_vertices + 255) & ~255; + vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3])); + } + segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1; + segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1; + segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1; + segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1; + segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1; + segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1; + VectorAdd(start, boxmins, boxstartmins); + VectorAdd(start, boxmaxs, boxstartmaxs); + VectorAdd(end, boxmins, boxendmins); + VectorAdd(end, boxmaxs, boxendmaxs); + Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL); + Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL); + if (maxvertices < model->surfmesh.num_vertices) + { + if (vertex3f) + Z_Free(vertex3f); + maxvertices = (model->surfmesh.num_vertices + 255) & ~255; + vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3])); } + model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL); + for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++) + Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs); } static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap) @@ -790,14 +833,23 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *ski //texture->textureflags = 0; texture->basematerialflags = MATERIALFLAG_WALL; - if (texture->currentskinframe->fog) + if (texture->currentskinframe->hasalpha) texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; texture->currentmaterialflags = texture->basematerialflags; + texture->offsetmapping = OFFSETMAPPING_OFF; + texture->offsetscale = 1; + texture->specularscalemod = 1; + texture->specularpowermod = 1; + texture->surfaceflags = 0; + texture->supercontents = SUPERCONTENTS_SOLID; + if (!(texture->basematerialflags & MATERIALFLAG_BLENDED)) + texture->supercontents |= SUPERCONTENTS_OPAQUE; } -static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername) +void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername) { int i; + static char stripbuf[MAX_QPATH]; skinfileitem_t *skinfileitem; if (skinfile) { @@ -811,7 +863,8 @@ static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfi // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw" if (!strcmp(skinfileitem->name, meshname)) { - Mod_LoadTextureFromQ3Shader(skin, skinfileitem->replacement, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS); + Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf)); + Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); break; } } @@ -824,7 +877,10 @@ static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfi } } else - Mod_LoadTextureFromQ3Shader(skin, shadername, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS); + { + Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf)); + Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); + } } #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)", loadmodel->name, VALUE, MIN, MAX); @@ -870,10 +926,15 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->Draw = R_Q1BSP_Draw; loadmodel->DrawDepth = R_Q1BSP_DrawDepth; loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; loadmodel->DrawLight = R_Q1BSP_DrawLight; loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; + // FIXME add TraceBrush! loadmodel->PointSuperContents = NULL; loadmodel->num_surfaces = 1; @@ -896,7 +957,7 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->numframes = LittleLong(pinmodel->numframes); BOUNDI(loadmodel->numframes,0,65536); loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype); - BOUNDI(loadmodel->synctype,0,2); + BOUNDI((int)loadmodel->synctype,0,2); // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc) i = LittleLong (pinmodel->flags); loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00); @@ -1027,11 +1088,10 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) // generate ushort elements array if possible if (loadmodel->surfmesh.num_vertices <= 65536) - { loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles); + if (loadmodel->surfmesh.data_element3s) for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; - } // load the frames loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); @@ -1160,6 +1220,16 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) surface->num_vertices = loadmodel->surfmesh.num_vertices; loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } } void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend) @@ -1200,10 +1270,14 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->Draw = R_Q1BSP_Draw; loadmodel->DrawDepth = R_Q1BSP_DrawDepth; loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; loadmodel->DrawLight = R_Q1BSP_DrawLight; loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; loadmodel->PointSuperContents = NULL; if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536) @@ -1270,7 +1344,7 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->num_texturesperskin = loadmodel->num_surfaces; loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME) - Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS); + Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); } else { @@ -1356,11 +1430,10 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend) // generate ushort elements array if possible if (loadmodel->surfmesh.num_vertices <= 65536) - { loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles); + if (loadmodel->surfmesh.data_element3s) for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; - } // load the frames datapointer = (base + LittleLong(pinmodel->ofs_frames)); @@ -1405,6 +1478,16 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend) surface->num_vertices = loadmodel->surfmesh.num_vertices; loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } } void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend) @@ -1440,10 +1523,14 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->Draw = R_Q1BSP_Draw; loadmodel->DrawDepth = R_Q1BSP_DrawDepth; loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; loadmodel->DrawLight = R_Q1BSP_DrawLight; loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; loadmodel->PointSuperContents = NULL; loadmodel->synctype = ST_RAND; // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc) @@ -1518,11 +1605,7 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]); loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t); if (meshvertices <= 65536) - { loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]); - for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) - loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; - } meshvertices = 0; meshtriangles = 0; @@ -1565,6 +1648,9 @@ void Mod_IDP3_Load(dp_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__); } + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); Mod_Alias_MorphMesh_CompileFrames(); Mod_Alias_CalculateBoundingBox(); @@ -1573,6 +1659,16 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } } void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) @@ -1580,7 +1676,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) zymtype1header_t *pinmodel, *pheader; unsigned char *pbase; int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements; - float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose; + float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale; zymvertex_t *verts, *vertdata; zymscene_t *scene; zymbone_t *bone; @@ -1653,10 +1749,14 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->Draw = R_Q1BSP_Draw; loadmodel->DrawDepth = R_Q1BSP_DrawDepth; loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; loadmodel->DrawLight = R_Q1BSP_DrawLight; loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; loadmodel->PointSuperContents = NULL; loadmodel->numframes = pheader->numscenes; @@ -1720,7 +1820,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) //zymlump_t lump_bones; // zymbone_t bone[numbones]; loadmodel->num_bones = pheader->numbones; - loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, pheader->numbones * sizeof(aliasbone_t)); + loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t)); bone = (zymbone_t *) (pheader->lump_bones.start + pbase); for (i = 0;i < pheader->numbones;i++) { @@ -1741,7 +1841,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) 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]); + loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones; meshvertices = pheader->numverts; meshtriangles = pheader->numtris; @@ -1749,7 +1849,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->nummodelsurfaces = loadmodel->num_surfaces; loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; loadmodel->num_texturesperskin = 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 <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[14]) + meshvertices * sizeof(int[4]) + meshvertices * sizeof(float[4]) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12])); + 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 <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[14]) + meshvertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12])); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); @@ -1762,21 +1862,55 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) 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_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_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]); + loadmodel->surfmesh.num_blends = 0; + loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short); if (loadmodel->surfmesh.num_vertices <= 65536) - { loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]); - for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) - loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; - } + loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]); + loadmodel->surfmesh.data_blendweights = NULL; //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data poses = (float *) (pheader->lump_poses.start + pbase); - for (i = 0;i < pheader->lump_poses.length / 4;i++) - loadmodel->data_poses[i] = BigFloat(poses[i]); + // figure out scale of model from root bone, for compatibility with old zmodel versions + tempvec[0] = BigFloat(poses[0]); + tempvec[1] = BigFloat(poses[1]); + tempvec[2] = BigFloat(poses[2]); + modelscale = VectorLength(tempvec); + biggestorigin = 0; + for (i = 0;i < loadmodel->num_bones * numposes * 12;i++) + { + f = fabs(BigFloat(poses[i])); + biggestorigin = max(biggestorigin, f); + } + loadmodel->num_posescale = biggestorigin / 32767.0f; + loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale; + for (i = 0;i < numposes;i++) + { + const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones; + for (j = 0;j < loadmodel->num_bones;j++) + { + float pose[12]; + matrix4x4_t posematrix; + for (k = 0;k < 12;k++) + pose[k] = BigFloat(frameposes[j*12+k]); + //if (j < loadmodel->num_bones) + // Con_Printf("%s: bone %i = %f %f %f %f : %f %f %f %f : %f %f %f %f : scale = %f\n", loadmodel->name, j, pose[0], pose[1], pose[2], pose[3], pose[4], pose[5], pose[6], pose[7], pose[8], pose[9], pose[10], pose[11], VectorLength(pose)); + // scale child bones to match the root scale + if (loadmodel->data_bones[j].parent >= 0) + { + pose[3] *= modelscale; + pose[7] *= modelscale; + pose[11] *= modelscale; + } + // normalize rotation matrix + VectorNormalize(pose + 0); + VectorNormalize(pose + 4); + VectorNormalize(pose + 8); + Matrix4x4_FromArray12FloatD3D(&posematrix, pose); + Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j)); + } + } //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length); @@ -1787,7 +1921,9 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) 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; + float m[12]; + for (k = 0;k < 12;k++) + m[k] = BigFloat(poses[i*12+k]); if (loadmodel->data_bones[i].parent >= 0) R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i); else @@ -1810,8 +1946,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) 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; + loadmodel->surfmesh.blends[j] = boneindex; } Z_Free(bonepose); // normals and tangents are calculated after elements are loaded @@ -1887,6 +2022,9 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) Mod_MakeSortedSurfaces(loadmodel); // compute all the mesh information that was not loaded from the file + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; 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); @@ -1894,12 +2032,22 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) 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; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } } void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) { dpmheader_t *pheader; - dpmframe_t *frame; + dpmframe_t *frames; dpmbone_t *bone; dpmmesh_t *dpmmesh; unsigned char *pbase; @@ -1907,6 +2055,9 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) skinfile_t *skinfiles; unsigned char *data; float *bonepose; + float biggestorigin, tempvec[3], modelscale; + float f; + float *poses; pheader = (dpmheader_t *)buffer; pbase = (unsigned char *)buffer; @@ -1955,10 +2106,14 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->Draw = R_Q1BSP_Draw; loadmodel->DrawDepth = R_Q1BSP_DrawDepth; loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; loadmodel->DrawLight = R_Q1BSP_DrawLight; loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; loadmodel->PointSuperContents = NULL; // model bbox @@ -1994,12 +2149,12 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->numframes = pheader->num_frames; loadmodel->num_bones = pheader->num_bones; - loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes; + loadmodel->num_poses = loadmodel->numframes; loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs; loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; loadmodel->num_texturesperskin = loadmodel->num_surfaces; // 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]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshtriangles * sizeof(int[3]) + meshvertices * (sizeof(float[14]) + sizeof(int[4]) + sizeof(float[4])) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]) + 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]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshtriangles * sizeof(int[3]) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short)) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + 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->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); @@ -2012,19 +2167,16 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) 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_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_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * 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); + loadmodel->surfmesh.num_blends = 0; + loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short); if (meshvertices <= 65536) - { loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]); - for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) - loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; - } + loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]); + loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t)); for (i = 0;i < loadmodel->numskins;i++) { @@ -2046,21 +2198,55 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) } // load the frames - frame = (dpmframe_t *) (pbase + pheader->ofs_frames); + frames = (dpmframe_t *) (pbase + pheader->ofs_frames); + // figure out scale of model from root bone, for compatibility with old dpmodel versions + poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions)); + tempvec[0] = BigFloat(poses[0]); + tempvec[1] = BigFloat(poses[1]); + tempvec[2] = BigFloat(poses[2]); + modelscale = VectorLength(tempvec); + biggestorigin = 0; for (i = 0;i < loadmodel->numframes;i++) { - const float *poses; - memcpy(loadmodel->animscenes[i].name, frame->name, sizeof(frame->name)); + memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name)); loadmodel->animscenes[i].firstframe = i; loadmodel->animscenes[i].framecount = 1; loadmodel->animscenes[i].loop = true; loadmodel->animscenes[i].framerate = 10; // load the bone poses for this frame - poses = (float *) (pbase + BigLong(frame->ofs_bonepositions)); + poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions)); for (j = 0;j < loadmodel->num_bones*12;j++) - loadmodel->data_poses[i * loadmodel->num_bones*12 + j] = BigFloat(poses[j]); + { + f = fabs(BigFloat(poses[j])); + biggestorigin = max(biggestorigin, f); + } // stuff not processed here: mins, maxs, yawradius, allradius - frame++; + } + loadmodel->num_posescale = biggestorigin / 32767.0f; + loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale; + for (i = 0;i < loadmodel->numframes;i++) + { + const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions)); + for (j = 0;j < loadmodel->num_bones;j++) + { + float pose[12]; + matrix4x4_t posematrix; + for (k = 0;k < 12;k++) + pose[k] = BigFloat(frameposes[j*12+k]); + // scale child bones to match the root scale + if (loadmodel->data_bones[j].parent >= 0) + { + pose[3] *= modelscale; + pose[7] *= modelscale; + pose[11] *= modelscale; + } + // normalize rotation matrix + VectorNormalize(pose + 0); + VectorNormalize(pose + 4); + VectorNormalize(pose + 8); + Matrix4x4_FromArray12FloatD3D(&posematrix, pose); + Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j)); + } } // load the meshes now @@ -2070,10 +2256,13 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) // reconstruct frame 0 matrices to allow reconstruction of the base mesh // (converting from weight-blending skeletal animation to // deformation-based skeletal animation) + poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions)); 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; + float m[12]; + for (k = 0;k < 12;k++) + m[k] = BigFloat(poses[i*12+k]); if (loadmodel->data_bones[i].parent >= 0) R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i); else @@ -2116,7 +2305,8 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts)); for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++) { - float sum; + int weightindex[4] = { 0, 0, 0, 0 }; + float weightinfluence[4] = { 0, 0, 0, 0 }; int l; int numweights = BigLong(((dpmvertex_t *)data)->numbones); data += sizeof(dpmvertex_t); @@ -2143,8 +2333,8 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) 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; + weightinfluence[0] = influence; + weightindex[0] = boneindex; } else { @@ -2152,33 +2342,25 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) // (which only accepts up to 4 bones per vertex) for (l = 0;l < 4;l++) { - if (loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] < influence) + if (weightinfluence[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]; + weightinfluence[l2] = weightinfluence[l2-1]; + weightindex[l2] = weightindex[l2-1]; } // store the new weight - loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] = influence; - loadmodel->surfmesh.data_vertexweightindex4i[j*4+l] = boneindex; + weightinfluence[l] = influence; + weightindex[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; - } + loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence); } // since dpm models do not have named sections, reuse their shader name as the section name @@ -2186,16 +2368,31 @@ void Mod_DARKPLACESMODEL_Load(dp_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__); } + if (loadmodel->surfmesh.num_blends < meshvertices) + loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t)); Z_Free(bonepose); Mod_FreeSkinFiles(skinfiles); Mod_MakeSortedSurfaces(loadmodel); // compute all the mesh information that was not loaded from the file + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; 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; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } } // no idea why PSK/PSA files contain weird quaternions but they do... @@ -2211,7 +2408,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) pskmatt_t *matts; pskboneinfo_t *bones; pskrawweights_t *rawweights; - pskboneinfo_t *animbones; + //pskboneinfo_t *animbones; pskaniminfo_t *anims; pskanimkeys_t *animkeys; void *animfilebuffer, *animbuffer, *animbufferend; @@ -2220,6 +2417,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) skinfile_t *skinfiles; char animname[MAX_QPATH]; size_t size; + float biggestorigin; pchunk = (pskchunk_t *)buffer; if (strcmp(pchunk->id, "ACTRHEAD")) @@ -2234,10 +2432,14 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->Draw = R_Q1BSP_Draw; loadmodel->DrawDepth = R_Q1BSP_DrawDepth; loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; loadmodel->DrawLight = R_Q1BSP_DrawLight; loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; loadmodel->PointSuperContents = NULL; loadmodel->synctype = ST_RAND; @@ -2272,8 +2474,8 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) version = LittleLong(pchunk->version); recordsize = LittleLong(pchunk->recordsize); numrecords = LittleLong(pchunk->numrecords); - if (developer.integer >= 100) - Con_Printf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords); + if (developer_extra.integer) + Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords); if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0) Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", loadmodel->name, pchunk->id, version); if (!strcmp(pchunk->id, "ACTRHEAD")) @@ -2443,8 +2645,8 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) version = LittleLong(pchunk->version); recordsize = LittleLong(pchunk->recordsize); numrecords = LittleLong(pchunk->numrecords); - if (developer.integer >= 100) - Con_Printf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords); + if (developer_extra.integer) + Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords); if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0) Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", animname, pchunk->id, version); if (!strcmp(pchunk->id, "ANIMHEAD")) @@ -2458,7 +2660,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id); // byteswap in place and keep the pointer numanimbones = numrecords; - animbones = (pskboneinfo_t *)animbuffer; + //animbones = (pskboneinfo_t *)animbuffer; // NOTE: supposedly psa does not need to match the psk model, the // bones missing from the psa would simply use their base // positions from the psk, but this is hard for me to implement @@ -2582,14 +2784,14 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) if (loadmodel->numskins < 1) loadmodel->numskins = 1; loadmodel->num_bones = numbones; - loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes; + loadmodel->num_poses = loadmodel->numframes; loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts; loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; loadmodel->num_texturesperskin = loadmodel->num_surfaces; loadmodel->surfmesh.num_vertices = meshvertices; loadmodel->surfmesh.num_triangles = meshtriangles; // do most allocations as one merged chunk - size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(int[4]) + loadmodel->surfmesh.num_vertices * sizeof(float[4]) + /*loadmodel->num_poses * sizeof(float[12]) + */loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0); + size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0); data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); @@ -2601,20 +2803,16 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]); loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]); loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]); - loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += loadmodel->surfmesh.num_vertices * sizeof(int[4]); - loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[4]); - //loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]); loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * 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); + loadmodel->surfmesh.num_blends = 0; + loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short); if (loadmodel->surfmesh.num_vertices <= 65536) - { loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]); - for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) - loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; - } - loadmodel->data_poses = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->num_poses * sizeof(float[12])); + loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]); + loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t)); for (i = 0;i < loadmodel->numskins;i++) { @@ -2675,8 +2873,9 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) // (which only accept up to 4 bones per vertex) for (index = 0;index < numvtxw;index++) { + int weightindex[4] = { 0, 0, 0, 0 }; + float weightinfluence[4] = { 0, 0, 0, 0 }; int l; - float sum; for (j = 0;j < numrawweights;j++) { if (rawweights[j].pntsindex == vtxw[index].pntsindex) @@ -2685,33 +2884,27 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) float influence = rawweights[j].weight; for (l = 0;l < 4;l++) { - if (loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] < influence) + if (weightinfluence[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]; + weightinfluence[l2] = weightinfluence[l2-1]; + weightindex[l2] = weightindex[l2-1]; } // store the new weight - loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] = influence; - loadmodel->surfmesh.data_vertexweightindex4i[index*4+l] = boneindex; + weightinfluence[l] = influence; + weightindex[l] = boneindex; break; } } } } - 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; - } + loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence); } + if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices) + loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t)); // set up the animscenes based on the anims for (index = 0, i = 0;index < numanims;index++) @@ -2722,17 +2915,38 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->animscenes[i].firstframe = i; loadmodel->animscenes[i].framecount = 1; loadmodel->animscenes[i].loop = true; - loadmodel->animscenes[i].framerate = 10; + loadmodel->animscenes[i].framerate = anims[index].fps; } } + // calculate the scaling value for bone origins so they can be compressed to short + biggestorigin = 0; + for (index = 0;index < numanimkeys;index++) + { + pskanimkeys_t *k = animkeys + index; + biggestorigin = max(biggestorigin, fabs(k->origin[0])); + biggestorigin = max(biggestorigin, fabs(k->origin[1])); + biggestorigin = max(biggestorigin, fabs(k->origin[2])); + } + loadmodel->num_posescale = biggestorigin / 32767.0f; + loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale; + // load the poses from the animkeys for (index = 0;index < numanimkeys;index++) { pskanimkeys_t *k = animkeys + index; - matrix4x4_t matrix; - Matrix4x4_FromOriginQuat(&matrix, k->origin[0], k->origin[1], k->origin[2], k->quat[0], k->quat[1], k->quat[2], k->quat[3]); - Matrix4x4_ToArray12FloatD3D(&matrix, loadmodel->data_poses + index*12); + float quat[4]; + Vector4Copy(k->quat, quat); + if (quat[3] > 0) + Vector4Negate(quat, quat); + Vector4Normalize2(quat, quat); + // compress poses to the short[6] format for longterm storage + loadmodel->data_poses6s[index*6+0] = k->origin[0] * loadmodel->num_poseinvscale; + loadmodel->data_poses6s[index*6+1] = k->origin[1] * loadmodel->num_poseinvscale; + loadmodel->data_poses6s[index*6+2] = k->origin[2] * loadmodel->num_poseinvscale; + loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f; + loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f; + loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f; } Mod_FreeSkinFiles(skinfiles); Mem_Free(animfilebuffer); @@ -2740,6 +2954,9 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) // compute all the mesh information that was not loaded from the file // TODO: honor smoothing groups somehow? + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; 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); @@ -2748,309 +2965,219 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) Mod_Alias_CalculateBoundingBox(); loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } } -void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) +void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) { -#if 0 - const char *textbase = (char *)buffer, *text = textbase; - char *s; - char *argv[512]; - char line[1024]; - char materialname[MAX_QPATH]; - int j, index1, index2, index3, first, prev, index; - int argc; - int linelen; - int numtriangles = 0; - int maxtriangles = 32768; - int *element3i = Mem_Alloc(tempmempool, maxtriangles * sizeof(int[3])); - int *oldelement3i; - int numsurfaces = 0; - int maxsurfaces = 0; - msurface_t *surfaces = NULL; - int linenumber = 0; - int hashindex; - float *v, *vt, *vn; - float *oldv, *oldvt, *oldvn; - int maxv = 65536, numv = 1; - int maxvt = 65536, numvt = 1; - int maxvn = 65536, numvn = 1; - int maxverthash = 65536, numverthash = 0; - int numhashindex = 65536; - struct objverthash_s - { - struct objverthash_s *next; - int s; - int v; - int vt; - int vn; - } - *hash, **verthash = Mem_Alloc(tempmempool, numhashindex * sizeof(*verthash)), *verthashdata = Mem_Alloc(tempmempool, maxverthash * sizeof(*verthashdata)), *oldverthashdata; + unsigned char *data; + const char *text; + unsigned char *pbase, *pend; + iqmheader_t *header; skinfile_t *skinfiles; + int i, j, k, meshvertices, meshtriangles; + float *vposition = NULL, *vtexcoord = NULL, *vnormal = NULL, *vtangent = NULL; + unsigned char *vblendindexes = NULL, *vblendweights = NULL; + iqmjoint_t *joint; + iqmanim_t *anim; + iqmpose_t *pose; + iqmmesh_t *mesh; + iqmbounds_t *bounds; + iqmvertexarray_t *va; + unsigned short *framedata; + float biggestorigin; + const int *inelements; + int *outelements; + float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector; - dpsnprintf(materialname, sizeof(materialname), "%s", loadmodel->name); - - skinfiles = Mod_LoadSkinFiles(); + pbase = (unsigned char *)buffer; + pend = (unsigned char *)bufferend; + header = (iqmheader_t *)buffer; + if (memcmp(header->id, "INTERQUAKEMODEL", 16)) + Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name); + if (LittleLong(header->version) != 1) + Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 models are currently supported (name = %s)", loadmodel->name); - loadmodel->modeldatatypestring = "OBJ"; + loadmodel->modeldatatypestring = "IQM"; loadmodel->type = mod_alias; - loadmodel->AnimateVertices = NULL; - loadmodel->DrawSky = NULL; + loadmodel->synctype = ST_RAND; + + // byteswap header + header->version = LittleLong(header->version); + header->filesize = LittleLong(header->filesize); + header->flags = LittleLong(header->flags); + header->num_text = LittleLong(header->num_text); + header->ofs_text = LittleLong(header->ofs_text); + header->num_meshes = LittleLong(header->num_meshes); + header->ofs_meshes = LittleLong(header->ofs_meshes); + header->num_vertexarrays = LittleLong(header->num_vertexarrays); + header->num_vertexes = LittleLong(header->num_vertexes); + header->ofs_vertexarrays = LittleLong(header->ofs_vertexarrays); + header->num_triangles = LittleLong(header->num_triangles); + header->ofs_triangles = LittleLong(header->ofs_triangles); + header->ofs_neighbors = LittleLong(header->ofs_neighbors); + header->num_joints = LittleLong(header->num_joints); + header->ofs_joints = LittleLong(header->ofs_joints); + header->num_poses = LittleLong(header->num_poses); + header->ofs_poses = LittleLong(header->ofs_poses); + header->num_anims = LittleLong(header->num_anims); + header->ofs_anims = LittleLong(header->ofs_anims); + header->num_frames = LittleLong(header->num_frames); + header->num_framechannels = LittleLong(header->num_framechannels); + header->ofs_frames = LittleLong(header->ofs_frames); + header->ofs_bounds = LittleLong(header->ofs_bounds); + header->num_comment = LittleLong(header->num_comment); + header->ofs_comment = LittleLong(header->ofs_comment); + header->num_extensions = LittleLong(header->num_extensions); + header->ofs_extensions = LittleLong(header->ofs_extensions); + + if (header->num_triangles < 1 || header->num_vertexes < 3 || header->num_vertexarrays < 1 || header->num_meshes < 1) + { + Con_Printf("%s has no geometry\n", loadmodel->name); + return; + } + if (header->num_frames < 1 || header->num_anims < 1) + { + Con_Printf("%s has no animations\n", loadmodel->name); + return; + } + + if (pbase + header->ofs_text + header->num_text > pend || + pbase + header->ofs_meshes + header->num_meshes*sizeof(iqmmesh_t) > pend || + pbase + header->ofs_vertexarrays + header->num_vertexarrays*sizeof(iqmvertexarray_t) > pend || + pbase + header->ofs_triangles + header->num_triangles*sizeof(int[3]) > pend || + (header->ofs_neighbors && pbase + header->ofs_neighbors + header->num_triangles*sizeof(int[3]) > pend) || + pbase + header->ofs_joints + header->num_joints*sizeof(iqmjoint_t) > pend || + pbase + header->ofs_poses + header->num_poses*sizeof(iqmpose_t) > pend || + pbase + header->ofs_anims + header->num_anims*sizeof(iqmanim_t) > pend || + pbase + header->ofs_frames + header->num_frames*header->num_framechannels*sizeof(unsigned short) > pend || + (header->ofs_bounds && pbase + header->ofs_bounds + header->num_frames*sizeof(iqmbounds_t) > pend) || + pbase + header->ofs_comment + header->num_comment > pend) + { + Con_Printf("%s has invalid size or offset information\n", loadmodel->name); + return; + } + + va = (iqmvertexarray_t *)(pbase + header->ofs_vertexarrays); + for (i = 0;i < (int)header->num_vertexarrays;i++) + { + size_t vsize; + va[i].type = LittleLong(va[i].type); + va[i].flags = LittleLong(va[i].flags); + va[i].format = LittleLong(va[i].format); + va[i].size = LittleLong(va[i].size); + va[i].offset = LittleLong(va[i].offset); + vsize = header->num_vertexes*va[i].size; + switch (va[i].format) + { + case IQM_FLOAT: vsize *= sizeof(float); break; + case IQM_UBYTE: vsize *= sizeof(unsigned char); break; + default: continue; + } + if (pbase + va[i].offset + vsize > pend) + continue; + switch (va[i].type) + { + case IQM_POSITION: + if (va[i].format == IQM_FLOAT && va[i].size == 3) + vposition = (float *)(pbase + va[i].offset); + break; + case IQM_TEXCOORD: + if (va[i].format == IQM_FLOAT && va[i].size == 2) + vtexcoord = (float *)(pbase + va[i].offset); + break; + case IQM_NORMAL: + if (va[i].format == IQM_FLOAT && va[i].size == 3) + vnormal = (float *)(pbase + va[i].offset); + break; + case IQM_TANGENT: + if (va[i].format == IQM_FLOAT && va[i].size == 4) + vtangent = (float *)(pbase + va[i].offset); + break; + case IQM_BLENDINDEXES: + if (va[i].format == IQM_UBYTE && va[i].size == 4) + vblendindexes = (unsigned char *)(pbase + va[i].offset); + break; + case IQM_BLENDWEIGHTS: + if (va[i].format == IQM_UBYTE && va[i].size == 4) + vblendweights = (unsigned char *)(pbase + va[i].offset); + break; + } + } + if (!vposition || !vtexcoord || !vblendindexes || !vblendweights) + { + Con_Printf("%s is missing vertex array data\n", loadmodel->name); + return; + } + + text = header->num_text && header->ofs_text ? (const char *)(pbase + header->ofs_text) : ""; + + loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices; + loadmodel->DrawSky = NULL; loadmodel->DrawAddWaterPlanes = NULL; loadmodel->Draw = R_Q1BSP_Draw; loadmodel->DrawDepth = R_Q1BSP_DrawDepth; loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; loadmodel->DrawLight = R_Q1BSP_DrawLight; loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; loadmodel->PointSuperContents = NULL; - // parse the OBJ text now - for(;;) - { - if (!*text) - break; - linenumber++; - linelen = 0; - for (linelen = 0;text[linelen] && text[linelen] != '\r' && text[linelen] != '\n';linelen++) - line[linelen] = text[linelen]; - line[linelen] = 0; - for (argc = 0;argc < (int)(sizeof(argv)/sizeof(argv[0]));argc++) - argv[argc] = ""; - argc = 0; - s = line; - while (*s == ' ' || *s == '\t') - s++; - while (*s) - { - argv[argc++] = s; - while (*s > ' ') - s++; - if (!*s) - break; - *s++ = 0; - while (*s == ' ' || *s == '\t') - s++; - } - if (!argc) - continue; - if (argv[0][0] == '#') - continue; - if (!strcmp(argv[0], "v")) - { - if (maxv <= numv) - { - maxv *= 2; - oldv = v; - v = Mem_Alloc(tempmempool, maxv * sizeof(float[3])); - if (oldv) - { - memcpy(v, oldv, numv * sizeof(float[3])); - Mem_Free(oldv); - } - } - v[numv*3+0] = atof(argv[1]); - v[numv*3+1] = atof(argv[2]); - v[numv*3+2] = atof(argv[3]); - numv++; - } - else if (!strcmp(argv[0], "vt")) - { - if (maxvt <= numvt) - { - maxvt *= 2; - oldvt = vt; - vt = Mem_Alloc(tempmempool, maxvt * sizeof(float[2])); - if (oldvt) - { - memcpy(vt, oldvt, numvt * sizeof(float[2])); - Mem_Free(oldvt); - } - } - vt[numvt*2+0] = atof(argv[1]); - vt[numvt*2+1] = atof(argv[2]); - numvt++; - } - else if (!strcmp(argv[0], "vn")) - { - if (maxvn <= numvn) - { - maxvn *= 2; - oldvn = vn; - vn = Mem_Alloc(tempmempool, maxvn * sizeof(float[3])); - if (oldvn) - { - memcpy(vn, oldvn, numvn * sizeof(float[3])); - Mem_Free(oldvn); - } - } - vn[numvn*3+0] = atof(argv[1]); - vn[numvn*3+1] = atof(argv[2]); - vn[numvn*3+2] = atof(argv[3]); - numvn++; - } - else if (!strcmp(argv[0], "f")) - { - if (!surface) - { - if (maxsurfaces <= numsurfaces) - { - maxsurfaces++; - oldsurfaces = surfaces; - surfaces = Mem_Alloc(tempmempool, maxsurfaces * sizeof(*surfaces)); - if (oldsurfaces) - { - memcpy(surfaces, oldsurfaces, numsurfaces * sizeof(*surfaces)); - Mem_Free(oldsurfaces); - } - } - surface = surfaces + numsurfaces++; - surface-> - } - for (j = 1;j < argc;j++) - { - index1 = atoi(argv[j]); - while(argv[j][0] && argv[j][0] != '/') - argv[j]++; - if (argv[j][0]) - argv[j]++; - if (index1 < 0) - index1 = numv + 1 - index1; - index2 = atoi(argv[j]); - if (index2 < 0) - index2 = numvt + 1 - index2; - while(argv[j][0] && argv[j][0] != '/') - argv[j]++; - if (argv[j][0]) - argv[j]++; - index3 = atoi(argv[j]); - if (index3 < 0) - index3 = numvn + 1 - index3; - hashindex = (index1 + index2 * 3571 + index3 * 42589) & (numhashindex - 1); - for (hash = verthash[hashindex];hash;hash = hash->next) - if (hash->surface == numsurfaces-1 && hash->v == index1 && hash->vt == index2 && hash->vn == index3) - break; - if (!hash) - { - if (maxverthash <= numverthash) - { - maxverthash *= 2; - oldverthashdata = verthashdata; - verthashdata = Mem_Alloc(tempmempool, maxverthash * sizeof(*verthashdata)); - if (oldverthashdata) - { - memcpy(verthashdata, oldverthashdata, numverthash * sizeof(*verthashdata)); - Mem_Free(oldverthashdata); - } - } - hash = verthashdata + numverthash++; - hash->next = verthash[hashindex]; - hash->s = numsurfaces; - hash->v = index1; - hash->vt = index2; - hash->vn = index3; - verthash[hashindex] = hash; - } - index = (int)((size_t)(hash - verthashdata)); - if (j == 1) - first = index; - else if (j >= 3) - { - if (maxtriangles <= numtriangles) - { - maxtriangles *= 2; - oldelement3i = element3i; - element3i = Mem_Alloc(tempmempool, numtriangles * sizeof(int[3])); - if (oldelement3i) - { - memcpy(element3i, oldelement3i, numtriangles * sizeof(int[3])); - Mem_Free(oldelement3i); - } - } - element3i[numtriangles*3+0] = first; - element3i[numtriangles*3+1] = prev; - element3i[numtriangles*3+2] = index; - numtriangles++; - } - prev = index; - } - } - else if (!strcmp(argv[0], "o") || !strcmp(argv[0], "g")) - surface = NULL; - else if (!!strcmp(argv[0], "usemtl")) - { - surface = NULL; - strlcpy(materialname, argv[1], sizeof(materialname); - } - text += linelen; - if (*text == '\r') - text++; - if (*text == '\n') - text++; - } + // load external .skin files if present + skinfiles = Mod_LoadSkinFiles(); + if (loadmodel->numskins < 1) + loadmodel->numskins = 1; - if (skinfiles) - Mod_FreeSkinFiles(skinfiles); + loadmodel->numframes = header->num_anims; + loadmodel->num_bones = header->num_joints; + loadmodel->num_poses = header->num_frames; + loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header->num_meshes; + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; - // now that we have the OBJ data loaded as-is, we can convert it - 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->num_poses = loadmodel->surfmesh.num_morphframes; - skinwidth = LittleLong(pinmodel->skinwidth); - skinheight = LittleLong(pinmodel->skinheight); - iskinwidth = 1.0f / skinwidth; - iskinheight = 1.0f / skinheight; + meshvertices = header->num_vertexes; + meshtriangles = header->num_triangles; - 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])); + // 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]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshtriangles * sizeof(int[3]) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short)) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + 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->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); - loadmodel->sortedmodelsurfaces[0] = 0; + 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.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->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * 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); - 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->synctype = ST_RAND; - - // load the skins - inskin = (char *)(base + LittleLong(pinmodel->ofs_skins)); - skinfiles = Mod_LoadSkinFiles(); - if (skinfiles) - { - loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; - loadmodel->num_texturesperskin = loadmodel->num_surfaces; - loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); - Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", ""); - Mod_FreeSkinFiles(skinfiles); - } - else if (loadmodel->numskins) - { - // skins found (most likely not a player model) - loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; - loadmodel->num_texturesperskin = loadmodel->num_surfaces; - loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); - for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME) - Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS); - } - else - { - // no skins (most likely a player model) - loadmodel->numskins = 1; - loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; - loadmodel->num_texturesperskin = loadmodel->num_surfaces; - loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); - Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL); - } + loadmodel->surfmesh.num_blends = 0; + loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short); + if (meshvertices <= 65536) + loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]); + loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]); + loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t)); - loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins); for (i = 0;i < loadmodel->numskins;i++) { loadmodel->skinscenes[i].firstframe = i; @@ -3059,120 +3186,290 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->skinscenes[i].framerate = 10; } - // load the triangles and stvert data - inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st)); - intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris)); - 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 - loadmodel->surfmesh.num_vertices = 0; - for (i = 0;i < loadmodel->surfmesh.num_triangles;i++) + // load the bone info + joint = (iqmjoint_t *) (pbase + header->ofs_joints); + for (i = 0;i < loadmodel->num_bones;i++) { + matrix4x4_t relbase, relinvbase, pinvbase, invbase; + joint[i].name = LittleLong(joint[i].name); + joint[i].parent = LittleLong(joint[i].parent); for (j = 0;j < 3;j++) { - xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]); - st = (unsigned short) LittleShort (intri[i].index_st[j]); - if (xyz >= numxyz) - { - Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i); - xyz = 0; - } - if (st >= numst) + joint[i].origin[j] = LittleFloat(joint[i].origin[j]); + joint[i].rotation[j] = LittleFloat(joint[i].rotation[j]); + joint[i].scale[j] = LittleFloat(joint[i].scale[j]); + } + strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name)); + loadmodel->data_bones[i].parent = joint[i].parent; + if (loadmodel->data_bones[i].parent >= i) + Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i); + Matrix4x4_FromDoom3Joint(&relbase, joint[i].origin[0], joint[i].origin[1], joint[i].origin[2], joint[i].rotation[0], joint[i].rotation[1], joint[i].rotation[2]); + Matrix4x4_Invert_Simple(&relinvbase, &relbase); + if (loadmodel->data_bones[i].parent >= 0) + { + Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent); + Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase); + Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i); + } + else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i); + } + + // set up the animscenes based on the anims + anim = (iqmanim_t *) (pbase + header->ofs_anims); + for (i = 0;i < (int)header->num_anims;i++) + { + anim[i].name = LittleLong(anim[i].name); + anim[i].first_frame = LittleLong(anim[i].first_frame); + anim[i].num_frames = LittleLong(anim[i].num_frames); + anim[i].framerate = LittleFloat(anim[i].framerate); + anim[i].flags = LittleLong(anim[i].flags); + strlcpy(loadmodel->animscenes[i].name, &text[anim[i].name], sizeof(loadmodel->animscenes[i].name)); + loadmodel->animscenes[i].firstframe = anim[i].first_frame; + loadmodel->animscenes[i].framecount = anim[i].num_frames; + loadmodel->animscenes[i].loop = ((anim[i].flags & IQM_LOOP) != 0); + loadmodel->animscenes[i].framerate = anim[i].framerate; + } + + pose = (iqmpose_t *) (pbase + header->ofs_poses); + biggestorigin = 0; + for (i = 0;i < (int)header->num_poses;i++) + { + float f; + pose[i].parent = LittleLong(pose[i].parent); + pose[i].channelmask = LittleLong(pose[i].channelmask); + pose[i].channeloffset[0] = LittleFloat(pose[i].channeloffset[0]); + pose[i].channeloffset[1] = LittleFloat(pose[i].channeloffset[1]); + pose[i].channeloffset[2] = LittleFloat(pose[i].channeloffset[2]); + pose[i].channeloffset[3] = LittleFloat(pose[i].channeloffset[3]); + pose[i].channeloffset[4] = LittleFloat(pose[i].channeloffset[4]); + pose[i].channeloffset[5] = LittleFloat(pose[i].channeloffset[5]); + pose[i].channeloffset[6] = LittleFloat(pose[i].channeloffset[6]); + pose[i].channeloffset[7] = LittleFloat(pose[i].channeloffset[7]); + pose[i].channeloffset[8] = LittleFloat(pose[i].channeloffset[8]); + pose[i].channelscale[0] = LittleFloat(pose[i].channelscale[0]); + pose[i].channelscale[1] = LittleFloat(pose[i].channelscale[1]); + pose[i].channelscale[2] = LittleFloat(pose[i].channelscale[2]); + pose[i].channelscale[3] = LittleFloat(pose[i].channelscale[3]); + pose[i].channelscale[4] = LittleFloat(pose[i].channelscale[4]); + pose[i].channelscale[5] = LittleFloat(pose[i].channelscale[5]); + pose[i].channelscale[6] = LittleFloat(pose[i].channelscale[6]); + pose[i].channelscale[7] = LittleFloat(pose[i].channelscale[7]); + pose[i].channelscale[8] = LittleFloat(pose[i].channelscale[8]); + f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f); + f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f); + f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f); + f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f); + f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f); + f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f); + } + loadmodel->num_posescale = biggestorigin / 32767.0f; + loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale; + + // load the pose data + framedata = (unsigned short *) (pbase + header->ofs_frames); + for (i = 0, k = 0;i < (int)header->num_frames;i++) + { + for (j = 0;j < (int)header->num_poses;j++, k++) + { + loadmodel->data_poses6s[k*6 + 0] = loadmodel->num_poseinvscale * (pose[j].channeloffset[0] + (pose[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[0] : 0)); + loadmodel->data_poses6s[k*6 + 1] = loadmodel->num_poseinvscale * (pose[j].channeloffset[1] + (pose[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[1] : 0)); + loadmodel->data_poses6s[k*6 + 2] = loadmodel->num_poseinvscale * (pose[j].channeloffset[2] + (pose[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[2] : 0)); + loadmodel->data_poses6s[k*6 + 3] = 32767.0f * (pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0)); + loadmodel->data_poses6s[k*6 + 4] = 32767.0f * (pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0)); + loadmodel->data_poses6s[k*6 + 5] = 32767.0f * (pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0)); + // skip scale data for now + if(pose[j].channelmask&64) framedata++; + if(pose[j].channelmask&128) framedata++; + if(pose[j].channelmask&256) framedata++; + } + } + + // load bounding box data + if (header->ofs_bounds) + { + float xyradius = 0, radius = 0; + bounds = (iqmbounds_t *) (pbase + header->ofs_bounds); + VectorClear(loadmodel->normalmins); + VectorClear(loadmodel->normalmaxs); + for (i = 0; i < (int)header->num_frames;i++) + { + bounds[i].mins[0] = LittleFloat(bounds[i].mins[0]); + bounds[i].mins[1] = LittleFloat(bounds[i].mins[1]); + bounds[i].mins[2] = LittleFloat(bounds[i].mins[2]); + bounds[i].maxs[0] = LittleFloat(bounds[i].maxs[0]); + bounds[i].maxs[1] = LittleFloat(bounds[i].maxs[1]); + bounds[i].maxs[2] = LittleFloat(bounds[i].maxs[2]); + bounds[i].xyradius = LittleFloat(bounds[i].xyradius); + bounds[i].radius = LittleFloat(bounds[i].radius); + if (!i) { - Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i); - st = 0; + VectorCopy(bounds[i].mins, loadmodel->normalmins); + VectorCopy(bounds[i].maxs, loadmodel->normalmaxs); } - hashindex = (xyz * 256 + st) & 65535; - for (hash = md2verthash[hashindex];hash;hash = hash->next) - if (hash->xyz == xyz && hash->st == st) - break; - if (hash == NULL) + else { - hash = md2verthashdata + loadmodel->surfmesh.num_vertices++; - hash->xyz = xyz; - hash->st = st; - hash->next = md2verthash[hashindex]; - md2verthash[hashindex] = hash; + if (loadmodel->normalmins[0] > bounds[i].mins[0]) loadmodel->normalmins[0] = bounds[i].mins[0]; + if (loadmodel->normalmins[1] > bounds[i].mins[1]) loadmodel->normalmins[1] = bounds[i].mins[1]; + if (loadmodel->normalmins[2] > bounds[i].mins[2]) loadmodel->normalmins[2] = bounds[i].mins[2]; + if (loadmodel->normalmaxs[0] < bounds[i].maxs[0]) loadmodel->normalmaxs[0] = bounds[i].maxs[0]; + if (loadmodel->normalmaxs[1] < bounds[i].maxs[1]) loadmodel->normalmaxs[1] = bounds[i].maxs[1]; + if (loadmodel->normalmaxs[2] < bounds[i].maxs[2]) loadmodel->normalmaxs[2] = bounds[i].maxs[2]; } - loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata); + if (bounds[i].xyradius > xyradius) + xyradius = bounds[i].xyradius; + if (bounds[i].radius > radius) + radius = bounds[i].radius; + } + loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius; + loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius; + 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; + } + + // load triangle data + inelements = (const int *) (pbase + header->ofs_triangles); + outelements = loadmodel->surfmesh.data_element3i; + for (i = 0;i < (int)header->num_triangles;i++) + { + outelements[0] = LittleLong(inelements[0]); + outelements[1] = LittleLong(inelements[1]); + outelements[2] = LittleLong(inelements[2]); + outelements += 3; + inelements += 3; + } + Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header->num_vertexes, __FILE__, __LINE__); + + if (header->ofs_neighbors) + { + inelements = (const int *) (pbase + header->ofs_neighbors); + outelements = loadmodel->surfmesh.data_neighbor3i; + for (i = 0;i < (int)header->num_triangles;i++) + { + outelements[0] = LittleLong(inelements[0]); + outelements[1] = LittleLong(inelements[1]); + outelements[2] = LittleLong(inelements[2]); + outelements += 3; + inelements += 3; } } - 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++) + // load vertex data + outvertex = loadmodel->surfmesh.data_vertex3f; + for (i = 0;i < (int)header->num_vertexes;i++) { - int sts, stt; - hash = md2verthashdata + i; - vertremap[i] = hash->xyz; - 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; + outvertex[0] = LittleFloat(vposition[0]); + outvertex[1] = LittleFloat(vposition[1]); + outvertex[2] = LittleFloat(vposition[2]); + vposition += 3; + outvertex += 3; } - Mem_Free(md2verthash); - Mem_Free(md2verthashdata); + outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f; + for (i = 0;i < (int)header->num_vertexes;i++) + { + outtexcoord[0] = LittleFloat(vtexcoord[0]); + outtexcoord[1] = LittleFloat(vtexcoord[1]); + vtexcoord += 2; + outtexcoord += 2; + } - // generate ushort elements array if possible - if (loadmodel->surfmesh.num_vertices <= 65536) + if(vnormal) { - loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles); - for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) - loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + outnormal = loadmodel->surfmesh.data_normal3f; + for (i = 0;i < (int)header->num_vertexes;i++) + { + outnormal[0] = LittleFloat(vnormal[0]); + outnormal[1] = LittleFloat(vnormal[1]); + outnormal[2] = LittleFloat(vnormal[2]); + vnormal += 3; + outnormal += 3; + } } - // load the frames - datapointer = (base + LittleLong(pinmodel->ofs_frames)); - for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++) + if(vnormal && vtangent) { - 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++) + outnormal = loadmodel->surfmesh.data_normal3f; + outsvector = loadmodel->surfmesh.data_svector3f; + outtvector = loadmodel->surfmesh.data_tvector3f; + for (i = 0;i < (int)header->num_vertexes;i++) { - loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]); - loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]); + outsvector[0] = LittleFloat(vtangent[0]); + outsvector[1] = LittleFloat(vtangent[1]); + outsvector[2] = LittleFloat(vtangent[2]); + if(LittleFloat(vtangent[3]) < 0) + CrossProduct(outsvector, outnormal, outtvector); + else + CrossProduct(outnormal, outsvector, outtvector); + vtangent += 4; + outnormal += 3; + outsvector += 3; + outtvector += 3; } - // 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); + } - strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name)); - loadmodel->animscenes[i].firstframe = i; - loadmodel->animscenes[i].framecount = 1; - loadmodel->animscenes[i].framerate = 10; - loadmodel->animscenes[i].loop = true; + for (i = 0; i < (int)header->num_vertexes;i++) + { + blendweights_t weights; + memcpy(weights.index, vblendindexes + i*4, 4); + memcpy(weights.influence, vblendweights + i*4, 4); + loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights); } - Mem_Free(vertremap); + // load meshes + mesh = (iqmmesh_t *) (pbase + header->ofs_meshes); + for (i = 0;i < (int)header->num_meshes;i++) + { + msurface_t *surface; + + mesh[i].name = LittleLong(mesh[i].name); + mesh[i].material = LittleLong(mesh[i].material); + mesh[i].first_vertex = LittleLong(mesh[i].first_vertex); + mesh[i].num_vertexes = LittleLong(mesh[i].num_vertexes); + mesh[i].first_triangle = LittleLong(mesh[i].first_triangle); + mesh[i].num_triangles = LittleLong(mesh[i].num_triangles); + loadmodel->sortedmodelsurfaces[i] = i; + surface = loadmodel->data_surfaces + i; + surface->texture = loadmodel->data_textures + i; + surface->num_firsttriangle = mesh[i].first_triangle; + surface->num_triangles = mesh[i].num_triangles; + surface->num_firstvertex = mesh[i].first_vertex; + surface->num_vertices = mesh[i].num_vertexes; + + Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh[i].name], &text[mesh[i].material]); + } + + Mod_FreeSkinFiles(skinfiles); Mod_MakeSortedSurfaces(loadmodel); - Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); - Mod_Alias_CalculateBoundingBox(); - Mod_Alias_MorphMesh_CompileFrames(); - surface = loadmodel->data_surfaces; - surface->texture = loadmodel->data_textures; - surface->num_firsttriangle = 0; - surface->num_triangles = loadmodel->surfmesh.num_triangles; - surface->num_firstvertex = 0; - surface->num_vertices = loadmodel->surfmesh.num_vertices; + // compute all the mesh information that was not loaded from the file + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + if (!vnormal) + Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true); + if (!vnormal || !vtangent) + 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); + if (!header->ofs_neighbors) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + if (!header->ofs_bounds) + Mod_Alias_CalculateBoundingBox(); - loadmodel->surfmesh.isanimated = false; -#endif + loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } } + +