Refinements to camera support according to AntonioND's docs

This commit is contained in:
Lior Halphon 2016-10-03 18:24:15 +03:00
parent dd23fffcc0
commit 8941504863
2 changed files with 25 additions and 16 deletions

View File

@ -2,7 +2,7 @@
uint8_t GB_camera_read_image(GB_gameboy_t *gb, uint16_t addr) uint8_t GB_camera_read_image(GB_gameboy_t *gb, uint16_t addr)
{ {
if (gb->camera_registers[GB_CAMERA_FLAGS] & 1) { if (gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] & 1) {
/* Forbid reading the image while the camera is busy. */ /* Forbid reading the image while the camera is busy. */
return 0xFF; return 0xFF;
} }
@ -18,16 +18,24 @@ uint8_t GB_camera_read_image(GB_gameboy_t *gb, uint16_t addr)
long color = gb->camera_get_pixel_callback? gb->camera_get_pixel_callback(gb, x,y) : (rand() & 0xFF); long color = gb->camera_get_pixel_callback? gb->camera_get_pixel_callback(gb, x,y) : (rand() & 0xFF);
/* Color is multiplied by the multiplier register. */ static const double gain_values[] = {0.8809390, 0.9149149, 0.9457498, 0.9739758,
/* It is unknown what register 1 does, but changing bits 2-3 from 0x4 to 0x8 seems equivalent to adding 0x2000 1.0000000, 1.0241412, 1.0466537, 1.0677433,
to the multiplier. Is it related to actual exposure time? */ 1.0875793, 1.1240310, 1.1568911, 1.1868043,
unsigned long multiplier_bias = (gb->camera_registers[GB_CAMERA_UNKNOWN_FLAGS] & 0xF) * 0x800; 1.2142561, 1.2396208, 1.2743837, 1.3157323,
color = color * ((gb->camera_registers[GB_CAMERA_MULTIPLIER_HIGH] << 8) + gb->camera_registers[GB_CAMERA_MULTIPLIER_LOW] + multiplier_bias) / 0x3000; 1.3525190, 1.3856512, 1.4157897, 1.4434309,
1.4689574, 1.4926697, 1.5148087, 1.5355703,
1.5551159, 1.5735801, 1.5910762, 1.6077008,
1.6235366, 1.6386550, 1.6531183, 1.6669808};
/* Multiply color by gain value */
color *= gain_values[gb->camera_registers[GB_CAMERA_GAIN_AND_EDGE_ENCHANCEMENT_FLAGS] & 0x1F];
/* Color is multiplied by the exposure register to simulate exposure. */
color = color * ((gb->camera_registers[GB_CAMERA_EXPOSURE_HIGH] << 8) + gb->camera_registers[GB_CAMERA_EXPOSURE_LOW]) / 0x1000;
/* The camera's registers are used as a threshold pattern, which defines the dithering */ /* The camera's registers are used as a threshold pattern, which defines the dithering */
uint8_t pattern_base = ((x & 3) + (y & 3) * 4) * 3 + GB_CAMERA_DITHERING_PATTERN_START; uint8_t pattern_base = ((x & 3) + (y & 3) * 4) * 3 + GB_CAMERA_DITHERING_PATTERN_START;
/* Todo: I have absolutely no reason to assume that this does not go backwards! */
if (color < gb->camera_registers[pattern_base]) { if (color < gb->camera_registers[pattern_base]) {
color = 3; color = 3;
} }
@ -60,16 +68,17 @@ void GB_set_camera_update_request_callback(GB_gameboy_t *gb, GB_camera_update_re
void GB_camera_updated(GB_gameboy_t *gb) void GB_camera_updated(GB_gameboy_t *gb)
{ {
gb->camera_registers[GB_CAMERA_FLAGS] &= ~1; gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] &= ~1;
} }
void GB_camera_write_register(GB_gameboy_t *gb, uint16_t addr, uint8_t value) void GB_camera_write_register(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
{ {
addr &= 0x7F; addr &= 0x7F;
if (addr == GB_CAMERA_FLAGS) { if (addr == GB_CAMERA_SHOOT_AND_1D_FLAGS) {
if ((value & 1) && !(gb->camera_registers[GB_CAMERA_FLAGS] & 1) && gb->camera_update_request_callback) { value &= 0x7;
if ((value & 1) && !(gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] & 1) && gb->camera_update_request_callback) {
/* If no callback is set, ignore the write as if the camera is instantly done */ /* If no callback is set, ignore the write as if the camera is instantly done */
gb->camera_registers[GB_CAMERA_FLAGS] |= 1; gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] |= 1;
gb->camera_update_request_callback(gb); gb->camera_update_request_callback(gb);
} }
} }
@ -85,7 +94,7 @@ 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) uint8_t GB_camera_read_register(GB_gameboy_t *gb, uint16_t addr)
{ {
if ((addr & 0x7F) == 0) { if ((addr & 0x7F) == 0) {
return gb->camera_registers[GB_CAMERA_FLAGS]; return gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS];
} }
return 0; return 0;
} }

View File

@ -3,10 +3,10 @@
#include "gb.h" #include "gb.h"
enum { enum {
GB_CAMERA_FLAGS = 0, GB_CAMERA_SHOOT_AND_1D_FLAGS = 0,
GB_CAMERA_UNKNOWN_FLAGS = 1, GB_CAMERA_GAIN_AND_EDGE_ENCHANCEMENT_FLAGS = 1,
GB_CAMERA_MULTIPLIER_HIGH = 2, GB_CAMERA_EXPOSURE_HIGH = 2,
GB_CAMERA_MULTIPLIER_LOW = 3, GB_CAMERA_EXPOSURE_LOW = 3,
GB_CAMERA_DITHERING_PATTERN_START = 6, GB_CAMERA_DITHERING_PATTERN_START = 6,
GB_CAMERA_DITHERING_PATTERN_END = 0x35, GB_CAMERA_DITHERING_PATTERN_END = 0x35,
}; };