SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
XdgThumbnailer/emulate.c
1 #include "emulate.h"
2
3 #include <glib.h>
4 #include <stdbool.h>
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "Core/gb.h"
10
11 // Auto-generated via `glib-compile-resources` from `resources.gresource.xml`.
12 #include "build/obj/XdgThumbnailer/resources.h"
13
14 #define NB_FRAMES_TO_EMULATE (60 * 10)
15
16 #define BOOT_ROM_SIZE (0x100 + 0x800) // The two "parts" of it, which are stored contiguously.
17
18 /* --- */
19
20 static char *async_input_callback(GB_gameboy_t *gb)
21 {
22 (void)gb;
23 return NULL;
24 }
25
26 static void log_callback(GB_gameboy_t *gb, const char *string, GB_log_attributes_t attributes)
27 {
28 (void)gb, (void)string, (void)attributes; // Swallow any logs.
29 }
30
31 static void vblank_callback(GB_gameboy_t *gb, GB_vblank_type_t type)
32 {
33 (void)type; // Ignore the type, we use VBlank counting as a kind of pacing (and to avoid tearing).
34
35 unsigned *nb_frames_left = GB_get_user_data(gb);
36 (*nb_frames_left)--;
37
38 // *Do* render the very last frame.
39 if (*nb_frames_left == 1) {
40 GB_set_rendering_disabled(gb, false);
41 }
42 }
43
44 static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
45 {
46 uint32_t rgba;
47 // The GdkPixbuf that will be created from the screen buffer later, expects components in the
48 // order [red, green, blue, alpha], from a uint8_t[] buffer.
49 // But SameBoy requires a uint32_t[] buffer, and don't know the endianness of `uint32_t`.
50 // So we treat each uint32_t as a 4-byte buffer, and write the bytes accordingly.
51 // This is guaranteed to not be UB, because casting a `T*` to any flavour of `char*` accesses
52 // and modifies the `T`'s "object representation".
53 uint8_t *bytes = (uint8_t *)&rgba;
54 bytes[0] = r;
55 bytes[1] = g;
56 bytes[2] = b;
57 bytes[3] = 0xFF;
58 return rgba;
59 }
60
61 uint8_t emulate(const char *path, uint32_t screen[static GB_SCREEN_WIDTH * GB_SCREEN_HEIGHT])
62 {
63 GB_gameboy_t gb;
64 GB_init(&gb, GB_MODEL_CGB_E);
65
66 const char *last_dot = strrchr(path, '.');
67 bool is_isx = last_dot && strcmp(last_dot + 1, "isx") == 0;
68 if (is_isx ? GB_load_isx(&gb, path) : GB_load_rom(&gb, path)) {
69 exit(EXIT_FAILURE);
70 }
71
72 GError *error = NULL;
73 GBytes *boot_rom = g_resource_lookup_data(resources_get_resource(), "/thumbnailer/cgb_boot_fast.bin",
74 G_RESOURCE_LOOKUP_FLAGS_NONE, &error);
75 g_assert_no_error(error); // This shouldn't be able to fail.
76 size_t boot_rom_size;
77 const uint8_t *boot_rom_data = g_bytes_get_data(boot_rom, &boot_rom_size);
78 g_assert_cmpuint(boot_rom_size, ==, BOOT_ROM_SIZE);
79 GB_load_boot_rom_from_buffer(&gb, boot_rom_data, boot_rom_size);
80 g_bytes_unref(boot_rom);
81
82 GB_set_vblank_callback(&gb, vblank_callback);
83 GB_set_pixels_output(&gb, screen);
84 GB_set_rgb_encode_callback(&gb, rgb_encode);
85 GB_set_async_input_callback(&gb, async_input_callback);
86 GB_set_log_callback(&gb, log_callback); // Anything bizarre the ROM does during emulation, we don't care about.
87 GB_set_color_correction_mode(&gb, GB_COLOR_CORRECTION_MODERN_BALANCED);
88
89 unsigned nb_frames_left = NB_FRAMES_TO_EMULATE;
90 GB_set_user_data(&gb, &nb_frames_left);
91
92 GB_set_rendering_disabled(&gb, true);
93 GB_set_turbo_mode(&gb, true, true);
94 while (nb_frames_left) {
95 GB_run(&gb);
96 }
97
98 int cgb_flag = GB_read_memory(&gb, 0x143) & 0xC0;
99 GB_free(&gb);
100 return cgb_flag;
101 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.