git.y1.nz

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.