xash3d-fwgs/ref/vk/vk_previous_frame.c
Ivan Avdeev e54913f8af rt: improve prev frame bone matrix tracking for studio models
Still has some artifacts, but is generally rather close. Will look at
this again when caching studio model BLASes, as we'd be able to look at
them without extra animations.
2023-05-15 09:47:03 -07:00

128 lines
3.6 KiB
C

#include "vk_studio.h"
#include "vk_common.h"
#include "vk_textures.h"
#include "vk_render.h"
#include "vk_geometry.h"
#include "camera.h"
#include "xash3d_mathlib.h"
#include "const.h"
#include "r_studioint.h"
#include "triangleapi.h"
#include "studio.h"
#include "pm_local.h"
#include "pmtrace.h"
#include "protocol.h"
#include "enginefeatures.h"
#include "pm_movevars.h"
#include "xash3d_types.h"
#include <memory.h>
#include <stdlib.h>
#define PREV_STATES_COUNT 1024
#define PREV_FRAMES_COUNT 2
typedef struct {
matrix3x4 bones_worldtransform[MAXSTUDIOBONES];
matrix4x4 model_transform;
float time;
uint bones_frame_updated;
uint frame_updated;
} prev_state_t;
typedef struct {
prev_state_t prev_states[PREV_FRAMES_COUNT][PREV_STATES_COUNT];
uint frame_index;
uint prev_frame_index;
uint current_frame_id;
uint previous_frame_id;
} prev_states_storage_t;
prev_states_storage_t g_prev = { 0 };
prev_state_t* prevStateInArrayBounds( int frame_storage_id, int entity_id )
{
int clamped_entity_id = entity_id;
if (entity_id >= PREV_STATES_COUNT)
{
gEngine.Con_Printf("Previous frame states data for entity %d overflows storage (size is %d). Increase it\n", entity_id, PREV_STATES_COUNT);
clamped_entity_id = PREV_STATES_COUNT - 1; // fallback to last correct value
}
else if (entity_id < 0)
{
clamped_entity_id = 0; // fallback to correct value
}
return &g_prev.prev_states[frame_storage_id][clamped_entity_id];
}
#define PREV_FRAME(entity_id) prevStateInArrayBounds( g_prev.previous_frame_id, (entity_id) )
#define CURRENT_FRAME(entity_id) prevStateInArrayBounds( g_prev.current_frame_id, (entity_id) )
void R_PrevFrame_StartFrame( void )
{
g_prev.frame_index++;
g_prev.current_frame_id = g_prev.frame_index % PREV_FRAMES_COUNT;
g_prev.previous_frame_id = (g_prev.frame_index - 1) % PREV_FRAMES_COUNT;
}
void R_PrevFrame_SaveCurrentBoneTransforms( int entity_id, matrix3x4* bones_transforms, const matrix4x4 rotationmatrix_inv )
{
prev_state_t *current_frame = CURRENT_FRAME(entity_id);
if (current_frame->bones_frame_updated == g_prev.frame_index)
return; // already updated for this entity
current_frame->bones_frame_updated = g_prev.frame_index;
for( int i = 0; i < MAXSTUDIOBONES; i++ )
Matrix3x4_ConcatTransforms( current_frame->bones_worldtransform[i], rotationmatrix_inv, bones_transforms[i] );
}
void R_PrevFrame_SaveCurrentState( int entity_id, matrix4x4 model_transform )
{
prev_state_t* current_frame = CURRENT_FRAME(entity_id);
if (current_frame->frame_updated == g_prev.frame_index)
return; // already updated for this entity
Matrix4x4_Copy( current_frame->model_transform, model_transform );
current_frame->time = gpGlobals->time;
current_frame->frame_updated = g_prev.frame_index;
}
matrix3x4* R_PrevFrame_BoneTransforms( int entity_id )
{
prev_state_t* prev_frame = PREV_FRAME(entity_id);
// fallback to current frame if previous is outdated
if (prev_frame->bones_frame_updated != g_prev.frame_index - 1)
return CURRENT_FRAME(entity_id)->bones_worldtransform;
return prev_frame->bones_worldtransform;
}
void R_PrevFrame_ModelTransform( int entity_id, matrix4x4 model_matrix )
{
prev_state_t* prev_frame = PREV_FRAME(entity_id);
// fallback to current frame if previous is outdated
if (prev_frame->frame_updated != g_prev.frame_index - 1)
prev_frame = CURRENT_FRAME(entity_id);
Matrix4x4_Copy(model_matrix, prev_frame->model_transform);
}
float R_PrevFrame_Time( int entity_id )
{
prev_state_t* prev_frame = PREV_FRAME(entity_id);
// fallback to current frame if previous is outdated
if (prev_frame->frame_updated != g_prev.frame_index - 1)
return gpGlobals->time;
return prev_frame->time;
}