#include "../tdkpin_flippers.h" #include "../tdkpin_collision_records.h" #include #include #include enum { RECORDS_BASE = 0x095b, LEFT_OUTER = 66, LEFT_EDGE = 67, LEFT_INNER = 68, RIGHT_INNER = 81, RIGHT_EDGE = 82, RIGHT_OUTER = 83, }; static uint8_t g_dgroup[0x5000]; static uint8_t g_objects[0x1000]; static uint8_t g_stack[0x1000]; static Win16FarPtr g_receiver; static unsigned g_get_dc_calls; static unsigned g_release_dc_calls; static unsigned g_restore_a_calls; static unsigned g_restore_b_calls; static unsigned g_present_calls; static bool g_expect_parent_stack_untouched; static uint16_t g_expected_parent_bp; int32_t borland_multiply_i32(int32_t left, int32_t right) { return (int32_t)((uint32_t)left * (uint32_t)right); } HDC16 GetDC16(HWND16 window) { assert(window == 0x2222); if (g_expect_parent_stack_untouched) { assert(win16_read_stack_u16( (uint16_t)(g_expected_parent_bp - 8)) == 0xaaaa); assert(win16_read_stack_u16( (uint16_t)(g_expected_parent_bp - 6)) == 0xbbbb); assert(win16_read_stack_u16( (uint16_t)(g_expected_parent_bp - 4)) == 0xcccc); assert(win16_read_stack_u16( (uint16_t)(g_expected_parent_bp - 2)) == 0xdddd); g_expect_parent_stack_untouched = false; } g_get_dc_calls++; return 0x3333; } INT16 ReleaseDC16(HWND16 window, HDC16 dc) { assert(window == 0x2222 && dc == 0x3333); g_release_dc_calls++; return 1; } static void assert_region( INT16 height, INT16 width, INT16 y, INT16 x, HDC16 dc) { assert(dc == 0x3333); if (height == 52) { assert(width == 47 && y == 373 && x == 93); } else { assert(height == 53 && width == 45 && y == 372 && x == 175); } } void tdkpin_restore_background_region_a( INT16 height, INT16 width, INT16 y, INT16 x, HDC16 dc) { assert_region(height, width, y, x, dc); g_restore_a_calls++; } void tdkpin_restore_background_region_b( INT16 height, INT16 width, INT16 y, INT16 x, HDC16 dc) { assert_region(height, width, y, x, dc); g_restore_b_calls++; } void tdkpin_present_background_region( INT16 height, INT16 width, INT16 y, INT16 x, HDC16 dc) { assert_region(height, width, y, x, dc); g_present_calls++; } static Win16FarPtr record(uint16_t id) { return win16_dgroup_pointer((uint16_t)( RECORDS_BASE + id * sizeof(TdkpinCollisionRecord))); } static void put(uint16_t id, size_t offset, int32_t value) { win16_write_u32(record(id), (uint16_t)offset, (uint32_t)value); } static int32_t get(uint16_t id, size_t offset) { return (int32_t)win16_read_u32( win16_far_add_offset(record(id), (uint16_t)offset)); } static void put_points( uint16_t id, int32_t point1_x, int32_t point1_y, int32_t point2_x, int32_t point2_y) { put(id, offsetof(TdkpinCollisionRecord, point1_x_milli), point1_x); put(id, offsetof(TdkpinCollisionRecord, point1_y_milli), point1_y); put(id, offsetof(TdkpinCollisionRecord, point2_x_milli), point2_x); put(id, offsetof(TdkpinCollisionRecord, point2_y_milli), point2_y); } static void assert_points( uint16_t id, int32_t point1_x, int32_t point1_y, int32_t point2_x, int32_t point2_y) { assert(get(id, offsetof(TdkpinCollisionRecord, point1_x_milli)) == point1_x); assert(get(id, offsetof(TdkpinCollisionRecord, point1_y_milli)) == point1_y); assert(get(id, offsetof(TdkpinCollisionRecord, point2_x_milli)) == point2_x); assert(get(id, offsetof(TdkpinCollisionRecord, point2_y_milli)) == point2_y); } static void put_bounds( uint16_t id, int32_t minimum_x, int32_t minimum_y, int32_t maximum_x, int32_t maximum_y) { put(id, offsetof(TdkpinCollisionRecord, bounds_min_x_milli), minimum_x); put(id, offsetof(TdkpinCollisionRecord, bounds_min_y_milli), minimum_y); put(id, offsetof(TdkpinCollisionRecord, bounds_max_x_milli), maximum_x); put(id, offsetof(TdkpinCollisionRecord, bounds_max_y_milli), maximum_y); } static void assert_bounds( uint16_t id, int32_t minimum_x, int32_t minimum_y, int32_t maximum_x, int32_t maximum_y) { assert(get(id, offsetof(TdkpinCollisionRecord, bounds_min_x_milli)) == minimum_x); assert(get(id, offsetof(TdkpinCollisionRecord, bounds_min_y_milli)) == minimum_y); assert(get(id, offsetof(TdkpinCollisionRecord, bounds_max_x_milli)) == maximum_x); assert(get(id, offsetof(TdkpinCollisionRecord, bounds_max_y_milli)) == maximum_y); } static void prepare_fixture(void) { memset(g_dgroup, 0, sizeof(g_dgroup)); memset(g_objects, 0, sizeof(g_objects)); memset(g_stack, 0, sizeof(g_stack)); win16_reset_segment_bindings(); win16_bind_segment(0x7000, g_objects, sizeof(g_objects), true); win16_bind_segment(0x7200, g_dgroup, sizeof(g_dgroup), true); win16_bind_segment(0x7300, g_stack, sizeof(g_stack), true); win16_set_dgroup_selector(0x7200); win16_set_stack_state(0x7300, 0); g_receiver = win16_make_far_pointer(0x7000, 0); win16_write_u16(g_receiver, 4, 0x2222); g_get_dc_calls = 0; g_release_dc_calls = 0; g_restore_a_calls = 0; g_restore_b_calls = 0; g_present_calls = 0; g_expect_parent_stack_untouched = false; g_expected_parent_bp = 0; } static void prepare_static_link(uint16_t parent_bp, uint16_t caller_bp) { win16_write_stack_u16((uint16_t)(parent_bp + 6), caller_bp); win16_write_stack_u16( (uint16_t)(caller_bp + 6), win16_far_offset(g_receiver)); win16_write_stack_u16( (uint16_t)(caller_bp + 8), win16_far_selector(g_receiver)); win16_write_stack_u16((uint16_t)(parent_bp - 8), 0xaaaa); win16_write_stack_u16((uint16_t)(parent_bp - 6), 0xbbbb); win16_write_stack_u16((uint16_t)(parent_bp - 4), 0xcccc); win16_write_stack_u16((uint16_t)(parent_bp - 2), 0xdddd); g_expect_parent_stack_untouched = true; g_expected_parent_bp = parent_bp; } static void test_left_flipper_raise(void) { const uint16_t parent_bp = 0x0200; const uint16_t caller_bp = 0x0300; prepare_fixture(); prepare_static_link(parent_bp, caller_bp); put_points(LEFT_OUTER, 100000, 200000, 300000, 400000); put_bounds(LEFT_EDGE, 10000, 20000, 100000, 200000); put_points(LEFT_EDGE, 30000, 40000, 0, 0); put_points(LEFT_INNER, 300000, 100000, 100000, 400000); win16_write_u16(g_receiver, 0x0bd4, 0); tdkpin_move_flipper_bitmap_geometry(parent_bp, 1, 1); assert_points(LEFT_OUTER, 114000, 204000, 310000, 444000); assert_bounds(LEFT_OUTER, 109000, 199000, 315000, 449000); assert_points(LEFT_EDGE, 31000, 82000, 0, 0); assert_bounds(LEFT_EDGE, 12000, 63000, 98000, 157000); assert_points(LEFT_INNER, 293000, 143000, 81000, 406000); assert_bounds(LEFT_INNER, 76000, 138000, 298000, 411000); assert(win16_read_stack_u16((uint16_t)(parent_bp - 4)) == 0); assert(win16_read_stack_u16((uint16_t)(parent_bp - 2)) == 0); assert(win16_read_stack_u16((uint16_t)(parent_bp - 8)) == 0xa7f8); assert(win16_read_stack_u16((uint16_t)(parent_bp - 6)) == 0); assert(g_restore_b_calls == 1 && g_restore_a_calls == 0); assert(g_present_calls == 1); assert(g_get_dc_calls == 1 && g_release_dc_calls == 1); } static void test_right_flipper_lower(void) { const uint16_t parent_bp = 0x0200; const uint16_t caller_bp = 0x0300; prepare_fixture(); prepare_static_link(parent_bp, caller_bp); put_points(RIGHT_OUTER, 100000, 200000, 300000, 400000); put_bounds(RIGHT_EDGE, 10000, 200000, 100000, 400000); put_points(RIGHT_EDGE, 30000, 200000, 0, 0); put_points(RIGHT_INNER, 300000, 400000, 100000, 200000); win16_write_u16(g_receiver, 0x0bd6, 1); tdkpin_move_flipper_bitmap_geometry(parent_bp, -1, 2); assert_points(RIGHT_OUTER, 111000, 155000, 316000, 397000); assert_bounds(RIGHT_OUTER, 106000, 150000, 321000, 402000); assert_points(RIGHT_EDGE, 32000, 157000, 0, 0); assert_bounds(RIGHT_EDGE, 12000, 157000, 98000, 443000); assert_points(RIGHT_INNER, 281000, 394000, 94000, 151000); assert_bounds(RIGHT_INNER, 89000, 146000, 286000, 399000); assert(win16_read_stack_u16((uint16_t)(parent_bp - 8)) == 0x5808); assert(win16_read_stack_u16((uint16_t)(parent_bp - 6)) == 0xffff); assert(g_restore_a_calls == 1 && g_restore_b_calls == 0); assert(g_present_calls == 1); assert(g_get_dc_calls == 1 && g_release_dc_calls == 1); } static void test_unknown_flipper_only_balances_dc(void) { prepare_fixture(); win16_write_u32(record(66), 0, 0x12345678); tdkpin_move_flipper_bitmap_geometry_for_receiver(g_receiver, 7, 3); assert(win16_read_u32(record(66)) == 0x12345678); assert(g_restore_a_calls == 0 && g_restore_b_calls == 0); assert(g_present_calls == 0); assert(g_get_dc_calls == 1 && g_release_dc_calls == 1); } int main(void) { test_left_flipper_raise(); test_right_flipper_lower(); test_unknown_flipper_only_balances_dc(); return 0; }