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
279 lines
9.0 KiB
C
279 lines
9.0 KiB
C
/* TDKPIN asset-loading progress and bitmap ownership paths. */
|
|
|
|
#include "tdkpin_game_assets.h"
|
|
|
|
#include "tdkpin_palette.h"
|
|
#include "tdkpin_window_placement.h"
|
|
|
|
enum {
|
|
FRAME_MEMORY_DC = -0x0c,
|
|
FRAME_PREVIOUS_BITMAP = -0x04,
|
|
FRAME_LOADING_BITMAP = -0x02,
|
|
FRAME_DESTINATION_DC = 0x0e,
|
|
LOADING_DESTINATION_X = 13,
|
|
LOADING_WIDTH = 328,
|
|
LOADING_HEIGHT = 202,
|
|
WIN16_SRCCOPY = 0x00cc0020,
|
|
DGROUP_OVERLAY_BITMAP = 0x0867,
|
|
WINDOW_HANDLE_OFFSET = 4,
|
|
OVERLAY_DAT_RESOURCE = 993,
|
|
DGROUP_PALETTE_UPDATE_ACTIVE = 0x07c4,
|
|
MESSAGE_WPARAM_OFFSET = 4,
|
|
MESSAGE_RESULT_OFFSET = 10,
|
|
DGROUP_PALETTE_HANDLE = 0x444e,
|
|
DGROUP_BOARD_INDEX = 0x07cd,
|
|
BOARD_DAT_RESOURCE_BASE = 1000,
|
|
WIN16_IDC_WAIT = 0x7f02,
|
|
WIN16_IDC_ARROW = 0x7f00,
|
|
BOARD_WIDTH = 640,
|
|
BOARD_HEIGHT = 460,
|
|
};
|
|
|
|
static Win16FarPtr frame_field(Win16FarPtr caller_bp, int16_t offset)
|
|
{
|
|
return win16_far_add_offset(caller_bp, (uint16_t)offset);
|
|
}
|
|
|
|
/*
|
|
* 1000:531e — draw one numbered asset-loading stage. The target receives the
|
|
* caller's BP, mutates its scratch HDC/HGDIOBJ words, and deletes the compatible
|
|
* DC through DeleteObject16 (not DeleteDC16). This unusual API choice is kept.
|
|
*/
|
|
void tdkpin_draw_loading_stage(Win16FarPtr caller_bp, uint8_t stage)
|
|
{
|
|
HDC16 destination =
|
|
win16_read_u16(frame_field(caller_bp, FRAME_DESTINATION_DC));
|
|
HDC16 memory_dc = CreateCompatibleDC16(destination);
|
|
win16_write_u16(
|
|
frame_field(caller_bp, FRAME_MEMORY_DC), 0, memory_dc);
|
|
HBITMAP16 loading_bitmap =
|
|
win16_read_u16(frame_field(caller_bp, FRAME_LOADING_BITMAP));
|
|
HGDIOBJ16 previous = SelectObject16(memory_dc, loading_bitmap);
|
|
win16_write_u16(
|
|
frame_field(caller_bp, FRAME_PREVIOUS_BITMAP), 0, previous);
|
|
uint16_t wrapped_y = (uint16_t)(((uint16_t)stage - 1) * 7);
|
|
(void)BitBlt16(
|
|
destination,
|
|
LOADING_DESTINATION_X,
|
|
(INT16)wrapped_y,
|
|
LOADING_WIDTH,
|
|
LOADING_HEIGHT,
|
|
memory_dc,
|
|
0,
|
|
0,
|
|
WIN16_SRCCOPY);
|
|
(void)SelectObject16(memory_dc, previous);
|
|
(void)DeleteObject16(memory_dc);
|
|
}
|
|
|
|
/* 1000:5be5 — finish TWindow setup, load DAT 993, then focus the HWND. */
|
|
void tdkpin_setup_overlay_window(Win16FarPtr window)
|
|
{
|
|
object_windows_setup_window(window);
|
|
HBITMAP16 overlay = tdkpin_load_bitmap_resource(
|
|
win16_make_far_pointer(0, OVERLAY_DAT_RESOURCE), g_win16_instance);
|
|
win16_write_u16(
|
|
win16_dgroup_pointer(DGROUP_OVERLAY_BITMAP), 0, overlay);
|
|
(void)SetFocus16(
|
|
win16_read_u16(win16_far_add_offset(window, WINDOW_HANDLE_OFFSET)));
|
|
}
|
|
|
|
static void invalidate_palette_window(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
HWND16 handle =
|
|
win16_read_u16(win16_far_add_offset(window, WINDOW_HANDLE_OFFSET));
|
|
win16_write_u8(
|
|
win16_dgroup_pointer(DGROUP_PALETTE_UPDATE_ACTIVE), 1);
|
|
(void)InvalidateRect16(handle, 0, 0);
|
|
(void)UpdateWindow16(handle);
|
|
win16_write_u32(message, MESSAGE_RESULT_OFFSET, 0);
|
|
}
|
|
|
|
/*
|
|
* 1000:58e7 — reset on wParam zero; otherwise begin one non-iconic palette
|
|
* refresh only while the reentrancy byte is clear. Suppressed paths return the
|
|
* target's uninitialized local word.
|
|
*/
|
|
uint16_t tdkpin_palette_change_variant_a(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
uint16_t wparam =
|
|
win16_read_u16(win16_far_add_offset(message, MESSAGE_WPARAM_OFFSET));
|
|
if (wparam == 0) {
|
|
win16_write_u8(
|
|
win16_dgroup_pointer(DGROUP_PALETTE_UPDATE_ACTIVE), 0);
|
|
return 0;
|
|
}
|
|
if (win16_read_u8(
|
|
win16_dgroup_pointer(DGROUP_PALETTE_UPDATE_ACTIVE)) == 0) {
|
|
HWND16 handle = win16_read_u16(
|
|
win16_far_add_offset(window, WINDOW_HANDLE_OFFSET));
|
|
if (IsIconic16(handle) == 0) {
|
|
invalidate_palette_window(window, message);
|
|
return 0;
|
|
}
|
|
}
|
|
return win16_indeterminate_u16();
|
|
}
|
|
|
|
/* 1000:5956 — zero-wParam refresh variant without the IsIconic test. */
|
|
void tdkpin_palette_change_variant_b(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
uint16_t wparam =
|
|
win16_read_u16(win16_far_add_offset(message, MESSAGE_WPARAM_OFFSET));
|
|
if (wparam == 0 &&
|
|
win16_read_u8(
|
|
win16_dgroup_pointer(DGROUP_PALETTE_UPDATE_ACTIVE)) == 0) {
|
|
invalidate_palette_window(window, message);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 1000:59a0 — WM_PALETTECHANGED. Ignore notifications originating from this
|
|
* window or its child; otherwise realize the global palette as a background
|
|
* palette, update mapped colors, restore the previous palette, and consume it.
|
|
*/
|
|
static uint16_t wm_palette_changed_impl(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
HWND16 window_handle =
|
|
win16_read_u16(win16_far_add_offset(window, WINDOW_HANDLE_OFFSET));
|
|
HWND16 changed_window =
|
|
win16_read_u16(win16_far_add_offset(message, MESSAGE_WPARAM_OFFSET));
|
|
if (changed_window == window_handle ||
|
|
GetParent16(changed_window) == window_handle) {
|
|
return 1;
|
|
}
|
|
|
|
HDC16 dc = GetDC16(window_handle);
|
|
HPALETTE16 palette = win16_read_u16(
|
|
win16_dgroup_pointer(DGROUP_PALETTE_HANDLE));
|
|
HPALETTE16 previous = SelectPalette16(dc, palette, 1);
|
|
(void)RealizePalette16(dc);
|
|
(void)UpdateColors16(dc);
|
|
(void)SelectPalette16(dc, previous, 0);
|
|
(void)ReleaseDC16(window_handle, dc);
|
|
win16_write_u32(message, MESSAGE_RESULT_OFFSET, 0);
|
|
return 0;
|
|
}
|
|
|
|
uint16_t tdkpin_wm_palette_changed(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
return wm_palette_changed_impl(window, message);
|
|
}
|
|
|
|
uint16_t tdkpin_wm_palette_changed_variant_b(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
return wm_palette_changed_impl(window, message);
|
|
}
|
|
|
|
uint16_t tdkpin_wm_palette_changed_variant_c(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
return wm_palette_changed_impl(window, message);
|
|
}
|
|
|
|
/*
|
|
* 1000:5a37 — WM_QUERYNEWPALETTE. Return/publish the signed number of palette
|
|
* entries remapped and invalidate the whole window only when that count > 0.
|
|
*/
|
|
static int16_t wm_query_new_palette_impl(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
HWND16 window_handle =
|
|
win16_read_u16(win16_far_add_offset(window, WINDOW_HANDLE_OFFSET));
|
|
HDC16 dc = GetDC16(window_handle);
|
|
HPALETTE16 palette = win16_read_u16(
|
|
win16_dgroup_pointer(DGROUP_PALETTE_HANDLE));
|
|
HPALETTE16 previous = SelectPalette16(dc, palette, 0);
|
|
int16_t changed = (int16_t)RealizePalette16(dc);
|
|
(void)SelectPalette16(dc, previous, 0);
|
|
(void)ReleaseDC16(window_handle, dc);
|
|
if (changed > 0) {
|
|
(void)InvalidateRect16(window_handle, 0, 0);
|
|
}
|
|
win16_write_u32(message, MESSAGE_RESULT_OFFSET, (uint16_t)changed);
|
|
return changed;
|
|
}
|
|
|
|
int16_t tdkpin_wm_query_new_palette(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
return wm_query_new_palette_impl(window, message);
|
|
}
|
|
|
|
int16_t tdkpin_wm_query_new_palette_variant_b(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
return wm_query_new_palette_impl(window, message);
|
|
}
|
|
|
|
int16_t tdkpin_wm_query_new_palette_variant_c(
|
|
Win16FarPtr window, Win16FarPtr message)
|
|
{
|
|
return wm_query_new_palette_impl(window, message);
|
|
}
|
|
|
|
/* 1000:6129 — setup one board window and load DAT 1000+board_index. */
|
|
void tdkpin_setup_board_window(Win16FarPtr window)
|
|
{
|
|
object_windows_setup_window(window);
|
|
HCURSOR16 wait_cursor = LoadCursor16(
|
|
0, win16_make_far_pointer(0, WIN16_IDC_WAIT));
|
|
(void)SetCursor16(wait_cursor);
|
|
uint16_t board_index = win16_read_u16(
|
|
win16_dgroup_pointer(DGROUP_BOARD_INDEX));
|
|
uint16_t resource_id =
|
|
(uint16_t)(board_index + BOARD_DAT_RESOURCE_BASE);
|
|
HBITMAP16 bitmap = tdkpin_load_bitmap_resource(
|
|
win16_make_far_pointer(0, resource_id), g_win16_instance);
|
|
win16_write_u16(
|
|
win16_dgroup_pointer(DGROUP_OVERLAY_BITMAP), 0, bitmap);
|
|
(void)SetFocus16(
|
|
win16_read_u16(win16_far_add_offset(window, WINDOW_HANDLE_OFFSET)));
|
|
}
|
|
|
|
/*
|
|
* 1000:616e — draw the current 640x460 board DAT through a compatible DC,
|
|
* preserving the caller's palette/object selections and restoring Arrow.
|
|
*/
|
|
void tdkpin_draw_board_overlay(
|
|
Win16FarPtr ignored_object,
|
|
uint16_t ignored_1,
|
|
uint16_t ignored_2,
|
|
HDC16 destination)
|
|
{
|
|
(void)ignored_object;
|
|
(void)ignored_1;
|
|
(void)ignored_2;
|
|
HPALETTE16 palette = win16_read_u16(
|
|
win16_dgroup_pointer(DGROUP_PALETTE_HANDLE));
|
|
HPALETTE16 previous_palette = SelectPalette16(destination, palette, 0);
|
|
(void)UnrealizeObject16(palette);
|
|
(void)RealizePalette16(destination);
|
|
HDC16 source = CreateCompatibleDC16(destination);
|
|
HBITMAP16 bitmap = win16_read_u16(
|
|
win16_dgroup_pointer(DGROUP_OVERLAY_BITMAP));
|
|
HGDIOBJ16 previous_bitmap = SelectObject16(source, bitmap);
|
|
(void)BitBlt16(
|
|
destination,
|
|
0,
|
|
0,
|
|
BOARD_WIDTH,
|
|
BOARD_HEIGHT,
|
|
source,
|
|
0,
|
|
0,
|
|
WIN16_SRCCOPY);
|
|
(void)SelectObject16(source, previous_bitmap);
|
|
(void)DeleteDC16(source);
|
|
(void)SelectPalette16(destination, previous_palette, 0);
|
|
HCURSOR16 arrow = LoadCursor16(
|
|
0, win16_make_far_pointer(0, WIN16_IDC_ARROW));
|
|
(void)SetCursor16(arrow);
|
|
}
|