Files
Jedi-Academy/tools/ModView/r_glm.cpp
2013-04-04 14:32:05 -07:00

1874 lines
57 KiB
C++

// 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; j<surfInfo->numChildren; 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 </*v->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; i<MAX_G2_SURFACES; i++)
{
// are we at the end of the list?
if (slist[i].surface == -1)
{
break;
}
// FIXME - is this the same as just using slist[i].surface instead of the surf->thisSurfaceIndex??
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; i<MAX_G2_SURFACES; i++)
{
// are we at the end of the list?
if (slist[i].surface == -1)
{
break;
}
// FIXME - is this the same as just using slist[i].surface instead of the surf->thisSurfaceIndex??
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; i<MAX_G2_SURFACES; i++)
{
if (slist[2].surface == -1) // EOL?
return MyFlags; // fuck it, couldn't find a parent, just return my flags
surf = mod->mdxmsurf[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; i<MAX_BONE_OVERRIDES; i++)
{
// if this bone entry has no info in it, bounce over it
if (blist->boneNumber == -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; i<MAX_BONE_OVERRIDES; i++)
{
// if this bone entry has info in it, bounce over it
if (blist[i].boneNumber != -1)
{
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;
}
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; i<MAX_BONE_OVERRIDES; i++)
{
if (blist[i].boneNumber == boneNum)
{
return i;
}
}
return -1;
}
// given a model, bonelist and bonename, lets stop an anim if it's playing.
qboolean G2_Stop_Bone_Anim_Index( boneInfo_t *blist, int index)
{
// 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;
}
//=========================================================================================
//// Public Bone Routines
// Given a model handle, and a bone name, we want to remove this bone from the bone override list
qboolean G2_Remove_Bone (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)
{
// 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<MAX_BONE_OVERRIDES; i++)
{
// we we a valid bone override?
if (blist[i].boneNumber != -1)
{
// are we animating?
if (blist[i].flags && (BONE_ANIM_OVERRIDE_LOOP || BONE_ANIM_OVERRIDE))
{
// set up old frame
blist[i].currentFrame = blist[i].newFrame;
// yes - add in animation speed to current frame
blist[i].newFrame += (blist[i].animSpeed * timeoffset);
// turn off new anim flag
blist[i].flags &= ~BONE_ANIM_NEW_ANIM;
// did we run off the end?
if (((blist[i].animSpeed > 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; i<MAX_BONE_OVERRIDES; i++)
{
blist[i].boneNumber = -1;
}
}
/// assorted Ghoul 2 functions.
/*
All bones should be an identity orientation to display the mesh exactly
as it is specified.
For all other frames, the bones represent the transformation from the
orientation of the bone in the base frame to the orientation in this
frame.
*/
//======================================================================
//
// Bone Manipulation code
// nasty little matrix multiply going on here..
void Multiply_4x4Matrix(mdxBone4_t *out, mdxBone4_t *in2, mdxBone4_t *in)
{
// first row of out
out->m[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; i<surface->numBoneReferences;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 /////////////////