mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Merge feat/render-pass-kit (ROTATION, counters, offline build fix)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -62,9 +62,6 @@ int psx_mod_finish_function(struct CPUState* cpu);
|
||||
/* Active function-entry hook count (0 = none). Hot callers test it before the
|
||||
* call, so a run without an active hook pays one load per interpreted entry. */
|
||||
extern uint32_t g_psx_mod_function_entry_hooks;
|
||||
/* Entry callbacks can make nested guest calls while retaining host registers.
|
||||
* Save/load and rewind must wait until that host context has returned. */
|
||||
int psx_mod_function_entry_active(void);
|
||||
|
||||
/* Always-on named event counters for trusted plugins (observability, not
|
||||
* logging): e.g. how often each guard in a hook rejected. `name` should be a
|
||||
@@ -72,6 +69,9 @@ int psx_mod_function_entry_active(void);
|
||||
* kept, further names are counted in an overflow bucket. Emulation-thread only.
|
||||
* TCP: {"cmd":"mod_counters"} lists every counter with its last frame. */
|
||||
void psx_mod_counter_add(const char* name, uint32_t delta);
|
||||
/* Entry callbacks can make nested guest calls while retaining host registers.
|
||||
* Save/load and rewind must wait until that host context has returned. */
|
||||
int psx_mod_function_entry_active(void);
|
||||
|
||||
/* Narrow guest services available to trusted plugin callbacks. */
|
||||
int psx_mod_game_started(void);
|
||||
|
||||
@@ -45,7 +45,11 @@ enum {
|
||||
PSX_MOTION_SVECTOR = 4, /* s16 x, y, z */
|
||||
/* s16 x, y, z angles, 4096 per turn: each blends along the shorter arc. */
|
||||
PSX_MOTION_ANGLES = 5,
|
||||
PSX_MOTION_SCALAR = 6 /* s32 */
|
||||
PSX_MOTION_SCALAR = 6, /* s32 */
|
||||
/* A bare 3x3 s16 rotation in 4.12 (18 bytes), blended like a MATRIX's;
|
||||
* pair it with a VECTOR / SVECTOR kind wherever its translation lives
|
||||
* (skeleton pose records, matrices stored apart from their position). */
|
||||
PSX_MOTION_ROTATION = 7
|
||||
};
|
||||
|
||||
typedef struct PSXMotionLimits {
|
||||
@@ -92,7 +96,7 @@ uint32_t psx_motion_prepare(PSXMotionSet* set, const PSXMotionLimits* limits,
|
||||
/* Write every prepared value at t (0 = previous frame, 1 = this frame). */
|
||||
void psx_motion_apply(const PSXMotionSet* set, double t);
|
||||
/* Blend one prepared value at t into `out` without writing guest RAM:
|
||||
* a PSXMotionMatrix for the MATRIX kinds, int32_t[3] for VECTOR / SVECTOR /
|
||||
* a PSXMotionMatrix for the MATRIX kinds and ROTATION (translation 0), int32_t[3] for VECTOR / SVECTOR /
|
||||
* ANGLES, int32_t for SCALAR. Returns 0 when that value does not blend this
|
||||
* frame (out then holds its current value) or was not tracked (out
|
||||
* untouched, returns -1). */
|
||||
|
||||
@@ -7802,14 +7802,6 @@ static void handle_input_route_status(int id, const char *json)
|
||||
* {"cmd":"ws_hud_mode","tag_rects":0|1}
|
||||
* tag_rects=1 lets TAGGED rect-family prims re-anchor too (Tomba's AP
|
||||
* counter renders through the tagged sprite funnel). */
|
||||
static void handle_ws_hud_mode(int id, const char *json)
|
||||
{
|
||||
int v = json_get_int(json, "tag_rects", -1);
|
||||
if (v < 0) { send_err(id, "missing tag_rects (0|1)"); return; }
|
||||
gpu_ws_set_nw_hud_tag_rects(v);
|
||||
send_fmt("{\"id\":%d,\"ok\":true,\"tag_rects\":%d}", id, v ? 1 : 0);
|
||||
}
|
||||
|
||||
/* Named plugin counters (psx_mod_counter_add), always on:
|
||||
* {"cmd":"mod_counters"}
|
||||
* -> counters: [{name, count, last_frame}], overflow. */
|
||||
@@ -7849,6 +7841,14 @@ static void handle_mod_counters(int id, const char *json)
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static void handle_ws_hud_mode(int id, const char *json)
|
||||
{
|
||||
int v = json_get_int(json, "tag_rects", -1);
|
||||
if (v < 0) { send_err(id, "missing tag_rects (0|1)"); return; }
|
||||
gpu_ws_set_nw_hud_tag_rects(v);
|
||||
send_fmt("{\"id\":%d,\"ok\":true,\"tag_rects\":%d}", id, v ? 1 : 0);
|
||||
}
|
||||
|
||||
/* Explicit HUD-anchor / background tag pipeline counters (always on):
|
||||
* {"cmd":"ws_tag_stats"}
|
||||
* -> hud / background: tag_calls, tag_rejected, hit, stale, guard_mismatch,
|
||||
|
||||
@@ -62,7 +62,9 @@ extern "C" void psx_event_step_conservative_env_init(void);
|
||||
#include "psx_netplay_rb.h"
|
||||
#include "psx_selfcheck.h"
|
||||
#include "psx_lobby_client.h"
|
||||
#if defined(PSX_HAS_RECOMP_NET)
|
||||
#include "recomp_net/host_relay.h" /* RNetHostRelayStatus for the launcher relay line */
|
||||
#endif
|
||||
#include "netplay_bios_settle.h"
|
||||
#include "netplay_exit_reason.h"
|
||||
#include "host_time.h"
|
||||
@@ -11024,6 +11026,7 @@ namespace {
|
||||
if (!out || !out_cap) return 0;
|
||||
out[0] = '\0';
|
||||
if (g_lnch_hosting_lan || g_lnch_joined_lan || !psx_lobby_in_lobby()) return 0;
|
||||
#if defined(PSX_HAS_RECOMP_NET)
|
||||
RNetHostRelayStatus st;
|
||||
if (!psx_lobby_host_relay_status(&st)) return 0;
|
||||
if (st.role == 1) {
|
||||
@@ -11066,6 +11069,9 @@ namespace {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return 0; /* offline build: recomp-net (and its host relay) is not linked */
|
||||
#endif
|
||||
}
|
||||
int ae_np_force_turn_set(void*, int force) {
|
||||
if (g_lnch_hosting_lan || g_lnch_joined_lan)
|
||||
|
||||
@@ -108,6 +108,9 @@ static void read_entry(MotionEntry* e) {
|
||||
for (int i = 0; i < 3; i++) e->v[9 + i] = m.t[i];
|
||||
break;
|
||||
}
|
||||
case PSX_MOTION_ROTATION:
|
||||
for (int i = 0; i < 9; i++) e->v[i] = (int16_t)psx_mod_read_half(e->addr + 2u * (uint32_t)i);
|
||||
break;
|
||||
case PSX_MOTION_VECTOR:
|
||||
for (int i = 0; i < 3; i++) e->v[i] = (int32_t)psx_mod_read_word(e->addr + 4u * (uint32_t)i);
|
||||
break;
|
||||
@@ -123,7 +126,7 @@ static void read_entry(MotionEntry* e) {
|
||||
|
||||
int psx_motion_track(PSXMotionSet* s, uint32_t kind, uint32_t addr, uint32_t identity) {
|
||||
MotionEntry* e;
|
||||
if (!s || kind < PSX_MOTION_MATRIX || kind > PSX_MOTION_SCALAR) return 0;
|
||||
if (!s || kind < PSX_MOTION_MATRIX || kind > PSX_MOTION_ROTATION) return 0;
|
||||
if (!s->began[s->cur] || s->n[s->cur] >= s->cap) return 0;
|
||||
e = &s->cap_buf[s->cur][s->n[s->cur]];
|
||||
memset(e, 0, sizeof *e);
|
||||
@@ -270,10 +273,11 @@ static int within_limits(const MotionEntry* a, const MotionEntry* b,
|
||||
const PSXMotionLimits* lim, uint32_t ticks) {
|
||||
const double move = lim->move_per_tick > 0 ? lim->move_per_tick * ticks : HUGE_VAL;
|
||||
switch (a->kind) {
|
||||
case PSX_MOTION_MATRIX: {
|
||||
case PSX_MOTION_MATRIX:
|
||||
case PSX_MOTION_ROTATION: {
|
||||
double ang;
|
||||
int16_t ra[9], rb[9];
|
||||
if (dist3(&a->v[9], &b->v[9]) > move) return 0;
|
||||
if (a->kind == PSX_MOTION_MATRIX && dist3(&a->v[9], &b->v[9]) > move) return 0;
|
||||
for (int i = 0; i < 9; i++) { ra[i] = (int16_t)a->v[i]; rb[i] = (int16_t)b->v[i]; }
|
||||
ang = rotation_angle(ra, rb);
|
||||
if (ang >= 0) return ang <= turn_limit(lim->turn_radians);
|
||||
@@ -344,7 +348,8 @@ uint32_t psx_motion_prepare(PSXMotionSet* s, const PSXMotionLimits* lim,
|
||||
/* Blend one pair into `v` (entry layout). */
|
||||
static void blend_entry(const MotionEntry* a, const MotionEntry* b, double t, int32_t* v) {
|
||||
switch (a->kind) {
|
||||
case PSX_MOTION_MATRIX: {
|
||||
case PSX_MOTION_MATRIX:
|
||||
case PSX_MOTION_ROTATION: {
|
||||
int16_t ra[9], rb[9], ro[9];
|
||||
for (int i = 0; i < 9; i++) { ra[i] = (int16_t)a->v[i]; rb[i] = (int16_t)b->v[i]; }
|
||||
blend_rotation(ra, rb, t, MOTION_PI * 2, ro); /* limits were applied at prepare */
|
||||
@@ -388,6 +393,9 @@ static void write_entry(uint8_t kind, uint32_t addr, const int32_t* v) {
|
||||
case PSX_MOTION_SCALAR:
|
||||
psx_mod_write_word(addr, (uint32_t)v[0]);
|
||||
break;
|
||||
case PSX_MOTION_ROTATION:
|
||||
for (int i = 0; i < 9; i++) psx_mod_write_half(addr + 2u * (uint32_t)i, (uint16_t)v[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,7 +413,8 @@ void psx_motion_apply(const PSXMotionSet* s, double t) {
|
||||
}
|
||||
|
||||
static void export_value(uint8_t kind, const int32_t* v, void* out) {
|
||||
if (kind == PSX_MOTION_MATRIX || kind == PSX_MOTION_MATRIX_TRANSLATION) {
|
||||
if (kind == PSX_MOTION_MATRIX || kind == PSX_MOTION_MATRIX_TRANSLATION ||
|
||||
kind == PSX_MOTION_ROTATION) {
|
||||
PSXMotionMatrix* m = (PSXMotionMatrix*)out;
|
||||
for (int i = 0; i < 9; i++) m->r[i] = (int16_t)v[i];
|
||||
for (int i = 0; i < 3; i++) m->t[i] = v[9 + i];
|
||||
|
||||
@@ -164,6 +164,27 @@ static void test_angles_vectors_scalars(void) {
|
||||
psx_motion_set_destroy(s);
|
||||
}
|
||||
|
||||
static void test_rotation_only(void) {
|
||||
PSXMotionSet* s = psx_motion_set_create(4);
|
||||
PSXMotionLimits lim = {100.0, 0};
|
||||
PSXMotionStats st;
|
||||
/* A bare rotation (as in a pose record) with other data right after it. */
|
||||
put_matrix(0xA00, 0.0, 0, 0, 0);
|
||||
psx_mod_write_word(0xA00 + 0x12, 0xDEADBEEFu);
|
||||
psx_motion_begin(s, 1);
|
||||
psx_motion_track(s, PSX_MOTION_ROTATION, 0xA00, 3);
|
||||
psx_motion_prepare(s, &lim, &st);
|
||||
put_matrix(0xA00, 1.0, 0, 0, 0);
|
||||
psx_mod_write_word(0xA00 + 0x12, 0xDEADBEEFu);
|
||||
psx_motion_begin(s, 2);
|
||||
psx_motion_track(s, PSX_MOTION_ROTATION, 0xA00, 3);
|
||||
CHECK(psx_motion_prepare(s, &lim, &st) == 1, "a bare rotation blends");
|
||||
psx_motion_apply(s, 0.5);
|
||||
CHECK(fabs(yaw_of(0xA00) - 0.5) < 0.002, "rotation-only slerps");
|
||||
CHECK(psx_mod_read_word(0xA00 + 0x12) == 0xDEADBEEFu, "nothing past the 18 bytes is written");
|
||||
psx_motion_set_destroy(s);
|
||||
}
|
||||
|
||||
static int s_fn_calls;
|
||||
static double s_fn_last;
|
||||
static int frame_fn(struct CPUState* cpu, void* user, uint32_t alpha) {
|
||||
@@ -209,6 +230,7 @@ int main(void) {
|
||||
test_matrix_slerp();
|
||||
test_identity_and_limits();
|
||||
test_angles_vectors_scalars();
|
||||
test_rotation_only();
|
||||
test_frame_driver();
|
||||
printf(failures ? "FAILED (%d)\n" : "ALL PASS\n", failures);
|
||||
return failures ? 1 : 0;
|
||||
|
||||
Reference in New Issue
Block a user