9d0a0d5798
build / build (push) Successful in 2m52s
- engine-debug-tools/: a debug dump hotkey + dump2png to inspect decoded critter frames independent of the renderer (see root README.md's "Debugging" section). - engine-patches/04,05: fix critter sprite scale and an OpenGL texture cache collision, found using that tooling. - mdlp: fix encodeFrames RLE-diffing upscaled frames against a previous-frame reference the real RSD8 decoder never implements (verified against Night Dive's original Mac source down to the 68K assembly) - was rendering as scattered static in-game. - Upscale pipeline: better color quantization (dithering, pure-ramp exclusion) and per-resource model selection.
154 lines
5.7 KiB
Diff
154 lines
5.7 KiB
Diff
--- a/src/GameSrc/objsim.c
|
|
+++ b/src/GameSrc/objsim.c
|
|
@@ -26,8 +26,10 @@
|
|
// Object simulator code for Citadel
|
|
#define __OBJSIM_SRC
|
|
|
|
-#include <string.h>
|
|
+#include <stdio.h>
|
|
#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <sys/stat.h>
|
|
|
|
#include "Shock.h"
|
|
|
|
@@ -1924,6 +1926,93 @@
|
|
*h = s_critterNativeH[id][frame];
|
|
}
|
|
|
|
+// Resource id of the last-drawn critter animation, updated every frame from
|
|
+// gameobj.c's FAUBJ_CRIT case - read by debug_dump_critter_animation() on
|
|
+// the debug dump hotkey (see engine-debug-tools/, root README.md's
|
|
+// "Debugging" section). Debug-build only: see
|
|
+// engine-debug-tools/engine-patches/.
|
|
+static Id s_lastCritterId = 0;
|
|
+
|
|
+void debug_track_critter_draw(Id id) { s_lastCritterId = id; }
|
|
+
|
|
+// Dumps every frame of the last-drawn critter's current animation (the
|
|
+// whole resource id, not just the currently-visible frame) as raw
|
|
+// palette-index bytes, one file per frame, independent of the renderer's
|
|
+// own texture/GL state - lets a corrupted frame be told apart from
|
|
+// corruption introduced later, in rendering. Format: 2-byte LE width,
|
|
+// 2-byte LE height, then width*height index bytes - converted to a viewable
|
|
+// image by engine-debug-tools/dump2png, not here, to avoid this debug path
|
|
+// depending on the renderer's own palette/SDL state.
|
|
+void debug_dump_critter_animation(void) {
|
|
+ RefTable *prt;
|
|
+ int numFrames, frame;
|
|
+ char path[256];
|
|
+ FILE *f;
|
|
+
|
|
+ if (s_lastCritterId == 0) {
|
|
+ fprintf(stderr, "[debug dump] no critter drawn yet\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ mkdir("dumps", 0755); // ignore EEXIST - fopen below reports any real failure
|
|
+
|
|
+ prt = (RefTable *)ResLock(s_lastCritterId);
|
|
+ if (prt == NULL) {
|
|
+ fprintf(stderr, "[debug dump] ResLock(%d) failed\n", (int)s_lastCritterId);
|
|
+ return;
|
|
+ }
|
|
+ numFrames = prt->numRefs;
|
|
+ ResUnlock(s_lastCritterId);
|
|
+
|
|
+ fprintf(stderr, "[debug dump] id=%d numFrames=%d\n", (int)s_lastCritterId, numFrames);
|
|
+
|
|
+ for (frame = 0; frame < numFrames; frame++) {
|
|
+ FrameDesc *fd;
|
|
+ grs_bitmap decoded;
|
|
+ uchar *bits;
|
|
+ short w, h;
|
|
+
|
|
+ fd = (FrameDesc *)RefLock(MKREF(s_lastCritterId, frame));
|
|
+ if (fd == NULL) {
|
|
+ fprintf(stderr, "[debug dump] RefLock frame %d failed\n", frame);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (fd->bm.type == BMT_RSD8) {
|
|
+ if (gr_rsd8_convert(&fd->bm, &decoded) != 0 /* GR_UNPACK_RSD8_OK */) {
|
|
+ fprintf(stderr, "[debug dump] gr_rsd8_convert frame %d failed\n", frame);
|
|
+ RefUnlock(MKREF(s_lastCritterId, frame));
|
|
+ continue;
|
|
+ }
|
|
+ bits = decoded.bits;
|
|
+ w = decoded.w;
|
|
+ h = decoded.h;
|
|
+ } else {
|
|
+ bits = fd->bm.bits;
|
|
+ w = fd->bm.w;
|
|
+ h = fd->bm.h;
|
|
+ }
|
|
+
|
|
+ snprintf(path, sizeof(path), "dumps/id%d_frame%d.raw", (int)s_lastCritterId, frame);
|
|
+ f = fopen(path, "wb");
|
|
+ if (f != NULL) {
|
|
+ uchar hdr[4];
|
|
+ hdr[0] = (uchar)(w & 0xFF);
|
|
+ hdr[1] = (uchar)((w >> 8) & 0xFF);
|
|
+ hdr[2] = (uchar)(h & 0xFF);
|
|
+ hdr[3] = (uchar)((h >> 8) & 0xFF);
|
|
+ fwrite(hdr, 1, 4, f);
|
|
+ fwrite(bits, 1, (size_t)w * (size_t)h, f);
|
|
+ fclose(f);
|
|
+ fprintf(stderr, "[debug dump] wrote %s (%dx%d)\n", path, (int)w, (int)h);
|
|
+ } else {
|
|
+ fprintf(stderr, "[debug dump] failed to open %s for writing\n", path);
|
|
+ }
|
|
+
|
|
+ RefUnlock(MKREF(s_lastCritterId, frame));
|
|
+ }
|
|
+}
|
|
+
|
|
errtype obj_set_secondary_properties() {
|
|
char i, j;
|
|
RefTable *prt;
|
|
--- a/src/GameSrc/Headers/objsim.h
|
|
+++ b/src/GameSrc/Headers/objsim.h
|
|
@@ -109,6 +109,10 @@
|
|
errtype obj_create_player(ObjLoc *plr_loc);
|
|
Ref ref_from_critter_data(ObjID oid, int triple, byte posture, short frame, short view);
|
|
void get_critter_native_size(Id id, short frame, short *w, short *h);
|
|
+// Debug-build only - see engine-debug-tools/, root README.md's "Debugging"
|
|
+// section.
|
|
+void debug_track_critter_draw(Id id);
|
|
+void debug_dump_critter_animation(void);
|
|
errtype obj_zero_unused();
|
|
grs_bitmap *obj_get_model_data(ObjID id, fix *x, fix *y, fix *z, grs_bitmap *bm2, Ref *ref1, Ref *ref2);
|
|
errtype obj_model_hack(ObjID id, uchar *hack_x, uchar *hack_y, uchar *hack_z, uchar *hack_type);
|
|
--- a/src/GameSrc/gameobj.c
|
|
+++ b/src/GameSrc/gameobj.c
|
|
@@ -1019,6 +1019,7 @@
|
|
{
|
|
short native_w = 0, native_h = 0;
|
|
get_critter_native_size(REFID(ref), REFINDEX(ref), &native_w, &native_h);
|
|
+ debug_track_critter_draw(REFID(ref));
|
|
_fr_draw_bitmap(tpdata, _fdt_dist, 0, anch.ul.x, anch.ul.y, native_w, native_h);
|
|
}
|
|
release_critter_bitmap_fast(ref);
|
|
--- a/src/Libraries/INPUT/Source/sdl_events.c
|
|
+++ b/src/Libraries/INPUT/Source/sdl_events.c
|
|
@@ -481,6 +481,19 @@
|
|
SDL_Event ev;
|
|
|
|
while (SDL_PollEvent(&ev)) {
|
|
+ // Debug-build only (engine-debug-tools/, root README.md's
|
|
+ // "Debugging" section): K dumps every frame of the last-drawn
|
|
+ // critter's current animation to dumps/. Checked here, before the
|
|
+ // switch below dispatches on event type at all, so it can never
|
|
+ // collide with an existing game keybinding - a plain letter rather
|
|
+ // than Insert, which some keyboards don't send at all (compact
|
|
+ // layouts, or routed through Fn).
|
|
+ if (ev.type == SDL_KEYDOWN && ev.key.keysym.sym == SDLK_k) {
|
|
+ extern void debug_dump_critter_animation(void);
|
|
+ debug_dump_critter_animation();
|
|
+ continue;
|
|
+ }
|
|
+
|
|
switch (ev.type) {
|
|
case SDL_QUIT:
|
|
// a bit hacky at this place, but this would allow exiting the game via the window's [x] button
|