Replace the partial mechanics transcriptions with a separate, readable C11 reconstruction of the complete Win16 image while preserving the original raw Ghidra export as immutable evidence. Cover all ordinary and overlapping entry points, Borland runtime behavior, Win16 imports, segmented data, callbacks, resources, indirect control flow, physics, rendering, persistence, and startup/shutdown lifecycles. Add deterministic extraction and audit tooling plus address-linked ledgers for functions, imports, DGROUP ranges and objects, relocations, resources, and callbacks. The final gate records zero raw, partial, restored, unknown, blocked, or unclassified required units. Keep the semantic-fidelity boundary explicit: the portable C is not claimed to reproduce a byte-identical Borland NE build. Add strict focused harnesses for every reconstructed C unit, exact resource round-trip checks, and a 16-bit Borland Real48 reference probe. No Rust source or Cargo metadata is changed in this phase. Test Plan: - `bash original/tools/test_reconstructed_c.sh` -- passed - `bash original/tools/probe_real48_reference.sh` -- passed bit-for-bit - `python3 original/tools/audit_reconstruction.py --require-complete` -- passed - `git diff --cached --check` -- passed - `git diff HEAD -- '*.rs' Cargo.toml Cargo.lock` -- empty
266 lines
7.7 KiB
C
266 lines
7.7 KiB
C
/* 281-frame, mask/image-composited panel animation from TDKPIN Code1. */
|
|
|
|
#include "tdkpin_panel_animation.h"
|
|
|
|
#include "tdkpin_sound.h"
|
|
|
|
static Win16FarPtr caller_receiver(uint16_t caller_bp)
|
|
{
|
|
uint16_t offset = win16_read_stack_u16((uint16_t)(caller_bp + 6));
|
|
uint16_t selector = win16_read_stack_u16((uint16_t)(caller_bp + 8));
|
|
return win16_make_far_pointer(selector, offset);
|
|
}
|
|
|
|
static INT16 twice(int32_t value)
|
|
{
|
|
return (INT16)(uint16_t)((uint32_t)value * 2u);
|
|
}
|
|
|
|
static void copy_region(
|
|
HDC16 destination,
|
|
INT16 destination_x,
|
|
INT16 destination_y,
|
|
INT16 width,
|
|
INT16 height,
|
|
HDC16 source,
|
|
INT16 source_x,
|
|
INT16 source_y)
|
|
{
|
|
(void)BitBlt16(
|
|
destination,
|
|
destination_x,
|
|
destination_y,
|
|
width,
|
|
height,
|
|
source,
|
|
source_x,
|
|
source_y,
|
|
0x00cc0020u);
|
|
}
|
|
|
|
static void mask_image_pair(
|
|
HDC16 panel,
|
|
INT16 destination_x,
|
|
INT16 destination_y,
|
|
INT16 width,
|
|
INT16 height,
|
|
HDC16 atlas,
|
|
INT16 mask_x,
|
|
INT16 mask_y,
|
|
INT16 image_x,
|
|
INT16 image_y)
|
|
{
|
|
(void)BitBlt16(
|
|
panel,
|
|
destination_x,
|
|
destination_y,
|
|
width,
|
|
height,
|
|
atlas,
|
|
mask_x,
|
|
mask_y,
|
|
0x008800c6u);
|
|
(void)BitBlt16(
|
|
panel,
|
|
destination_x,
|
|
destination_y,
|
|
width,
|
|
height,
|
|
atlas,
|
|
image_x,
|
|
image_y,
|
|
0x00ee0086u);
|
|
}
|
|
|
|
static void phase_1_to_44(
|
|
int32_t frame, HDC16 panel, HDC16 atlas)
|
|
{
|
|
mask_image_pair(
|
|
panel,
|
|
20,
|
|
0,
|
|
45,
|
|
twice(frame),
|
|
atlas,
|
|
45,
|
|
(INT16)(twice(45 - frame) + 89),
|
|
0,
|
|
(INT16)(twice(45 - frame) + 89));
|
|
}
|
|
|
|
static void phase_66_to_128(
|
|
int32_t frame, HDC16 panel, HDC16 atlas)
|
|
{
|
|
copy_region(panel, 0, 33, 91, 90, atlas, 180, 90);
|
|
if (frame < 83) {
|
|
mask_image_pair(
|
|
panel,
|
|
0,
|
|
twice(82 - frame),
|
|
91,
|
|
90,
|
|
atlas,
|
|
362,
|
|
90,
|
|
271,
|
|
90);
|
|
} else {
|
|
INT16 height = twice(128 - frame);
|
|
INT16 source_y = (INT16)(twice(frame - 82) + 90);
|
|
mask_image_pair(
|
|
panel, 0, 0, 91, height,
|
|
atlas, 362, source_y, 271, source_y);
|
|
}
|
|
if (frame < 111) {
|
|
INT16 height = twice(110 - frame);
|
|
INT16 source_y = (INT16)(twice(frame - 66) + 90);
|
|
mask_image_pair(
|
|
panel, 20, 0, 45, height,
|
|
atlas, 135, source_y, 90, source_y);
|
|
}
|
|
}
|
|
|
|
static void phase_159_to_221(
|
|
int32_t frame, HDC16 panel, HDC16 atlas)
|
|
{
|
|
copy_region(panel, 0, 33, 91, 90, atlas, 180, 90);
|
|
if (frame < 204) {
|
|
INT16 height = twice(frame - 159);
|
|
INT16 source_y = (INT16)(twice(204 - frame) + 90);
|
|
mask_image_pair(
|
|
panel, 0, 0, 91, height,
|
|
atlas, 362, source_y, 453, source_y);
|
|
} else {
|
|
mask_image_pair(
|
|
panel, 0, twice(frame - 204), 91, 90,
|
|
atlas, 362, 90, 453, 90);
|
|
}
|
|
if (frame > 176) {
|
|
if (frame == 221) {
|
|
mask_image_pair(
|
|
panel, 20, 0, 45, 88,
|
|
atlas, 135, 90, 90, 90);
|
|
} else {
|
|
INT16 height = twice(frame - 177);
|
|
INT16 source_y = (INT16)(twice(222 - frame) + 89);
|
|
mask_image_pair(
|
|
panel, 20, 0, 45, height,
|
|
atlas, 135, source_y, 90, source_y);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void full_panel_mask_image(HDC16 panel, HDC16 atlas)
|
|
{
|
|
mask_image_pair(
|
|
panel, 0, 33, 91, 90,
|
|
atlas, 362, 90, 453, 90);
|
|
}
|
|
|
|
static void phase_238_to_281(
|
|
int32_t frame, HDC16 panel, HDC16 atlas)
|
|
{
|
|
full_panel_mask_image(panel, atlas);
|
|
INT16 height = twice(281 - frame);
|
|
INT16 source_y = (INT16)(twice(frame - 238) + 90);
|
|
mask_image_pair(
|
|
panel, 20, 0, 45, height,
|
|
atlas, 45, source_y, 0, source_y);
|
|
}
|
|
|
|
/* 1000:7440 -- render one frame of the 91x123 board-panel animation. */
|
|
void tdkpin_draw_panel_animation(uint16_t caller_bp)
|
|
{
|
|
Win16FarPtr receiver = caller_receiver(caller_bp);
|
|
HWND16 window = win16_read_u16(win16_far_add_offset(receiver, 4));
|
|
HDC16 dc = GetDC16(window);
|
|
HDC16 atlas_dc = CreateCompatibleDC16(dc);
|
|
HGDIOBJ16 old_atlas = SelectObject16(
|
|
atlas_dc, win16_read_u16(win16_dgroup_pointer(0x085f)));
|
|
HDC16 panel_dc = CreateCompatibleDC16(dc);
|
|
HBITMAP16 panel_bitmap = CreateCompatibleBitmap16(dc, 91, 123);
|
|
HGDIOBJ16 old_panel = SelectObject16(panel_dc, panel_bitmap);
|
|
copy_region(panel_dc, 0, 0, 91, 123, atlas_dc, 79, 0);
|
|
(void)SelectObject16(
|
|
atlas_dc, win16_read_u16(win16_dgroup_pointer(0x0859)));
|
|
|
|
int32_t frame = (int32_t)win16_read_u32(win16_dgroup_pointer(0x0851));
|
|
int16_t phase_frame = (int16_t)frame;
|
|
if (phase_frame >= 1 && phase_frame <= 44) {
|
|
if (frame == 1) {
|
|
tdkpin_play_sound_if_not_tilted(13);
|
|
(void)SelectObject16(
|
|
panel_dc, win16_read_u16(win16_dgroup_pointer(0x085b)));
|
|
copy_region(panel_dc, 79, 0, 91, 90, atlas_dc, 271, 90);
|
|
(void)SelectObject16(panel_dc, panel_bitmap);
|
|
}
|
|
phase_1_to_44(frame, panel_dc, atlas_dc);
|
|
} else if (phase_frame >= 45 && phase_frame <= 57) {
|
|
if (frame == 45) {
|
|
(void)tdkpin_stop_sound_if_active();
|
|
}
|
|
mask_image_pair(
|
|
panel_dc, 20, 0, 45, 88,
|
|
atlas_dc, 45, 90, 0, 90);
|
|
} else if (phase_frame >= 58 && phase_frame <= 65) {
|
|
if (frame == 58) {
|
|
tdkpin_play_sound_if_not_tilted(12);
|
|
}
|
|
mask_image_pair(
|
|
panel_dc, 20, 0, 45, 88,
|
|
atlas_dc, 135, 90, 90, 90);
|
|
} else if (phase_frame >= 66 && phase_frame <= 128) {
|
|
if (frame == 66) {
|
|
tdkpin_play_sound_if_not_tilted(13);
|
|
}
|
|
phase_66_to_128(frame, panel_dc, atlas_dc);
|
|
} else if (phase_frame >= 129 && phase_frame <= 158) {
|
|
if (frame == 129) {
|
|
(void)tdkpin_stop_sound_if_active();
|
|
}
|
|
copy_region(panel_dc, 0, 33, 91, 90, atlas_dc, 180, 90);
|
|
} else if (phase_frame >= 159 && phase_frame <= 221) {
|
|
if (frame == 159) {
|
|
tdkpin_play_sound_if_not_tilted(13);
|
|
}
|
|
phase_159_to_221(frame, panel_dc, atlas_dc);
|
|
} else if (phase_frame >= 222 && phase_frame <= 229) {
|
|
if (frame == 222) {
|
|
(void)tdkpin_stop_sound_if_active();
|
|
}
|
|
full_panel_mask_image(panel_dc, atlas_dc);
|
|
mask_image_pair(
|
|
panel_dc, 20, 0, 45, 88,
|
|
atlas_dc, 135, 90, 90, 90);
|
|
} else if (phase_frame >= 230 && phase_frame <= 237) {
|
|
if (frame == 230) {
|
|
tdkpin_play_sound_if_not_tilted(12);
|
|
}
|
|
full_panel_mask_image(panel_dc, atlas_dc);
|
|
mask_image_pair(
|
|
panel_dc, 20, 0, 45, 88,
|
|
atlas_dc, 45, 90, 0, 90);
|
|
} else if (phase_frame >= 238 && phase_frame <= 281) {
|
|
if (frame == 238) {
|
|
tdkpin_play_sound_if_not_tilted(13);
|
|
}
|
|
phase_238_to_281(frame, panel_dc, atlas_dc);
|
|
if (frame == 281) {
|
|
(void)SelectObject16(
|
|
panel_dc, win16_read_u16(win16_dgroup_pointer(0x085b)));
|
|
(void)SelectObject16(
|
|
atlas_dc, win16_read_u16(win16_dgroup_pointer(0x085d)));
|
|
copy_region(panel_dc, 79, 0, 91, 90, atlas_dc, 79, 0);
|
|
(void)SelectObject16(panel_dc, panel_bitmap);
|
|
}
|
|
}
|
|
|
|
copy_region(dc, 79, 0, 91, 123, panel_dc, 0, 0);
|
|
(void)SelectObject16(panel_dc, old_panel);
|
|
(void)SelectObject16(atlas_dc, old_atlas);
|
|
(void)DeleteObject16(panel_bitmap);
|
|
(void)DeleteDC16(panel_dc);
|
|
(void)DeleteDC16(atlas_dc);
|
|
(void)ReleaseDC16(window, dc);
|
|
}
|