#include "../tdkpin_panel_animation.h" #include #include typedef struct { HDC16 destination; HGDIOBJ16 destination_object; INT16 destination_x; INT16 destination_y; INT16 width; INT16 height; HDC16 source; HGDIOBJ16 source_object; INT16 source_x; INT16 source_y; uint32_t rop; } RecordedBlit; static uint8_t g_stack[0x400]; static uint8_t g_object[0x0c00]; static uint8_t g_dgroup[0x5000]; static Win16FarPtr g_receiver; static unsigned g_create_dc_calls; static unsigned g_select_calls; static unsigned g_blit_calls; static unsigned g_delete_dc_calls; static unsigned g_play_calls; static unsigned g_stop_calls; static uint16_t g_played_sound; static HGDIOBJ16 g_source_selected; static HGDIOBJ16 g_panel_selected; static RecordedBlit g_blits[16]; HDC16 GetDC16(HWND16 window) { assert(window == 0x2222); return 0x3333; } HDC16 CreateCompatibleDC16(HDC16 dc) { assert(dc == 0x3333 && g_create_dc_calls < 2); return (HDC16)(0x4001 + g_create_dc_calls++); } HBITMAP16 CreateCompatibleBitmap16(HDC16 dc, INT16 width, INT16 height) { assert(dc == 0x3333 && width == 91 && height == 123); return 0x5000; } HGDIOBJ16 SelectObject16(HDC16 dc, HGDIOBJ16 object) { g_select_calls++; if (dc == 0x4001) { HGDIOBJ16 old = g_source_selected; g_source_selected = object; return old; } assert(dc == 0x4002); HGDIOBJ16 old = g_panel_selected; g_panel_selected = object; return old; } BOOL16 BitBlt16( HDC16 destination, INT16 destination_x, INT16 destination_y, INT16 width, INT16 height, HDC16 source, INT16 source_x, INT16 source_y, uint32_t raster_operation) { assert(g_blit_calls < 16); RecordedBlit *blit = &g_blits[g_blit_calls++]; *blit = (RecordedBlit){ destination, destination == 0x4001 ? g_source_selected : destination == 0x4002 ? g_panel_selected : 0, destination_x, destination_y, width, height, source, source == 0x4001 ? g_source_selected : source == 0x4002 ? g_panel_selected : 0, source_x, source_y, raster_operation}; return 1; } BOOL16 DeleteObject16(HGDIOBJ16 object) { assert(object == 0x5000); return 1; } BOOL16 DeleteDC16(HDC16 dc) { assert(dc == (g_delete_dc_calls == 0 ? 0x4002 : 0x4001)); g_delete_dc_calls++; return 1; } INT16 ReleaseDC16(HWND16 window, HDC16 dc) { assert(window == 0x2222 && dc == 0x3333); return 1; } void tdkpin_play_sound_if_not_tilted(uint16_t sound_number) { g_played_sound = sound_number; g_play_calls++; } uint16_t tdkpin_stop_sound_if_active(void) { g_stop_calls++; return 0xabcd; } static void prepare_fixture(int32_t frame) { memset(g_stack, 0, sizeof(g_stack)); memset(g_object, 0, sizeof(g_object)); memset(g_dgroup, 0, sizeof(g_dgroup)); memset(g_blits, 0, sizeof(g_blits)); win16_reset_segment_bindings(); win16_bind_segment(0x7000, g_stack, sizeof(g_stack), true); win16_bind_segment(0x7100, g_object, sizeof(g_object), true); win16_bind_segment(0x7200, g_dgroup, sizeof(g_dgroup), true); win16_set_dgroup_selector(0x7200); win16_set_stack_state(0x7000, 0); g_receiver = win16_make_far_pointer(0x7100, 0); win16_write_stack_u16(0x0106, win16_far_offset(g_receiver)); win16_write_stack_u16(0x0108, win16_far_selector(g_receiver)); win16_write_u16(g_receiver, 4, 0x2222); win16_write_u16(win16_dgroup_pointer(0x085f), 0, 0x6000); win16_write_u16(win16_dgroup_pointer(0x0859), 0, 0x6001); win16_write_u16(win16_dgroup_pointer(0x085b), 0, 0x6002); win16_write_u16(win16_dgroup_pointer(0x085d), 0, 0x6003); win16_write_u32(win16_dgroup_pointer(0x0851), 0, (uint32_t)frame); g_create_dc_calls = 0; g_select_calls = 0; g_blit_calls = 0; g_delete_dc_calls = 0; g_play_calls = 0; g_stop_calls = 0; g_played_sound = 0; g_source_selected = 0x7001; g_panel_selected = 0x7002; } static void assert_common_edges(void) { assert(g_create_dc_calls == 2 && g_delete_dc_calls == 2); assert(g_blits[0].destination == 0x4002); assert(g_blits[0].width == 91 && g_blits[0].height == 123); assert(g_blits[0].source_object == 0x6000); assert(g_blits[0].source_x == 79 && g_blits[0].source_y == 0); RecordedBlit *last = &g_blits[g_blit_calls - 1]; assert(last->destination == 0x3333); assert(last->destination_x == 79 && last->destination_y == 0); assert(last->width == 91 && last->height == 123); assert(last->source == 0x4002 && last->source_x == 0); assert(last->source_y == 0 && last->rop == 0x00cc0020u); } static void run_count_case( int32_t frame, unsigned expected_blits, uint16_t expected_sound, unsigned expected_stops) { prepare_fixture(frame); tdkpin_draw_panel_animation(0x0100); assert(g_blit_calls == expected_blits); assert(g_stop_calls == expected_stops); assert(g_play_calls == (expected_sound != 0 ? 1u : 0u)); assert(g_played_sound == expected_sound); assert_common_edges(); } static void test_phase_boundaries(void) { run_count_case(45, 4, 0, 1); run_count_case(58, 4, 12, 0); run_count_case(66, 7, 13, 0); run_count_case(111, 5, 0, 0); run_count_case(129, 3, 0, 1); run_count_case(159, 5, 13, 0); run_count_case(177, 7, 0, 0); run_count_case(204, 7, 0, 0); run_count_case(221, 7, 0, 0); run_count_case(222, 6, 0, 1); run_count_case(230, 6, 12, 0); run_count_case(238, 6, 13, 0); } static void test_first_frame_and_formulas(void) { prepare_fixture(1); tdkpin_draw_panel_animation(0x0100); assert(g_blit_calls == 5 && g_played_sound == 13); assert(g_blits[1].destination_object == 0x6002); assert(g_blits[1].destination_x == 79 && g_blits[1].width == 91); assert(g_blits[1].height == 90 && g_blits[1].source_x == 271); assert(g_blits[2].destination_x == 20 && g_blits[2].height == 2); assert(g_blits[2].source_x == 45 && g_blits[2].source_y == 177); assert(g_blits[2].rop == 0x008800c6u); assert(g_blits[3].source_x == 0 && g_blits[3].source_y == 177); assert_common_edges(); prepare_fixture(83); tdkpin_draw_panel_animation(0x0100); assert(g_blits[2].destination_y == 0 && g_blits[2].height == 90); assert(g_blits[2].source_y == 92); assert(g_blits[4].height == 54 && g_blits[4].source_y == 124); } static void test_final_frame_background_commit(void) { prepare_fixture(281); tdkpin_draw_panel_animation(0x0100); assert(g_blit_calls == 7); RecordedBlit *commit = &g_blits[5]; assert(commit->destination == 0x4002); assert(commit->destination_object == 0x6002); assert(commit->destination_x == 79 && commit->destination_y == 0); assert(commit->width == 91 && commit->height == 90); assert(commit->source_object == 0x6003); assert(commit->source_x == 79 && commit->source_y == 0); assert_common_edges(); } int main(void) { test_phase_boundaries(); test_first_frame_and_formulas(); test_final_frame_background_commit(); return 0; }