Gameboy Camera API
This commit is contained in:
parent
b3b041a151
commit
ab5f66795a
89
Core/camera.c
Normal file
89
Core/camera.c
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include "camera.h"
|
||||||
|
|
||||||
|
static int8_t dither_random(uint8_t x, uint8_t y)
|
||||||
|
{
|
||||||
|
static bool once = false;
|
||||||
|
static int8_t random[128*112];
|
||||||
|
if (!once) {
|
||||||
|
unsigned int r = 0x1337c0de;
|
||||||
|
for (int i = 0; i < sizeof(random); i++) {
|
||||||
|
random[i] = r % 85 - 42;
|
||||||
|
r += 11;
|
||||||
|
r *= 25214903917;
|
||||||
|
}
|
||||||
|
once = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return random[x + y * 128];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t GB_camera_read_image(GB_gameboy_t *gb, uint16_t addr)
|
||||||
|
{
|
||||||
|
uint8_t tile_x = addr / 0x10 % 0x10;
|
||||||
|
uint8_t tile_y = addr / 0x10 / 0x10;
|
||||||
|
|
||||||
|
uint8_t y = ((addr >> 1) & 0x7) + tile_y * 8;
|
||||||
|
uint8_t bit = addr & 1;
|
||||||
|
|
||||||
|
uint8_t ret = 0;
|
||||||
|
|
||||||
|
for (uint8_t x = tile_x * 8; x < tile_x * 8 + 8; x++) {
|
||||||
|
|
||||||
|
int color = gb->camera_get_pixel_callback? ~gb->camera_get_pixel_callback(gb, x,y) : (rand() & 0xFF);
|
||||||
|
|
||||||
|
/* Dither using a deterministic random */
|
||||||
|
color += dither_random(x, y);
|
||||||
|
if (color > 255) {
|
||||||
|
color = 255;
|
||||||
|
}
|
||||||
|
else if (color < 0) {
|
||||||
|
color = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret <<= 1;
|
||||||
|
ret |= (color >> (6 + bit)) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GB_set_camera_get_pixel_callback(GB_gameboy_t *gb, GB_camera_get_pixel_callback_t callback)
|
||||||
|
{
|
||||||
|
gb->camera_get_pixel_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GB_set_camera_update_request_callback(GB_gameboy_t *gb, GB_camera_update_request_callback_t callback)
|
||||||
|
{
|
||||||
|
gb->camera_update_request_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GB_camera_updated(GB_gameboy_t *gb)
|
||||||
|
{
|
||||||
|
gb->camera_registers[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GB_camera_write_register(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
addr &= 0x7F;
|
||||||
|
if (addr == 0) {
|
||||||
|
if ((value & 1) && gb->camera_update_request_callback) {
|
||||||
|
/* If no callback is set, ignore the write as if the camera is instantly done */
|
||||||
|
gb->camera_update_request_callback(gb);
|
||||||
|
gb->camera_registers[0] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (addr >= 0x36) {
|
||||||
|
GB_log(gb, "Wrote invalid camera register %02x: %2x\n", addr, value);
|
||||||
|
}
|
||||||
|
/* Todo: find out what these registers do */
|
||||||
|
gb->camera_registers[addr] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t GB_camera_read_register(GB_gameboy_t *gb, uint16_t addr)
|
||||||
|
{
|
||||||
|
if ((addr & 0x7F) == 0) {
|
||||||
|
return gb->camera_registers[0];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
15
Core/camera.h
Normal file
15
Core/camera.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef camera_h
|
||||||
|
#define camera_h
|
||||||
|
#include "gb.h"
|
||||||
|
|
||||||
|
uint8_t GB_camera_read_image(GB_gameboy_t *gb, uint16_t addr);
|
||||||
|
|
||||||
|
void GB_set_camera_get_pixel_callback(GB_gameboy_t *gb, GB_camera_get_pixel_callback_t callback);
|
||||||
|
void GB_set_camera_update_request_callback(GB_gameboy_t *gb, GB_camera_update_request_callback_t callback);
|
||||||
|
|
||||||
|
void GB_camera_updated(GB_gameboy_t *gb);
|
||||||
|
|
||||||
|
void GB_camera_write_register(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||||
|
uint8_t GB_camera_read_register(GB_gameboy_t *gb, uint16_t addr);
|
||||||
|
|
||||||
|
#endif
|
@ -159,6 +159,8 @@ typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, GB_log_a
|
|||||||
typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb);
|
typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb);
|
||||||
typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b);
|
typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b);
|
||||||
typedef void (*GB_infrared_callback_t)(GB_gameboy_t *gb, bool on, long cycles_since_last_update);
|
typedef void (*GB_infrared_callback_t)(GB_gameboy_t *gb, bool on, long cycles_since_last_update);
|
||||||
|
typedef uint8_t (*GB_camera_get_pixel_callback_t)(GB_gameboy_t *gb, uint8_t x, uint8_t y);
|
||||||
|
typedef void (*GB_camera_update_request_callback_t)(GB_gameboy_t *gb);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
enum {
|
enum {
|
||||||
@ -284,6 +286,7 @@ typedef struct GB_gameboy_s {
|
|||||||
};
|
};
|
||||||
uint16_t mbc_rom0_bank; /* For some MBC1 wirings. */
|
uint16_t mbc_rom0_bank; /* For some MBC1 wirings. */
|
||||||
bool camera_registers_mapped;
|
bool camera_registers_mapped;
|
||||||
|
uint8_t camera_registers[0x36];
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -380,6 +383,8 @@ typedef struct GB_gameboy_s {
|
|||||||
GB_rgb_encode_callback_t rgb_encode_callback;
|
GB_rgb_encode_callback_t rgb_encode_callback;
|
||||||
GB_vblank_callback_t vblank_callback;
|
GB_vblank_callback_t vblank_callback;
|
||||||
GB_infrared_callback_t infrared_callback;
|
GB_infrared_callback_t infrared_callback;
|
||||||
|
GB_camera_get_pixel_callback_t camera_get_pixel_callback;
|
||||||
|
GB_camera_update_request_callback_t camera_update_request_callback;
|
||||||
|
|
||||||
/* IR */
|
/* IR */
|
||||||
long cycles_since_ir_change;
|
long cycles_since_ir_change;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "debugger.h"
|
#include "debugger.h"
|
||||||
#include "mbc.h"
|
#include "mbc.h"
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
|
#include "camera.h"
|
||||||
|
|
||||||
typedef uint8_t GB_read_function_t(GB_gameboy_t *gb, uint16_t addr);
|
typedef uint8_t GB_read_function_t(GB_gameboy_t *gb, uint16_t addr);
|
||||||
typedef void GB_write_function_t(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
typedef void GB_write_function_t(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||||
@ -83,13 +84,17 @@ static uint8_t read_mbc_ram(GB_gameboy_t *gb, uint16_t addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (gb->camera_registers_mapped) {
|
if (gb->camera_registers_mapped) {
|
||||||
return 0;
|
return GB_camera_read_register(gb, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gb->mbc_ram) {
|
if (!gb->mbc_ram) {
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gb->cartridge_type->mbc_subtype == GB_CAMERA && gb->mbc_ram_bank == 0 && addr >= 0xa100 && addr < 0xaf00) {
|
||||||
|
return GB_camera_read_image(gb, addr - 0xa100);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t ret = gb->mbc_ram[((addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000) & (gb->mbc_ram_size - 1)];
|
uint8_t ret = gb->mbc_ram[((addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000) & (gb->mbc_ram_size - 1)];
|
||||||
if (gb->cartridge_type->mbc_type == GB_MBC2) {
|
if (gb->cartridge_type->mbc_type == GB_MBC2) {
|
||||||
ret |= 0xF0;
|
ret |= 0xF0;
|
||||||
@ -329,6 +334,11 @@ static void write_vram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
|
|
||||||
static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
|
if (gb->camera_registers_mapped) {
|
||||||
|
GB_camera_write_register(gb, addr, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!gb->mbc_ram_enable || !gb->mbc_ram_size) return;
|
if (!gb->mbc_ram_enable || !gb->mbc_ram_size) return;
|
||||||
|
|
||||||
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
||||||
@ -340,10 +350,6 @@ static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb->camera_registers_mapped) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gb->mbc_ram[((addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000) & (gb->mbc_ram_size - 1)] = value;
|
gb->mbc_ram[((addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000) & (gb->mbc_ram_size - 1)] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user