mirror of
https://github.com/BanjoRecomp/BanjoRecomp
synced 2026-07-07 20:11:58 -04:00
Manual vertex velocity computation. (#46)
* Update RT64 for vertex velocity segment support. * Switch to using extended velocity data for CPU skinning. * Integrate actor tracking into vertex velocity calculation * Add vertex velocity calculation to overlay draws (e.g. Clanker) --------- Co-authored-by: Mr-Wiseguy <mrwiseguyromhacking@gmail.com>
This commit is contained in:
+1
-1
Submodule lib/rt64 updated: b5b19802c0...1583c508d3
@@ -14,6 +14,9 @@ extern struct {
|
||||
void (*unk14)(s32, s32);
|
||||
} sOverlay;
|
||||
|
||||
void recomp_setup_overlay_skinning(int overlay_id);
|
||||
void recomp_clear_overlay_skinning();
|
||||
|
||||
// @recomp: Patched to assign an ID to Clanker.
|
||||
RECOMP_PATCH void func_80322E64(Gfx **gfx, Mtx **mtx, Vtx **vtx){
|
||||
// @recomp If the current level is Clanker's Cavern, set up the model ID for Clanker.
|
||||
@@ -22,8 +25,14 @@ RECOMP_PATCH void func_80322E64(Gfx **gfx, Mtx **mtx, Vtx **vtx){
|
||||
cur_drawn_model_transform_id = CLANKER_TRANSFORM_ID_START;
|
||||
}
|
||||
|
||||
// @recomp Setup the overlay skinning data.
|
||||
recomp_setup_overlay_skinning(overlayManagergetLoadedId());
|
||||
|
||||
if(sOverlay.draw)
|
||||
sOverlay.draw(gfx, mtx, vtx);
|
||||
|
||||
// @recomp Clear the overlay skinning setup.
|
||||
recomp_clear_overlay_skinning();
|
||||
|
||||
// @recomp Reset the current transform ID.
|
||||
cur_drawn_model_transform_id = prev_transform_id;
|
||||
|
||||
@@ -11,6 +11,7 @@ void animMtxList_setBoned(AnimMtxList **this_ptr, BKAnimationList *anim_list, Bo
|
||||
|
||||
extern s32 cur_model_would_have_been_culled_in_demo;
|
||||
bool recomp_in_demo_playback_game_mode();
|
||||
void recomp_setup_marker_skinning(ActorMarker *marker);
|
||||
|
||||
int frustum_checks_enabled = TRUE;
|
||||
void set_frustum_checks_enabled(int enabled) {
|
||||
@@ -188,6 +189,9 @@ RECOMP_PATCH void actor_predrawMethod(Actor *this){
|
||||
}
|
||||
|
||||
if(this->unkF4_30){
|
||||
// @recomp Set up skinning data for this actor.
|
||||
recomp_setup_marker_skinning(this->marker);
|
||||
|
||||
sp40 = func_80330C74(this);
|
||||
if(this->unk138_29){
|
||||
sp34[0] = this->pitch;
|
||||
|
||||
@@ -10,12 +10,17 @@
|
||||
|
||||
RECOMP_DECLARE_EVENT(recomp_on_init());
|
||||
|
||||
void recomp_init_vertex_skinning(void);
|
||||
|
||||
// @recomp Patched to perform some initialization after core2 has been loaded.
|
||||
RECOMP_PATCH void dummy_func_8025AFB0(void) {
|
||||
// @recomp Initialize note saving data before the init event is run.
|
||||
// This will allow mods to override it as necessary.
|
||||
init_note_saving();
|
||||
|
||||
// @recomp Perform the necessary initialization for vertex skinning.
|
||||
recomp_init_vertex_skinning();
|
||||
|
||||
// @recomp Register actor extension data and call the init event.
|
||||
recomp_on_init();
|
||||
|
||||
|
||||
@@ -74,6 +74,9 @@ void osWriteBackDCacheAll(void);
|
||||
#define gEXMatrixGroupDecomposedNormal(cmd, id, push, proj, edit) \
|
||||
gEXMatrixGroupDecomposed(cmd, id, push, proj, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE, G_EX_ORDER_LINEAR, edit, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_AUTO)
|
||||
|
||||
#define gEXMatrixGroupDecomposedNormalTcs(cmd, id, push, proj, edit) \
|
||||
gEXMatrixGroupDecomposed(cmd, id, push, proj, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE, G_EX_ORDER_LINEAR, edit, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_AUTO)
|
||||
|
||||
#define gEXMatrixGroupDecomposedSkipRot(cmd, id, push, proj, edit) \
|
||||
gEXMatrixGroupDecomposed(cmd, id, push, proj, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE, G_EX_ORDER_LINEAR, edit, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_AUTO)
|
||||
|
||||
|
||||
+111
-35
@@ -35,6 +35,7 @@ s32 cur_drawn_model_skip_interpolation = FALSE;
|
||||
s32 cur_model_transform_id_offset = 0;
|
||||
s32 cur_model_uses_bones = FALSE;
|
||||
s32 cur_model_would_have_been_culled_in_demo = FALSE;
|
||||
s32 cur_model_uses_ex_vertex = FALSE;
|
||||
|
||||
Mtx identity_fixed_mtx = {{
|
||||
{
|
||||
@@ -211,24 +212,18 @@ bool set_model_matrix_group(Gfx **gfx, void *geo_list, bool skip_rotation) {
|
||||
// Skip interpolation if all interpolation is currently skipped or the transform was specified to be skipped.
|
||||
gEXMatrixGroupSkipAll((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
}
|
||||
else if (cur_model_uses_bones) {
|
||||
// Tag the matrix with simple matrix interpolation if the model uses bones.
|
||||
if (skip_rotation) {
|
||||
gEXMatrixGroupSimpleVertsSkipRot((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
}
|
||||
else {
|
||||
gEXMatrixGroupSimpleVerts((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Tag the matrix with decomposed matrix interpolation on any other model.
|
||||
if (skip_rotation) {
|
||||
gEXMatrixGroupDecomposedVertsSkipRot((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
}
|
||||
else {
|
||||
gEXMatrixGroupDecomposedVerts((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
}
|
||||
// Tag the matrix with simple matrix interpolation if the model uses bones.
|
||||
// Use decomposed matrix interpolation on any other model.
|
||||
u8 interpolation_mode = cur_model_uses_bones ? G_EX_INTERPOLATE_SIMPLE : G_EX_INTERPOLATE_DECOMPOSE;
|
||||
u8 rotation_mode = skip_rotation ? G_EX_COMPONENT_SKIP : G_EX_COMPONENT_INTERPOLATE;
|
||||
u8 vertex_interpolation_mode = cur_drawn_model_is_map ? G_EX_COMPONENT_INTERPOLATE : G_EX_COMPONENT_SKIP;
|
||||
u8 texcoord_interpolation_mode = cur_drawn_model_is_map ? G_EX_COMPONENT_INTERPOLATE : G_EX_COMPONENT_SKIP;
|
||||
gEXMatrixGroup((*gfx)++, group_id, interpolation_mode, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_COMPONENT_INTERPOLATE, rotation_mode,
|
||||
G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, vertex_interpolation_mode, G_EX_COMPONENT_INTERPOLATE,
|
||||
G_EX_ORDER_LINEAR, G_EX_EDIT_NONE, G_EX_ASPECT_AUTO, texcoord_interpolation_mode, G_EX_COMPONENT_AUTO);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (skip_all_interpolation) {
|
||||
@@ -451,31 +446,79 @@ RECOMP_PATCH void func_80339124(Gfx ** gfx, Mtx ** mtx, BKGeoList *geo_list){
|
||||
}while(1);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
u32 frameCount;
|
||||
u32 modelId;
|
||||
u32 floatStart;
|
||||
} ModelSkinningData;
|
||||
|
||||
// @recomp Applies CPU skinning and saves the result to a higher precision vertex buffer.
|
||||
#define SKINNING_POSITIONS_MAX 65536
|
||||
|
||||
f32 sSkinningFloats[SKINNING_POSITIONS_MAX] __attribute__((aligned(8)));
|
||||
f32 sSkinningPosFloats[2][SKINNING_POSITIONS_MAX] __attribute__((aligned(8)));
|
||||
f32 sSkinningVelFloats[SKINNING_POSITIONS_MAX] __attribute__((aligned(8)));
|
||||
u32 sSkinningFloatCount;
|
||||
u32 sSkinningFloatFrame;
|
||||
MarkerExtensionId sMarkerSkinningExtensionId;
|
||||
ModelSkinningData *sCurModelSkinningData;
|
||||
u32 sCurModelId;
|
||||
|
||||
ModelSkinningData sOverlaySkinningData;
|
||||
|
||||
void recomp_setup_overlay_skinning(int overlay_id) {
|
||||
sCurModelSkinningData = &sOverlaySkinningData;
|
||||
sCurModelId = overlay_id; // Using the overlay ID as the model ID since there's no easy way to get the model ID for overlay draws.
|
||||
}
|
||||
|
||||
void recomp_clear_overlay_skinning() {
|
||||
sCurModelSkinningData = NULL;
|
||||
sCurModelId = 0;
|
||||
}
|
||||
|
||||
void recomp_reset_skinning_stack() {
|
||||
sSkinningFloatCount = 0;
|
||||
sSkinningFloatFrame++;
|
||||
}
|
||||
|
||||
float *recomp_apply_cpu_skinning(BKModelUnk28List *arg0, BKVertexList *arg1, AnimMtxList *mtx_list) {
|
||||
void recomp_init_vertex_skinning() {
|
||||
sMarkerSkinningExtensionId = bkrecomp_extend_marker_all(sizeof(ModelSkinningData));
|
||||
}
|
||||
|
||||
void recomp_setup_marker_skinning(ActorMarker *marker) {
|
||||
sCurModelSkinningData = bkrecomp_get_extended_marker_data(marker, sMarkerSkinningExtensionId);
|
||||
sCurModelId = marker->modelId;
|
||||
}
|
||||
|
||||
bool recomp_apply_cpu_skinning(BKModelUnk28List *arg0, BKVertexList *arg1, AnimMtxList *mtx_list, float **pos, float **vel) {
|
||||
*pos = NULL;
|
||||
*vel = NULL;
|
||||
|
||||
ModelSkinningData prev_skinning_data = {0};
|
||||
u32 cur_model_id = sCurModelId;
|
||||
if (sCurModelSkinningData != NULL) {
|
||||
prev_skinning_data = *sCurModelSkinningData;
|
||||
sCurModelSkinningData->frameCount = sSkinningFloatFrame;
|
||||
sCurModelSkinningData->modelId = cur_model_id;
|
||||
sCurModelSkinningData->floatStart = sSkinningFloatCount;
|
||||
}
|
||||
sCurModelSkinningData = NULL;
|
||||
sCurModelId = 0;
|
||||
|
||||
if (sSkinningFloatCount + (arg1->count * 3) > SKINNING_POSITIONS_MAX) {
|
||||
return NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Copy unmodified positions.
|
||||
float *dst_pos = &sSkinningFloats[sSkinningFloatCount];
|
||||
s32 i, j;
|
||||
float *dst_pos = &sSkinningPosFloats[sSkinningFloatFrame & 0x1][sSkinningFloatCount];
|
||||
s32 i, j = 0;
|
||||
for (i = 0; i < arg1->count; i++) {
|
||||
sSkinningFloats[sSkinningFloatCount++] = arg1->vtx_18[i].v.ob[0];
|
||||
sSkinningFloats[sSkinningFloatCount++] = arg1->vtx_18[i].v.ob[1];
|
||||
sSkinningFloats[sSkinningFloatCount++] = arg1->vtx_18[i].v.ob[2];
|
||||
dst_pos[j++] = arg1->vtx_18[i].v.ob[0];
|
||||
dst_pos[j++] = arg1->vtx_18[i].v.ob[1];
|
||||
dst_pos[j++] = arg1->vtx_18[i].v.ob[2];
|
||||
}
|
||||
|
||||
// Always align to multiples of 2.
|
||||
|
||||
// Increase the current float count. Always align to multiples of 2.
|
||||
sSkinningFloatCount += arg1->count * 3;
|
||||
if (sSkinningFloatCount & 0x1) {
|
||||
sSkinningFloatCount++;
|
||||
}
|
||||
@@ -507,7 +550,25 @@ float *recomp_apply_cpu_skinning(BKModelUnk28List *arg0, BKVertexList *arg1, Ani
|
||||
i_ptr = (BKModelUnk28 *)((s16 *)(i_ptr + 1) + (i_ptr->vtx_count - 1));
|
||||
}
|
||||
|
||||
return dst_pos;
|
||||
// Compute velocities if applicable.
|
||||
// To apply, the frame index stored on the extended marker data must be exactly the previous frame and the model ID must match.
|
||||
if (prev_skinning_data.frameCount == sSkinningFloatFrame - 1 && prev_skinning_data.modelId == cur_model_id) {
|
||||
const float *prev_pos = &sSkinningPosFloats[(sSkinningFloatFrame & 0x1) ^ 1][prev_skinning_data.floatStart];
|
||||
float *dst_vel = &sSkinningVelFloats[sSkinningFloatCount];
|
||||
j = 0;
|
||||
for (i = 0; i < arg1->count; i++) {
|
||||
for (s32 k = 0; k < 3; k++) {
|
||||
dst_vel[j] = dst_pos[j] - prev_pos[j];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
*vel = dst_vel;
|
||||
}
|
||||
|
||||
// Return the vertex float segments that should be used.
|
||||
*pos = dst_pos;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -765,15 +826,22 @@ RECOMP_PATCH BKModelBin *modelRender_draw(Gfx **gfx, Mtx **mtx, f32 position[3],
|
||||
}
|
||||
|
||||
// @recomp Use higher precision vertex buffer when the model requires CPU skinning.
|
||||
bool ex_vertex_components_used = FALSE;
|
||||
cur_model_uses_ex_vertex = FALSE;
|
||||
|
||||
if(model_bin->unk28 != NULL && D_8038371C != NULL){
|
||||
func_802E6BD0((u8*)modelRenderModelBin + modelRenderModelBin->unk28, modelRendervertexList, D_8038371C);
|
||||
|
||||
// @recomp Do the skinning again on a high precision version of the vertex buffer. Force its usage for any subsequent display lists.
|
||||
f32 *skinned_pos = recomp_apply_cpu_skinning((u8 *)modelRenderModelBin + modelRenderModelBin->unk28, modelRendervertexList, D_8038371C);
|
||||
if (skinned_pos != NULL) {
|
||||
f32 *skinned_pos, *skinned_vel;
|
||||
if (recomp_apply_cpu_skinning((u8 *)modelRenderModelBin + modelRenderModelBin->unk28, modelRendervertexList, D_8038371C, &skinned_pos, &skinned_vel)) {
|
||||
gEXSetVertexSegment((*gfx)++, G_EX_VERTEX_POSITION, G_EX_ENABLED, skinned_pos, &modelRendervertexList->vtx_18);
|
||||
ex_vertex_components_used = TRUE;
|
||||
if (skinned_vel != NULL) {
|
||||
gEXSetVertexSegment((*gfx)++, G_EX_VERTEX_VELOCITY, G_EX_ENABLED, skinned_vel, &modelRendervertexList->vtx_18);
|
||||
}
|
||||
else {
|
||||
gEXSetVertexSegment((*gfx)++, G_EX_VERTEX_VELOCITY, G_EX_DISABLED, 0, 0);
|
||||
}
|
||||
cur_model_uses_ex_vertex = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -800,14 +868,21 @@ RECOMP_PATCH BKModelBin *modelRender_draw(Gfx **gfx, Mtx **mtx, f32 position[3],
|
||||
gSPMatrix((*gfx)++, (*mtx)++, G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
|
||||
// @recomp Create a matrix group if a transform id is set.
|
||||
bool pushed_matrix_group = FALSE;
|
||||
if (skip_all_interpolation || cur_drawn_model_skip_interpolation) {
|
||||
// @recomp Skip interpolation if all interpolation is currently skipped or the transform was specified to be skipped.
|
||||
gEXMatrixGroupSkipAll((*gfx)++, cur_drawn_model_transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
pushed_matrix_group = TRUE;
|
||||
}
|
||||
else if (cur_drawn_model_is_map) {
|
||||
gEXMatrixGroupDecomposedVerts((*gfx)++, cur_drawn_model_transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
pushed_matrix_group = TRUE;
|
||||
}
|
||||
else if (cur_drawn_model_transform_id != 0) {
|
||||
gEXMatrixGroupDecomposedVerts((*gfx)++, cur_drawn_model_transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
gEXMatrixGroupDecomposedNormalTcs((*gfx)++, cur_drawn_model_transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
pushed_matrix_group = TRUE;
|
||||
}
|
||||
|
||||
|
||||
modelRenderScale = scale;
|
||||
if(rotation){
|
||||
modelRenderRotation[0] = rotation[0];
|
||||
@@ -833,13 +908,14 @@ RECOMP_PATCH BKModelBin *modelRender_draw(Gfx **gfx, Mtx **mtx, f32 position[3],
|
||||
gSPPopMatrix((*gfx)++, G_MTX_MODELVIEW);
|
||||
|
||||
// @recomp Pop the matrix group if a transform id is set.
|
||||
if (cur_drawn_model_transform_id != 0) {
|
||||
if (pushed_matrix_group) {
|
||||
gEXPopMatrixGroup((*gfx)++, G_MTX_MODELVIEW);
|
||||
}
|
||||
|
||||
// @recomp Clear use of high precision vertex buffers.
|
||||
if (ex_vertex_components_used) {
|
||||
if (cur_model_uses_ex_vertex) {
|
||||
gEXSetVertexSegment((*gfx)++, G_EX_VERTEX_POSITION, G_EX_DISABLED, 0, 0);
|
||||
gEXSetVertexSegment((*gfx)++, G_EX_VERTEX_VELOCITY, G_EX_DISABLED, 0, 0);
|
||||
}
|
||||
|
||||
if(modelRenderCallback.post_method != NULL){
|
||||
|
||||
Reference in New Issue
Block a user