Esempio n. 1
0
/*
===============
R_InitAnimations
===============
*/
void R_InitAnimations() {
    skelAnimation_t* anim;

    // leave a space for nullptr animation
    tr.numAnimations = 0;

    anim = R_AllocAnimation();
    anim->type = AT_BAD;
    strcpy(anim->name, "<default animation>");
}
Esempio n. 2
0
/*
===============
RE_RegisterAnimationIQM

Animation data has already been loaded
===============
*/
qhandle_t RE_RegisterAnimationIQM( const char *name, IQAnim_t *data )
{
	qhandle_t       hAnim;
	skelAnimation_t *anim;

	if ( !name || !name[ 0 ] )
	{
		Log::Warn("Empty name passed to RE_RegisterAnimationIQM" );
		return 0;
	}

	if ( strlen( name ) >= MAX_QPATH )
	{
		Log::Warn("Animation name exceeds MAX_QPATH" );
			return 0;
	}

	// search the currently loaded animations
	for ( hAnim = 1; hAnim < tr.numAnimations; hAnim++ )
	{
		anim = tr.animations[ hAnim ];

		if ( !Q_stricmp( anim->name, name ) )
		{
			if ( anim->type == animType_t::AT_BAD )
			{
				return 0;
			}

			return hAnim;
		}
	}

	// allocate a new model_t
	if ( ( anim = R_AllocAnimation() ) == nullptr )
	{
		Log::Warn("RE_RegisterAnimationIQM: R_AllocAnimation() failed for '%s'", name );
		return 0;
	}

	// only set the name after the animation has been successfully allocated
	Q_strncpyz( anim->name, name, sizeof( anim->name ) );
	anim->type = animType_t::AT_IQM;
	anim->iqm = data;

	return anim->index;
}
Esempio n. 3
0
/*
===============
RE_RegisterAnimation
===============
*/
qhandle_t RE_RegisterAnimation(const char *name)
{
	qhandle_t       hAnim;
	skelAnimation_t *anim;
	char           *buffer;
	int             bufferLen;
	qboolean		loaded = qfalse;

	if(!name || !name[0])
	{
		ri.Printf(PRINT_WARNING, "Empty name passed to RE_RegisterAnimation\n");
		return 0;
	}

	//ri.Printf(PRINT_ALL, "RE_RegisterAnimation(%s)\n", name);

	if(strlen(name) >= MAX_QPATH)
	{
		ri.Printf(PRINT_WARNING, "Animation name exceeds MAX_QPATH\n");
		return 0;
	}

	// search the currently loaded animations
	for(hAnim = 1; hAnim < tr.numAnimations; hAnim++)
	{
		anim = tr.animations[hAnim];
		if(!Q_stricmp(anim->name, name))
		{
			if(anim->type == AT_BAD)
			{
				return 0;
			}
			return hAnim;
		}

		if(anim->type == AT_PSA && anim->psa)
		{
			const char *animName;

			animName = strstr(name, "::");

			//ri.Printf(PRINT_ALL, "animName = '%s'\n", animName ? (animName + 2) : NULL);
			if(animName && *(animName + 2) && !Q_stricmp(anim->psa->info.name, (animName + 2)))
			{
				return hAnim;
			}
		}
	}

	// allocate a new model_t
	if((anim = R_AllocAnimation()) == NULL)
	{
		ri.Printf(PRINT_WARNING, "RE_RegisterAnimation: R_AllocAnimation() failed for '%s'\n", name);
		return 0;
	}

	// only set the name after the animation has been successfully allocated
	Q_strncpyz(anim->name, name, sizeof(anim->name));

	// make sure the render thread is stopped
	R_SyncRenderThread();

	// load and parse the .md5anim file
	bufferLen = ri.FS_ReadFile(name, (void **)&buffer);
	if(!buffer)
	{
		return 0;
	}

	if(!Q_stricmpn((const char *)buffer, "MD5Version", 10))
	{
		loaded = R_LoadMD5Anim(anim, buffer, bufferLen, name);
	}
	else if(!Q_stricmpn((const char *)buffer, "ANIMHEAD", 8))
	{
		loaded = R_LoadPSA(anim, buffer, bufferLen, name);
	}
	else
	{
		ri.Printf(PRINT_WARNING, "RE_RegisterAnimation: unknown fileid for '%s'\n", name);
	}

	ri.FS_FreeFile(buffer);

	if(!loaded)
	{
		ri.Printf(PRINT_WARNING, "couldn't load '%s'\n", name);

		// we still keep the model_t around, so if the model name is asked for
		// again, we won't bother scanning the filesystem
		anim->type = AT_BAD;
	}

	return anim->index;
}
Esempio n. 4
0
static qboolean R_LoadPSA(skelAnimation_t * skelAnim, void *buffer, int bufferSize, const char *name)
{
	int             i, j, k;
	memStream_t    *stream;
	axChunkHeader_t	chunkHeader;
	int				numReferenceBones;
	axReferenceBone_t *refBone;
	axReferenceBone_t *refBones;

	int				numSequences;
	axAnimationInfo_t *animInfo;

	axAnimationKey_t *key;

	psaAnimation_t *psa;
	skelAnimation_t *extraAnim;
	growList_t      extraAnims;

	stream = AllocMemStream(buffer, bufferSize);
	GetChunkHeader(stream, &chunkHeader);

	// check indent again
	if(Q_stricmpn(chunkHeader.ident, "ANIMHEAD", 8))
	{
		ri.Printf(PRINT_WARNING, "R_LoadPSA: '%s' has wrong chunk indent ('%s' should be '%s')\n", name, chunkHeader.ident, "ANIMHEAD");
		FreeMemStream(stream);
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	// read reference bones
	GetChunkHeader(stream, &chunkHeader);
	if(Q_stricmpn(chunkHeader.ident, "BONENAMES", 9))
	{
		ri.Printf(PRINT_WARNING, "R_LoadPSA: '%s' has wrong chunk indent ('%s' should be '%s')\n", name, chunkHeader.ident, "BONENAMES");
		FreeMemStream(stream);
		return qfalse;
	}

	if(chunkHeader.dataSize != sizeof(axReferenceBone_t))
	{
		ri.Printf(PRINT_WARNING, "R_LoadPSA: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", name, chunkHeader.dataSize, sizeof(axReferenceBone_t));
		FreeMemStream(stream);
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numReferenceBones = chunkHeader.numData;
	if(numReferenceBones < 1)
	{
		ri.Printf(PRINT_WARNING, "R_LoadPSA: '%s' has no bones\n", name);
		FreeMemStream(stream);
		return qfalse;
	}
	if(numReferenceBones > MAX_BONES)
	{
		ri.Printf(PRINT_WARNING, "R_LoadPSA: '%s' has more than %i bones (%i)\n", name, MAX_BONES, numReferenceBones);
		FreeMemStream(stream);
		return qfalse;
	}

	refBones = ri.Hunk_Alloc(numReferenceBones * sizeof(axReferenceBone_t), h_low);
	for(i = 0, refBone = refBones; i < numReferenceBones; i++, refBone++)
	{
		MemStreamRead(stream, refBone->name, sizeof(refBone->name));

		refBone->flags = MemStreamGetLong(stream);
		refBone->numChildren = MemStreamGetLong(stream);
		refBone->parentIndex = MemStreamGetLong(stream);

		if(i == 0)
		{
			refBone->parentIndex = -1;
		}

		GetBone(stream, &refBone->bone);

#if 0
		ri.Printf(PRINT_ALL, "R_LoadPSA: axReferenceBone_t(%i):\n"
				"axReferenceBone_t::name: '%s'\n"
				"axReferenceBone_t::flags: %i\n"
				"axReferenceBone_t::numChildren %i\n"
				"axReferenceBone_t::parentIndex: %i\n"
				"axReferenceBone_t::quat: %f %f %f %f\n"
				"axReferenceBone_t::position: %f %f %f\n"
				"axReferenceBone_t::length: %f\n"
				"axReferenceBone_t::xSize: %f\n"
				"axReferenceBone_t::ySize: %f\n"
				"axReferenceBone_t::zSize: %f\n",
				i,
				refBone->name,
				refBone->flags,
				refBone->numChildren,
				refBone->parentIndex,
				refBone->bone.quat[0], refBone->bone.quat[1], refBone->bone.quat[2], refBone->bone.quat[3],
				refBone->bone.position[0], refBone->bone.position[1], refBone->bone.position[2],
				refBone->bone.length,
				refBone->bone.xSize,
				refBone->bone.ySize,
				refBone->bone.zSize);
#endif
	}

	// load animation info
	GetChunkHeader(stream, &chunkHeader);
	if(Q_stricmpn(chunkHeader.ident, "ANIMINFO", 8))
	{
		ri.Printf(PRINT_WARNING, "R_LoadPSA: '%s' has wrong chunk indent ('%s' should be '%s')\n", name, chunkHeader.ident, "ANIMINFO");
		FreeMemStream(stream);
		return qfalse;
	}

	if(chunkHeader.dataSize != sizeof(axAnimationInfo_t))
	{
		ri.Printf(PRINT_WARNING, "R_LoadPSA: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", name, chunkHeader.dataSize, sizeof(axAnimationInfo_t));
		FreeMemStream(stream);
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numSequences = chunkHeader.numData;
	Com_InitGrowList(&extraAnims, numSequences -1);
	for(i = 0; i < numSequences; i++)
	{
		if(i == 0)
		{
			Q_strncpyz(skelAnim->name, name, sizeof(skelAnim->name));
			skelAnim->type = AT_PSA;
			skelAnim->psa = psa = ri.Hunk_Alloc(sizeof(*psa), h_low);
		}
		else
		{
			// allocate a new skelAnimation_t
			if((extraAnim = R_AllocAnimation()) == NULL)
			{
				ri.Printf(PRINT_WARNING, "R_LoadPSA: R_AllocAnimation() failed for '%s'\n", name);
				return qfalse;
			}

			Q_strncpyz(extraAnim->name, name, sizeof(extraAnim->name));
			extraAnim->type = AT_PSA;
			extraAnim->psa = psa = ri.Hunk_Alloc(sizeof(*psa), h_low);

			Com_AddToGrowList(&extraAnims, extraAnim);
		}

		psa->numBones = numReferenceBones;
		psa->bones = refBones;

		animInfo = &psa->info;

		MemStreamRead(stream, animInfo->name, sizeof(animInfo->name));
		MemStreamRead(stream, animInfo->group, sizeof(animInfo->group));

		animInfo->numBones = MemStreamGetLong(stream);

		if(animInfo->numBones != numReferenceBones)
		{
			ri.Error(ERR_DROP, "R_LoadPSA: axAnimationInfo_t contains different number than reference bones exist: %i != %i for anim '%s'", animInfo->numBones, numReferenceBones, name);
		}

		animInfo->rootInclude = MemStreamGetLong(stream);

		animInfo->keyCompressionStyle = MemStreamGetLong(stream);
		animInfo->keyQuotum = MemStreamGetLong(stream);
		animInfo->keyReduction = MemStreamGetFloat(stream);

		animInfo->trackTime = MemStreamGetFloat(stream);

		animInfo->frameRate = MemStreamGetFloat(stream);

		animInfo->startBoneIndex = MemStreamGetLong(stream);

		animInfo->firstRawFrame = MemStreamGetLong(stream);
		animInfo->numRawFrames = MemStreamGetLong(stream);

#if 0
		ri.Printf(PRINT_ALL, "R_LoadPSA: axAnimationInfo_t(%i):\n"
				"axAnimationInfo_t::name: '%s'\n"
				"axAnimationInfo_t::group: '%s'\n"
				"axAnimationInfo_t::numBones: %i\n"
				"axAnimationInfo_t::rootInclude: %i\n"
				"axAnimationInfo_t::keyCompressionStyle: %i\n"
				"axAnimationInfo_t::keyQuotum: %i\n"
				"axAnimationInfo_t::keyReduction: %f\n"
				"axAnimationInfo_t::trackTime: %f\n"
				"axAnimationInfo_t::frameRate: %f\n"
				"axAnimationInfo_t::startBoneIndex: %i\n"
				"axAnimationInfo_t::firstRawFrame: %i\n"
				"axAnimationInfo_t::numRawFrames: %i\n",
				i,
				animInfo->name,
				animInfo->group,
				animInfo->numBones,
				animInfo->rootInclude,
				animInfo->keyCompressionStyle,
				animInfo->keyQuotum,
				animInfo->keyReduction,
				animInfo->trackTime,
				animInfo->frameRate,
				animInfo->startBoneIndex,
				animInfo->firstRawFrame,
				animInfo->numRawFrames);
#endif
	}

	// load the animation frame keys
	GetChunkHeader(stream, &chunkHeader);
	if(Q_stricmpn(chunkHeader.ident, "ANIMKEYS", 8))
	{
		ri.Printf(PRINT_WARNING, "R_LoadPSA: '%s' has wrong chunk indent ('%s' should be '%s')\n", name, chunkHeader.ident, "ANIMKEYS");
		FreeMemStream(stream);
		return qfalse;
	}

	if(chunkHeader.dataSize != sizeof(axAnimationKey_t))
	{
		ri.Printf(PRINT_WARNING, "R_LoadPSA: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", name, chunkHeader.dataSize, sizeof(axAnimationKey_t));
		FreeMemStream(stream);
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	for(i = 0; i < numSequences; i++)
	{
		if(i == 0)
		{
			psa = skelAnim->psa;
		}
		else
		{
			extraAnim = Com_GrowListElement(&extraAnims, i - 1);
			psa = extraAnim->psa;
		}

		psa->numKeys = psa->info.numBones * psa->info.numRawFrames;
		psa->keys = ri.Hunk_Alloc(psa->numKeys * sizeof(axAnimationKey_t), h_low);

		for(j = 0, key = &psa->keys[0]; j < psa->numKeys; j++, key++)
		{
			for(k = 0; k < 3; k++)
			{
				key->position[k] = MemStreamGetFloat(stream);
			}

			// Tr3B: see R_LoadPSK ...
			if((j % psa->info.numBones) == 0)
			{
				key->quat[0] = MemStreamGetFloat(stream);
				key->quat[1] = -MemStreamGetFloat(stream);
				key->quat[2] = MemStreamGetFloat(stream);
				key->quat[3] = MemStreamGetFloat(stream);
			}
			else
			{
				key->quat[0] = -MemStreamGetFloat(stream);
				key->quat[1] = -MemStreamGetFloat(stream);
				key->quat[2] = -MemStreamGetFloat(stream);
				key->quat[3] = MemStreamGetFloat(stream);
			}

			key->time = MemStreamGetFloat(stream);
		}
	}

	Com_DestroyGrowList(&extraAnims);
	FreeMemStream(stream);

	return qtrue;
}
Esempio n. 5
0
/*
===============
RE_RegisterAnimation
===============
*/
qhandle_t RE_RegisterAnimation( const char *name )
{
	qhandle_t       hAnim;
	skelAnimation_t *anim;
	char            *buffer;
	bool        loaded = false;

	if ( !name || !name[ 0 ] )
	{
		Log::Warn("Empty name passed to RE_RegisterAnimation" );
		return 0;
	}

	//Log::Notice("RE_RegisterAnimation(%s)", name);

	if ( strlen( name ) >= MAX_QPATH )
	{
		Log::Warn("Animation name exceeds MAX_QPATH" );
		return 0;
	}

	// search the currently loaded animations
	for ( hAnim = 1; hAnim < tr.numAnimations; hAnim++ )
	{
		anim = tr.animations[ hAnim ];

		if ( !Q_stricmp( anim->name, name ) )
		{
			if ( anim->type == animType_t::AT_BAD )
			{
				return 0;
			}

			return hAnim;
		}
	}

	// allocate a new model_t
	if ( ( anim = R_AllocAnimation() ) == nullptr )
	{
		Log::Warn("RE_RegisterAnimation: R_AllocAnimation() failed for '%s'", name );
		return 0;
	}

	// only set the name after the animation has been successfully allocated
	Q_strncpyz( anim->name, name, sizeof( anim->name ) );

	// make sure the render thread is stopped
	R_SyncRenderThread();

	// load and parse the .md5anim file
	int bufferLen = ri.FS_ReadFile( name, ( void ** ) &buffer );

	if ( !buffer )
	{
		return 0;
	}

	if ( bufferLen >= 10 && !Q_strnicmp( ( const char * ) buffer, "MD5Version", 10 ) )
	{
		loaded = R_LoadMD5Anim( anim, buffer, name );
	}
	else
	{
		Log::Warn("RE_RegisterAnimation: unknown fileid for '%s'", name );
	}

	ri.FS_FreeFile( buffer );

	if ( !loaded )
	{
		Log::Warn("couldn't load '%s'", name );

		// we still keep the model_t around, so if the model name is asked for
		// again, we won't bother scanning the filesystem
		anim->type = animType_t::AT_BAD;
	}

	return anim->index;
}