Files
ddidderr 8b99e9607c feat(reconstruction): complete binary-backed C recovery
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
2026-08-23 16:41:17 +02:00

187 lines
6.1 KiB
C

/* Low-level TDKPIN background/overlay bitmap blits. */
#include "tdkpin_render.h"
#include "tdkpin_arithmetic.h"
enum {
DGROUP_BACKGROUND_BITMAP = 0x085b,
DGROUP_OVERLAY_BITMAP_B = 0x085d,
DGROUP_OVERLAY_BITMAP_A = 0x085f,
WIN16_SRCCOPY = 0x00cc0020,
WIN16_SRCAND = 0x008800c6,
DGROUP_DIGIT_BITMAP = 0x0861,
DGROUP_PLAYER_SCORE_INDEX_BASE = 0x097e,
};
static HBITMAP16 dgroup_bitmap(uint16_t offset)
{
return win16_read_u16(win16_dgroup_pointer(offset));
}
/* 1008:07b6 — copy a supplied bitmap's origin into the background bitmap. */
void tdkpin_blit_bitmap_to_background(
HBITMAP16 bitmap,
INT16 height,
INT16 width,
INT16 y,
INT16 x,
HDC16 reference_dc)
{
HDC16 background_dc = CreateCompatibleDC16(reference_dc);
HDC16 bitmap_dc = CreateCompatibleDC16(reference_dc);
HGDIOBJ16 old_background = SelectObject16(
background_dc, dgroup_bitmap(DGROUP_BACKGROUND_BITMAP));
HGDIOBJ16 old_bitmap = SelectObject16(bitmap_dc, bitmap);
(void)BitBlt16(
background_dc, x, y, width, height,
bitmap_dc, 0, 0, WIN16_SRCCOPY);
(void)SelectObject16(bitmap_dc, old_bitmap);
(void)SelectObject16(background_dc, old_background);
(void)DeleteDC16(bitmap_dc);
(void)DeleteDC16(background_dc);
}
/* 1008:0837 — restore a rectangle from overlay bitmap 085f. */
void tdkpin_restore_background_region_a(
INT16 height,
INT16 width,
INT16 y,
INT16 x,
HDC16 reference_dc)
{
HDC16 background_dc = CreateCompatibleDC16(reference_dc);
HDC16 overlay_dc = CreateCompatibleDC16(reference_dc);
HGDIOBJ16 old_background = SelectObject16(
background_dc, dgroup_bitmap(DGROUP_BACKGROUND_BITMAP));
HGDIOBJ16 old_overlay = SelectObject16(
overlay_dc, dgroup_bitmap(DGROUP_OVERLAY_BITMAP_A));
(void)BitBlt16(
background_dc, x, y, width, height,
overlay_dc, x, y, WIN16_SRCCOPY);
(void)SelectObject16(overlay_dc, old_overlay);
(void)SelectObject16(background_dc, old_background);
(void)DeleteDC16(overlay_dc);
(void)DeleteDC16(background_dc);
}
/* 1008:08bb — byte-identical restore using overlay bitmap 085d. */
void tdkpin_restore_background_region_b(
INT16 height,
INT16 width,
INT16 y,
INT16 x,
HDC16 reference_dc)
{
HDC16 background_dc = CreateCompatibleDC16(reference_dc);
HDC16 overlay_dc = CreateCompatibleDC16(reference_dc);
HGDIOBJ16 old_background = SelectObject16(
background_dc, dgroup_bitmap(DGROUP_BACKGROUND_BITMAP));
HGDIOBJ16 old_overlay = SelectObject16(
overlay_dc, dgroup_bitmap(DGROUP_OVERLAY_BITMAP_B));
(void)BitBlt16(
background_dc, x, y, width, height,
overlay_dc, x, y, WIN16_SRCCOPY);
(void)SelectObject16(overlay_dc, old_overlay);
(void)SelectObject16(background_dc, old_background);
(void)DeleteDC16(overlay_dc);
(void)DeleteDC16(background_dc);
}
/* 1008:093f — copy one background rectangle to the destination DC. */
void tdkpin_present_background_region(
INT16 height,
INT16 width,
INT16 y,
INT16 x,
HDC16 destination)
{
HDC16 background_dc = CreateCompatibleDC16(destination);
HGDIOBJ16 old_background = SelectObject16(
background_dc, dgroup_bitmap(DGROUP_BACKGROUND_BITMAP));
(void)BitBlt16(
destination, x, y, width, height,
background_dc, x, y, WIN16_SRCCOPY);
(void)SelectObject16(background_dc, old_background);
(void)DeleteDC16(background_dc);
}
static int16_t score_destination_x(uint16_t player_or_value)
{
switch (player_or_value) {
case 1:
return 0x129 - 20;
case 2:
return 0x155 - 20;
case 3:
return 0x181 - 20;
case 4:
return 0x1ad - 20;
default:
return 0x0fd - 20;
}
}
static int32_t resolve_score_value(int32_t value_or_player)
{
if (value_or_player < 1 || value_or_player > 4) {
return value_or_player;
}
uint16_t offset = (uint16_t)(
DGROUP_PLAYER_SCORE_INDEX_BASE + (uint16_t)value_or_player * 4);
return (int32_t)win16_read_u32(win16_dgroup_pointer(offset));
}
/*
* 1008:0996 — compose an eight-place decimal score into a 40x150 temporary
* bitmap. Values 1..4 select the corresponding one-based player score; all
* other int32 values render directly. Leading zeroes are suppressed except the
* least-significant position, and digit sprites are combined with SRCAND.
*/
void tdkpin_draw_score(HDC16 destination, int32_t value_or_player)
{
HDC16 background_dc = CreateCompatibleDC16(destination);
HDC16 score_dc = CreateCompatibleDC16(destination);
HBITMAP16 score_bitmap =
CreateCompatibleBitmap16(destination, 40, 150);
int16_t destination_x =
score_destination_x((uint16_t)value_or_player);
int32_t value = resolve_score_value(value_or_player);
HGDIOBJ16 old_background = SelectObject16(
background_dc, dgroup_bitmap(DGROUP_BACKGROUND_BITMAP));
HGDIOBJ16 old_score = SelectObject16(score_dc, score_bitmap);
(void)BitBlt16(
score_dc, 0, 0, 40, 130,
background_dc, destination_x, 478, WIN16_SRCCOPY);
for (uint8_t position = 0; position < 8; position++) {
BorlandDivI32Result digit_division = borland_divide_i32(value, 10);
uint8_t digit = (uint8_t)digit_division.remainder;
BorlandDivI32Result quotient_division = borland_divide_i32(value, 10);
value = quotient_division.quotient;
if (digit != 0 || value > 0 || position == 0) {
(void)SelectObject16(
background_dc, dgroup_bitmap(DGROUP_DIGIT_BITMAP));
(void)BitBlt16(
score_dc,
0,
(INT16)((7 - position) * 16),
28,
16,
background_dc,
(INT16)((uint16_t)digit << 4),
0,
WIN16_SRCAND);
}
}
(void)BitBlt16(
destination, destination_x, 478, 40, 130,
score_dc, 0, 0, WIN16_SRCCOPY);
(void)SelectObject16(background_dc, old_background);
(void)SelectObject16(score_dc, old_score);
(void)DeleteObject16(score_bitmap);
(void)DeleteDC16(background_dc);
(void)DeleteDC16(score_dc);
}