All Projects → fwsGonzo → gamebro

fwsGonzo / gamebro

Licence: MIT license
Gameboy Color emulator library for C++17

Programming Languages

C++
36643 projects - #6 most used programming language
CMake
9771 projects
shell
77523 projects

Projects that are alternatives of or similar to gamebro

worldwide
A toy GameBoy Color emulator written in golang.
Stars: ✭ 563 (+3211.76%)
Mutual labels:  gameboy-emulator, gbc, gbc-emulator
ostrich
A Game Boy Sound System player for macOS, written in Swift
Stars: ✭ 37 (+117.65%)
Mutual labels:  gameboy-emulator
Fundude
Gameboy emulator: Zig -> wasm
Stars: ✭ 98 (+476.47%)
Mutual labels:  gameboy-emulator
Goboy
Multi-platform Nintendo Game Boy Color emulator written in Go
Stars: ✭ 2,403 (+14035.29%)
Mutual labels:  gameboy-emulator
Gbemu
WebAssembly based Gameboy Emulator
Stars: ✭ 120 (+605.88%)
Mutual labels:  gameboy-emulator
Binjgb
Gameboy emulator implemented in C
Stars: ✭ 222 (+1205.88%)
Mutual labels:  gameboy-emulator
Cryboy
A Game Boy (Color) emulator written in Crystal
Stars: ✭ 68 (+300%)
Mutual labels:  gameboy-emulator
demo-emulator
Nintendo Game Boy emulator written in Go to be used in workshops about emulator programming
Stars: ✭ 41 (+141.18%)
Mutual labels:  gameboy-emulator
RGB
RGB (Rust Game Boy) is a simple emulator for the original game boy
Stars: ✭ 19 (+11.76%)
Mutual labels:  gameboy-emulator
Gopher Boy
🎮 A Game Boy emulator written in Go
Stars: ✭ 206 (+1111.76%)
Mutual labels:  gameboy-emulator
Jitboy
A Game Boy emulator with dynamic recompilation (JIT)
Stars: ✭ 190 (+1017.65%)
Mutual labels:  gameboy-emulator
Giibiiadvance
A GB, GBC and GBA emulator with GB Camera support.
Stars: ✭ 141 (+729.41%)
Mutual labels:  gameboy-emulator
Rustyboy
A Gameboy emulator written in Rust.
Stars: ✭ 224 (+1217.65%)
Mutual labels:  gameboy-emulator
Gameboy emulator
Gameboy Emulator written in Rust
Stars: ✭ 98 (+476.47%)
Mutual labels:  gameboy-emulator
emu-gameboy
A Gameboy emulator written in C++
Stars: ✭ 55 (+223.53%)
Mutual labels:  gameboy-emulator
Espeon
Gameboy emulator for the ESP32
Stars: ✭ 71 (+317.65%)
Mutual labels:  gameboy-emulator
Metroboy
MetroBoy - A playable, circuit-level simulation of an entire Game Boy
Stars: ✭ 169 (+894.12%)
Mutual labels:  gameboy-emulator
Mgba
mGBA Game Boy Advance Emulator
Stars: ✭ 3,355 (+19635.29%)
Mutual labels:  gameboy-emulator
mealybug-tearoom-tests
🪲☕️ Game Boy emulator test ROMs
Stars: ✭ 40 (+135.29%)
Mutual labels:  gameboy-emulator
jsGBC
👾 A GameBoy Color Emulator written in JavaScript
Stars: ✭ 44 (+158.82%)
Mutual labels:  gbc

GBC emulator library and trainer written in modern C++

Load a ROM

    std::vector<uint8_t> romdata = load_file(...);
    gbc::Machine machine(romdata);

Pixel output

Intended for embedded where you have direct access to framebuffers. Your computer needs a way to get a high-precision timestamp and sleep for micros at a time. Delegates will be called async from the virtual machine, and you must call the system calls from there. You can tell the virtual machine about key presses through the API.

The virtual machine does not copy the ROM data unnecessarily, and uses memory conservatively. The instruction decoder is written to reduce instruction count. When building with clang you should enable LTO.

    // trap on palette writes, resulting in a 15-bit RGB color
    machine->gpu.on_palchange(
        [] (const uint8_t idx, const uint16_t color)
        {
            // do some magic with the 5-5-5 bit channels
        });
    // trap on V-blank interrupts
    machine->set_handler(gbc::Machine::VBLANK,
        [] (gbc::Machine& machine, gbc::interrupt_t&)
        {
            // Retrieve a vector of indexed colors
            const auto& pixels = machine.gpu.pixels();

            for (int y = 0; y < gbc::GPU::SCREEN_H; y++)
            for (int x = 0; x < gbc::GPU::SCREEN_W; x++)
            {
                const uint16_t idx = pixels.at(gbc::GPU::SCREEN_W * y + x);
                // in mode13h just write index directly to backbuffer
                set_pixel(x+80, y+32, idx);
            }
            // blit and flip front framebuffer here
            /* gbz80_limited_blit(...); */
        });

You can assume that the index gbc::GPU::WHITE_IDX is always a white color.

GB color palettes

The emulator has some predefined color palettes for GB.

    enum dmg_variant_t {
        LIGHTER_GREEN = 0,
        DARKER_GREEN,
        GRAYSCALE
    };
    machine.gpu.set_dmg_variant(...);
    // now we can expand color indices on V-blanks
    uint32_t color = machine.gpu.expand_dmg_color(idx);

If you don't trap on palette writes in CGB mode, you can still expand CGB color indices like this:

    // Expand CGB color index to 32-bit RGB (with no alpha):
    uint32_t color = machine.gpu.expand_cgb_color(idx);

16-bit pixel buffer

The pixel buffer contains indices for colors in the current frame. You must assume that the palette changes between frames, and in some games even changes during frame rendering. An index is 8-bits and the machine needs 64 (0-63), where index 32 is white. The pixel buffer element size is 16-bits so that it can fit 15-bit colors if anyone wants to re-add the support. It is somewhat costly to do it this way without using macros. The emulator used to support a wide variety of color modes, but it's too costly to maintain and the vast majority of GBC games don't change palettes mid-frame, even though they can. You can replace some code in the GPU, specifically the return values of colorize_tile() and colorize_sprite(), to just write the color directly to the pixel buffer. The method to computing a CGB color is simply:

  uint16_t rgb15 = this->getpal(index*2) | (this->getpal(index*2+1) << 8);

You should apply a curve to the 15-bit color to make it more appealing, or dull if you want to emulate the real GBC LCD screen. You can use the last bit (bit 15) for something extra.

Debugging

Run the command-line variant in your favorite OS, and press Ctrl+C to break into a debugger. Only caveat is that the break is always at the next instruction.

#include <libgbc/machine.hpp>
#include <signal.h>

static gbc::Machine* machine = nullptr;
static void int_handler(int) {
	machine->break_now();
}

int main(int argc, char** args)
{
	machine = new gbc::Machine(romvector); // load this yourself
	machine->break_now();                  // start in breakpoint
	signal(SIGINT, int_handler);           // break on Ctrl+C

	while (machine->is_running())
	{
		machine->simulate();
	}
    return 0;
}

Replaying

By trapping on joypad reads, the implementor can give the virtual machine inputs exactly only when necessary, reducing state by several magnitudes. 7kB of uncompressed input data (when recording only on dpad reads) is typically 60+ seconds of gameplay. With knowledge about how many times a specific game reads the I/O register per frame, the amount can probably be halved again.

Recording example:

// disable rendering to pixel buffer
machine->gpu.scanline_rendering(false);
// trap on joypad reads
machine->io.on_joypad_read(
    [] (gbc::Machine& machine, const int mode)
    {
        // recording on dpad reads, which saves an extra magnitude of data
        if (mode == 1) {
            const uint64_t frame = machine.gpu.frame_count();
            // create record of sporadic jumps
            const uint8_t jp = (frame % 2) ? gbc::BUTTON_A : 0;
            keyboard_buffer.push_back(jp);
        }
    });

Playback example:

// trap on joypad reads
machine->io.on_joypad_read(
    [] (gbc::Machine& machine, const int mode)
    {
        // recording on dpad reads, which saves an extra magnitude of data
        if (mode == 1) {
            if (counter < keyboard_buffer->size()) {
                // input 1 byte from buffer and increment
                machine.set_inputs(keyboard_buffer->at(counter++));
            }
        }
    });

Replay example: https://cloud.nwcs.no/index.php/s/2iGRYDj7FJLpK7j

Training

We can use reinforcement learning with full machine-inspection to train a neural network to play games well. Use cheat searching in other GUI-based emulators to get memory addresses that can be used as rewards.

Post-mortem tidbits after writing a GBC emulator

Click here to read POSTERITY.md

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].