X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=model_alias.c;h=9ab4295e63a8db269d7b6bcf83a32c888ad1b314;hb=3d164924a905fa9a5486f412fd1df10c3c3e9edf;hp=e0e786922b4223d3cdeb05f85f10da509f03f5f9;hpb=1fd37f5239fe019e4d53c3e19b6fa9ff67da12e1;p=xonotic%2Fdarkplaces.git diff --git a/model_alias.c b/model_alias.c index e0e78692..9ab4295e 100644 --- a/model_alias.c +++ b/model_alias.c @@ -46,189 +46,269 @@ void Mod_AliasInit (void) 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) +int Mod_Skeletal_AddBlend(dp_model_t *model, const int *newindex, const float *newinfluence) +{ + int i, total; + float scale; + blendweights_t *weights; + 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(newweights.influence[i] > 0 && total > 255) + { + newweights.influence[i]--; + total--; + } + } + } + while (total < 255) + { + for (i = 0; i < 4;i++) + { + if(newweights.influence[i] < 255 && total < 255) + { + newweights.influence[i]++; + total++; + } + } + } + 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; +} + +static int maxbonepose = 0; +static float (*bonepose)[12] = NULL; + +void Mod_Skeletal_FreeBuffers(void) +{ + if(bonepose) + Mem_Free(bonepose); + maxbonepose = 0; + bonepose = NULL; +} + +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) { -#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]; + float m[12]; + float (*boneposerelative)[12]; + const blendweights_t * RESTRICT weights; - // interpolate matrices and concatenate them to their parents - for (i = 0;i < model->num_bones;i++) + if (maxbonepose < model->num_bones*2 + model->surfmesh.num_blends) { - for (k = 0;k < 12;k++) - m[k] = 0; - VectorClear(desiredscale); - for (blends = 0;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++) + if (bonepose) + Mem_Free(bonepose); + maxbonepose = model->num_bones*2 + model->surfmesh.num_blends; + bonepose = (float (*)[12])Mem_Alloc(r_main_mempool, maxbonepose * sizeof(float[12])); + } + + boneposerelative = bonepose + model->num_bones; + + if (skeleton && !skeleton->relativetransforms) + skeleton = NULL; + + // interpolate matrices + if (skeleton) + { + for (i = 0;i < model->num_bones;i++) { - matrix = model->data_poses + (frameblend[blends].subframe * 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); + Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m); + if (model->data_bones[i].parent >= 0) + R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]); + else + memcpy(bonepose[i], m, sizeof(m)); + + // 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]); } - 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 - if (vertex3f) + } + else { - 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) + float originscale = model->num_posescale; + float x,y,z,w,lerp; + const short * RESTRICT pose6s; + for (i = 0;i < model->num_bones;i++) { - if (wf[0] == 1) + memset(m, 0, sizeof(m)); + for (blends = 0;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++) { - 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]); + pose6s = model->data_poses6s + 6 * (frameblend[blends].subframe * model->num_bones + i); + lerp = frameblend[blends].lerp; + x = pose6s[3] * (1.0f / 32767.0f); + y = pose6s[4] * (1.0f / 32767.0f); + z = pose6s[5] * (1.0f / 32767.0f); + w = 1.0f - (x*x+y*y+z*z); + w = w > 0.0f ? -sqrt(w) : 0.0f; + m[ 0] += (1-2*(y*y+z*z)) * lerp; + m[ 1] += ( 2*(x*y-z*w)) * lerp; + m[ 2] += ( 2*(x*z+y*w)) * lerp; + m[ 3] += (pose6s[0] * originscale) * lerp; + m[ 4] += ( 2*(x*y+z*w)) * lerp; + m[ 5] += (1-2*(x*x+z*z)) * lerp; + m[ 6] += ( 2*(y*z-x*w)) * lerp; + m[ 7] += (pose6s[1] * originscale) * lerp; + m[ 8] += ( 2*(x*z-y*w)) * lerp; + m[ 9] += ( 2*(y*z+x*w)) * lerp; + m[10] += (1-2*(x*x+y*y)) * lerp; + m[11] += (pose6s[2] * originscale) * lerp; } + VectorNormalize(m ); + VectorNormalize(m + 4); + VectorNormalize(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 - { - 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]); - } - } + memcpy(bonepose[i], m, sizeof(m)); + // 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]); + } + } + + // generate matrices for all blend combinations + weights = model->surfmesh.data_blendweights; + for (i = 0;i < model->surfmesh.num_blends;i++, weights++) + { + float * RESTRICT b = boneposerelative[model->num_bones + i]; + const float * RESTRICT m = boneposerelative[weights->index[0]]; + float f = weights->influence[0] * (1.0f / 255.0f); + b[ 0] = f*m[ 0]; b[ 1] = f*m[ 1]; b[ 2] = f*m[ 2]; b[ 3] = f*m[ 3]; + b[ 4] = f*m[ 4]; b[ 5] = f*m[ 5]; b[ 6] = f*m[ 6]; b[ 7] = f*m[ 7]; + b[ 8] = f*m[ 8]; b[ 9] = f*m[ 9]; b[10] = f*m[10]; b[11] = f*m[11]; + for (k = 1;k < 4 && weights->influence[k];k++) + { + m = boneposerelative[weights->index[k]]; + f = weights->influence[k] * (1.0f / 255.0f); + b[ 0] += f*m[ 0]; b[ 1] += f*m[ 1]; b[ 2] += f*m[ 2]; b[ 3] += f*m[ 3]; + b[ 4] += f*m[ 4]; b[ 5] += f*m[ 5]; b[ 6] += f*m[ 6]; b[ 7] += f*m[ 7]; + b[ 8] += f*m[ 8]; b[ 9] += f*m[ 9]; b[10] += f*m[10]; b[11] += f*m[11]; } } - if (normal3f) + + // transform vertex attributes by blended matrices + if (vertex3f) { - 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) + const float * RESTRICT v = model->surfmesh.data_vertex3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + // special case common combinations of attributes to avoid repeated loading of matrices + if (normal3f) { - if (wf[0] == 1) + const float * RESTRICT n = model->surfmesh.data_normal3f; + if (svector3f && tvector3f) { - const float *m = boneposerelative[wi[0]]; - normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]); + const float * RESTRICT sv = model->surfmesh.data_svector3f; + const float * RESTRICT tv = model->surfmesh.data_tvector3f; + for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, n += 3, sv += 3, tv += 3, b++, vertex3f += 3, normal3f += 3, svector3f += 3, tvector3f += 3) + { + const float * RESTRICT m = boneposerelative[*b]; + 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]); + 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]); + 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]); + 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]); + } + return; + } + for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, n += 3, b++, vertex3f += 3, normal3f += 3) + { + const float * RESTRICT m = boneposerelative[*b]; + 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]); + 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 + } + else + { + for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, b++, vertex3f += 3) { - 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]); - } + const float * RESTRICT m = boneposerelative[*b]; + 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 if (normal3f) + { + const float * RESTRICT n = model->surfmesh.data_normal3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + for (i = 0;i < model->surfmesh.num_vertices;i++, n += 3, b++, normal3f += 3) + { + const float * RESTRICT m = boneposerelative[*b]; + 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]); + } + } + 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) + const float * RESTRICT sv = model->surfmesh.data_svector3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + for (i = 0;i < model->surfmesh.num_vertices;i++, sv += 3, b++, svector3f += 3) { - 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]); - } - } + const float * RESTRICT m = boneposerelative[*b]; + 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]); } } + if (tvector3f) { - 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) + const float * RESTRICT tv = model->surfmesh.data_tvector3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + for (i = 0;i < model->surfmesh.num_vertices;i++, tv += 3, b++, tvector3f += 3) { - 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]); - } - } + const float * RESTRICT m = boneposerelative[*b]; + 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]); } } } -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; @@ -317,7 +397,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; @@ -414,34 +494,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) @@ -450,35 +561,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; } @@ -503,47 +636,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 *in12f = loadmodel->data_poses; - float *out12f; - float *outinv12f = loadmodel->data_baseboneposeinverse; + int boneindex; + matrix4x4_t *basebonepose; + float *outinvmatrix = loadmodel->data_baseboneposeinverse; + matrix4x4_t bonematrix; + matrix4x4_t tempbonematrix; if (!loadmodel->num_bones) return; - out12f = basebonepose = (float *) Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(float[12])); - for (i = 0;i < loadmodel->num_bones;i++, in12f += 12, out12f += 12, outinv12f += 12) + 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); } @@ -565,7 +676,7 @@ static void Mod_Alias_CalculateBoundingBox(void) radius = 0; 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) @@ -622,7 +733,7 @@ static void Mod_Alias_MorphMesh_CompileFrames(void) for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--) { frameblend[0].subframe = i; - loadmodel->AnimateVertices(loadmodel, frameblend, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL); + 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++) @@ -633,12 +744,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; - vec3_t shiftstart, shiftend; float segmentmins[3], segmentmaxs[3]; - frameblend_t frameblend[MAX_FRAMEBLENDS]; msurface_t *surface; static int maxvertices = 0; static float *vertex3f = NULL; @@ -646,9 +755,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].subframe = frame; - frameblend[0].lerp = 1; if (maxvertices < model->surfmesh.num_vertices) { if (vertex3f) @@ -656,53 +762,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])); } + 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 VectorAdd(start, boxmins, shiftstart); VectorAdd(end, boxmins, shiftend); - segmentmins[0] = min(shiftstart[0], shiftend[0]) - 1; - segmentmins[1] = min(shiftstart[1], shiftend[1]) - 1; - segmentmins[2] = min(shiftstart[2], shiftend[2]) - 1; - segmentmaxs[0] = max(shiftstart[0], shiftend[0]) + 1; - segmentmaxs[1] = max(shiftstart[1], shiftend[1]) + 1; - segmentmaxs[2] = max(shiftstart[2], shiftend[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, shiftstart, shiftend, 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); - } + 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, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 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) @@ -806,12 +931,20 @@ 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; skinfileitem_t *skinfileitem; @@ -827,7 +960,7 @@ 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); + Mod_LoadTextureFromQ3Shader(skin, skinfileitem->replacement, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); break; } } @@ -840,7 +973,7 @@ 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); + Mod_LoadTextureFromQ3Shader(skin, shadername, 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); @@ -886,10 +1019,14 @@ 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; loadmodel->PointSuperContents = NULL; loadmodel->num_surfaces = 1; @@ -912,7 +1049,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); @@ -1043,11 +1180,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); @@ -1176,6 +1312,15 @@ 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->TraceBox = Mod_CollisionBIH_TraceBox; + 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) @@ -1216,10 +1361,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) @@ -1286,7 +1435,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 { @@ -1372,11 +1521,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)); @@ -1421,6 +1569,15 @@ 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->TraceBox = Mod_CollisionBIH_TraceBox; + 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) @@ -1456,10 +1613,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) @@ -1534,11 +1695,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; @@ -1581,6 +1738,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(); @@ -1589,6 +1749,15 @@ 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->TraceBox = Mod_CollisionBIH_TraceBox; + 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) @@ -1596,7 +1765,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; @@ -1669,10 +1838,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; @@ -1765,7 +1938,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 * loadmodel->num_bones * 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); @@ -1778,21 +1951,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 * loadmodel->num_bones * 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); @@ -1803,7 +2010,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 @@ -1826,8 +2035,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 @@ -1903,6 +2111,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); @@ -1910,12 +2121,21 @@ 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->TraceBox = Mod_CollisionBIH_TraceBox; + 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; @@ -1923,6 +2143,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; @@ -1971,10 +2194,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 @@ -2015,7 +2242,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) 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 * loadmodel->num_bones * 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); @@ -2028,19 +2255,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 * loadmodel->num_bones * 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++) { @@ -2062,21 +2286,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 @@ -2086,10 +2344,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 @@ -2132,7 +2393,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); @@ -2159,8 +2421,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 { @@ -2168,33 +2430,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_AddBlend(loadmodel, weightindex, weightinfluence); } // since dpm models do not have named sections, reuse their shader name as the section name @@ -2202,16 +2456,30 @@ 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->TraceBox = Mod_CollisionBIH_TraceBox; + 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... @@ -2227,7 +2495,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; @@ -2236,6 +2504,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")) @@ -2250,10 +2519,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; @@ -2288,8 +2561,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")) @@ -2459,8 +2732,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")) @@ -2474,7 +2747,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 @@ -2605,7 +2878,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) 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 * loadmodel->num_bones * 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); @@ -2617,19 +2890,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 * loadmodel->num_bones * 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_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++) { @@ -2690,8 +2960,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) @@ -2700,33 +2971,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_AddBlend(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++) @@ -2741,13 +3006,34 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) } } + // 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); @@ -2755,6 +3041,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); @@ -2763,431 +3052,13 @@ 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; -} - -void Mod_OBJ_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; - skinfile_t *skinfiles; - - dpsnprintf(materialname, sizeof(materialname), "%s", loadmodel->name); - - skinfiles = Mod_LoadSkinFiles(); - - loadmodel->modeldatatypestring = "OBJ"; - - loadmodel->type = mod_alias; - loadmodel->AnimateVertices = NULL; - loadmodel->DrawSky = NULL; - loadmodel->DrawAddWaterPlanes = NULL; - loadmodel->Draw = R_Q1BSP_Draw; - loadmodel->DrawDepth = R_Q1BSP_DrawDepth; - loadmodel->DrawDebug = R_Q1BSP_DrawDebug; - loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; - loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; - loadmodel->DrawLight = R_Q1BSP_DrawLight; - loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; - 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++; - } - if (skinfiles) - Mod_FreeSkinFiles(skinfiles); - - // 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; - - loadmodel->num_surfaces = 1; - loadmodel->nummodelsurfaces = loadmodel->num_surfaces; - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3])); - loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); - loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); - loadmodel->sortedmodelsurfaces[0] = 0; - loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); - loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]); - loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); - loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); - - loadmodel->synctype = ST_RAND; - - // load the skins - inskin = (char *)(base + LittleLong(pinmodel->ofs_skins)); - skinfiles = Mod_LoadSkinFiles(); - if (skinfiles) + if (!loadmodel->surfmesh.isanimated) { - 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); + Mod_MakeCollisionBIH(loadmodel, true); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; } - 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->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins); - for (i = 0;i < loadmodel->numskins;i++) - { - loadmodel->skinscenes[i].firstframe = i; - loadmodel->skinscenes[i].framecount = 1; - loadmodel->skinscenes[i].loop = true; - 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++) - { - 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) - { - Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i); - st = 0; - } - hashindex = (xyz * 256 + st) & 65535; - for (hash = md2verthash[hashindex];hash;hash = hash->next) - if (hash->xyz == xyz && hash->st == st) - break; - if (hash == NULL) - { - hash = md2verthashdata + loadmodel->surfmesh.num_vertices++; - hash->xyz = xyz; - hash->st = st; - hash->next = md2verthash[hashindex]; - md2verthash[hashindex] = hash; - } - loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata); - } - } - - vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int)); - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t)); - loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]); - loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t); - for (i = 0;i < loadmodel->surfmesh.num_vertices;i++) - { - int sts, stt; - hash = md2verthashdata + i; - vertremap[i] = hash->xyz; - sts = LittleShort(inst[hash->st*2+0]); - stt = LittleShort(inst[hash->st*2+1]); - if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight) - { - Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i); - sts = 0; - stt = 0; - } - loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth; - loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight; - } - - Mem_Free(md2verthash); - Mem_Free(md2verthashdata); - - // 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); - 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)); - for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++) - { - int k; - trivertx_t *v; - trivertx_t *out; - pinframe = (md2frame_t *)datapointer; - datapointer += sizeof(md2frame_t); - // store the frame scale/translate into the appropriate array - for (j = 0;j < 3;j++) - { - loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]); - loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]); - } - // 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; - } - - Mem_Free(vertremap); - - 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; - - loadmodel->surfmesh.isanimated = false; -#endif }