// leave this as first line for PCH reasons... // //Anything above this #include will be ignored by the compiler #include "../qcommon/exe_headers.h" #if !defined(TR_LOCAL_H) #include "../renderer/tr_local.h" #endif #if !defined(G2_H_INC) #include "G2.h" #endif #include "G2_local.h" #pragma warning(disable : 4512) //assignment op could not be genereated class CConstructBoneList { public: int surfaceNum; int *boneUsedList; surfaceInfo_v &rootSList; model_t *currentModel; boneInfo_v &boneList; CConstructBoneList( int initsurfaceNum, int *initboneUsedList, surfaceInfo_v &initrootSList, model_t *initcurrentModel, boneInfo_v &initboneList): surfaceNum(initsurfaceNum), boneUsedList(initboneUsedList), rootSList(initrootSList), currentModel(initcurrentModel), boneList(initboneList) { } }; extern void G2_ConstructUsedBoneList(CConstructBoneList &CBL); //===================================================================================================================== // Surface List handling routines - so entities can determine what surfaces attached to a model are operational or not. // find a particular surface in the surface override list surfaceInfo_t *G2_FindOverrideSurface(int surfaceNum, surfaceInfo_v &surfaceList) { int i; // look through entire list for(i=0; imdxm + mod_m->mdxm->ofsSurfHierarchy ); for ( int i = 0 ; i < mod_m->mdxm->numSurfaces ; i++) { if (!stricmp(surfaceName, surf->name)) { *flags = surf->flags; return i; } // find the next surface surf = (mdxmSurfHierarchy_t *)( (byte *)surf + (int)( &((mdxmSurfHierarchy_t *)0)->childIndexes[ surf->numChildren ] )); } return -1; } /************************************************************************************************ * G2_FindSurface * find a surface in a ghoul2 surface override list based on it's name * * Input * filename of model, surface list of model instance, name of surface, int to be filled in * with the index of this surface (defaults to NULL) * * Output * pointer to surface if successful, false otherwise * ************************************************************************************************/ mdxmSurface_t *G2_FindSurface(CGhoul2Info *ghlInfo, surfaceInfo_v &slist, const char *surfaceName, int *surfIndex/*NULL*/) { int i = 0; // find the model we want model_t *mod = (model_t *)ghlInfo->currentModel; 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); if (surfIndex) { *surfIndex = -1; } return 0; } // first find if we already have this surface in the list for (i = slist.size() - 1; i >= 0; i--) { if ((slist[i].surface != 10000) && (slist[i].surface != -1)) { mdxmSurface_t *surf = (mdxmSurface_t *)G2_FindSurface((void *)mod, slist[i].surface, 0); // back track and get the surfinfo struct for this surface surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surf->thisSurfaceIndex]); // are these the droids we're looking for? if (!stricmp (surfInfo->name, surfaceName)) { // yup if (surfIndex) { *surfIndex = i; } return surf; } } } // didn't find it if (surfIndex) { *surfIndex = -1; } return 0; } // 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 (CGhoul2Info *ghlInfo, surfaceInfo_v &slist, const char *surfaceName, const int offFlags) { int surfIndex = -1; surfaceInfo_t temp_slist_entry; mdxmSurface_t *surf; // find the model we want model_t *mod = (model_t *)ghlInfo->currentModel; // 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 surf = G2_FindSurface(ghlInfo, slist, surfaceName, &surfIndex); if (surf) { // set descendants value // slist[surfIndex].offFlags = offFlags; // seems to me that we shouldn't overwrite the other flags. // the only bit we really care about in the incoming flags is the off bit slist[surfIndex].offFlags &= ~(G2SURFACEFLAG_OFF | G2SURFACEFLAG_NODESCENDANTS); slist[surfIndex].offFlags |= offFlags & (G2SURFACEFLAG_OFF | G2SURFACEFLAG_NODESCENDANTS); return qtrue; } else { // ok, not in the list already - in that case, lets verify this surface exists in the model mesh int flags; int surfaceNum = G2_IsSurfaceLegal((void*)mod, surfaceName, &flags); if (surfaceNum != -1) { int newflags = flags; // the only bit we really care about in the incoming flags is the off bit newflags &= ~(G2SURFACEFLAG_OFF | G2SURFACEFLAG_NODESCENDANTS); newflags |= offFlags & (G2SURFACEFLAG_OFF | G2SURFACEFLAG_NODESCENDANTS); if (newflags != flags) { // insert here then because it changed, no need to add an override otherwise temp_slist_entry.offFlags = newflags; temp_slist_entry.surface = surfaceNum; slist.push_back(temp_slist_entry); } return qtrue; } } return qfalse; } void G2_SetSurfaceOnOffFromSkin (CGhoul2Info *ghlInfo, qhandle_t renderSkin) { int j; const skin_t *skin = R_GetSkinByHandle( renderSkin ); ghlInfo->mSlist.clear(); //remove any overrides we had before. ghlInfo->mMeshFrameNum = 0; for ( j = 0 ; j < skin->numSurfaces ; j++ ) { // the names have both been lowercased if ( !strcmp( skin->surfaces[j]->shader->name , "*off") ) { G2_SetSurfaceOnOff(ghlInfo, ghlInfo->mSlist, skin->surfaces[j]->name, G2SURFACEFLAG_OFF); } else { int flags; int surfaceNum = G2_IsSurfaceLegal((void *)ghlInfo->currentModel, skin->surfaces[j]->name, &flags); if ( (surfaceNum != -1) && (!(flags&G2SURFACEFLAG_OFF)) ) //only turn on if it's not an "_off" surface { G2_SetSurfaceOnOff(ghlInfo, ghlInfo->mSlist, skin->surfaces[j]->name, 0); } } } } // return a named surfaces off flags - should tell you if this surface is on or off. int G2_IsSurfaceOff (CGhoul2Info *ghlInfo, surfaceInfo_v &slist, const char *surfaceName) { model_t *mod = (model_t *)ghlInfo->currentModel; int surfIndex = -1; mdxmSurface_t *surf = 0; // did we find a ghoul 2 model or not? if (!mod->mdxm) { return 0; } // first find if we already have this surface in the list surf = G2_FindSurface(ghlInfo, slist, surfaceName, &surfIndex); if (surf) { // set descendants value return slist[surfIndex].offFlags; } // ok, we didn't find it in the surface list. Lets look at the original surface then. mdxmSurfHierarchy_t *surface = (mdxmSurfHierarchy_t *) ( (byte *)mod->mdxm + mod->mdxm->ofsSurfHierarchy ); for ( int i = 0 ; i < mod->mdxm->numSurfaces ; i++) { if (!stricmp(surfaceName, surface->name)) { return surface->flags; } // find the next surface surface = (mdxmSurfHierarchy_t *)( (byte *)surface + (int)( &((mdxmSurfHierarchy_t *)0)->childIndexes[ surface->numChildren ] )); } assert(0); return 0; } void G2_FindRecursiveSurface(model_t *currentModel, int surfaceNum, surfaceInfo_v &rootList, int *activeSurfaces) { int i; mdxmSurface_t *surface = (mdxmSurface_t *)G2_FindSurface((void *)currentModel, surfaceNum, 0); mdxmHierarchyOffsets_t *surfIndexes = (mdxmHierarchyOffsets_t *)((byte *)currentModel->mdxm + sizeof(mdxmHeader_t)); mdxmSurfHierarchy_t *surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surface->thisSurfaceIndex]); // see if we have an override surface in the surface list surfaceInfo_t *surfOverride = G2_FindOverrideSurface(surfaceNum, rootList); // really, we should use the default flags for this surface unless it's been overriden int offFlags = surfInfo->flags; // set the off flags if we have some if (surfOverride) { offFlags = surfOverride->offFlags; } // if this surface is not off, indicate as such in the active surface list if (!(offFlags & G2SURFACEFLAG_OFF)) { activeSurfaces[surfaceNum] = 1; } else // if we are turning off all descendants, then stop this recursion now if (offFlags & G2SURFACEFLAG_NODESCENDANTS) { return; } // now recursively call for the children for (i=0; i< surfInfo->numChildren; i++) { surfaceNum = surfInfo->childIndexes[i]; G2_FindRecursiveSurface(currentModel, surfaceNum, rootList, activeSurfaces); } } void G2_RemoveRedundantGeneratedSurfaces(surfaceInfo_v &slist, int *activeSurfaces) { int i; // walk the surface list, removing surface overrides or generated surfaces that are pointing at surfaces that aren't active anymore for (i=0; imdxm) { return qfalse; } // first find if we already have this surface in the list surf = G2_IsSurfaceLegal(mod_m, surfaceName, &flags); if (surf != -1) { // first see if this ghoul2 model already has this as a root surface if (ghoul2[modelIndex].mSurfaceRoot == surf) { return qtrue; } // set the root surface ghoul2[modelIndex].mSurfaceRoot = surf; // ok, now the tricky bits. // firstly, generate a list of active / on surfaces below the root point // gimme some space to put this list into activeSurfaces = (int *)Z_Malloc(mod_m->mdxm->numSurfaces * 4, TAG_GHOUL2, qtrue); memset(activeSurfaces, 0, (mod_m->mdxm->numSurfaces * 4)); activeBones = (int *)Z_Malloc(mod_a->mdxa->numBones * 4, TAG_GHOUL2, qtrue); memset(activeBones, 0, (mod_a->mdxa->numBones * 4)); G2_FindRecursiveSurface(mod_m, surf, ghoul2[modelIndex].mSlist, activeSurfaces); // now generate the used bone list CConstructBoneList CBL(ghoul2[modelIndex].mSurfaceRoot, activeBones, ghoul2[modelIndex].mSlist, mod_m, ghoul2[modelIndex].mBlist); G2_ConstructUsedBoneList(CBL); // now remove all procedural or override surfaces that refer to surfaces that arent on this list G2_RemoveRedundantGeneratedSurfaces(ghoul2[modelIndex].mSlist, activeSurfaces); // now remove all bones that are pointing at bones that aren't active G2_RemoveRedundantBoneOverrides(ghoul2[modelIndex].mBlist, activeBones); // then remove all bolts that point at surfaces or bones that *arent* active. G2_RemoveRedundantBolts(ghoul2[modelIndex].mBltlist, ghoul2[modelIndex].mSlist, activeSurfaces, activeBones); // then remove all models on this ghoul2 instance that use those bolts that are being removed. for (int i=0; i> MODEL_SHIFT) & MODEL_AND; int boltNum = (ghoul2[i].mModelBoltLink >> BOLT_SHIFT) & BOLT_AND; // if either the bolt list is too small, or the bolt we are pointing at references nothing, remove this model if ((ghoul2[boltMod].mBltlist.size() <= boltNum) || ((ghoul2[boltMod].mBltlist[boltNum].boneNumber == -1) && (ghoul2[boltMod].mBltlist[boltNum].surfaceNumber == -1))) { CGhoul2Info_v *g2i = &ghoul2; G2API_RemoveGhoul2Model((CGhoul2Info_v **)&g2i, i); } } } //No support for this, for now. // remember to free what we used Z_Free(activeSurfaces); Z_Free(activeBones); return (qtrue); } /* //g2r if (entstate->ghoul2) { CGhoul2Info_v &ghoul2 = *((CGhoul2Info_v *)entstate->ghoul2); model_t *mod_m = R_GetModelByHandle(RE_RegisterModel(ghoul2[modelIndex].mFileName)); model_t *mod_a = R_GetModelByHandle(mod_m->mdxm->animIndex); int surf; int flags; int *activeSurfaces, *activeBones; // did we find a ghoul 2 model or not? if (!mod_m->mdxm) { return qfalse; } // first find if we already have this surface in the list surf = G2_IsSurfaceLegal(mod_m, surfaceName, &flags); if (surf != -1) { // first see if this ghoul2 model already has this as a root surface if (ghoul2[modelIndex].mSurfaceRoot == surf) { return qtrue; } // set the root surface ghoul2[modelIndex].mSurfaceRoot = surf; // ok, now the tricky bits. // firstly, generate a list of active / on surfaces below the root point // gimme some space to put this list into activeSurfaces = (int *)Z_Malloc(mod_m->mdxm->numSurfaces * 4, TAG_GHOUL2, qtrue); memset(activeSurfaces, 0, (mod_m->mdxm->numSurfaces * 4)); activeBones = (int *)Z_Malloc(mod_a->mdxa->numBones * 4, TAG_GHOUL2, qtrue); memset(activeBones, 0, (mod_a->mdxa->numBones * 4)); G2_FindRecursiveSurface(mod_m, surf, ghoul2[modelIndex].mSlist, activeSurfaces); // now generate the used bone list CConstructBoneList CBL(ghoul2[modelIndex].mSurfaceRoot, activeBones, ghoul2[modelIndex].mSlist, mod_m, ghoul2[modelIndex].mBlist); G2_ConstructUsedBoneList(CBL); // now remove all procedural or override surfaces that refer to surfaces that arent on this list G2_RemoveRedundantGeneratedSurfaces(ghoul2[modelIndex].mSlist, activeSurfaces); // now remove all bones that are pointing at bones that aren't active G2_RemoveRedundantBoneOverrides(ghoul2[modelIndex].mBlist, activeBones); // then remove all bolts that point at surfaces or bones that *arent* active. G2_RemoveRedundantBolts(ghoul2[modelIndex].mBltlist, ghoul2[modelIndex].mSlist, activeSurfaces, activeBones); // then remove all models on this ghoul2 instance that use those bolts that are being removed. for (int i=0; i> MODEL_SHIFT) & MODEL_AND; int boltNum = (ghoul2[i].mModelBoltLink >> BOLT_SHIFT) & BOLT_AND; // if either the bolt list is too small, or the bolt we are pointing at references nothing, remove this model if ((ghoul2[boltMod].mBltlist.size() <= boltNum) || ((ghoul2[boltMod].mBltlist[boltNum].boneNumber == -1) && (ghoul2[boltMod].mBltlist[boltNum].surfaceNumber == -1))) { G2API_RemoveGhoul2Model(entstate, i); } } } // remember to free what we used Z_Free(activeSurfaces); Z_Free(activeBones); return (qtrue); } } assert(0);*/ return qfalse; } extern int G2_DecideTraceLod(CGhoul2Info &ghoul2, int useLod); int G2_AddSurface(CGhoul2Info *ghoul2, int surfaceNumber, int polyNumber, float BarycentricI, float BarycentricJ, int lod ) { surfaceInfo_t temp_slist_entry; // decide if LOD is legal lod = G2_DecideTraceLod(*(CGhoul2Info *)(ghoul2), lod); // first up, see if we have a free one already set up - look only from the end of the constant surfaces onwards for (int i=0; imSlist.size(); i++) { // is the surface count -1? That would indicate it's free if (ghoul2->mSlist[i].surface == -1) { ghoul2->mSlist[i].offFlags = G2SURFACEFLAG_GENERATED; ghoul2->mSlist[i].surface = 10000; // no model will ever have 10000 surfaces ghoul2->mSlist[i].genBarycentricI = BarycentricI; ghoul2->mSlist[i].genBarycentricJ = BarycentricJ; ghoul2->mSlist[i].genPolySurfaceIndex = ((polyNumber & 0xffff) << 16) | (surfaceNumber & 0xffff); ghoul2->mSlist[i].genLod = lod; return i; } } // ok, didn't find one. Better create one temp_slist_entry.offFlags = G2SURFACEFLAG_GENERATED; temp_slist_entry.surface = 10000; temp_slist_entry.genBarycentricI = BarycentricI; temp_slist_entry.genBarycentricJ = BarycentricJ; temp_slist_entry.genPolySurfaceIndex = ((polyNumber & 0xffff) << 16) | (surfaceNumber & 0xffff); temp_slist_entry.genLod = lod; ghoul2->mSlist.push_back(temp_slist_entry); return (ghoul2->mSlist.size() -1 ); } qboolean G2_RemoveSurface(surfaceInfo_v &slist, const int index) { // did we find it? if (index != -1) { // set us to be the 'not active' state slist[index].surface = -1; unsigned int newSize = slist.size(); // now look through the list from the back and see if there is a block of -1's we can resize off the end of the list for (int i=slist.size()-1; i>-1; i--) { if (slist[i].surface == -1) { newSize = i; } // once we hit one that isn't a -1, we are done. else { break; } } // do we need to resize? if (newSize != slist.size()) { // yes, so lets do it slist.resize(newSize); } return qtrue; } assert(0); // no return qfalse; } int G2_GetParentSurface(CGhoul2Info *ghlInfo, const int index) { model_t *mod = (model_t *)ghlInfo->currentModel; mdxmSurface_t *surf = 0; mdxmHierarchyOffsets_t *surfIndexes = (mdxmHierarchyOffsets_t *)((byte *)mod->mdxm + sizeof(mdxmHeader_t)); mdxmSurfHierarchy_t *surfInfo = 0; // walk each surface and see if this index is listed in it's children surf = (mdxmSurface_t *)G2_FindSurface((void *)mod, index, 0); surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surf->thisSurfaceIndex]); return surfInfo->parentIndex; } int G2_GetSurfaceIndex(CGhoul2Info *ghlInfo, const char *surfaceName) { model_t *mod = (model_t *)ghlInfo->currentModel; int flags; return G2_IsSurfaceLegal(mod, surfaceName, &flags); } int G2_IsSurfaceRendered(CGhoul2Info *ghlInfo, const char *surfaceName, surfaceInfo_v &slist) { int flags = 0;//, surfFlags = 0; int surfIndex = 0; assert(ghlInfo->currentModel); assert(ghlInfo->currentModel->mdxm); if (!ghlInfo->currentModel->mdxm) { return -1; } // now travel up the skeleton to see if any of it's ancestors have a 'no descendants' turned on // find the original surface in the surface list int surfNum = G2_IsSurfaceLegal((model_t *)ghlInfo->currentModel, surfaceName, &flags); if ( surfNum != -1 ) {//must be legal const mdxmHierarchyOffsets_t *surfIndexes = (mdxmHierarchyOffsets_t *)((byte *)ghlInfo->currentModel->mdxm + sizeof(mdxmHeader_t)); const mdxmSurfHierarchy_t *surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surfNum]); surfNum = surfInfo->parentIndex; // walk the surface hierarchy up until we hit the root while (surfNum != -1) { const mdxmSurface_t *parentSurf; int parentFlags; const mdxmSurfHierarchy_t *parentSurfInfo; parentSurfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surfNum]); // find the original surface in the surface list //G2 was bug, above comment was accurate, but we don't want the original flags, we want the parent flags G2_IsSurfaceLegal((model_t *)ghlInfo->currentModel, parentSurfInfo->name, &parentFlags); // now see if we already have overriden this surface in the slist parentSurf = G2_FindSurface(ghlInfo, slist, parentSurfInfo->name, &surfIndex); if (parentSurf) { // set descendants value parentFlags = slist[surfIndex].offFlags; } // now we have the parent flags, lets see if any have the 'no descendants' flag set if (parentFlags & G2SURFACEFLAG_NODESCENDANTS) { flags |= G2SURFACEFLAG_OFF; break; } // set up scan of next parent surfNum = parentSurfInfo->parentIndex; } } else { return -1; } if ( flags == 0 ) {//it's not being overridden by a parent // now see if we already have overriden this surface in the slist const mdxmSurface_t *surf = G2_FindSurface(ghlInfo, slist, surfaceName, &surfIndex); if (surf) { // set descendants value flags = slist[surfIndex].offFlags; } // ok, at this point in flags we have what this surface is set to, and the index of the surface itself } return flags; }