예제 #1
0
파일: r_skm.c 프로젝트: codetwister/qfusion
/*
* 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;
}
예제 #2
0
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;
}
예제 #3
0
		const Vector4* Vector4::normalize(){return Vector4Normalize(this,*this);}
예제 #4
0
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
    
}