/* ============= RB_StretchPic ============= */ static void RB_StretchPic ( const void *data ) { const stretchPicCommand_t *cmd; shader_t *shader; int *indexes; vec2_t *texCoords; vecSimd_t *xyz; color4ub_t *colors; cmd = (const stretchPicCommand_t *)data; if ( !backEnd.projection2D ) { RB_SetGL2D(); } shader = cmd->shader; if ( shader != tess.shader ) { RB_EndSurface(); RB_BeginSurface( shader, 0 ); } RB_CheckOverflow( 4, 6 ); indexes = tess.indexes + tess.numIndexes; indexes[0] = tess.numVertexes + 3; indexes[1] = tess.numVertexes + 0; indexes[2] = tess.numVertexes + 2; indexes[3] = tess.numVertexes + 2; indexes[4] = tess.numVertexes + 0; indexes[5] = tess.numVertexes + 1; colors = tess.colors + tess.numVertexes; Byte4Copy( backEnd.color2D, colors[0] ); Byte4Copy( backEnd.color2D, colors[1] ); Byte4Copy( backEnd.color2D, colors[2] ); Byte4Copy( backEnd.color2D, colors[3] ); xyz = tess.xyz + tess.numVertexes; VectorSet( xyz[0], cmd->x, cmd->y, 0 ); VectorSet( xyz[1], cmd->x + cmd->w, cmd->y, 0 ); VectorSet( xyz[2], cmd->x + cmd->w, cmd->y + cmd->h, 0 ); VectorSet( xyz[3], cmd->x, cmd->y + cmd->h, 0 ); texCoords = tess.texCoords + tess.numVertexes; texCoords[0][0] = cmd->s1; texCoords[0][1] = cmd->t1; texCoords[1][0] = cmd->s2; texCoords[1][1] = cmd->t1; texCoords[2][0] = cmd->s2; texCoords[2][1] = cmd->t2; texCoords[3][0] = cmd->s1; texCoords[3][1] = cmd->t2; tess.numVertexes += 4; tess.numIndexes += 6; }
/* * RB_SurfaceAnim */ void RB_SurfaceAnim(md4Surface_t *surface) { int i, j, k; float frontlerp, backlerp; int *triangles; int indexes; int baseIndex, baseVertex; int numVerts; md4Vertex_t *v; md4Bone_t bones[MD4_MAX_BONES]; md4Bone_t *bonePtr, *bone; md4Header_t *header; md4Frame_t *frame; md4Frame_t *oldFrame; int frameSize; if(backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame){ backlerp = 0; frontlerp = 1; }else{ backlerp = backEnd.currentEntity->e.backlerp; frontlerp = 1.0f - backlerp; } header = (md4Header_t*)((byte*)surface + surface->ofsHeader); frameSize = (size_t)(&((md4Frame_t*)0)->bones[ header->numBones ]); frame = (md4Frame_t*)((byte*)header + header->ofsFrames + backEnd.currentEntity->e.frame * frameSize); oldFrame = (md4Frame_t*)((byte*)header + header->ofsFrames + backEnd.currentEntity->e.oldframe * frameSize); RB_CheckOverflow(surface->numVerts, surface->numTriangles * 3); triangles = (int*)((byte*)surface + surface->ofsTriangles); indexes = surface->numTriangles * 3; baseIndex = tess.numIndexes; baseVertex = tess.numVertexes; for(j = 0; j < indexes; j++) tess.indexes[baseIndex + j] = baseIndex + triangles[j]; tess.numIndexes += indexes; /* * lerp all the needed bones * */ if(!backlerp){ /* no lerping needed */ bonePtr = frame->bones; }else{ bonePtr = bones; for(i = 0; i < header->numBones*12; i++) ((float*)bonePtr)[i] = frontlerp * ((float*)frame->bones)[i] + backlerp * ((float*)oldFrame->bones)[i]; } /* * deform the vertexes by the lerped bones * */ numVerts = surface->numVerts; /* FIXME * This makes TFC's skeletons work. Shouldn't be necessary anymore, but left * in for reference. * v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts + 12); */ v = (md4Vertex_t*)((byte*)surface + surface->ofsVerts); for(j = 0; j < numVerts; j++){ Vec3 tempVert, tempNormal; md4Weight_t *w; clearv3(tempVert); clearv3(tempNormal); w = v->weights; for(k = 0; k < v->numWeights; k++, w++){ bone = bonePtr + w->boneIndex; tempVert[0] += w->boneWeight * (dotv3(bone->matrix[0], w->offset) + bone->matrix[0][3]); tempVert[1] += w->boneWeight * (dotv3(bone->matrix[1], w->offset) + bone->matrix[1][3]); tempVert[2] += w->boneWeight * (dotv3(bone->matrix[2], w->offset) + bone->matrix[2][3]); tempNormal[0] += w->boneWeight * dotv3(bone->matrix[0], v->normal); tempNormal[1] += w->boneWeight * dotv3(bone->matrix[1], v->normal); tempNormal[2] += w->boneWeight * dotv3(bone->matrix[2], v->normal); } tess.xyz[baseVertex + j][0] = tempVert[0]; tess.xyz[baseVertex + j][1] = tempVert[1]; tess.xyz[baseVertex + j][2] = tempVert[2]; tess.normal[baseVertex + j][0] = tempNormal[0]; tess.normal[baseVertex + j][1] = tempNormal[1]; tess.normal[baseVertex + j][2] = tempNormal[2]; tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; /* FIXME * This makes TFC's skeletons work. Shouldn't be necessary anymore, but left * in for reference. * v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 ); */ v = (md4Vertex_t*)&v->weights[v->numWeights]; } tess.numVertexes += surface->numVerts; }
void RB_SurfaceAnim( md4Surface_t *surface ) { int i, j, k; float frontlerp, backlerp; int *triangles; int indexes; int baseIndex, baseVertex; int numVerts; md4Vertex_t *v; md4Bone_t bones[MD4_MAX_BONES]; md4Bone_t *bonePtr, *bone; md4Header_t *header; md4Frame_t *frame; md4Frame_t *oldFrame; size_t frameSize; if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) { backlerp = 0; frontlerp = 1; } else { backlerp = backEnd.currentEntity->e.backlerp; frontlerp = 1.0f - backlerp; } header = (md4Header_t *)((byte *)surface + surface->ofsHeader); frameSize = offsetof( md4Frame_t, bones[header->numBones] ); frame = (md4Frame_t *)((byte *)header + header->ofsFrames + backEnd.currentEntity->e.frame * frameSize ); oldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames + backEnd.currentEntity->e.oldframe * frameSize ); RB_CheckOverflow( surface->numVerts, surface->numTriangles * 3 ); triangles = (int *) ((byte *)surface + surface->ofsTriangles); indexes = surface->numTriangles * 3; baseIndex = tess.numIndexes; baseVertex = tess.numVertexes; for (j = 0 ; j < indexes ; j++) { tess.indexes[baseIndex + j] = baseIndex + triangles[j]; } tess.numIndexes += indexes; // // lerp all the needed bones // if ( !backlerp ) { // no lerping needed bonePtr = frame->bones; } else { bonePtr = bones; for ( i = 0 ; i < header->numBones*12 ; i++ ) { ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i]; } } // // deform the vertexes by the lerped bones // numVerts = surface->numVerts; // FIXME // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left // in for reference. //v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts + 12); v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts); for ( j = 0; j < numVerts; j++ ) { vector3 tempVert, tempNormal; md4Weight_t *w; VectorClear( &tempVert ); VectorClear( &tempNormal ); w = v->weights; for ( k = 0 ; k < v->numWeights ; k++, w++ ) { bone = bonePtr + w->boneIndex; tempVert.x += w->boneWeight * ( DotProduct( (vector3 *)&bone->matrix[0], &w->offset ) + bone->matrix[0][3] ); tempVert.y += w->boneWeight * ( DotProduct( (vector3 *)&bone->matrix[1], &w->offset ) + bone->matrix[1][3] ); tempVert.z += w->boneWeight * ( DotProduct( (vector3 *)&bone->matrix[2], &w->offset ) + bone->matrix[2][3] ); tempNormal.x += w->boneWeight * DotProduct( (vector3 *)&bone->matrix[0], &v->normal ); tempNormal.y += w->boneWeight * DotProduct( (vector3 *)&bone->matrix[1], &v->normal ); tempNormal.z += w->boneWeight * DotProduct( (vector3 *)&bone->matrix[2], &v->normal ); } tess.xyz[baseVertex + j].x = tempVert.x; tess.xyz[baseVertex + j].y = tempVert.y; tess.xyz[baseVertex + j].z = tempVert.z; tess.normal[baseVertex + j].x = tempNormal.x; tess.normal[baseVertex + j].y = tempNormal.y; tess.normal[baseVertex + j].z = tempNormal.z; tess.texCoords[baseVertex + j][0].x = v->texCoords.x; tess.texCoords[baseVertex + j][0].y = v->texCoords.y; // FIXME // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left // in for reference. //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 ); v = (md4Vertex_t *)&v->weights[v->numWeights]; } tess.numVertexes += surface->numVerts; }
void RB_MDRSurfaceAnim( md4Surface_t *surface ) { int i, j, k; float frontlerp, backlerp; int *triangles; int indexes; int baseIndex, baseVertex; int numVerts; mdrVertex_t *v; mdrHeader_t *header; mdrFrame_t *frame; mdrFrame_t *oldFrame; mdrBone_t bones[MD4_MAX_BONES], *bonePtr, *bone; int frameSize; // don't lerp if lerping off, or this is the only frame, or the last frame... // if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame) { backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used frontlerp = 1; } else { backlerp = backEnd.currentEntity->e.backlerp; frontlerp = 1.0f - backlerp; } header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader); frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); frame = (mdrFrame_t *)((byte *)header + header->ofsFrames + backEnd.currentEntity->e.frame * frameSize ); oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames + backEnd.currentEntity->e.oldframe * frameSize ); RB_CheckOverflow( surface->numVerts, surface->numTriangles ); triangles = (int *) ((byte *)surface + surface->ofsTriangles); indexes = surface->numTriangles * 3; baseIndex = tess.numIndexes; baseVertex = tess.numVertexes; // Set up all triangles. for (j = 0 ; j < indexes ; j++) { tess.indexes[baseIndex + j] = baseVertex + triangles[j]; } tess.numIndexes += indexes; // // lerp all the needed bones // if ( !backlerp ) { // no lerping needed bonePtr = frame->bones; } else { bonePtr = bones; for ( i = 0 ; i < header->numBones*12 ; i++ ) { ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i]; } } // // deform the vertexes by the lerped bones // numVerts = surface->numVerts; v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts); for ( j = 0; j < numVerts; j++ ) { vector3 tempVert, tempNormal; mdrWeight_t *w; VectorClear( tempVert ); VectorClear( tempNormal ); w = v->weights; for ( k = 0 ; k < v->numWeights ; k++, w++ ) { bone = bonePtr + w->boneIndex; tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] ); tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] ); tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] ); tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal ); tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal ); tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal ); } tess.xyz[baseVertex + j][0] = tempVert[0]; tess.xyz[baseVertex + j][1] = tempVert[1]; tess.xyz[baseVertex + j][2] = tempVert[2]; tess.normal[baseVertex + j][0] = tempNormal[0]; tess.normal[baseVertex + j][1] = tempNormal[1]; tess.normal[baseVertex + j][2] = tempNormal[2]; tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; v = (mdrVertex_t *)&v->weights[v->numWeights]; } tess.numVertexes += surface->numVerts; }
/* ============== R_CalcBones The list of bones[] should only be built and modified from within here ============== */ void R_CalcBones(mdsHeader_t *header, const refEntity_t *refent, int *boneList, int numBones) { int i; int *boneRefs; float torsoWeight; // if the entity has changed since the last time the bones were built, reset them if (memcmp(&lastBoneEntity, refent, sizeof(refEntity_t))) { // different, cached bones are not valid memset(validBones, 0, header->numBones); lastBoneEntity = *refent; // (SA) also reset these counter statics //----(SA) print stats for the complete model (not per-surface) if (r_bonesDebug->integer == 4 && totalrt) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, totalrv, totalv, totalrt, totalt, ( float )(100.0 * totalrt) / (float) totalt); } totalrv = totalrt = totalv = totalt = 0; } memset(newBones, 0, header->numBones); if (refent->oldframe == refent->frame) { backlerp = 0; frontlerp = 1; } else { backlerp = refent->backlerp; frontlerp = 1.0f - backlerp; } if (refent->oldTorsoFrame == refent->torsoFrame) { torsoBacklerp = 0; torsoFrontlerp = 1; } else { torsoBacklerp = refent->torsoBacklerp; torsoFrontlerp = 1.0f - torsoBacklerp; } frameSize = (int) (sizeof(mdsFrame_t) + (header->numBones - 1) * sizeof(mdsBoneFrameCompressed_t)); frame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->frame * frameSize); torsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->torsoFrame * frameSize); oldFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->oldframe * frameSize); oldTorsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->oldTorsoFrame * frameSize); // lerp all the needed bones (torsoParent is always the first bone in the list) cBoneList = frame->bones; cBoneListTorso = torsoFrame->bones; boneInfo = ( mdsBoneInfo_t * )((byte *)header + header->ofsBones); boneRefs = boneList; // Matrix3Transpose(refent->torsoAxis, torsoAxis); #ifdef HIGH_PRECISION_BONES if (qtrue) { #else if (!backlerp && !torsoBacklerp) { #endif for (i = 0; i < numBones; i++, boneRefs++) { if (validBones[*boneRefs]) { // this bone is still in the cache bones[*boneRefs] = rawBones[*boneRefs]; continue; } // find our parent, and make sure it has been calculated if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent])) { R_CalcBone(header, refent, boneInfo[*boneRefs].parent); } R_CalcBone(header, refent, *boneRefs); } } else // interpolated { cOldBoneList = oldFrame->bones; cOldBoneListTorso = oldTorsoFrame->bones; for (i = 0; i < numBones; i++, boneRefs++) { if (validBones[*boneRefs]) { // this bone is still in the cache bones[*boneRefs] = rawBones[*boneRefs]; continue; } // find our parent, and make sure it has been calculated if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent])) { R_CalcBoneLerp(header, refent, boneInfo[*boneRefs].parent); } R_CalcBoneLerp(header, refent, *boneRefs); } } // adjust for torso rotations torsoWeight = 0; boneRefs = boneList; for (i = 0; i < numBones; i++, boneRefs++) { thisBoneInfo = &boneInfo[*boneRefs]; bonePtr = &bones[*boneRefs]; // add torso rotation if (thisBoneInfo->torsoWeight > 0) { if (!newBones[*boneRefs]) { // just copy it back from the previous calc bones[*boneRefs] = oldBones[*boneRefs]; continue; } if (!(thisBoneInfo->flags & BONEFLAG_TAG)) { // 1st multiply with the bone->matrix // 2nd translation for rotation relative to bone around torso parent offset VectorSubtract(bonePtr->translation, torsoParentOffset, t); Matrix4FromAxisPlusTranslation(bonePtr->matrix, t, m1); // 3rd scaled rotation // 4th translate back to torso parent offset // use previously created matrix if available for the same weight if (torsoWeight != thisBoneInfo->torsoWeight) { Matrix4FromScaledAxisPlusTranslation(torsoAxis, thisBoneInfo->torsoWeight, torsoParentOffset, m2); torsoWeight = thisBoneInfo->torsoWeight; } // multiply matrices to create one matrix to do all calculations Matrix4MultiplyInto3x3AndTranslation(m2, m1, bonePtr->matrix, bonePtr->translation); } else // tag's require special handling { // rotate each of the axis by the torsoAngles LocalScaledMatrixTransformVector(bonePtr->matrix[0], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[0]); LocalScaledMatrixTransformVector(bonePtr->matrix[1], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[1]); LocalScaledMatrixTransformVector(bonePtr->matrix[2], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[2]); memcpy(bonePtr->matrix, tmpAxis, sizeof(tmpAxis)); // rotate the translation around the torsoParent VectorSubtract(bonePtr->translation, torsoParentOffset, t); LocalScaledMatrixTransformVector(t, thisBoneInfo->torsoWeight, torsoAxis, bonePtr->translation); VectorAdd(bonePtr->translation, torsoParentOffset, bonePtr->translation); } } } // backup the final bones memcpy(oldBones, bones, sizeof(bones[0]) * header->numBones); } #ifdef DBG_PROFILE_BONES #define DBG_SHOWTIME Ren_Print("%i: %i, ", di++, (dt = ri.Milliseconds()) - ldt); ldt = dt; #else #define DBG_SHOWTIME ; #endif /* ============== RB_SurfaceAnim ============== */ void RB_SurfaceAnim(mdsSurface_t *surface) { int j, k; refEntity_t *refent; int *boneList; mdsHeader_t *header; #ifdef DBG_PROFILE_BONES int di = 0, dt, ldt; dt = ri.Milliseconds(); ldt = dt; #endif refent = &backEnd.currentEntity->e; boneList = ( int * )((byte *)surface + surface->ofsBoneReferences); header = ( mdsHeader_t * )((byte *)surface + surface->ofsHeader); R_CalcBones(header, (const refEntity_t *)refent, boneList, surface->numBoneReferences); DBG_SHOWTIME // calculate LOD // TODO: lerp the radius and origin VectorAdd(refent->origin, frame->localOrigin, vec); lodRadius = frame->radius; lodScale = RB_CalcMDSLod(refent, vec, lodRadius, header->lodBias, header->lodScale); //DBG_SHOWTIME // modification to allow dead skeletal bodies to go below minlod (experiment) if (refent->reFlags & REFLAG_DEAD_LOD) { if (lodScale < 0.35) // allow dead to lod down to 35% (even if below surf->minLod) (%35 is arbitrary and probably not good generally. worked for the blackguard/infantry as a test though) { lodScale = 0.35; } render_count = ROUND_INT(surface->numVerts * lodScale); } else { render_count = ROUND_INT(surface->numVerts * lodScale); if (render_count < surface->minLod) { if (!(refent->reFlags & REFLAG_DEAD_LOD)) { render_count = surface->minLod; } } } if (render_count > surface->numVerts) { render_count = surface->numVerts; } RB_CheckOverflow(render_count, surface->numTriangles); //DBG_SHOWTIME // setup triangle list RB_CheckOverflow(surface->numVerts, surface->numTriangles * 3); //DBG_SHOWTIME collapse_map = ( int * )(( byte * )surface + surface->ofsCollapseMap); triangles = ( int * )((byte *)surface + surface->ofsTriangles); indexes = surface->numTriangles * 3; baseIndex = tess.numIndexes; baseVertex = tess.numVertexes; oldIndexes = baseIndex; tess.numVertexes += render_count; pIndexes = &tess.indexes[baseIndex]; //DBG_SHOWTIME if (render_count == surface->numVerts) { memcpy(pIndexes, triangles, sizeof(triangles[0]) * indexes); if (baseVertex) { glIndex_t *indexesEnd; for (indexesEnd = pIndexes + indexes ; pIndexes < indexesEnd ; pIndexes++) { *pIndexes += baseVertex; } } tess.numIndexes += indexes; } else { int *collapseEnd; pCollapse = collapse; for (j = 0; j < render_count; pCollapse++, j++) { *pCollapse = j; } pCollapseMap = &collapse_map[render_count]; for (collapseEnd = collapse + surface->numVerts ; pCollapse < collapseEnd; pCollapse++, pCollapseMap++) { *pCollapse = collapse[*pCollapseMap]; } for (j = 0 ; j < indexes ; j += 3) { p0 = collapse[*(triangles++)]; p1 = collapse[*(triangles++)]; p2 = collapse[*(triangles++)]; // FIXME // note: serious optimization opportunity here, // by sorting the triangles the following "continue" // could have been made into a "break" statement. if (p0 == p1 || p1 == p2 || p2 == p0) { continue; } *(pIndexes++) = baseVertex + p0; *(pIndexes++) = baseVertex + p1; *(pIndexes++) = baseVertex + p2; tess.numIndexes += 3; } baseIndex = tess.numIndexes; } //DBG_SHOWTIME // deform the vertexes by the lerped bones numVerts = surface->numVerts; v = ( mdsVertex_t * )((byte *)surface + surface->ofsVerts); tempVert = ( float * )(tess.xyz + baseVertex); tempNormal = ( float * )(tess.normal + baseVertex); for (j = 0; j < render_count; j++, tempVert += 4, tempNormal += 4) { mdsWeight_t *w; VectorClear(tempVert); w = v->weights; for (k = 0 ; k < v->numWeights ; k++, w++) { bone = &bones[w->boneIndex]; LocalAddScaledMatrixTransformVectorTranslate(w->offset, w->boneWeight, bone->matrix, bone->translation, tempVert); } LocalMatrixTransformVector(v->normal, bones[v->weights[0].boneIndex].matrix, tempNormal); tess.texCoords0[baseVertex + j].v[0] = v->texCoords[0]; tess.texCoords0[baseVertex + j].v[1] = v->texCoords[1]; v = (mdsVertex_t *)&v->weights[v->numWeights]; } DBG_SHOWTIME if (r_bonesDebug->integer) { if (r_bonesDebug->integer < 3) { int i; // DEBUG: show the bones as a stick figure with axis at each bone boneRefs = ( int * )((byte *)surface + surface->ofsBoneReferences); for (i = 0; i < surface->numBoneReferences; i++, boneRefs++) { bonePtr = &bones[*boneRefs]; GL_Bind(tr.whiteImage); qglLineWidth(1); qglBegin(GL_LINES); for (j = 0; j < 3; j++) { VectorClear(vec); vec[j] = 1; qglColor3fv(vec); qglVertex3fv(bonePtr->translation); VectorMA(bonePtr->translation, 5, bonePtr->matrix[j], vec); qglVertex3fv(vec); } qglEnd(); // connect to our parent if it's valid if (validBones[boneInfo[*boneRefs].parent]) { qglLineWidth(2); qglBegin(GL_LINES); qglColor3f(.6, .6, .6); qglVertex3fv(bonePtr->translation); qglVertex3fv(bones[boneInfo[*boneRefs].parent].translation); qglEnd(); } qglLineWidth(1); } } if (r_bonesDebug->integer == 3 || r_bonesDebug->integer == 4) { int render_indexes = (tess.numIndexes - oldIndexes); // show mesh edges tempVert = ( float * )(tess.xyz + baseVertex); tempNormal = ( float * )(tess.normal + baseVertex); GL_Bind(tr.whiteImage); qglLineWidth(1); qglBegin(GL_LINES); qglColor3f(.0, .0, .8); pIndexes = &tess.indexes[oldIndexes]; for (j = 0; j < render_indexes / 3; j++, pIndexes += 3) { qglVertex3fv(tempVert + 4 * pIndexes[0]); qglVertex3fv(tempVert + 4 * pIndexes[1]); qglVertex3fv(tempVert + 4 * pIndexes[1]); qglVertex3fv(tempVert + 4 * pIndexes[2]); qglVertex3fv(tempVert + 4 * pIndexes[2]); qglVertex3fv(tempVert + 4 * pIndexes[0]); } qglEnd(); // track debug stats if (r_bonesDebug->integer == 4) { totalrv += render_count; totalrt += render_indexes / 3; totalv += surface->numVerts; totalt += surface->numTriangles; } if (r_bonesDebug->integer == 3) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, render_count, surface->numVerts, render_indexes / 3, surface->numTriangles, ( float )(100.0 * render_indexes / 3) / (float) surface->numTriangles); } } } if (r_bonesDebug->integer > 1) { // dont draw the actual surface tess.numIndexes = oldIndexes; tess.numVertexes = baseVertex; return; } #ifdef DBG_PROFILE_BONES Ren_Print("\n"); #endif }
/* ============== RB_SurfaceAnim ============== */ void RB_SurfaceAnim( md4Surface_t *surface ) { int i, j, k; float frontlerp, backlerp; int *triangles; int *indexes; int numIndexes; int numVerts; md4Vertex_t *v; md4Bone_t bones[MD4_MAX_BONES]; md4Bone_t *bonePtr, *bone; md4Header_t *header; md4Frame_t *frame; md4Frame_t *oldFrame; int frameSize; float *xyz, *normal; vec2_t *texCoords; RB_CheckShaderTime( backEnd.refdef->time - backEnd.currentModel->shaderTime, backEnd.refdef->timeFraction ); if ( backEnd.currentModel->oldframe == backEnd.currentModel->frame ) { backlerp = 0; frontlerp = 1; } else { backlerp = backEnd.currentModel->backlerp; frontlerp = 1.0f - backlerp; } header = (md4Header_t *)((byte *)surface + surface->ofsHeader); frameSize = (size_t)( &((md4Frame_t *)0)->bones[ header->numBones ] ); frame = (md4Frame_t *)((byte *)header + header->ofsFrames + backEnd.currentModel->frame * frameSize ); oldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames + backEnd.currentModel->oldframe * frameSize ); numIndexes = surface->numTriangles * 3; RB_CheckOverflow( surface->numVerts, numIndexes ); triangles = (int *) ((byte *)surface + surface->ofsTriangles); indexes = tess.indexes + tess.numIndexes; for (j = 0 ; j < numIndexes ; j++) { indexes[j] = tess.numIndexes + triangles[j]; } tess.numIndexes += numIndexes; // // lerp all the needed bones // if ( !backlerp ) { // no lerping needed bonePtr = frame->bones; } else { bonePtr = bones; for ( i = 0 ; i < header->numBones*12 ; i++ ) { ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i]; } } // // deform the vertexes by the lerped bones // numVerts = surface->numVerts; xyz = (tess.xyz + tess.numVertexes)[0]; normal = (tess.normal + tess.numVertexes)[0]; texCoords = tess.texCoords + tess.numVertexes; // FIXME // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left // in for reference. //v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts + 12); v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts); for ( j = 0; j < numVerts; j++, xyz += VEC_SIMD, normal+= VEC_SIMD, texCoords++ ) { md4Weight_t *w; VectorClear( xyz ); VectorClear( normal ); w = v->weights; for ( k = 0 ; k < v->numWeights ; k++, w++ ) { bone = bonePtr + w->boneIndex; xyz[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] ); xyz[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] ); xyz[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] ); normal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal ); normal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal ); normal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal ); } texCoords[0][0] = v->texCoords[0]; texCoords[0][1] = v->texCoords[1]; // FIXME // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left // in for reference. //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 ); v = (md4Vertex_t *)&v->weights[v->numWeights]; } tess.numVertexes += surface->numVerts; }
/* ============== RB_SurfaceAnim ============== */ void RB_SurfaceAnim( mdsSurface_t *surface ) { int i, j, k; int render_count; int p0, p1, p2, indexes; refEntity_t *refent; int *boneList, *triangles; glIndex_t *indexesEnd, *pIndexes; mdsHeader_t *header; mdsFrame_t *backframe; mdsBoneFrame_t *bone; mdsVertex_t *v; float *tempVert, *tempNormal; int baseIndex, baseVertex, oldIndexes, numVerts; int frameSize; refent = &backEnd.currentEntity->e; boneList = ( int * )( (byte *)surface + surface->ofsBoneReferences ); header = ( mdsHeader_t * )( (byte *)surface + surface->ofsHeader ); frameSize = (int) ( sizeof( mdsFrame_t ) + ( header->numBones - 1 ) * sizeof( mdsBoneFrameCompressed_t ) ); backframe = ( mdsFrame_t * )( (byte *)header + header->ofsFrames + refent->frame * frameSize ); render_count = surface->numVerts; RB_CheckOverflow( render_count, surface->numTriangles ); // // setup triangle list // RB_CheckOverflow( surface->numVerts, surface->numTriangles * 3 ); triangles = ( int * )( (byte *)surface + surface->ofsTriangles ); indexes = surface->numTriangles * 3; baseIndex = tess.numIndexes; baseVertex = tess.numVertexes; oldIndexes = baseIndex; tess.numVertexes += render_count; pIndexes = &tess.indexes[baseIndex]; //memcpy( pIndexes, triangles, sizeof( triangles[0] ) * indexes ); for ( i = 0 ; i < indexes ; i++ ) { *pIndexes++ = baseVertex + *triangles++; } tess.numIndexes += indexes; // // deform the vertexes by the lerped bones // numVerts = surface->numVerts; v = ( mdsVertex_t * )( (byte *)surface + surface->ofsVerts ); tempVert = ( float * )( tess.xyz + baseVertex ); tempNormal = ( float * )( tess.normal + baseVertex ); //LockBones R_CalcBones( header, (const refEntity_t *)refent, boneList, surface->numBoneReferences, 1 ); for ( j = 0; j < render_count; j++, tempVert += 4, tempNormal += 4 ) { mdsWeight_t *w; VectorClear( tempVert ); w = v->weights; for ( k = 0 ; k < v->numWeights ; k++, w++ ) { bone = &smpbones[1][w->boneIndex]; LocalAddScaledMatrixTransformVectorTranslate( w->offset, w->boneWeight, bone->matrix, bone->translation, tempVert ); } LocalMatrixTransformVector( v->normal, smpbones[1][v->weights[0].boneIndex].matrix, tempNormal ); tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; v = (mdsVertex_t *)&v->weights[v->numWeights]; } //UnlockBones }