Skip to content

Commit

Permalink
Move skeleton building and blending to engine
Browse files Browse the repository at this point in the history
  • Loading branch information
VReaperV committed Jan 8, 2025
1 parent 782d78f commit 06b3c18
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 13 deletions.
28 changes: 24 additions & 4 deletions src/engine/client/cg_msgdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,38 @@ namespace Util {
}
};

template<> struct SerializeTraits<std::vector<BoneMod>> {
static void Write( Writer& stream, const std::vector<BoneMod>& boneMods ) {
stream.WriteSize( boneMods.size() );
stream.WriteData( boneMods.data(), boneMods.size() * sizeof( BoneMod ) );
}

static std::vector<BoneMod> Read( Reader& stream ) {
std::vector<BoneMod> boneMods;
const size_t size = stream.ReadSize<BoneMod>();
boneMods.resize( size );
stream.ReadData( boneMods.data(), size * sizeof( BoneMod ) );
return boneMods;
}
};

// Use that bone optimization for refEntity_t
template<> struct SerializeTraits<refEntity_t> {
static void Write(Writer& stream, const refEntity_t& ent)
{
stream.WriteData(&ent, offsetof(refEntity_t, skeleton));
stream.Write<refSkeleton_t>(ent.skeleton);
stream.WriteData(&ent, offsetof(refEntity_t, tag));
stream.Write<std::string>( ent.tag );
stream.Write<std::vector<BoneMod>>( ent.boneMods );
// stream.Write<refSkeleton_t>(ent.skeleton);
}

static refEntity_t Read(Reader& stream)
{
refEntity_t ent;
stream.ReadData(&ent, offsetof(refEntity_t, skeleton));
ent.skeleton = stream.Read<refSkeleton_t>();
stream.ReadData(&ent, offsetof(refEntity_t, tag));
ent.tag = stream.Read<std::string>();
ent.boneMods = stream.Read<std::vector<BoneMod>>();
// ent.skeleton = stream.Read<refSkeleton_t>();
return ent;
}
};
Expand Down
27 changes: 27 additions & 0 deletions src/engine/renderer/tr_animation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,32 @@ static int IQMBuildSkeleton( refSkeleton_t *skel, skelAnimation_t *skelAnim,
return true;
}

void R_TransformSkeleton( refSkeleton_t* skel, const float scale ) {
skel->scale = scale;

switch ( skel->type ) {
case refSkeletonType_t::SK_INVALID:
case refSkeletonType_t::SK_ABSOLUTE:
return;

default:
break;
}

// calculate absolute transforms
for ( refBone_t* bone = &skel->bones[0]; bone < &skel->bones[skel->numBones]; bone++ ) {
if ( bone->parentIndex >= 0 ) {
refBone_t* parent;

parent = &skel->bones[bone->parentIndex];

TransCombine( &bone->t, &parent->t, &bone->t );
}
}

skel->type = refSkeletonType_t::SK_ABSOLUTE;
}

/*
==============
RE_BuildSkeleton
Expand Down Expand Up @@ -1468,6 +1494,7 @@ int RE_BuildSkeleton( refSkeleton_t *skel, qhandle_t hAnim, int startFrame, int
}

// FIXME: clear existing bones and bounds?
skel->numBones = 0;
return false;
}

Expand Down
1 change: 1 addition & 0 deletions src/engine/renderer/tr_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -3730,6 +3730,7 @@ inline bool checkGLErrors()
int RE_CheckSkeleton( refSkeleton_t *skel, qhandle_t hModel, qhandle_t hAnim );
int RE_BuildSkeleton( refSkeleton_t *skel, qhandle_t anim, int startFrame, int endFrame, float frac,
bool clearOrigin );
void R_TransformSkeleton( refSkeleton_t* skel, const float scale );
int RE_BlendSkeleton( refSkeleton_t *skel, const refSkeleton_t *blend, float frac );
int RE_AnimNumFrames( qhandle_t hAnim );
int RE_AnimFrameRate( qhandle_t hAnim );
Expand Down
162 changes: 158 additions & 4 deletions src/engine/renderer/tr_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2031,6 +2031,33 @@ static void R_SortDrawSurfs()
R_AddDrawViewCmd( false );
}

static void PositionEntityOnTag( refEntity_t* entity, const refEntity_t* parent, orientation_t* orientation ) {
// FIXME: allow origin offsets along tag?
VectorCopy( parent->origin, entity->origin );

for ( int i = 0; i < 3; i++ ) {
VectorMA( entity->origin, orientation->origin[i], parent->axis[i], entity->origin );
}

// had to cast away the const to avoid compiler problems...
AxisMultiply( orientation->axis, ( ( refEntity_t* ) parent )->axis, entity->axis );
entity->backlerp = parent->backlerp;
}

static void PositionRotatedEntityOnTag( refEntity_t* entity, const refEntity_t* parent, orientation_t* orientation ) {
// FIXME: allow origin offsets along tag?
VectorCopy( parent->origin, entity->origin );

for ( int i = 0; i < 3; i++ ) {
VectorMA( entity->origin, orientation->origin[i], parent->axis[i], entity->origin );
}

// had to cast away the const to avoid compiler problems...
axis_t tempAxis;
AxisMultiply( entity->axis, orientation->axis, tempAxis );
AxisMultiply( tempAxis, ( ( refEntity_t* ) parent )->axis, entity->axis );
}

/*
=============
R_AddEntitySurfaces
Expand Down Expand Up @@ -2095,19 +2122,146 @@ void R_AddEntitySurfaces()
}
else
{
switch ( tr.currentModel->type )
{
switch ( tr.currentModel->type ) {
case modtype_t::MOD_MESH:
R_AddMDVSurfaces( ent );
break;

case modtype_t::MOD_MD5:
R_AddMD5Surfaces( ent );
/* Log::Warn("%i %s: old: %i-%i %f new: %i-%i %f | %f %f", ent->e.animationHandle,
R_GetAnimationByHandle( ent->e.animationHandle )->name, ent->e.startFrame,
ent->e.endFrame, ent->e.lerp, ent->e.startFrame2, ent->e.endFrame2, ent->e.lerp2,
ent->e.blendLerp, ent->e.scale ); */
switch ( ent->e.positionOnTag ) {
case EntityTag::ON_TAG:
{
orientation_t orientation;
RE_LerpTagET( &orientation, &tr.refdef.entities[ent->e.attachmentEntity].e, ent->e.tag.c_str(), 0 );
PositionEntityOnTag( &ent->e, &tr.refdef.entities[ent->e.attachmentEntity].e, &orientation );
R_RotateEntityForViewParms( ent, &tr.viewParms, &tr.orientation );
break;
}

case EntityTag::ON_TAG_ROTATED:
{
orientation_t orientation;
RE_LerpTagET( &orientation, &tr.refdef.entities[ent->e.attachmentEntity].e, ent->e.tag.c_str(), 0 );
PositionRotatedEntityOnTag( &ent->e, &tr.refdef.entities[ent->e.attachmentEntity].e, &orientation );
R_RotateEntityForViewParms( ent, &tr.viewParms, &tr.orientation );
break;
}

case EntityTag::NONE:
default:
break;
}

if ( ent->e.scale == 0 ) {
ent->e.scale = 1;
}
if ( ent->e.animationHandle == 0 ) {
ent->e.animationHandle = ent->e.animationHandle2;
} else if ( ent->e.animationHandle2 == 0 ) {
ent->e.animationHandle2 = ent->e.animationHandle;
}

RE_BuildSkeleton( &ent->e.skeleton, ent->e.animationHandle, ent->e.startFrame, ent->e.endFrame,
ent->e.lerp, ent->e.clearOrigin );
ent->e.skeleton.scale = ent->e.scale;
if ( ent->e.blendLerp > 0.0 ) {
refSkeleton_t skel;
RE_BuildSkeleton( &skel, ent->e.animationHandle2, ent->e.startFrame2, ent->e.endFrame2,
ent->e.lerp2, ent->e.clearOrigin2 );
RE_BlendSkeleton( &ent->e.skeleton, &skel, ent->e.blendLerp );
}

for ( const BoneMod& boneMod : ent->e.boneMods ) {
QuatMultiply2( ent->e.skeleton.bones[boneMod.index].t.rot, boneMod.rotation );
}

if ( ent->e.boundsAdd ) {
matrix_t mat;
vec3_t bounds[2];

MatrixFromAngles( mat, ent->e.boundsRotation[0], ent->e.boundsRotation[1], ent->e.boundsRotation[2] );
MatrixTransformBounds( mat, ent->e.skeleton.bounds[0], ent->e.skeleton.bounds[1], bounds[0], bounds[1] );
BoundsAdd( ent->e.skeleton.bounds[0], ent->e.skeleton.bounds[1], bounds[0], bounds[1] );
}

if ( !( ent->e.renderfx & RF_NORENDER ) ) {
R_AddMD5Surfaces( ent );
}
break;

case modtype_t::MOD_IQM:
R_AddIQMSurfaces( ent );
{
/* Log::Warn("%i %s: old: %i-%i %f new: %i-%i %f | %f %f", ent->e.animationHandle,
R_GetAnimationByHandle( ent->e.animationHandle )->name, ent->e.startFrame,
ent->e.endFrame, ent->e.lerp, ent->e.startFrame2, ent->e.endFrame2, ent->e.lerp2,
ent->e.blendLerp, ent->e.scale ); */
switch ( ent->e.positionOnTag ) {
case EntityTag::ON_TAG:
{
orientation_t orientation;
RE_LerpTagET( &orientation, &tr.refdef.entities[ent->e.attachmentEntity].e, ent->e.tag.c_str(), 0 );
PositionEntityOnTag( &ent->e, &tr.refdef.entities[ent->e.attachmentEntity].e, &orientation );
R_RotateEntityForViewParms( ent, &tr.viewParms, &tr.orientation );
break;
}

case EntityTag::ON_TAG_ROTATED:
{
orientation_t orientation;
RE_LerpTagET( &orientation, &tr.refdef.entities[ent->e.attachmentEntity].e, ent->e.tag.c_str(), 0 );
PositionRotatedEntityOnTag( &ent->e, &tr.refdef.entities[ent->e.attachmentEntity].e, &orientation );
R_RotateEntityForViewParms( ent, &tr.viewParms, &tr.orientation );
break;
}

case EntityTag::NONE:
default:
break;
}

bool transform = true;
if ( ent->e.scale == 0 ) {
ent->e.scale = 1;
}
if ( ent->e.animationHandle == 0 ) {
ent->e.animationHandle = ent->e.animationHandle2;
} else if ( ent->e.animationHandle2 == 0 ) {
ent->e.animationHandle2 = ent->e.animationHandle;
}

ent->e.skeleton.scale = ent->e.scale;
RE_BuildSkeleton( &ent->e.skeleton, ent->e.animationHandle, ent->e.startFrame, ent->e.endFrame,
ent->e.lerp, ent->e.clearOrigin );
if ( ent->e.blendLerp > 0.0 ) {
refSkeleton_t skel;
RE_BuildSkeleton( &skel, ent->e.animationHandle2, ent->e.startFrame2, ent->e.endFrame2,
ent->e.lerp2, ent->e.clearOrigin2 );
RE_BlendSkeleton( &ent->e.skeleton, &skel, ent->e.blendLerp );
}

for ( const BoneMod& boneMod : ent->e.boneMods ) {
QuatMultiply2( ent->e.skeleton.bones[boneMod.index].t.rot, boneMod.rotation );
}
R_TransformSkeleton( &ent->e.skeleton, ent->e.scale );

if ( ent->e.boundsAdd ) {
matrix_t mat;
vec3_t bounds[2];

MatrixFromAngles( mat, ent->e.boundsRotation[0], ent->e.boundsRotation[1], ent->e.boundsRotation[2] );
MatrixTransformBounds( mat, ent->e.skeleton.bounds[0], ent->e.skeleton.bounds[1], bounds[0], bounds[1] );
BoundsAdd( ent->e.skeleton.bounds[0], ent->e.skeleton.bounds[1], bounds[0], bounds[1] );
}

if ( !( ent->e.renderfx & RF_NORENDER ) ) {
R_AddIQMSurfaces( ent );
}
break;
}

case modtype_t::MOD_BSP:
R_AddBSPModelSurfaces( ent );
Expand Down
35 changes: 35 additions & 0 deletions src/engine/renderer/tr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ using bool8_t = uint8_t;
// animation without needing to know the frame count
#define RF_FORCENOLOD 0x000400
#define RF_SWAPCULL 0x000800 // swap CT_FRONT_SIDED and CT_BACK_SIDED
#define RF_NORENDER 0x001000 // HACK: This is only used to put weapons in correct positions on skeletal models

// refdef flags
#define RDF_NOWORLDMODEL ( 1 << 0 ) // used for player configuration screen
Expand Down Expand Up @@ -156,6 +157,12 @@ enum class refSkeletonType_t
SK_ABSOLUTE
};

struct BoneMod {
int index;
vec3_t translation;
quat_t rotation;
};

struct alignas(16) refSkeleton_t
{
refSkeletonType_t type; // skeleton has been reset
Expand All @@ -170,6 +177,12 @@ struct alignas(16) refSkeleton_t

// XreaL END

enum class EntityTag {
NONE,
ON_TAG,
ON_TAG_ROTATED
};

struct refEntity_t
{
refEntityType_t reType;
Expand Down Expand Up @@ -211,6 +224,28 @@ struct refEntity_t

int altShaderIndex;

qhandle_t animationHandle;
int startFrame;
int endFrame;
float lerp;
int clearOrigin;
qhandle_t animationHandle2;
int startFrame2;
int endFrame2;
float lerp2;
int clearOrigin2;
float blendLerp;
float scale;

int boundsAdd;
vec3_t boundsRotation;

EntityTag positionOnTag = EntityTag::NONE;
int attachmentEntity;
std::string tag;

std::vector<BoneMod> boneMods;

// KEEP SKELETON AT THE END OF THE STRUCTURE
// it is to make a serialization hack for refEntity_t easier
// by memcpying up to skeleton and then serializing skeleton
Expand Down
13 changes: 10 additions & 3 deletions src/shared/client/cg_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,14 @@ void trap_R_ClearScene()
cmdBuffer.SendMsg<Render::ClearSceneMsg>();
}

void trap_R_AddRefEntityToScene( const refEntity_t *re )
/* HACK: We need the entityNum to get the correct positions for entities that need to be attached to another entity's bone
This must be equal to the r_numEntities in engine at the time of adding the entity */
static int entityNum;
int trap_R_AddRefEntityToScene( const refEntity_t *re )
{
cmdBuffer.SendMsg<Render::AddRefEntityToSceneMsg>(*re);
entityNum++;
return entityNum - 1;
}

void trap_R_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts )
Expand Down Expand Up @@ -362,6 +367,7 @@ void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r,

void trap_R_RenderScene( const refdef_t *fd )
{
entityNum = 0;
cmdBuffer.SendMsg<Render::RenderSceneMsg>(*fd);
}

Expand Down Expand Up @@ -403,7 +409,7 @@ void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs )
VectorCopy(mymaxs, maxs);
}

int trap_R_LerpTag( orientation_t *tag, const refEntity_t *refent, const char *tagName, int startIndex )
int trap_R_LerpTag( orientation_t *tag, const refEntity_t* refent, const char *tagName, int startIndex )
{
int result;
VM::SendMsg<Render::LerpTagMsg>(*refent, tagName, startIndex, *tag, result);
Expand Down Expand Up @@ -448,6 +454,7 @@ qhandle_t trap_R_RegisterAnimation( const char *name )
int trap_R_BuildSkeleton( refSkeleton_t *skel, qhandle_t anim, int startFrame, int endFrame, float frac, bool clearOrigin )
{
int result;
skel->numBones = 0;
VM::SendMsg<Render::BuildSkeletonMsg>(anim, startFrame, endFrame, frac, clearOrigin, *skel, result);
return result;
}
Expand All @@ -460,7 +467,7 @@ int trap_R_BlendSkeleton( refSkeleton_t *skel, const refSkeleton_t *blend, float

if ( skel->numBones != blend->numBones )
{
Log::Warn("trap_R_BlendSkeleton: different number of bones %d != %d", skel->numBones, blend->numBones);
// Log::Warn("trap_R_BlendSkeleton: different number of bones %d != %d", skel->numBones, blend->numBones);
return false;
}

Expand Down
Loading

0 comments on commit 06b3c18

Please sign in to comment.