/* * Mod_LoadSkeletalModel */ void Mod_LoadSkeletalModel( model_t *mod, const model_t *parent, void *buffer, bspFormatDesc_t *unused ) { unsigned int i, j, k; size_t filesize; qbyte *pbase; size_t memsize; qbyte *pmem; iqmheader_t *header; char *texts; iqmvertexarray_t *va; iqmjoint_t *joints; bonepose_t *baseposes; iqmpose_t *poses; unsigned short *framedata; const int *inelems; elem_t *outelems; iqmmesh_t *inmesh; iqmbounds_t *inbounds; float *vposition, *vtexcoord, *vnormal, *vtangent; qbyte *vblendindices_byte, *vblendweights_byte; int *vblendindexes_int; float *vblendweights_float; mskmodel_t *poutmodel; baseposes = NULL; header = ( iqmheader_t * )buffer; // check IQM magic if( memcmp( header->magic, "INTERQUAKEMODEL", 16 ) ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s is not an Inter-Quake Model\n", mod->name ); goto error; } // check header version header->version = LittleLong( header->version ); if( header->version != IQM_VERSION ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has wrong type number (%i should be %i)\n", mod->name, header->version, IQM_VERSION ); goto error; } // byteswap header #define H_SWAP(s) (header->s = LittleLong( header->s )) H_SWAP( filesize ); H_SWAP( flags ); H_SWAP( num_text ); H_SWAP( ofs_text ); H_SWAP( num_meshes ); H_SWAP( ofs_meshes ); H_SWAP( num_vertexarrays ); H_SWAP( num_vertexes ); H_SWAP( ofs_vertexarrays ); H_SWAP( num_triangles ); H_SWAP( ofs_triangles ); H_SWAP( ofs_adjacency ); H_SWAP( num_joints ); H_SWAP( ofs_joints ); H_SWAP( num_poses ); H_SWAP( ofs_poses ); H_SWAP( num_anims ); H_SWAP( ofs_anims ); H_SWAP( num_frames ); H_SWAP( num_framechannels ); H_SWAP( ofs_frames ); H_SWAP( ofs_bounds ); H_SWAP( num_comment ); H_SWAP( ofs_comment ); H_SWAP( num_extensions ); H_SWAP( ofs_extensions ); #undef H_SWAP if( header->num_triangles < 1 || header->num_vertexes < 3 || header->num_vertexarrays < 1 || header->num_meshes < 1 ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has no geometry\n", mod->name ); goto error; } if( header->num_frames < 1 || header->num_anims < 1 ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has no animations\n", mod->name ); goto error; } if( header->num_joints != header->num_poses ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has an invalid number of poses: %i vs %i\n", mod->name, header->num_joints, header->num_poses ); goto error; } if( !header->ofs_bounds ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has no frame bounds\n", mod->name ); goto error; } pbase = ( qbyte * )buffer; filesize = header->filesize; // check data offsets against the filesize if( header->ofs_text + header->num_text > filesize || header->ofs_vertexarrays + header->num_vertexarrays * sizeof( iqmvertexarray_t ) > filesize || header->ofs_joints + header->num_joints * sizeof( iqmjoint_t ) > filesize || header->ofs_frames + header->num_frames * header->num_framechannels * sizeof( unsigned short ) > filesize || header->ofs_triangles + header->num_triangles * sizeof( int[3] ) > filesize || header->ofs_meshes + header->num_meshes * sizeof( iqmmesh_t ) > filesize || header->ofs_bounds + header->num_frames * sizeof( iqmbounds_t ) > filesize ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has invalid size or offset information\n", mod->name ); goto error; } poutmodel = mod->extradata = Mod_Malloc( mod, sizeof( *poutmodel ) ); // load text texts = Mod_Malloc( mod, header->num_text + 1 ); if( header->ofs_text ) { memcpy( texts, (const char *)(pbase + header->ofs_text), header->num_text ); } texts[header->ofs_text] = '\0'; // load vertex arrays vposition = NULL; vtexcoord = NULL; vnormal = NULL; vtangent = NULL; vblendindices_byte = NULL; vblendindexes_int = NULL; vblendweights_byte = NULL; vblendweights_float = NULL; va = ( iqmvertexarray_t * )( pbase + header->ofs_vertexarrays ); for( i = 0; i < header->num_vertexarrays; i++ ) { size_t vsize; va[i].type = LittleLong( va[i].type ); va[i].flags = LittleLong( va[i].flags ); va[i].format = LittleLong( va[i].format ); va[i].size = LittleLong( va[i].size ); va[i].offset = LittleLong( va[i].offset ); vsize = header->num_vertexes*va[i].size; switch( va[i].format ) { case IQM_FLOAT: vsize *= sizeof( float ); break; case IQM_INT: case IQM_UINT: vsize *= sizeof( int ); break; case IQM_BYTE: case IQM_UBYTE: vsize *= sizeof( unsigned char ); break; default: continue; } if( va[i].offset + vsize > filesize ) { continue; } switch( va[i].type ) { case IQM_POSITION: if( va[i].format == IQM_FLOAT && va[i].size == 3 ) { vposition = ( float * )( pbase + va[i].offset ); } break; case IQM_TEXCOORD: if( va[i].format == IQM_FLOAT && va[i].size == 2 ) { vtexcoord = ( float * )( pbase + va[i].offset ); } break; case IQM_NORMAL: if( va[i].format == IQM_FLOAT && va[i].size == 3 ) { vnormal = ( float * )( pbase + va[i].offset ); } break; case IQM_TANGENT: if( va[i].format == IQM_FLOAT && va[i].size == 4 ) { vtangent = ( float * )( pbase + va[i].offset ); } break; case IQM_BLENDINDEXES: if( va[i].size != SKM_MAX_WEIGHTS ) break; if( va[i].format == IQM_BYTE || va[i].format == IQM_UBYTE ) { vblendindices_byte = ( qbyte * )( pbase + va[i].offset ); } else if( va[i].format == IQM_INT || va[i].format == IQM_UINT ) { vblendindexes_int = ( int * )( pbase + va[i].offset ); } break; case IQM_BLENDWEIGHTS: if( va[i].size != SKM_MAX_WEIGHTS ) break; if( va[i].format == IQM_UBYTE ) { vblendweights_byte = ( qbyte * )( pbase + va[i].offset ); } else if( va[i].format == IQM_FLOAT ) { vblendweights_float = ( float * )( pbase + va[i].offset ); } break; default: break; } } if( !vposition || !vtexcoord || !(vblendindices_byte || vblendindexes_int) || !(vblendweights_byte || vblendweights_float) ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s is missing vertex array data\n", mod->name ); goto error; } // load joints memsize = 0; memsize += sizeof( bonepose_t ) * header->num_joints; pmem = Mod_Malloc( mod, memsize ); baseposes = ( void * )pmem; pmem += sizeof( *baseposes ); memsize = 0; memsize += sizeof( mskbone_t ) * header->num_joints; memsize += sizeof( bonepose_t ) * header->num_joints; pmem = Mod_Malloc( mod, memsize ); poutmodel->numbones = header->num_joints; poutmodel->bones = ( void * )pmem; pmem += sizeof( *poutmodel->bones ) * poutmodel->numbones; poutmodel->invbaseposes = ( void * )pmem; pmem += sizeof( *poutmodel->invbaseposes ) * poutmodel->numbones; joints = ( iqmjoint_t * )( pbase + header->ofs_joints ); for( i = 0; i < poutmodel->numbones; i++ ) { joints[i].name = LittleLong( joints[i].name ); joints[i].parent = LittleLong( joints[i].parent ); for( j = 0; j < 3; j++ ) { joints[i].translate[j] = LittleFloat( joints[i].translate[j] ); joints[i].rotate[j] = LittleFloat( joints[i].rotate[j] ); joints[i].scale[j] = LittleFloat( joints[i].scale[j] ); } if( joints[i].parent >= (int)i ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s bone[%i].parent(%i) >= %i\n", mod->name, i, joints[i].parent, i ); goto error; } poutmodel->bones[i].name = texts + joints[i].name; poutmodel->bones[i].parent = joints[i].parent; DualQuat_FromQuat3AndVector( joints[i].rotate, joints[i].translate, baseposes[i].dualquat ); // scale is unused // reconstruct invserse bone pose if( joints[i].parent >= 0 ) { bonepose_t bp, *pbp; bp = baseposes[i]; pbp = &baseposes[joints[i].parent]; DualQuat_Multiply( pbp->dualquat, bp.dualquat, baseposes[i].dualquat ); } DualQuat_Copy( baseposes[i].dualquat, poutmodel->invbaseposes[i].dualquat ); DualQuat_Invert( poutmodel->invbaseposes[i].dualquat ); } // load frames poses = ( iqmpose_t * )( pbase + header->ofs_poses ); for( i = 0; i < header->num_poses; i++ ) { poses[i].parent = LittleLong( poses[i].parent ); poses[i].mask = LittleLong( poses[i].mask ); for( j = 0; j < 10; j++ ) { poses[i].channeloffset[j] = LittleFloat( poses[i].channeloffset[j] ); poses[i].channelscale[j] = LittleFloat( poses[i].channelscale[j] ); } } memsize = 0; memsize += sizeof( mskframe_t ) * header->num_frames; memsize += sizeof( bonepose_t ) * header->num_joints * header->num_frames; pmem = Mod_Malloc( mod, memsize ); poutmodel->numframes = header->num_frames; poutmodel->frames = ( mskframe_t * )pmem; pmem += sizeof( mskframe_t ) * poutmodel->numframes; framedata = ( unsigned short * )( pbase + header->ofs_frames ); for( i = 0; i < header->num_frames; i++ ) { bonepose_t *pbp; vec3_t translate; quat_t rotate; poutmodel->frames[i].boneposes = ( bonepose_t * )pmem; pmem += sizeof( bonepose_t ) * poutmodel->numbones; for( j = 0, pbp = poutmodel->frames[i].boneposes; j < header->num_poses; j++, pbp++ ) { translate[0] = poses[j].channeloffset[0]; if( poses[j].mask & 0x01 ) translate[0] += *framedata++ * poses[j].channelscale[0]; translate[1] = poses[j].channeloffset[1]; if( poses[j].mask & 0x02 ) translate[1] += *framedata++ * poses[j].channelscale[1]; translate[2] = poses[j].channeloffset[2]; if( poses[j].mask & 0x04 ) translate[2] += *framedata++ * poses[j].channelscale[2]; rotate[0] = poses[j].channeloffset[3]; if( poses[j].mask & 0x08 ) rotate[0] += *framedata++ * poses[j].channelscale[3]; rotate[1] = poses[j].channeloffset[4]; if( poses[j].mask & 0x10 ) rotate[1] += *framedata++ * poses[j].channelscale[4]; rotate[2] = poses[j].channeloffset[5]; if( poses[j].mask & 0x20 ) rotate[2] += *framedata++ * poses[j].channelscale[5]; rotate[3] = poses[j].channeloffset[6]; if( poses[j].mask & 0x40 ) rotate[3] += *framedata++ * poses[j].channelscale[6]; if( rotate[3] > 0 ) { Vector4Inverse( rotate ); } Vector4Normalize( rotate ); // scale is unused if( poses[j].mask & 0x80 ) framedata++; if( poses[j].mask & 0x100 ) framedata++; if( poses[j].mask & 0x200 ) framedata++; DualQuat_FromQuatAndVector( rotate, translate, pbp->dualquat ); } } // load triangles memsize = 0; memsize += sizeof( *outelems ) * header->num_triangles * 3; pmem = Mod_Malloc( mod, memsize ); poutmodel->numtris = header->num_triangles; poutmodel->elems = ( elem_t * )pmem; pmem += sizeof( *outelems ) * header->num_triangles * 3; inelems = ( const int * )(pbase + header->ofs_triangles); outelems = poutmodel->elems; for( i = 0; i < header->num_triangles; i++ ) { for( j = 0; j < 3; j++ ) { outelems[j] = LittleLong( inelems[j] ); } inelems += 3; outelems += 3; } // load vertices memsize = 0; memsize += sizeof( *poutmodel->sVectorsArray ) * header->num_vertexes; // 16-bytes aligned memsize += sizeof( *poutmodel->xyzArray ) * header->num_vertexes; memsize += sizeof( *poutmodel->normalsArray ) * header->num_vertexes; memsize += sizeof( *poutmodel->stArray ) * header->num_vertexes; memsize += sizeof( *poutmodel->blendWeights ) * header->num_vertexes * SKM_MAX_WEIGHTS; memsize += sizeof( *poutmodel->blendIndices ) * header->num_vertexes * SKM_MAX_WEIGHTS; pmem = Mod_Malloc( mod, memsize ); poutmodel->numverts = header->num_vertexes; // S-vectors poutmodel->sVectorsArray = ( vec4_t * )pmem; pmem += sizeof( *poutmodel->sVectorsArray ) * header->num_vertexes; if( vtangent ) { for( i = 0; i < header->num_vertexes; i++ ) { for( j = 0; j < 4; j++ ) { poutmodel->sVectorsArray[i][j] = LittleFloat( vtangent[j] ); } vtangent += 4; } } // XYZ positions poutmodel->xyzArray = ( vec4_t * )pmem; pmem += sizeof( *poutmodel->xyzArray ) * header->num_vertexes; for( i = 0; i < header->num_vertexes; i++ ) { for( j = 0; j < 3; j++ ) { poutmodel->xyzArray[i][j] = LittleFloat( vposition[j] ); } poutmodel->xyzArray[i][3] = 1; vposition += 3; } // normals poutmodel->normalsArray = ( vec4_t * )pmem; pmem += sizeof( *poutmodel->normalsArray ) * header->num_vertexes; for( i = 0; i < header->num_vertexes; i++ ) { for( j = 0; j < 3; j++ ) { poutmodel->normalsArray[i][j] = LittleFloat( vnormal[j] ); } poutmodel->normalsArray[i][3] = 0; vnormal += 3; } // texture coordinates poutmodel->stArray = ( vec2_t * )pmem; pmem += sizeof( *poutmodel->stArray ) * header->num_vertexes; for( i = 0; i < header->num_vertexes; i++ ) { for( j = 0; j < 2; j++ ) { poutmodel->stArray[i][j] = LittleFloat( vtexcoord[j] ); } vtexcoord += 2; } if( !vtangent ) { // if the loaded file is missing precomputed S-vectors, compute them now R_BuildTangentVectors( poutmodel->numverts, poutmodel->xyzArray, poutmodel->normalsArray, poutmodel->stArray, poutmodel->numtris, poutmodel->elems, poutmodel->sVectorsArray ); } // blend indices poutmodel->blendIndices = ( qbyte * )pmem; pmem += sizeof( *poutmodel->blendIndices ) * header->num_vertexes * SKM_MAX_WEIGHTS; if( vblendindices_byte ) { memcpy( poutmodel->blendIndices, vblendindices_byte, sizeof( qbyte ) * header->num_vertexes * SKM_MAX_WEIGHTS ); } else if( vblendindexes_int ) { for( j = 0; j < header->num_vertexes * SKM_MAX_WEIGHTS; j++ ) { poutmodel->blendIndices[j] = LittleLong( vblendindexes_int[j] ); } } // blend weights poutmodel->blendWeights = ( qbyte * )pmem; pmem += sizeof( *poutmodel->blendWeights ) * header->num_vertexes * SKM_MAX_WEIGHTS; if( vblendweights_byte ) { memcpy( poutmodel->blendWeights, vblendweights_byte, sizeof( qbyte ) * header->num_vertexes * SKM_MAX_WEIGHTS ); } else if( vblendweights_float ) { for( j = 0; j < header->num_vertexes * SKM_MAX_WEIGHTS; j++ ) { poutmodel->blendWeights[j] = LittleFloat( vblendweights_float[j] ) * 255.0f; } } // blends memsize = 0; memsize += poutmodel->numverts * ( sizeof( mskblend_t ) + sizeof( unsigned int ) ); pmem = Mod_Malloc( mod, memsize ); poutmodel->numblends = 0; poutmodel->blends = ( mskblend_t * )pmem; pmem += sizeof( *poutmodel->blends ) * poutmodel->numverts; poutmodel->vertexBlends = ( unsigned int * )pmem; vblendindices_byte = poutmodel->blendIndices; vblendweights_byte = poutmodel->blendWeights; for( i = 0; i < poutmodel->numverts; i++ ) { mskblend_t blend; for( j = 0; j < SKM_MAX_WEIGHTS; j++ ) { blend.indices[j] = vblendindices_byte[j]; blend.weights[j] = vblendweights_byte[j]; } poutmodel->vertexBlends[i] = Mod_SkeletalModel_AddBlend( poutmodel, &blend ); vblendindices_byte += SKM_MAX_WEIGHTS; vblendweights_byte += SKM_MAX_WEIGHTS; } // meshes memsize = 0; memsize += sizeof( mskmesh_t ) * header->num_meshes; memsize += sizeof( drawSurfaceSkeletal_t ) * header->num_meshes; pmem = Mod_Malloc( mod, memsize ); poutmodel->nummeshes = header->num_meshes; poutmodel->meshes = ( mskmesh_t * )pmem; pmem += sizeof( *poutmodel->meshes ) * header->num_meshes; inmesh = ( iqmmesh_t * )(pbase + header->ofs_meshes); for( i = 0; i < header->num_meshes; i++ ) { inmesh[i].name = LittleLong( inmesh[i].name ); inmesh[i].material = LittleLong( inmesh[i].material ); inmesh[i].first_vertex = LittleLong( inmesh[i].first_vertex ); inmesh[i].num_vertexes = LittleLong( inmesh[i].num_vertexes ); inmesh[i].first_triangle = LittleLong( inmesh[i].first_triangle ); inmesh[i].num_triangles = LittleLong( inmesh[i].num_triangles ); poutmodel->meshes[i].name = texts + inmesh[i].name; Mod_StripLODSuffix( poutmodel->meshes[i].name ); poutmodel->meshes[i].skin.name = texts + inmesh[i].material; poutmodel->meshes[i].skin.shader = R_RegisterSkin( poutmodel->meshes[i].skin.name ); poutmodel->meshes[i].elems = poutmodel->elems + inmesh[i].first_triangle * 3; poutmodel->meshes[i].numtris = inmesh[i].num_triangles; poutmodel->meshes[i].numverts = inmesh[i].num_vertexes; poutmodel->meshes[i].xyzArray = poutmodel->xyzArray + inmesh[i].first_vertex; poutmodel->meshes[i].normalsArray = poutmodel->normalsArray + inmesh[i].first_vertex; poutmodel->meshes[i].stArray = poutmodel->stArray + inmesh[i].first_vertex; poutmodel->meshes[i].sVectorsArray = poutmodel->sVectorsArray + inmesh[i].first_vertex; poutmodel->meshes[i].blendIndices = poutmodel->blendIndices + inmesh[i].first_vertex * SKM_MAX_WEIGHTS; poutmodel->meshes[i].blendWeights = poutmodel->blendWeights + inmesh[i].first_vertex * SKM_MAX_WEIGHTS; poutmodel->meshes[i].vertexBlends = poutmodel->vertexBlends + inmesh[i].first_vertex; // elements are always offset to start vertex 0 for each mesh outelems = poutmodel->meshes[i].elems; for( j = 0; j < poutmodel->meshes[i].numtris; j++ ) { outelems[0] -= inmesh[i].first_vertex; outelems[1] -= inmesh[i].first_vertex; outelems[2] -= inmesh[i].first_vertex; outelems += 3; } poutmodel->meshes[i].maxWeights = 1; vblendweights_byte = poutmodel->meshes[i].blendWeights; for( j = 0; j < poutmodel->meshes[i].numverts; j++ ) { for( k = 1; k < SKM_MAX_WEIGHTS && vblendweights_byte[k]; k++ ); if( k > poutmodel->meshes[i].maxWeights ) { poutmodel->meshes[i].maxWeights = k; if( k == SKM_MAX_WEIGHTS ) { break; } } vblendweights_byte += SKM_MAX_WEIGHTS; } // creating a VBO only makes sense if GLSL is present and the number of bones // we can handle on the GPU is sufficient if( glConfig.ext.vertex_buffer_object && poutmodel->numbones <= glConfig.maxGLSLBones ) { // build a static vertex buffer object for this mesh Mod_SkeletalBuildStaticVBOForMesh( &poutmodel->meshes[i] ); } } poutmodel->drawSurfs = ( drawSurfaceSkeletal_t * )pmem; pmem += sizeof( *poutmodel->drawSurfs ) * header->num_meshes; for( i = 0; i < header->num_meshes; i++ ) { poutmodel->drawSurfs[i].type = ST_SKELETAL; poutmodel->drawSurfs[i].model = mod; poutmodel->drawSurfs[i].mesh = poutmodel->meshes + i; } // bounds ClearBounds( mod->mins, mod->maxs ); inbounds = ( iqmbounds_t * )(pbase + header->ofs_bounds); for( i = 0; i < header->num_frames; i++ ) { for( j = 0; j < 3; j++ ) { inbounds[i].bbmin[j] = LittleFloat( inbounds[i].bbmin[j] ); inbounds[i].bbmax[j] = LittleFloat( inbounds[i].bbmax[j] ); } inbounds[i].radius = LittleFloat( inbounds[i].radius ); inbounds[i].xyradius = LittleFloat( inbounds[i].xyradius ); VectorCopy( inbounds[i].bbmin, poutmodel->frames[i].mins ); VectorCopy( inbounds[i].bbmax, poutmodel->frames[i].maxs ); poutmodel->frames[i].radius = inbounds[i].radius; AddPointToBounds( poutmodel->frames[i].mins, mod->mins, mod->maxs ); AddPointToBounds( poutmodel->frames[i].maxs, mod->mins, mod->maxs ); } mod->radius = RadiusFromBounds( mod->mins, mod->maxs ); mod->type = mod_skeletal; mod->registrationSequence = rsh.registrationSequence; mod->touch = &Mod_TouchSkeletalModel; R_Free( baseposes ); return; error: if( baseposes ) { R_Free( baseposes ); } mod->type = mod_bad; }
void gamerRenderInitAllObjects( tAnimModel const* pAnimModel, tAnimSequence* pAnimSequence, tAnimHierarchy const* pAnimHierarchy ) { const float fStartingPosRadius = 5.0f; Matrix44Identity( &gIdentityMat ); siNumRenderObjects = 1; saRenderObjects = sGameRenderObjectFactory.alloc( siNumRenderObjects ); saAnimModelInstances = sAnimModelInstanceFactory.alloc( siNumRenderObjects ); saObjectInfo = sVectorFactory.alloc( siNumRenderObjects * 3 ); saAnimHierarchies = sAnimHierarchyFactory.alloc( siNumRenderObjects ); memset( saObjectInfo, 0, sizeof( tVector4 ) * siNumRenderObjects * 3 ); float fAnglePart = ( 2.0f * 3.14159f ) / (float)siNumRenderObjects; int iCount = 0; for( int i = 0; i < siNumRenderObjects; i++ ) { // animation model instance tAnimModelInstance* pAnimModelInstance = &saAnimModelInstances[i]; animModelInstanceInit( pAnimModelInstance ); animModelInstanceSet( pAnimModelInstance, pAnimModel ); animModelInstanceSetupGL( pAnimModelInstance ); tGameRenderObject* pRenderObject = &saRenderObjects[i]; pRenderObject->miType = RENDEROBJECT_ANIMMODEL; pRenderObject->mpAnimModelInstance = &saAnimModelInstances[i]; // position, heading and speed pRenderObject->mpPosition = &saObjectInfo[iCount++]; pRenderObject->mpSize = &saObjectInfo[iCount++]; pRenderObject->mpHeading = &saObjectInfo[iCount++]; pRenderObject->mfSpeed = 0.0f; pRenderObject->mpPosition->fW = 1.0f; pRenderObject->mpSize->fW = 1.0f; pRenderObject->mpHeading->fW = 1.0f; // heading tVector4 xVec = { 1.0f, 0.0f, 0.0f, 1.0f }; tMatrix44 rotMatY; Matrix44RotateY( &rotMatY, fAnglePart * (float)i ); Matrix44Transform( pRenderObject->mpHeading, &xVec, &rotMatY ); Vector4Normalize( pRenderObject->mpHeading, pRenderObject->mpHeading ); // position pRenderObject->mpPosition->fX = pRenderObject->mpHeading->fX * fStartingPosRadius - 15.0f; pRenderObject->mpPosition->fZ = pRenderObject->mpHeading->fZ * fStartingPosRadius; pRenderObject->mfAnimMult = 0.5f + (float)( rand() % 500 ) * 0.001f; pRenderObject->mfSpeed = pRenderObject->mfAnimMult; pRenderObject->mfSpeed *= 0.01f; pRenderObject->mpSize->fX = 1.5f; pRenderObject->mpSize->fY = 1.5f; pRenderObject->mpSize->fZ = 1.5f; // duplicate of the hierarchy for storing skin matrices animHierarchyCopy( &saAnimHierarchies[i], pAnimHierarchy, &gJointFactory, &gMatrixFactory ); // use this hierarchy for this model instance pAnimModelInstance->mpAnimHierarchy = &saAnimHierarchies[i]; pAnimModelInstance->mpAnimModel = pAnimModel; pAnimModelInstance->maRotations = (tVector4 *)malloc( sizeof( tVector4 ) ); pAnimModelInstance->maPositions = (tVector4 *)malloc( sizeof( tVector4 ) ); pAnimModelInstance->maScalings = (tVector4 *)malloc( sizeof( tVector4 ) ); pAnimModelInstance->maRotatePivot = (tVector4 *)malloc( sizeof( tVector4 ) ); pAnimModelInstance->maScalePivot = (tVector4 *)malloc( sizeof( tVector4 ) ); //memcpy( pAnimModelInstance->maRotatePivot, &pAnimModel->mCenter, sizeof( tVector4 ) ); //memcpy( pAnimModelInstance->maScalePivot, &pAnimModel->mCenter, sizeof( tVector4 ) ); memset( pAnimModelInstance->maRotatePivot, 0, sizeof( tVector4 ) ); memset( pAnimModelInstance->maScalePivot, 0, sizeof( tVector4 ) ); pAnimModelInstance->miNumXForms = 1; } spAnimSequence = pAnimSequence; }
const Vector4* Vector4::normalize(){return Vector4Normalize(this,*this);}
void octGridGetVisibleNodes( tOctGrid const* pOctGrid, CCamera const* pCamera, std::vector<tOctNode const*>& aVisibleNodes ) { // determine the extent of the frustum tVector4 topLeftNear = { 9999.0f, -9999.0f, 9999.0f }; tVector4 bottomRightFar = { -9999.0f, 9999.0f, -9999.0f }; getExtent( &topLeftNear, &bottomRightFar, &pCamera->mFarBottomLeft ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mFarBottomRight ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mFarTopLeft ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mFarTopRight ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mNearBottomLeft ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mNearBottomRight ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mNearTopLeft ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mNearTopRight ); tVector4 nodeSize = { pOctGrid->mDimension.fX / (float)pOctGrid->miNumNodesInDimension, pOctGrid->mDimension.fY / (float)pOctGrid->miNumNodesInDimension, pOctGrid->mDimension.fZ / (float)pOctGrid->miNumNodesInDimension, 1.0 }; tVector4 gridNearTopLeft = { -nodeSize.fX * (float)pOctGrid->miNumNodesInDimension * 0.5f, nodeSize.fY * (float)pOctGrid->miNumNodesInDimension * 0.5f, -nodeSize.fZ * (float)pOctGrid->miNumNodesInDimension * 0.5f, 1.0f }; tVector4 gridFarBottomRight = { nodeSize.fX * (float)pOctGrid->miNumNodesInDimension * 0.5f, -nodeSize.fY * (float)pOctGrid->miNumNodesInDimension * 0.5f, nodeSize.fZ * (float)pOctGrid->miNumNodesInDimension * 0.5f, 1.0f }; // get the octnode indices in the grid float fLeft = topLeftNear.fX / nodeSize.fX; float fRight = bottomRightFar.fX / nodeSize.fX; float fTop = topLeftNear.fY / nodeSize.fY; float fBottom = bottomRightFar.fY / nodeSize.fY; float fNear = topLeftNear.fZ / nodeSize.fZ; float fFar = bottomRightFar.fZ / nodeSize.fZ; // X int iLeft = (int)ceilf( fLeft ); int iRight = (int)ceilf( fRight ); // Y int iTop = (int)ceilf( fTop ); int iBottom = (int)ceilf( fBottom ); // Z int iNear = (int)ceilf( fNear ); int iFar = (int)ceilf( fFar ); // floor for sign correctness if( fLeft < 0.0 ) { iLeft = (int)floorf( fLeft ); } if( fRight < 0.0 ) { iRight = (int)floorf( fRight ); } if( fTop < 0.0 ) { iTop = (int)floorf( fTop ); } if( fBottom < 0.0 ) { iBottom = (int)floorf( fBottom ); } if( fNear < 0.0 ) { iNear = (int)floorf( fNear ); } if( fFar < 0.0 ) { iFar = (int)floorf( fFar ); } // grid index extent int iGridLeft = (int)floorf( gridNearTopLeft.fX / nodeSize.fX ); int iGridRight = (int)ceilf( gridFarBottomRight.fX / nodeSize.fX ); int iGridTop = (int)ceilf( gridNearTopLeft.fY / nodeSize.fY ); int iGridBottom = (int)ceilf( gridFarBottomRight.fY / nodeSize.fY ); int iGridNear = (int)floorf( gridNearTopLeft.fZ / nodeSize.fZ ); int iGridFar = (int)ceilf( gridFarBottomRight.fZ / nodeSize.fZ ); // clamp if( iLeft < iGridLeft ) { iLeft = iGridLeft; } if( iRight >= iGridRight ) { iRight = iGridRight - 1; } if( iBottom < iGridBottom ) { iBottom = iGridBottom; } if( iTop >= iGridTop ) { iTop = iGridTop - 1; } if( iNear < iGridNear ) { iNear = iGridNear; } if( iFar >= iGridFar ) { iFar = iGridFar - 1; } int iNumNodes = pOctGrid->miNumNodesInDimension; int iHalfNumNodes = iNumNodes >> 1; // shift to (0, num nodes) iLeft += iHalfNumNodes; iRight += iHalfNumNodes; iTop += iHalfNumNodes; iBottom += iHalfNumNodes; iNear += iHalfNumNodes; iFar += iHalfNumNodes; // check for nodes in boundary tOctNode const* aNodes = pOctGrid->maNodes; for( int iZ = iNear; iZ <= iFar; iZ++ ) { for( int iY = iBottom; iY <= iTop; iY++ ) { for( int iX = iLeft; iX <= iRight; iX++ ) { int iIndex = iZ * iNumNodes * iNumNodes + iY * iNumNodes + iX; tOctNode const* pOctNode = &aNodes[iIndex]; bool bInFrustum = pCamera->cubeInFrustum( pOctNode->mpCenter, pOctNode->mfSize ); if( bInFrustum ) { aVisibleNodes.push_back( pOctNode ); //OUTPUT( "%d OCTNODE IN FRUSTUM ( %f, %f, %f )\n", (int)aVisibleNodes.size(), pOctNode->mpCenter->fX, pOctNode->mpCenter->fY, pOctNode->mpCenter->fZ ); } } // for x = left to right } // for y = bottom to top } // for z = near to far #if 0 aVisibleNodes.clear(); // camera direction tVector4 const* pCamPos = pCamera->getPosition(); tVector4 const* pLookAt = pCamera->getLookAt(); tVector4 dir; Vector4Subtract( &dir, pLookAt, pCamPos ); Vector4Normalize( &dir, &dir ); tVector4 const* aCenters = pOctGrid->maNodeCenters; float fNodeSize = pOctGrid->maNodes[0].mfSize; // brute force for now for( int iZ = 0; iZ < iNumNodes; iZ++ ) { for( int iY = 0; iY < iNumNodes; iY++ ) { for( int iX = 0; iX < iNumNodes; iX++ ) { bool bInFrustum = pCamera->cubeInFrustum( aCenters, fNodeSize ); ++aCenters; if( bInFrustum ) { int iIndex = iZ * iNumNodes * iNumNodes + iY * iNumNodes + iX; WTFASSERT2( iIndex < pOctGrid->miNumNodes, "nodes out of bounds while getting visible" ); aVisibleNodes.push_back( &pOctGrid->maNodes[iIndex] ); } } // for x = 0 to num nodes } // for y = 0 to num nodes } // for z = 0 to num nodes #endif // #if 0 }