// Filename:- R_GLM.cpp // // contains a whole wodge of code pasted from our other codebases in order to quickly get this format up and running... // #include "stdafx.h" #include "includes.h" #include "R_Common.h" #include "R_Model.h" #include "R_Image.h" #include "matcomp.h" #include "textures.h" #include "skins.h" #include "oldskins.h" #include "modviewtreeview.h" // for GetString() #include "mc_compress2.h" #include "special_defines.h" // #include "r_glm.h" /* ============== RB_SurfaceAnim ============== */ void RB_SurfaceGhoul( surfaceInfo_t *surf ) { int j, k; int baseIndex, baseVertex; int numVerts; mdxmVertex_t *v; mdxaBone_t *bonePtr, *bone; int *triangles; int indexes; // grab the pointer to the surface info within the loaded mesh file mdxmSurface_t *surface = (mdxmSurface_t *)surf->surfaceData; int *piBoneRefTable = (int*)((byte*)surface + surface->ofsBoneReferences); // stats... // giSurfaceVertsDrawn = surface->numVerts; giSurfaceTrisDrawn = surface->numTriangles; giRenderedBoneWeights = 0; giOmittedBoneWeights = 0; // // deform the vertexes by the lerped bones // // first up, sanity check our numbers RB_CheckOverflow( surface->numVerts, surface->numTriangles ); // now copy the right number of verts to the temporary area for verts for this shader 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] = baseVertex + triangles[j]; } tess.numIndexes += indexes; // point us at the bone structure that should have been pre-computed bonePtr = (mdxaBone_t *)surf->boneList; // whip through and actually transform each vertex numVerts = surface->numVerts; v = (mdxmVertex_t *) ((byte *)surface + surface->ofsVerts); mdxmVertexTexCoord_t *pTexCoords = (mdxmVertexTexCoord_t *) &v[numVerts]; for ( j = 0; j < numVerts; j++ ) { vec3_t tempVert, tempNormal; VectorClear( tempVert ); VectorClear( tempNormal ); // w = v->weights; const int iNumWeights = G2_GetVertWeights( v ); int iWeightsUsed = 0; int iWeightsOmitted = 0; float fTotalWeight = 0.0f; for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( v, k ); float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); if (!AppVars.bBoneWeightThreshholdingActive || fBoneWeight * 100 > AppVars.fBoneWeightThreshholdPercent ) { bone = &bonePtr[piBoneRefTable[iBoneIndex]]; tempVert[0] += fBoneWeight * ( DotProduct( bone->matrix[0], v->vertCoords ) + bone->matrix[0][3] ); tempVert[1] += fBoneWeight * ( DotProduct( bone->matrix[1], v->vertCoords ) + bone->matrix[1][3] ); tempVert[2] += fBoneWeight * ( DotProduct( bone->matrix[2], v->vertCoords ) + bone->matrix[2][3] ); tempNormal[0] += fBoneWeight * DotProduct( bone->matrix[0], v->normal ); tempNormal[1] += fBoneWeight * DotProduct( bone->matrix[1], v->normal ); tempNormal[2] += fBoneWeight * DotProduct( bone->matrix[2], v->normal ); iWeightsUsed++; } else { iWeightsOmitted++; } } giRenderedBoneWeights += iWeightsUsed; tess.WeightsUsed [baseVertex + j] = iWeightsUsed; giOmittedBoneWeights += iWeightsOmitted; tess.WeightsOmitted [baseVertex + j] = iWeightsOmitted; // assert(fabs(tempVert[0]) < 1000.0f); // assert(fabs(tempVert[1]) < 1000.0f); // assert(fabs(tempVert[2]) < 1000.0f); 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] = pTexCoords[j].texCoords[0]; tess.texCoords[baseVertex + j][0][1] = pTexCoords[j].texCoords[1]; // OutputDebugString(va("tex: %1.4f, %1.4f\n",v->texCoords[0],v->texCoords[1])); // v = (mdxmVertex_t *)&v->weights[/*v->numWeights*/surface->maxVertBoneWeights]; v++; } tess.numVertexes += surface->numVerts; // modview stuff for surface highlighting.... // { tess.iSurfaceNum = surface->thisSurfaceIndex; // // sigh, need to work out if this surface is a tag or not... // mdxmHeader_t *pMDXMHeader = (mdxmHeader_t *) ((byte *)surface + surface->ofsHeader); mdxmHierarchyOffsets_t *pHierarchyOffsets = (mdxmHierarchyOffsets_t *) ((byte *) pMDXMHeader + sizeof(*pMDXMHeader)); mdxmSurfHierarchy_t *pSurfHierarchy = (mdxmSurfHierarchy_t *) ((byte *) pHierarchyOffsets + pHierarchyOffsets->offsets[surface->thisSurfaceIndex]); tess.bSurfaceIsG2Tag = (pSurfHierarchy->flags & G2SURFACEFLAG_ISBOLT); // if (tess.bSurfaceIsG2Tag) // { // OutputDebugString(va("Surface %d is a tag\n",surface->thisSurfaceIndex)); // } } } /* ================= R_LoadMDXM - load a Ghoul 2 Mesh file ================= */ qboolean R_LoadMDXM( model_t *mod, void *buffer, const char *mod_name ) { int i,l, j; mdxmHeader_t *pinmodel, *mdxm; mdxmLOD_t *lod; mdxmSurface_t *surf; int version; int size; //MODVIEWREM shader_t *sh; mdxmSurfHierarchy_t *surfInfo; #ifndef _M_IX86 int k; int frameSize; mdxmTag_t *tag; mdxmTriangle_t *tri; mdxmVertex_t *v; mdxmFrame_t *cframe; int *boneRef; #endif // bool bSkinsExist = Skins_FilesExist(mod_name) || OldSkins_FilesExist(mod_name); bool bOldSkinsExist = OldSkins_FilesExist(mod_name); pinmodel = (mdxmHeader_t *)buffer; version = LittleLong (pinmodel->version); if (version != MDXM_VERSION) { ri.Printf( PRINT_WARNING, "R_LoadMDXM: %s has wrong version (%i should be %i)\n", mod_name, version, MDXM_VERSION); return qfalse; } mod->type = MOD_MDXM; size = LittleLong(pinmodel->ofsEnd); mod->dataSize += size; mdxm = mod->mdxm = (mdxmHeader_t*) ri.Hunk_Alloc( size ); memcpy( mdxm, buffer, size ); LL(mdxm->ident); LL(mdxm->version); LL(mdxm->numLODs); LL(mdxm->ofsLODs); LL(mdxm->numSurfaces); if (mdxm->numSurfaces > MAX_G2_SURFACES) { ri.Printf( PRINT_WARNING, "R_LoadMDXM: numSurfaces == %d, max is %d\n", mdxm->numSurfaces, MAX_G2_SURFACES); return qfalse; } LL(mdxm->ofsSurfHierarchy); LL(mdxm->ofsEnd); // first up, go load in the animation file we need that has the skeletal animation info for this model #if 1 // kludge code for overriding skeletons if (AppVars.bAllowGLAOverrides) { if (GetYesNo(va("Override anim file:\n\n\"%s\" ?\n\n( Model: \"%s\" )",mdxm->animName,mdxm->name))) { LPCSTR psNewAnimName = GetString("Enter new anim name",mdxm->animName); if (psNewAnimName) { strncpy(mdxm->animName,psNewAnimName,sizeof(mdxm->animName)-1); mdxm->animName[sizeof(mdxm->animName)-1]='\0'; } } } #endif mdxm->animIndex = RE_RegisterModel( va ("%s.gla",mdxm->animName)); if (!mdxm->animIndex) { ri.Printf( PRINT_WARNING, "R_LoadMDXM: missing animation file %s for mesh %s\n", mdxm->animName, mdxm->name); return qfalse; } // this shouldn't be needed unless someone has failed to recompile something... // mdxaHeader_t *pMDXAHeader = (mdxaHeader_t *) RE_GetModelData( mdxm->animIndex ); if (pMDXAHeader->numBones != mdxm->numBones) { ri.Error (ERR_DROP, "R_LoadMDXM: # bones mismatch!\n\n\"%s\" has %d bones\n\n\"%s\" has %d\n\nThis model probably needs recompiling", mod_name, mdxm->numBones, pMDXAHeader->name, pMDXAHeader->numBones); } surfInfo = (mdxmSurfHierarchy_t *)( (byte *)mdxm + mdxm->ofsSurfHierarchy); for ( i = 0 ; i < mdxm->numSurfaces ; i++) { LL(surfInfo->numChildren); LL(surfInfo->parentIndex); // do all the children indexs for (j=0; jnumChildren; j++) { LL(surfInfo->childIndexes[j]); } /* MODVIEWREM // get the shader name sh = R_FindShader( surfInfo->shader, LIGHTMAP_NONE, qtrue ); // insert it in the surface list if ( sh->defaultShader ) { surfInfo->shaderIndex = 0; } else { surfInfo->shaderIndex = sh->index; } */ // weird logic here, for speed. If there's a slash in the name (which therefore precludes it from being a SOF2 // material name, and there's no old-type skin file (which precludes it being an overridden CHC surface shader), // then load the file directly as a texture/shader, // else leave it for later skin-binding. // if (!bOldSkinsExist && (strchr(surfInfo->shader,'/') || strchr(surfInfo->shader,'\\'))) { surfInfo->shaderIndex = Texture_Load(surfInfo->shader); } else { surfInfo->shaderIndex = -1; } // find the next surface surfInfo = (mdxmSurfHierarchy_t *)( (byte *)surfInfo + (int)( &((mdxmSurfHierarchy_t *)0)->childIndexes[ surfInfo->numChildren ] )); } mod->numLods = mdxm->numLODs -1 ; //copy this up to the model for ease of use - it will get inced after this. // swap all the LOD's (we need to do the middle part of this even for intel, because of shader reg and err-check) lod = (mdxmLOD_t *) ( (byte *)mdxm + mdxm->ofsLODs ); for ( l = 0 ; l < mdxm->numLODs ; l++) { LL(lod->ofsEnd); // swap all the surfaces mdxmLODSurfOffset_t *pLODSurfOffset = (mdxmLODSurfOffset_t*) ( (byte *)lod + sizeof (mdxmLOD_t) ); for ( i = 0 ; i < mdxm->numSurfaces ; i++) { LL(pLODSurfOffset->offsets[i]); surf = (mdxmSurface_t *) ((byte*)pLODSurfOffset + pLODSurfOffset->offsets[i]); LL(surf->numTriangles); LL(surf->ofsTriangles); LL(surf->numVerts); LL(surf->ofsVerts); LL(surf->ofsEnd); LL(surf->ofsHeader); LL(surf->numBoneReferences); LL(surf->ofsBoneReferences); if ( surf->numVerts > (bQ3RulesApply?SHADER_MAX_VERTEXES:ACTUAL_SHADER_MAX_VERTEXES) ) { ri.Error (ERR_DROP, "R_LoadMDXM: %s has more than %i verts on a surface (%i)", mod_name, (bQ3RulesApply?SHADER_MAX_VERTEXES:ACTUAL_SHADER_MAX_VERTEXES), surf->numVerts ); } if ( surf->numTriangles*3 > (bQ3RulesApply?SHADER_MAX_INDEXES:ACTUAL_SHADER_MAX_INDEXES) ) { ri.Error (ERR_DROP, "R_LoadMDXM: %s has more than %i triangles on a surface (%i)", mod_name, (bQ3RulesApply?SHADER_MAX_INDEXES:ACTUAL_SHADER_MAX_INDEXES) / 3, surf->numTriangles ); } // change to surface identifier surf->ident = SF_MDX; // set pointer to surface in the model surface pointer array assert(i != MAX_G2_SURFACES); mod->mdxmsurf[l][i] = surf; // register the shaders #ifndef _M_IX86 // // optimisation, we don't bother doing this for standard intel case since our data's already in that format... // // FIXME - is this correct? // do all the bone reference data boneRef = (int *) ( (byte *)surf + surf->ofsBoneReferences ); for ( j = 0 ; j < surf->numBoneReferences ; j++ ) { LL(boneRef[j]); } // swap all the triangles tri = (mdxmTriangle_t *) ( (byte *)surf + surf->ofsTriangles ); for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { LL(tri->indexes[0]); LL(tri->indexes[1]); LL(tri->indexes[2]); } // swap all the vertexes v = (mdxmVertex_t *) ( (byte *)surf + surf->ofsVerts ); for ( j = 0 ; j < surf->numVerts ; j++ ) { v->normal[0] = LittleFloat( v->normal[0] ); v->normal[1] = LittleFloat( v->normal[1] ); v->normal[2] = LittleFloat( v->normal[2] ); v->texCoords[0] = LittleFloat( v->texCoords[0] ); v->texCoords[1] = LittleFloat( v->texCoords[1] ); v->numWeights = LittleLong( v->numWeights ); v->offset[0] = LittleFloat( v->offset[0] ); v->offset[1] = LittleFloat( v->offset[1] ); v->offset[2] = LittleFloat( v->offset[2] ); for ( k = 0 ; k numWeights*/surf->maxVertBoneWeights ; k++ ) { v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex ); v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight ); } v = (mdxmVertex_t *)&v->weights[/*v->numWeights*/surf->maxVertBoneWeights]; } #endif // find the next surface surf = (mdxmSurface_t *)( (byte *)surf + surf->ofsEnd ); } // find the next LOD lod = (mdxmLOD_t *)( (byte *)lod + lod->ofsEnd ); } #ifndef _M_IX86 // // optimisation, we don't bother doing this for standard intel case since our data's already in that format... // tag = (mdxmTag_t *) ( (byte *)mdxm + mdxm->ofsTags ); for ( i = 0 ; i < md4->numTags ; i++) { LL(tag->boneIndex); tag++; } #endif return qtrue; } /* ================= R_LoadMDXA - load a Ghoul 2 animation file ================= */ qboolean R_LoadMDXA( model_t *mod, void *buffer, const char *mod_name ) { mdxaHeader_t *pinmodel, *mdxa; int version; int size; #ifndef _M_IX86 int j, k, i; int frameSize; mdxaFrame_t *cframe; mdxaSkel_t *boneInfo; #endif pinmodel = (mdxaHeader_t *)buffer; version = LittleLong (pinmodel->version); if (version != MDXA_VERSION) { ri.Printf( PRINT_WARNING, "R_LoadMDXA: %s has wrong version (%i should be %i)\n", mod_name, version, MDXA_VERSION); return qfalse; } mod->type = MOD_MDXA; size = LittleLong(pinmodel->ofsEnd); mod->dataSize += size; mdxa = mod->mdxa = (mdxaHeader_t*) ri.Hunk_Alloc( size ); memcpy( mdxa, buffer, size ); LL(mdxa->ident); LL(mdxa->version); LL(mdxa->numFrames); LL(mdxa->numBones); LL(mdxa->ofsFrames); LL(mdxa->ofsEnd); if ( mdxa->numFrames < 1 ) { ri.Printf( PRINT_WARNING, "R_LoadMDXAa: %s has no frames\n", mod_name ); return qfalse; } if ( mdxa->numBones > MAX_POSSIBLE_BONES ) { ri.Error (ERR_DROP, "R_LoadMDXA: %s has more than %i bones (%i)", mod_name, MAX_POSSIBLE_BONES, mdxa->numBones ); } return qtrue; } /* ================ R_GetMDXTag for Ghoul II models... ================ */ // itu? void R_GetMDXATag( mdxmHeader_t *mod, int framenum, const char *tagName ,md3Tag_t * dest) { // int i; // int frameSize; mdxaHeader_t *mdxa; // mdxaFrame_t *cframe; // mdxmTag_t *tag; // md4Bone_t tbone; mdxa = tr.models[mod->animIndex]->mdxa; if ( framenum >= mdxa->numFrames ) { // it is possible to have a bad frame while changing models, so don't error framenum = mdxa->numFrames - 1; } AxisClear( dest->axis ); VectorClear( dest->origin ); } //===================================================================================================================== // Surface List handling routines - so entities can determine what surfaces attached to a model are operational or not. // set a named surface offFlags - if it doesn't find a surface with this name in the list then it will add one. qboolean G2_SetSurfaceOnOff (qhandle_t model, surfaceInfo_t *slist, const char *surfaceName, const SurfaceOnOff_t offFlags, const int surface) { int i; mdxmSurface_t *surf; // find the model we want model_t *mod = R_GetModelByHandle(model); mdxmHierarchyOffsets_t *surfIndexes = (mdxmHierarchyOffsets_t *)((byte *)mod->mdxm + sizeof(mdxmHeader_t)); mdxmSurfHierarchy_t *surfInfo; // did we find a ghoul 2 model or not? if (!mod->mdxm) { assert(0); return qfalse; } // first find if we already have this surface in the list for (i=0; ithisSurfaceIndex?? surf = mod->mdxmsurf[0][slist[i].surface]; // back track and get the surfinfo struct for this surface surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surf->thisSurfaceIndex]); // same name as one already in? if (!stricmp (surfInfo->name, surfaceName)) { assert(surface == i); // set descendants value slist[i].offFlags = offFlags; return qtrue; } } // run out of space? if (i == MAX_G2_SURFACES) { assert(0); return qfalse; } // OutputDebugString(va("Storing surface # %d in slot %d ('%s')\n",surface,i,surfaceName)); assert(surface == i); if (surface != i) { // fill this in later /////ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)", } // insert here then slist[i].offFlags = offFlags; slist[i].surface = surface; slist[i].ident = SF_MDX; slist[i].surfaceData = (void *)mod->mdxmsurf[0][surface]; // if we can, set the next surface pointer to a -1 to make the walking of the lists faster if (i+1 < MAX_G2_SURFACES) { slist[i+1].surface = -1; } return qtrue; } // search through all the surfaces in the model looking for those with '_off_' in the name. This indicates this surface is due to be off to begin with void G2_GetSurfaceList (qhandle_t model, surfaceInfo_t *slist) { model_t *mod; mdxmSurfHierarchy_t *surf; int i; // init the surface list memset(slist, 0, sizeof(slist) * MAX_G2_SURFACES); slist[0].surface = -1; // find the model we want mod = R_GetModelByHandle(model); // did we find a ghoul 2 model or not? if (!mod->mdxm) { return; } // set up pointers to surface info surf = (mdxmSurfHierarchy_t *) ( (byte *)mod->mdxm + mod->mdxm->ofsSurfHierarchy ); mdxmLODSurfOffset_t * pLODSurfOffset = (mdxmLODSurfOffset_t *)((byte *)mod->mdxm + mod->mdxm->ofsLODs + sizeof(mdxmLOD_t)); for ( i = 0 ; i < mod->mdxm->numSurfaces ; i++) { mdxmSurface_t *surface = (mdxmSurface_t *) ((byte*)pLODSurfOffset + pLODSurfOffset->offsets[i]); // OutputDebugString(va("Master surface list %d/%d: '%s'\n",i,mod->mdxm->numSurfaces,surf->name)); // if we have the word "_off_" in the name, then we want it off to begin with if (!stricmp("_off", &surf->name[strlen(surf->name)-4])) { G2_SetSurfaceOnOff(model, slist, surf->name, SURF_OFF, i); } else { G2_SetSurfaceOnOff(model, slist, surf->name, SURF_ON, i); } // find the next surface surf = (mdxmSurfHierarchy_t *)( (byte *)surf + (int)( &((mdxmSurfHierarchy_t *)0)->childIndexes[ surf->numChildren ] )); surface =(mdxmSurface_t *)( (byte *)surface + surface->ofsEnd ); } } // return a named surfaces off flags - should tell you if this surface is on or off. SurfaceOnOff_t MyFlags; // globalised for one specific query, only valid if function itself returns SURF_INHERENTLYOFF SurfaceOnOff_t G2_IsSurfaceOff (qhandle_t model, surfaceInfo_t *slist, const char *surfaceName) { model_t *mod = R_GetModelByHandle(model); int i; mdxmSurface_t *surf; mdxmHierarchyOffsets_t *surfIndexes = (mdxmHierarchyOffsets_t *)((byte *)mod->mdxm + sizeof(mdxmHeader_t)); mdxmSurfHierarchy_t *surfInfo; // did we find a ghoul 2 model or not? if (!mod->mdxm) { return SURF_ERROR; } // first find if we already have this surface in the list for (i=0; ithisSurfaceIndex?? surf = mod->mdxmsurf[0][slist[i].surface]; // back track and get the surfinfo struct for this surface surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surf->thisSurfaceIndex]); // same name as one already in? if (!stricmp (surfInfo->name, surfaceName)) { // if this surface is root or OFF+NO DESCENDANTS, then just return it, else if it's OFF or ON, then for // 100% accuracy we should really check the ancestors to see if we're inherently off because of // a higher surface having no descendants // if (slist[i].offFlags == SURF_NO_DESCENDANTS || surfInfo->parentIndex == -1) // ... or root surface return slist[i].offFlags; /*SurfaceOnOff_t */MyFlags = slist[i].offFlags; // now made global // check the surfaces above this one then... // while (1) { if (slist[i].offFlags == SURF_NO_DESCENDANTS) return SURF_INHERENTLYOFF; // someone above us has no descendants if (surfInfo->parentIndex == -1) return MyFlags; // reached the root, so I'm ok // get parent surface... // surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surfInfo->parentIndex]); surfaceName = surfInfo->name; for (i=0; imdxmsurf[0][slist[i].surface]; surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surf->thisSurfaceIndex]); if (!stricmp (surfInfo->name, surfaceName)) break; } } return MyFlags; // will never reach here now } } assert(0); return SURF_ERROR; } //===================================================================================================================== // Bone List handling routines - so entities can override bone info on a bone by bone level, and also interrogate this info // Given a bone name, see if that bone is already in our bone list - note the model_t pointer that gets passed in here MUST point at the // gla file, not the glm file type. int G2_Find_Bone(const model_t *mod, boneInfo_t *blist, const char *boneName) { int i; mdxaSkel_t *skel; mdxaSkelOffsets_t *offsets; offsets = (mdxaSkelOffsets_t *)((byte *)mod->mdxa + sizeof(mdxaHeader_t)); skel = (mdxaSkel_t *)((byte *)mod->mdxa + sizeof(mdxaHeader_t) + offsets->offsets[0]); // look through entire list for(i=0; iboneNumber == -1) { continue; } // figure out what skeletal info structure this bone entry is looking at skel = (mdxaSkel_t *)((byte *)mod->mdxa + sizeof(mdxaHeader_t) + offsets->offsets[blist[i].boneNumber]); // if name is the same, we found it if (!stricmp(skel->name, boneName)) { return i; } } // didn't find it return -1; } // we need to add a bone to the list - find a free one and see if we can find a corresponding bone in the gla file int G2_Add_Bone (const model_t *mod, boneInfo_t *blist, const char *boneName) { int i, x; mdxaSkel_t *skel; mdxaSkelOffsets_t *offsets; offsets = (mdxaSkelOffsets_t *)((byte *)mod->mdxa + sizeof(mdxaHeader_t)); // look through entire list for(i=0; imdxa + sizeof(mdxaHeader_t) + offsets->offsets[blist[i].boneNumber]); // if name is the same, we found it if (!stricmp(skel->name, boneName)) { return i; } continue; } // walk the entire list of bones in the gla file for this model and see if any match the name of the bone we want to find for (x=0; x< mod->mdxa->numBones; x++) { skel = (mdxaSkel_t *)((byte *)mod->mdxa + sizeof(mdxaHeader_t) + offsets->offsets[x]); // if name is the same, we found it if (!stricmp(skel->name, boneName)) { blist[i].flags = 0; blist[i].boneNumber = x; return i; } } // we found a free one, but no bone to correspond with the bone name assert(0); return -1; } assert(0); return -1; } // Given a model handle, and a bone name, we want to remove this bone from the bone override list qboolean G2_Remove_Bone_Index ( boneInfo_t *blist, int index) { // did we find it? if (index != -1) { // check the flags first - if it's still being used Do NOT remove it if (!blist[index].flags) { // set this bone to not used blist[index].boneNumber = -1; return qtrue; } } assert(0); // no return qfalse; } // given a bone number, see if there is an override bone in the bone list int G2_Find_Bone_In_List(boneInfo_t *blist, const int boneNum) { int i; // look through entire list for(i=0; imdxm->animIndex); int index = G2_Find_Bone(mod_a, blist, boneName); // did we find it? if (index != -1) { // set this bone to not used blist[index].boneNumber = -1; return qtrue; } assert(0); // no return qfalse; } // Given a model handle, and a bone name, we want to set angles specifically for overriding qboolean G2_Set_Bone_Angles(const qhandle_t model, boneInfo_t *blist, const char *boneName, const float *angles, const int flags) { model_t *mod_m = R_GetModelByHandle(model); model_t *mod_a = R_GetModelByHandle(mod_m->mdxm->animIndex); int index = G2_Find_Bone(mod_a, blist, boneName); // did we find it? if (index != -1) { // yes, so set the angles and flags correctly blist[index].flags |= flags; VectorCopy(angles,blist[index].angles); return qtrue; } // no - lets try and add this bone in index = G2_Add_Bone(mod_a, blist, boneName); // did we find a free one? if (index != -1) { // yes, so set the angles and flags correctly blist[index].flags |= flags; VectorCopy(angles,blist[index].angles); return qtrue; } assert(0); // no return qfalse; } // Given a model handle, and a bone name, we want to get the override angles and return them qboolean G2_Get_Bone_Angles(const qhandle_t model, boneInfo_t *blist, const char *boneName, float *angles) { model_t *mod_m = R_GetModelByHandle(model); model_t *mod_a = R_GetModelByHandle(mod_m->mdxm->animIndex); int index = G2_Find_Bone(mod_a, blist, boneName); // did we find it? if (index != -1) { // yes, so copy the angles into the return set VectorCopy(blist[index].angles, angles); return qtrue; } assert(0); // no return qfalse; } // given a model, bone name, a bonelist, a start/end frame number, a anim speed and some anim flags, set up or modify an existing bone entry for a new set of anims qboolean G2_Set_Bone_Anim(const qhandle_t model, boneInfo_t *blist, const char *boneName, const int startFrame, const int endFrame, const int flags, const float animSpeed) { model_t *mod_m = R_GetModelByHandle(model); model_t *mod_a = R_GetModelByHandle(mod_m->mdxm->animIndex); int index = G2_Find_Bone(mod_a, blist, boneName); // did we find it? if (index != -1) { // yes, so set the anim data and flags correctly blist[index].endFrame = endFrame; blist[index].startFrame = startFrame; blist[index].animSpeed = animSpeed; // start up the animation:) blist[index].newFrame = startFrame; // if we weren't previously animating, set the current frame to the same as the new frame so interpolation doesn't freak out if (!(blist[index].flags && (BONE_ANIM_OVERRIDE | BONE_ANIM_OVERRIDE_LOOP))) { blist[index].currentFrame = startFrame; } blist[index].flags |= flags; return qtrue; } // no - lets try and add this bone in index = G2_Add_Bone(mod_a, blist, boneName); // did we find a free one? if (index != -1) { // yes, so set the anim data and flags correctly blist[index].endFrame = endFrame; blist[index].startFrame = startFrame; blist[index].animSpeed = animSpeed; // start up the animation:) blist[index].newFrame = startFrame; // if we weren't previously animating, set the current frame to the same as the new frame so interpolation doesn't freak out if (!(blist[index].flags && (BONE_ANIM_OVERRIDE | BONE_ANIM_OVERRIDE_LOOP))) { blist[index].currentFrame = startFrame; } blist[index].flags |= flags; return qtrue; } assert(0); // no return qfalse; } // given a model, bonelist and bonename, return the current frame, startframe and endframe of the current animation // NOTE if we aren't running an animation, then qfalse is returned qboolean G2_Get_Bone_Anim(const qhandle_t model, boneInfo_t *blist, const char *boneName, float *currentFrame, int *startFrame, int *endFrame) { model_t *mod_m = R_GetModelByHandle(model); model_t *mod_a = R_GetModelByHandle(mod_m->mdxm->animIndex); int index = G2_Find_Bone(mod_a, blist, boneName); // did we find it? if (index != -1) { // are we an animating bone? if (blist[index].flags && (BONE_ANIM_OVERRIDE_LOOP || BONE_ANIM_OVERRIDE)) { *currentFrame = blist[index].currentFrame; *startFrame = blist[index].startFrame; *endFrame = blist[index].endFrame; return qtrue; } } assert(0); return qfalse; } // given a model, bonelist and bonename, lets stop an anim if it's playing. qboolean G2_Stop_Bone_Anim(const qhandle_t model, boneInfo_t *blist, const char *boneName) { model_t *mod_m = R_GetModelByHandle(model); model_t *mod_a = R_GetModelByHandle(mod_m->mdxm->animIndex); int index = G2_Find_Bone(mod_a, blist, boneName); // did we find it? if (index != -1) { blist[index].flags &= ~(BONE_ANIM_OVERRIDE_LOOP || BONE_ANIM_OVERRIDE); // try and remove this bone if we can return G2_Remove_Bone_Index(blist, index); } assert(0); return qfalse; } // given a model, bonelist and bonename, lets stop an anim if it's playing. qboolean G2_Stop_Bone_Angles(const qhandle_t model, boneInfo_t *blist, const char *boneName) { model_t *mod_m = R_GetModelByHandle(model); model_t *mod_a = R_GetModelByHandle(mod_m->mdxm->animIndex); int index = G2_Find_Bone(mod_a, blist, boneName); // did we find it? if (index != -1) { blist[index].flags &= ~(BONE_ANGLES_RELATIVE || BONE_ANGLES_ADDITIVE || BONE_ANGLES_ABSOLUTE); // try and remove this bone if we can return G2_Remove_Bone_Index(blist, index); } assert(0); return qfalse; } // actually walk the bone list and animate each and every bone if there is a need for it. void G2_Animate_Bone_List(boneInfo_t *blist, float timeoffset) { int i; // look through entire list for(i=0; i 0.0f) && (blist[i].newFrame >= (float)blist[i].endFrame)) || ((blist[i].animSpeed < 0.0f) && (blist[i].newFrame <= (float)blist[i].startFrame))) { // yep - decide what to do if (blist[i].flags & BONE_ANIM_OVERRIDE_LOOP) { // allow us to play the anim backwards if ((blist[i].animSpeed) > 0.0f) { // loop it blist[i].newFrame = blist[i].startFrame; } else { // loop it blist[i].newFrame = blist[i].endFrame; } // we've changed anims, the bone interpolater needs to know this. Activate the flag blist[i].flags |= BONE_ANIM_NEW_ANIM; } else { // nope, just stop it. And remove the bone if possible G2_Stop_Bone_Anim_Index(blist, i); } } } } } } // set the bone list to all unused so the bone transformation routine ignores it. void G2_Init_Bone_List(boneInfo_t *blist) { int i; // look through entire list for(i=0; im[0][0] = (in2->m[0][0] * in->m[0][0]) + (in2->m[0][1] * in->m[1][0]) + (in2->m[0][2] * in->m[2][0]) + (in2->m[0][3] * in->m[3][0]); out->m[0][1] = (in2->m[0][0] * in->m[0][1]) + (in2->m[0][1] * in->m[1][1]) + (in2->m[0][2] * in->m[2][1]) + (in2->m[0][3] * in->m[3][1]); out->m[0][2] = (in2->m[0][0] * in->m[0][2]) + (in2->m[0][1] * in->m[1][2]) + (in2->m[0][2] * in->m[2][2]) + (in2->m[0][3] * in->m[3][2]); // second row of out out->m[1][0] = (in2->m[1][0] * in->m[0][0]) + (in2->m[1][1] * in->m[1][0]) + (in2->m[1][2] * in->m[2][0]) + (in2->m[1][3] * in->m[3][0]); out->m[1][1] = (in2->m[1][0] * in->m[0][1]) + (in2->m[1][1] * in->m[1][1]) + (in2->m[1][2] * in->m[2][1]) + (in2->m[1][3] * in->m[3][1]); out->m[1][2] = (in2->m[1][0] * in->m[0][2]) + (in2->m[1][1] * in->m[1][2]) + (in2->m[1][2] * in->m[2][2]) + (in2->m[1][3] * in->m[3][2]); // third row of out out->m[2][0] = (in2->m[2][0] * in->m[0][0]) + (in2->m[2][1] * in->m[1][0]) + (in2->m[2][2] * in->m[2][0]) + (in2->m[2][3] * in->m[3][0]); out->m[2][1] = (in2->m[2][0] * in->m[0][1]) + (in2->m[2][1] * in->m[1][1]) + (in2->m[2][2] * in->m[2][1]) + (in2->m[2][3] * in->m[3][1]); out->m[2][2] = (in2->m[2][0] * in->m[0][2]) + (in2->m[2][1] * in->m[1][2]) + (in2->m[2][2] * in->m[2][2]) + (in2->m[2][3] * in->m[3][2]); // fourth row of out out->m[3][0] = (in2->m[3][0] * in->m[0][0]) + (in2->m[3][1] * in->m[1][0]) + (in2->m[3][2] * in->m[2][0]) + (in2->m[3][3] * in->m[3][0]); out->m[3][1] = (in2->m[3][0] * in->m[0][1]) + (in2->m[3][1] * in->m[1][1]) + (in2->m[3][2] * in->m[2][1]) + (in2->m[3][3] * in->m[3][1]); out->m[3][2] = (in2->m[3][0] * in->m[0][2]) + (in2->m[3][1] * in->m[1][2]) + (in2->m[3][2] * in->m[2][2]) + (in2->m[3][3] * in->m[3][2]); } // nasty little matrix multiply going on here.. void Multiply_3x3Matrix(mdxaBone_t *out, mdxaBone_t *in2, mdxaBone_t *in) { // first row of out out->matrix[0][0] = (in2->matrix[0][0] * in->matrix[0][0]) + (in2->matrix[0][1] * in->matrix[1][0]) + (in2->matrix[0][2] * in->matrix[2][0]); out->matrix[0][1] = (in2->matrix[0][0] * in->matrix[0][1]) + (in2->matrix[0][1] * in->matrix[1][1]) + (in2->matrix[0][2] * in->matrix[2][1]); out->matrix[0][2] = (in2->matrix[0][0] * in->matrix[0][2]) + (in2->matrix[0][1] * in->matrix[1][2]) + (in2->matrix[0][2] * in->matrix[2][2]); // second row of out out->matrix[1][0] = (in2->matrix[1][0] * in->matrix[0][0]) + (in2->matrix[1][1] * in->matrix[1][0]) + (in2->matrix[1][2] * in->matrix[2][0]); out->matrix[1][1] = (in2->matrix[1][0] * in->matrix[0][1]) + (in2->matrix[1][1] * in->matrix[1][1]) + (in2->matrix[1][2] * in->matrix[2][1]); out->matrix[1][2] = (in2->matrix[1][0] * in->matrix[0][2]) + (in2->matrix[1][1] * in->matrix[1][2]) + (in2->matrix[1][2] * in->matrix[2][2]); // third row of out out->matrix[2][0] = (in2->matrix[2][0] * in->matrix[0][0]) + (in2->matrix[2][1] * in->matrix[1][0]) + (in2->matrix[2][2] * in->matrix[2][0]); out->matrix[2][1] = (in2->matrix[2][0] * in->matrix[0][1]) + (in2->matrix[2][1] * in->matrix[1][1]) + (in2->matrix[2][2] * in->matrix[2][1]); out->matrix[2][2] = (in2->matrix[2][0] * in->matrix[0][2]) + (in2->matrix[2][1] * in->matrix[1][2]) + (in2->matrix[2][2] * in->matrix[2][2]); } // convert a 3x4 matrix into a 4x4 ready for multiplication void From3x4(mdxaBone_t *mat, mdxBone4_t *out) { for (int i=0; i<4; i++) { for (int j=0; j<3; j++) { out->m[i][j]=mat->matrix[j][i]; } } // set right row to identity out->m[0][3] = 0.0f; out->m[1][3] = 0.0f; out->m[2][3] = 0.0f; out->m[3][3] = 1.0f; } // convert a 4x4 m back into a 3x4 m void To3x4(mdxBone4_t *in, mdxaBone_t *mat) { for (int i=0; i<4; i++) { for (int j=0; j<3; j++) { mat->matrix[j][i] = in->m[i][j]; } } } // create a matrix thats at angle 0,0,0 void Create_Identity_Matrix(mdxaBone_t *matrix) { // make the identity matrix - ie matrix of 0,0,0 degrees matrix->matrix[0][1] = matrix->matrix[0][2] = matrix->matrix[1][0] = matrix->matrix[1][2] = matrix->matrix[2][0] = matrix->matrix[2][1] = 0.0f; matrix->matrix[0][0] = matrix->matrix[1][1] = matrix->matrix[2][2] = 1.0f; } // create a matrix using a set of angles void Create_Matrix(vec3_t angle, mdxaBone_t *matrix) { mdxaBone_t matrix_temp; float cos_temp, sin_temp; Create_Identity_Matrix(matrix); // create matrix_x if we have a YAW angle if (angle[0]) { cos_temp = (float)cos(-angle[PITCH]); sin_temp = (float)sin(-angle[PITCH]); // we can afford to stuff these in directly, since YAW is the first thing hit matrix->matrix[1][1] = cos_temp; matrix->matrix[1][2] = -sin_temp; matrix->matrix[2][1] = sin_temp; matrix->matrix[2][2] = cos_temp; } // create matrix_y if we have a PITCH angle if (angle[1]) { Create_Identity_Matrix(&matrix_temp); cos_temp = (float)cos(-angle[YAW]); sin_temp = (float)sin(-angle[YAW]); matrix_temp.matrix[0][0] = cos_temp; matrix_temp.matrix[0][2] = sin_temp; matrix_temp.matrix[2][0] = -sin_temp; matrix_temp.matrix[2][2] = cos_temp; Multiply_3x3Matrix(matrix, &matrix_temp, matrix); } // create matrix_z if we have a ROLL angle if (angle[2]) { Create_Identity_Matrix(&matrix_temp); cos_temp = (float)cos(angle[ROLL]); sin_temp = (float)sin(angle[ROLL]); matrix_temp.matrix[0][0] = cos_temp; matrix_temp.matrix[0][1] = -sin_temp; matrix_temp.matrix[1][0] = sin_temp; matrix_temp.matrix[1][1] = cos_temp; Multiply_3x3Matrix(matrix, &matrix_temp, matrix); } } static int G2_GetBonePoolIndex( const mdxaHeader_t *pMDXAHeader, int iFrame, int iBone) { const int iOffsetToIndex = (iFrame * pMDXAHeader->numBones * 3) + (iBone * 3); mdxaIndex_t *pIndex = (mdxaIndex_t *) ((byte*) pMDXAHeader + pMDXAHeader->ofsFrames + iOffsetToIndex); return pIndex->iIndex & 0x00FFFFFF; // this will cause problems for big-endian machines... ;-) } /*static inline*/ void UnCompressBone(float mat[3][4], int iBoneIndex, const mdxaHeader_t *pMDXAHeader, int iFrame) { mdxaCompQuatBone_t *pCompBonePool = (mdxaCompQuatBone_t *) ((byte *)pMDXAHeader + pMDXAHeader->ofsCompBonePool); int index = G2_GetBonePoolIndex( pMDXAHeader, iFrame, iBoneIndex ); MC_UnCompressQuat(mat, pCompBonePool[ index ].Comp); } // transform each individual bone's information - making sure to use any override information provided, both for angles and for animations, as // well as multiplying each bone's matrix by it's parents matrix int g_iTotalG2BonesXformed; int iTempLastBoneBeforeSecondary; int iLastBoneBeforeSecondary; void G2_TransformBone (mdxaBone_t *pModViewFeedback_BoneList, bool *pModViewFeedback_Validity, // dirty code: copy this back up to the appropriate container list for bone-pos viewing... int newFrame, int currentFrame, int parent, int child, mdxaHeader_t *header, float framelerp, float backlerp, int *usedBoneList, int lastIndex, bool bPrimary, int iBoneNum_SecondaryStart ) { mdxaBone_t *bonePtr; mdxaBone_t tbone[3]; mdxaSkel_t *skel; mdxaSkelOffsets_t *offsets; boneInfo_t *boneList; int i, boneListIndex; mdxBone4_t outMatrix, inMatrix, in2Matrix; /*MODVIEWREM float delta, actualFrame; mdxBone4_t overrideMatrix; */ int angleOverride = 0; // decide here if we should go down this path? - is this bone used? -If not, return from this function. Due the hierarchial nature of the bones // any bone below this one in the tree shouldn't be used either. if (!usedBoneList[child]) { return; } if (bPrimary && child == iBoneNum_SecondaryStart) { iLastBoneBeforeSecondary = iTempLastBoneBeforeSecondary; return; } iTempLastBoneBeforeSecondary = child; g_iTotalG2BonesXformed++; boneList = tr.currentEntity->e.blist; // should this bone be overridden by a bone in the bone list? boneListIndex = G2_Find_Bone_In_List(boneList, child); if (boneListIndex != -1) { /*MODVIEWREM*/ } // decide where the transformed bone is going bonePtr = tr.currentEntity->e.tempBoneList; // // lerp this bone - use the temp space on the ref entity to put the bone transforms into // //MODVIEWREM if (boneList[lastIndex].newFrame == boneList[lastIndex].currentFrame ) if (newFrame == currentFrame ) { if (child) { // MC_UnCompress(tbone[2].matrix,pCompBonePool[aframe->boneIndexes[child]].Comp); UnCompressBone(tbone[2].matrix, child, header, newFrame); } else { // MC_UnCompress(bonePtr[child].matrix,pCompBonePool[aframe->boneIndexes[child]].Comp); UnCompressBone(bonePtr[child].matrix, child, header, newFrame); } } else { // MC_UnCompress(tbone[0].matrix,pCompBonePool[ aframe->boneIndexes[child]].Comp); // MC_UnCompress(tbone[1].matrix,pCompBonePool[aoldFrame->boneIndexes[child]].Comp); UnCompressBone(tbone[0].matrix, child, header, newFrame); UnCompressBone(tbone[1].matrix, child, header, currentFrame); int j; if (child) { for ( j = 0 ; j < 12 ; j++ ) { ((float *)&tbone[2])[j] = backlerp * ((float *)&tbone[0])[j] + (1.0 - backlerp) * ((float *)&tbone[1])[j]; } } else { for ( j = 0 ; j < 12 ; j++ ) { ((float *)&bonePtr[child])[j] = backlerp * ((float *)&tbone[0])[j] + (1.0 - backlerp) * ((float *)&tbone[1])[j]; } } } // now transform the matrix by it's parent, asumming we have a parent, and we aren't overriding the angles absolutely if (child) { // convert from 3x4 matrix to a 4x4 matrix From3x4(&bonePtr[parent], &inMatrix); From3x4(&tbone[2], &in2Matrix); // do the multiplication Multiply_4x4Matrix(&outMatrix, &in2Matrix, &inMatrix); // convert result back into a 3x4 matrix for use later To3x4(&outMatrix, &bonePtr[child]); } { // modview hack... :-) // pModViewFeedback_BoneList[child] = bonePtr[child]; pModViewFeedback_Validity[child] = true; } // figure out where the bone hirearchy info is offsets = (mdxaSkelOffsets_t *)((byte *)header + sizeof(mdxaHeader_t)); skel = (mdxaSkel_t *)((byte *)header + sizeof(mdxaHeader_t) + offsets->offsets[child]); // now work out what children we have to call this recursively for for (i=0; i< skel->numChildren; i++) { G2_TransformBone(pModViewFeedback_BoneList, pModViewFeedback_Validity, // modview hack newFrame, currentFrame, child, skel->children[i], header, framelerp, backlerp, usedBoneList, lastIndex, bPrimary, iBoneNum_SecondaryStart ); } } // start the recursive hierarchical bone transform and lerp process for this model void G2_TransformGhoulBones( mdxaHeader_t *header, int *usedBoneList, refEntity_t e) { // calculate the lerp factor - current client time minus the last time we got a snap shot, divided by 200 which is one 10hz frame // this should never get above 1.0f, and if it does, then we should have run the animation function on this models blist // to predict the next set of frames. // now recursively call the bone transform routines using the bone hierarchy g_iTotalG2BonesXformed = 0; //updateme // open the file for writing //OutputDebugString("=====\n"); G2_TransformBone(e.pXFormedG2Bones, e.pXFormedG2BonesValid, // dirty code: copy this back up to the appropriate container list for bone-pos viewing... e.iFrame_Primary, e.iOldFrame_Primary, 0, 0, header, 1.0f - e.backlerp, e.backlerp, usedBoneList, 0, true, e.iBoneNum_SecondaryStart); // need to transform secondary anim bones?... // if (e.iBoneNum_SecondaryStart != -1) { G2_TransformBone(e.pXFormedG2Bones, e.pXFormedG2BonesValid, // dirty code: copy this back up to the appropriate container list for bone-pos viewing... e.iFrame_Secondary, e.iOldFrame_Secondary, iLastBoneBeforeSecondary, e.iBoneNum_SecondaryStart, header, 1.0f - e.backlerp, e.backlerp, usedBoneList, 0, false, e.iBoneNum_SecondaryStart); } // OutputDebugString(va("%d G2 bones xformed\n",g_iTotalG2BonesXformed)); if ( e.piXformedG2Bones) { *e.piXformedG2Bones = g_iTotalG2BonesXformed; } /* // if ( !mdview.interpolate || pModel->iNumFrames == 0 || iNextFrame == pModel->iNumFrames // 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 = mdview.frameFrac; frontlerp = 1.0f - backlerp; } header = (md4Header_t *)((byte *)surface + surface->ofsHeader); */ } //====================================================================== // // Surface Manipulation code void R_RenderSurfaces(surfaceInfo_t *slist, trRefEntity_t *ent, int iLOD)//MODVIEWREM, shader_t *cust_shader, int fogNum, qboolean personalModel) { int i; shader_t *shader = 0; GLuint gluiTextureBind = 0; // back track and get the surfinfo struct for this surface mdxmSurface_t *surface = tr.currentModel->mdxmsurf[iLOD][slist->surface]; mdxmHierarchyOffsets_t *surfIndexes = (mdxmHierarchyOffsets_t *)((byte *)tr.currentModel->mdxm + sizeof(mdxmHeader_t)); mdxmSurfHierarchy_t *surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surface->thisSurfaceIndex]); // if this surface is not off, add it to the shader render list // // Update, previously I checked to see if we should actually render tag surfaces, but because of the // way I do surface bolt-ons I now always pass them on to the renderer to do the xform calcs, // if (AppVars.iSurfaceNumToHighlight == surface->thisSurfaceIndex || slist->offFlags == SURF_ON /* && ( // special check for displaying tag surfaces or not... // AppVars.bShowTagSurfaces // show tag surfaces as well (in which case anything's fine) || !(surfInfo->flags & G2SURFACEFLAG_ISBOLT) // ... or this isn't a tag surface so don't worry // or it is a tag surface, but we're highlighting either all tag surfaces, or just this one explicitly || (AppVars.bSurfaceHighlight && (AppVars.iSurfaceNumToHighlight == iITEMHIGHLIGHT_ALL_TAGSURFACES || AppVars.iSurfaceNumToHighlight == surface->thisSurfaceIndex)) // or it is a tag surface, but something's bolted to it so we need to process it to fill in matrix info for bolted object || (Model_CountItemsBoltedHere(ent->e.hModel, surface->thisSurfaceIndex, false)) // aaarggh!!! This is horrible!!! ) */ ) { // set the surface info to point at the where the transformed bone list is going to be for when the surface gets rendered out slist->boneList = ent->e.tempBoneList; slist->surfaceData = (void *)surface; /*MODVIEWREM if ( ent->e.customShader ) { shader = cust_shader; } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) { skin_t *skin; int j; skin = R_GetSkinByHandle( ent->e.customSkin ); // match the surface name to something in the skin file shader = tr.defaultShader; for ( j = 0 ; j < skin->numSurfaces ; j++ ) { // the names have both been lowercased if ( !strcmp( skin->surfaces[j]->name, surfInfo->name ) ) { shader = skin->surfaces[j]->shader; break; } } } else { */ //shader = R_GetShaderByHandle( surfInfo->shaderIndex ); if (AppVars.bForceWhite) { gluiTextureBind = 0; } else { if (surfInfo->shaderIndex == -1) { gluiTextureBind = AnySkin_GetGLBind( ent->e.hModel, surfInfo->shader, surfInfo->name ); } else { gluiTextureBind = Texture_GetGLBind( surfInfo->shaderIndex ); } } /* } // we will add shadows even if the main object isn't visible in the view // stencil shadows can't do personal models unless I polyhedron clip if ( !personalModel && r_shadows->integer == 2 && fogNum == 0 && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) && shader->sort == SS_OPAQUE ) { R_AddDrawSurf( (surfaceType_t *)slist, tr.shadowShader, 0, qfalse ); } // projection shadows work fine with personal models if ( r_shadows->integer == 3 && fogNum == 0 && (ent->e.renderfx & RF_SHADOW_PLANE ) && shader->sort == SS_OPAQUE ) { R_AddDrawSurf( (surfaceType_t *)slist, tr.projectionShadowShader, 0, qfalse ); } // don't add third_person objects if not viewing through a portal if ( !personalModel ) { R_AddDrawSurf( (surfaceType_t *)slist, shader, fogNum, qfalse ); } */ R_AddDrawSurf( (surfaceType_t *)slist, gluiTextureBind); } else // if we are turning off all descendants, then stop this recursion now if (slist->offFlags == SURF_NO_DESCENDANTS) { return; } // now recursively call for the children for (i=0; i< surfInfo->numChildren; i++) { R_RenderSurfaces(&ent->e.slist[surfInfo->childIndexes[i]], ent, iLOD);//MODVIEWREM, cust_shader, fogNum, personalModel); } } // build the used bone list so when doing bone transforms we can determine if we need to do it or not void G2_ConstructUsedBoneList(surfaceInfo_t *slist, int *boneUsedList, trRefEntity_t *ent) { int i,j; // back track and get the surfinfo struct for this surface mdxmSurface_t *surface = tr.currentModel->mdxmsurf[0][slist->surface]; // always use LOD 0 mdxmHierarchyOffsets_t *surfIndexes = (mdxmHierarchyOffsets_t *)((byte *)tr.currentModel->mdxm + sizeof(mdxmHeader_t)); mdxmSurfHierarchy_t *surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surface->thisSurfaceIndex]); model_t *mod_a = R_GetModelByHandle(tr.currentModel->mdxm->animIndex); mdxaSkelOffsets_t *offsets = (mdxaSkelOffsets_t *)((byte *)mod_a->mdxa + sizeof(mdxaHeader_t)); mdxaSkel_t *skel, *childSkel; /* OutputDebugString(va("G2_ConstructUsedBoneList(): Surface %s\n",surfInfo->name)); if (stricmp(surfInfo->name,"stupidtriangle_off")==0) { int z=1; } if (stricmp(surfInfo->name,"head_side")==0) { int z=1; } */ // if this surface is not off, add it to the shader render list if (AppVars.iSurfaceNumToHighlight == surface->thisSurfaceIndex || slist->offFlags == SURF_ON || slist->offFlags == SURF_OFF) // stetemp { int *bonesReferenced = (int *)((byte*)surface + surface->ofsBoneReferences); // now whip through the bones this surface uses for (i=0; inumBoneReferences;i++) { const int iBoneIndex = bonesReferenced[i]; boneUsedList[iBoneIndex] = 1; // OutputDebugString(va("boneUsedList[%d]=1\n",bonesReferenced[i])); // now go and check all the descendant bones attached to this bone and see if any have the always flag on them. If so, activate them skel = (mdxaSkel_t *)((byte *)mod_a->mdxa + sizeof(mdxaHeader_t) + offsets->offsets[iBoneIndex]); // for every child bone... for (j=0; j< skel->numChildren; j++) { // get the skel data struct for each child bone of the referenced bone childSkel = (mdxaSkel_t *)((byte *)mod_a->mdxa + sizeof(mdxaHeader_t) + offsets->offsets[skel->children[j]]); // does it have the always on flag on? if (childSkel->flags & G2BONEFLAG_ALWAYSXFORM) { // yes, make sure it's in the list of bones to be transformed. boneUsedList[skel->children[j]] = 1; // OutputDebugString(va("boneUsedList[%d]=1 (child)\n",skel->children[j])); } } // now we need to ensure that the parents of this bone are actually active... // int iParentBone = skel->parent; while (iParentBone != -1) { if (boneUsedList[iParentBone]) // no need to go higher break; boneUsedList[iParentBone] = 1; skel = (mdxaSkel_t *)((byte *)mod_a->mdxa + sizeof(mdxaHeader_t) + offsets->offsets[iParentBone]); iParentBone = skel->parent; } } } else // if we are turning off all descendants, then stop this recursion now if (slist->offFlags == SURF_NO_DESCENDANTS) { return; } // now recursively call for the children // OutputDebugString(va("Scanning %d children\n",surfInfo->numChildren)); for (i=0; i< surfInfo->numChildren; i++) { /* if (surfInfo->childIndexes[i] == 0) { int z=1; }*/ G2_ConstructUsedBoneList(&ent->e.slist[surfInfo->childIndexes[i]], boneUsedList, ent); } } void R_AddGhoulSurfaces( trRefEntity_t *ent ) { mdxaHeader_t *aHeader; mdxmHeader_t *mHeader; mdxmLOD_t *lod; shader_t *shader = 0; shader_t *cust_shader = 0; int fogNum = 0; /*MODVIEWREM qboolean personalModel; int cull; */ int i, whichLod; int boneUsedList[MAX_POSSIBLE_BONES]; // don't add third_person objects if not in a portal //MODVIEWREM personalModel = (qboolean)((ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal); aHeader = tr.models[tr.currentModel->mdxm->animIndex]->mdxa; mHeader = tr.currentModel->mdxm; if ( ent->e.renderfx & RF_CAP_FRAMES) { // this stuff is probably not needed now, because we're in ModView instead of Q3, but... // if (ent->e.iFrame_Primary > aHeader->numFrames-1) { ent->e.iFrame_Primary = aHeader->numFrames-1; } if (ent->e.iOldFrame_Primary > aHeader->numFrames-1) { ent->e.iOldFrame_Primary = aHeader->numFrames-1; } // // and new stuff for compatibility... // if (ent->e.iFrame_Secondary > aHeader->numFrames-1) { ent->e.iFrame_Secondary = aHeader->numFrames-1; } if (ent->e.iOldFrame_Secondary > aHeader->numFrames-1) { ent->e.iOldFrame_Secondary = aHeader->numFrames-1; } } else if ( ent->e.renderfx & RF_WRAP_FRAMES ) { ent->e.iFrame_Primary %= aHeader->numFrames; ent->e.iOldFrame_Primary %= aHeader->numFrames; // ent->e.iFrame_Secondary %= aHeader->numFrames; ent->e.iOldFrame_Secondary %= aHeader->numFrames; } // // Validate the frames so there is no chance of a crash. // This will write directly into the entity structure, so // when the surfaces are rendered, they don't need to be // range checked again. // // ModView: ITU? Oh, well... if ( (ent->e.iFrame_Primary >= aHeader->numFrames) || (ent->e.iFrame_Primary < 0) || (ent->e.iOldFrame_Primary >= aHeader->numFrames) || (ent->e.iOldFrame_Primary < 0) ) { #ifdef _DEBUG ri.Printf (PRINT_ALL, "R_AddGhoulSurfaces: no such frame %d to %d for '%s'\n", #else ri.Printf (PRINT_DEVELOPER, "R_AddGhoulSurfaces: no such frame %d to %d for '%s'\n", #endif ent->e.iOldFrame_Primary, ent->e.iFrame_Primary, tr.currentModel->name ); ent->e.iFrame_Primary = 0; ent->e.iOldFrame_Primary = 0; } // new stuff. still probably not needed, but... if ( (ent->e.iFrame_Secondary >= aHeader->numFrames) || (ent->e.iFrame_Secondary < 0) || (ent->e.iOldFrame_Secondary >= aHeader->numFrames) || (ent->e.iOldFrame_Secondary < 0) ) { #ifdef _DEBUG ri.Printf (PRINT_ALL, "R_AddGhoulSurfaces: no such frame %d to %d for '%s'\n", #else ri.Printf (PRINT_DEVELOPER, "R_AddGhoulSurfaces: no such frame %d to %d for '%s'\n", #endif ent->e.iOldFrame_Secondary, ent->e.iFrame_Secondary, tr.currentModel->name ); ent->e.iFrame_Secondary = 0; ent->e.iOldFrame_Secondary = 0; } /*MODVIEWREM // // cull the entire model if merged bounding box of both frames // is outside the view frustum. // cull = R_GCullModel ( aHeader, ent ); if ( cull == CULL_OUT ) { return; } */ // // compute LOD // lod = (mdxmLOD_t *)( (byte *)mHeader + mHeader->ofsLODs ); whichLod = R_ComputeLOD( ent ); if (whichLod >= mHeader->numLODs) { whichLod = mHeader->numLODs -1; } for ( i = 0; i < whichLod; i++) { lod = (mdxmLOD_t*)( (byte *)lod + lod->ofsEnd ); } /*MODVIEWREM // // set up lighting now that we know we aren't culled // if ( !personalModel || r_shadows->integer > 1 ) { // FIXME!! Is there something here we should be looking at? R_SetupEntityLighting( &tr.refdef, ent ); } // // see if we are in a fog volume // fogNum = R_GComputeFogNum( aHeader, ent ); // // draw all surfaces // cust_shader = R_GetShaderByHandle( ent->e.customShader ); */ // construct a list of all bones used by this model - this makes the bone transform go a bit faster since it will dump out bones // that aren't being used. - NOTE this will fuck up any models that have surfaces turned off where the lower surfaces aren't. memset(boneUsedList, 0, sizeof(boneUsedList)); // findmeste // // if highlighting, ensure that the bone we're over is transformed, even if no surfaces actually reference it // ( this is only needed when force-keeping the motion bone during compile) // extern ModelContainer_t* gpContainerBeingRendered; if (gpContainerBeingRendered // arrrghhh!!!! && AppVars.bBoneHighlight ) { if (gpContainerBeingRendered->iBoneHighlightNumber >= 0) { boneUsedList[gpContainerBeingRendered->iBoneHighlightNumber] = 1; } } // OutputDebugString("### Start\n"); int iStartSurface = ent->e.iSurfaceNum_RootOverride; if (iStartSurface == -1) { iStartSurface = 0; } G2_ConstructUsedBoneList(&ent->e.slist[iStartSurface],boneUsedList,ent); // make sure the root bone is marked as being referenced boneUsedList[0] =1; // pre-transform all the bones of this model G2_TransformGhoulBones( aHeader, boneUsedList, ent->e ); // start the walk of the surface hierarchy R_RenderSurfaces(&ent->e.slist[iStartSurface], ent, whichLod);// MODVIEWREM, cust_shader, fogNum, personalModel); } /* void R_LoadQuaternionIndex(const char* filename) { int len; FILE* in; in = fopen(filename, "rb"); if(in) { fseek(in, 0, SEEK_END); len = ftell(in); rewind(in); quaternionIndex = (cqpoint_t*)malloc(len); fread(quaternionIndex,1,len,in); fclose(in); } } */ //////////////////// eof /////////////////