void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CCollisionRecord *collRecMap, int entNum, EG2_Collision eG2TraceType, int useLod, float fRadius) { int i, lod; skin_t *skin; shader_t *cust_shader; // walk each possible model for this entity and try tracing against it for (i=0; i<ghoul2.size(); i++) { // don't bother with models that we don't care about. if (!ghoul2[i].mValid) { continue; } assert(G2_MODEL_OK(&ghoul2[i])); // do we really want to collide with this object? if (ghoul2[i].mFlags & GHOUL2_NOCOLLIDE) { continue; } if (ghoul2[i].mCustomShader) { cust_shader = R_GetShaderByHandle(ghoul2[i].mCustomShader ); } else { cust_shader = NULL; } // figure out the custom skin thing if ( ghoul2[i].mSkin > 0 && ghoul2[i].mSkin < tr.numSkins ) { skin = R_GetSkinByHandle( ghoul2[i].mSkin ); } else { skin = NULL; } lod = G2_DecideTraceLod(ghoul2[i],useLod); //reset the quick surface override lookup G2_FindOverrideSurface(-1, ghoul2[i].mSlist); CTraceSurface TS(ghoul2[i].mSurfaceRoot, ghoul2[i].mSlist, ghoul2[i].currentModel, lod, rayStart, rayEnd, collRecMap, entNum, i, skin, cust_shader, ghoul2[i].mTransformedVertsArray, eG2TraceType, fRadius); // start the surface recursion loop G2_TraceSurfaces(TS); // if we've hit one surface on one model, don't bother doing the rest if (TS.hitOne) { break; } } }
// main calling point for the model transform for collision detection. At this point all of the skeleton has been transformed. void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod) { int i, lod; vec3_t correctScale; VectorCopy(scale, correctScale); // check for scales of 0 - that's the default I believe if (!scale[0]) { correctScale[0] = 1.0; } if (!scale[1]) { correctScale[1] = 1.0; } if (!scale[2]) { correctScale[2] = 1.0; } // walk each possible model for this entity and try rendering it out for (i=0; i<ghoul2.size(); i++) { CGhoul2Info &g=ghoul2[i]; // don't bother with models that we don't care about. if (!g.mValid) { continue; } assert(g.mBoneCache); assert(G2_MODEL_OK(&g)); // stop us building this model more than once per frame g.mMeshFrameNum = frameNum; // decide the LOD lod = G2_DecideTraceLod(g, useLod); // give us space for the transformed vertex array to be put in ghoul2[i].mTransformedVertsArray = (int*)G2VertSpace->MiniHeapAlloc(g.currentModel->mdxm->numSurfaces * 4); if (!g.mTransformedVertsArray) { Com_Error(ERR_DROP, "Ran out of transform space for Ghoul2 Models. Adjust MiniHeapSize in SV_SpawnServer.\n"); } memset(g.mTransformedVertsArray, 0,(g.currentModel->mdxm->numSurfaces * 4)); G2_FindOverrideSurface(-1,g.mSlist); //reset the quick surface override lookup; // recursively call the model surface transform G2_TransformSurfaces(g.mSurfaceRoot, g.mSlist, g.mBoneCache, g.currentModel, lod, correctScale, G2VertSpace, g.mTransformedVertsArray, false); } }
int G2_DecideTraceLod(CGhoul2Info &ghoul2, int useLod) { int returnLod = useLod; // if we are overriding the LOD at top level, then we can afford to only check this level of model if (ghoul2.mLodBias > returnLod) { returnLod = ghoul2.mLodBias; } assert(G2_MODEL_OK(&ghoul2)); assert(ghoul2.currentModel); assert(ghoul2.currentModel->mdxm); //what about r_lodBias? // now ensure that we haven't selected a lod that doesn't exist for this model if ( returnLod >= ghoul2.currentModel->mdxm->numLODs ) { returnLod = ghoul2.currentModel->mdxm->numLODs - 1; } return returnLod; }
/************************************************************************************************ * 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 * ************************************************************************************************/ const mdxmSurface_t *G2_FindSurface(CGhoul2Info *ghlInfo, surfaceInfo_v &slist, const char *surfaceName, int *surfIndex/*NULL*/) { int i = 0; // find the model we want assert(G2_MODEL_OK(ghlInfo)); const mdxmHierarchyOffsets_t *surfIndexes = (mdxmHierarchyOffsets_t *)((byte *)ghlInfo->currentModel->mdxm + sizeof(mdxmHeader_t)); // 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)) { const mdxmSurface_t *surf = (mdxmSurface_t *)G2_FindSurface(ghlInfo->currentModel, slist[i].surface, 0); // back track and get the surfinfo struct for this surface const mdxmSurfHierarchy_t *surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surf->thisSurfaceIndex]); // are these the droids we're looking for? if (!Q_stricmp (surfInfo->name, surfaceName)) { // yup if (surfIndex) { *surfIndex = i; } return surf; } } } // didn't find it if (surfIndex) { *surfIndex = -1; } return 0; }
int G2_Add_Bolt(CGhoul2Info *ghlInfo, boltInfo_v &bltlist, surfaceInfo_v &slist, const char *boneName) { assert(ghlInfo&&ghlInfo->mValid); int surfNum = -1; mdxaSkel_t *skel; mdxaSkelOffsets_t *offsets; boltInfo_t tempBolt; uint32_t flags; assert(G2_MODEL_OK(ghlInfo)); // first up, we'll search for that which this bolt names in all the surfaces surfNum = G2_IsSurfaceLegal(ghlInfo->currentModel, boneName, &flags); // did we find it as a surface? if (surfNum != -1) { // look through entire list - see if it's already there first for(size_t i=0; i<bltlist.size(); i++) { // already there?? if (bltlist[i].surfaceNumber == surfNum) { // increment the usage count bltlist[i].boltUsed++; return i; } } // look through entire list - see if we can re-use one for(size_t i=0; i<bltlist.size(); i++) { // if this surface entry has info in it, bounce over it if (bltlist[i].boneNumber == -1 && bltlist[i].surfaceNumber == -1) { // if we found an entry that had a -1 for the bone / surface number, then we hit a surface / bone slot that was empty bltlist[i].surfaceNumber = surfNum; bltlist[i].boltUsed = 1; bltlist[i].surfaceType = 0; return i; } } // ok, we didn't find an existing surface of that name, or an empty slot. Lets add an entry tempBolt.surfaceNumber = surfNum; tempBolt.boneNumber = -1; tempBolt.boltUsed = 1; tempBolt.surfaceType = 0; bltlist.push_back(tempBolt); return bltlist.size()-1; } // no, check to see if it's a bone then offsets = (mdxaSkelOffsets_t *)((byte *)ghlInfo->aHeader + sizeof(mdxaHeader_t)); int x; // 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< ghlInfo->aHeader->numBones; x++) { skel = (mdxaSkel_t *)((byte *)ghlInfo->aHeader + sizeof(mdxaHeader_t) + offsets->offsets[x]); // if name is the same, we found it if (!Q_stricmp(skel->name, boneName)) { break; } } // check to see we did actually make a match with a bone in the model if (x == ghlInfo->aHeader->numBones) { // didn't find it? Error //assert(0&&x == mod_a->mdxa->numBones); #if _DEBUG G2_Bolt_Not_Found(boneName,ghlInfo->mFileName); #endif return -1; } // look through entire list - see if it's already there first for(size_t i=0; i<bltlist.size(); i++) { // already there?? if (bltlist[i].boneNumber == x) { // increment the usage count bltlist[i].boltUsed++; return i; } } // look through entire list - see if we can re-use it for(size_t i=0; i<bltlist.size(); i++) { // if this bone entry has info in it, bounce over it if (bltlist[i].boneNumber == -1 && bltlist[i].surfaceNumber == -1) { // if we found an entry that had a -1 for the bonenumber, then we hit a bone slot that was empty bltlist[i].boneNumber = x; bltlist[i].boltUsed = 1; bltlist[i].surfaceType = 0; return i; } } // ok, we didn't find an existing bone of that name, or an empty slot. Lets add an entry tempBolt.boneNumber = x; tempBolt.surfaceNumber = -1; tempBolt.boltUsed = 1; tempBolt.surfaceType = 0; bltlist.push_back(tempBolt); return bltlist.size()-1; }