Browse Source

Add buggy SDL rendering, background drawing.

master
Ben Kurtovic 8 years ago
parent
commit
a69328a234
3 changed files with 180 additions and 8 deletions
  1. +55
    -2
      src/emulator.c
  2. +4
    -0
      src/io.c
  3. +121
    -6
      src/vdp.c

+ 55
- 2
src/emulator.c View File

@@ -2,12 +2,19 @@
Released under the terms of the MIT License. See LICENSE for details. */

#include <signal.h>
#include <SDL.h>

#include "emulator.h"
#include "logging.h"

#define SCREEN_WIDTH 3 * (160 + 96) // TODO: define elsewhere; use scale
#define SCREEN_HEIGHT 3 * (144 + 48)

static GameGear *global_gg;

static SDL_Window *window;
SDL_Renderer* renderer;

/*
Signal handler for SIGINT.
*/
@@ -19,12 +26,56 @@ static void handle_sigint(int sig)
}

/*
TODO: ...
*/
static void setup_graphics()
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
FATAL("SDL failed to initialize: %s", SDL_GetError());

SDL_CreateWindowAndRenderer(SCREEN_WIDTH, SCREEN_HEIGHT,
SDL_WINDOW_BORDERLESS/* |SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE ? */,
&window, &renderer);

if (!window)
FATAL("SDL failed to create a window: %s", SDL_GetError());
if (!renderer)
FATAL("SDL failed to create a renderer: %s", SDL_GetError());

SDL_SetRenderDrawColor(renderer, 0x33, 0x33, 0x33, 0xFF);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}

/*
GameGear callback: handle SDL logic at the end of a frame.
*/
static void draw_frame(GameGear *gg)
{
(void) gg;
// TODO: SDL draw / switch buffers here
SDL_RenderPresent(renderer);

SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
gamegear_power_off(gg);
return;
}
}

SDL_SetRenderDrawColor(renderer, 0x33, 0x33, 0x33, 0xFF);
SDL_RenderClear(renderer);
}

/*
TODO: ...
*/
static void cleanup_graphics()
{
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
window = NULL;
renderer = NULL;
SDL_Quit();
}

/*
@@ -37,6 +88,7 @@ void emulate(GameGear *gg)
global_gg = gg;
signal(SIGINT, handle_sigint);
gamegear_set_callback(gg, draw_frame);
setup_graphics();

gamegear_simulate(gg);

@@ -47,6 +99,7 @@ void emulate(GameGear *gg)
if (DEBUG_LEVEL)
gamegear_print_state(gg);

cleanup_graphics();
gamegear_clear_callback(gg);
signal(SIGINT, SIG_DFL);
global_gg = NULL;


+ 4
- 0
src/io.c View File

@@ -34,6 +34,8 @@ bool io_check_irq(IO *io)
uint8_t io_port_read(IO *io, uint8_t port)
{
if (port <= 0x06) {
if (port == 0x00)
return 0xC0;
// TODO: GG specific registers; initial state: C0 7F FF 00 FF 00 FF
} else if (port <= 0x3F) {
return 0xFF;
@@ -47,8 +49,10 @@ uint8_t io_port_read(IO *io, uint8_t port)
return vdp_read_control(io->vdp);
} else if (port == 0xCD || port == 0xDC) {
// TODO: Return the I/O port A/B register
return 0xFF;
} else if (port == 0xC1 || port == 0xDD) {
// TODO: Return the I/O port B/misc. register
return 0xFF;
} else {
return 0xFF;
}


+ 121
- 6
src/vdp.c View File

@@ -2,6 +2,7 @@
Released under the terms of the MIT License. See LICENSE for details. */

#include <string.h>
#include <SDL.h>

#include "vdp.h"
#include "util.h"
@@ -11,6 +12,8 @@
#define CODE_REG_WRITE 2
#define CODE_CRAM_WRITE 3

extern SDL_Renderer* renderer;

/*
Initialize the Video Display Processor (VDP).
*/
@@ -100,6 +103,89 @@ static uint8_t get_backdrop_addr(const VDP *vdp)
}

/*
TODO: ...
*/
static void draw_pixel(uint8_t y, uint8_t x, uint16_t color)
{
uint8_t r = 0x11 * (color & 0x000F);
uint8_t g = 0x11 * ((color & 0x00F0) >> 4);
uint8_t b = 0x11 * ((color & 0x0F00) >> 8);

SDL_SetRenderDrawColor(renderer, r, g, b, 0xFF);

uint8_t i, j;
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++)
SDL_RenderDrawPoint(renderer, 3 * x + i, 3 * y + j);
}
}

/*
Draw the background of the current scanline.
*/
static void draw_background(VDP *vdp)
{
uint8_t *pnt = vdp->vram + get_pnt_base(vdp);

uint8_t row = (vdp->v_counter + vdp->regs[0x09]) % (28 * 8);
uint8_t col;

for (col = 6; col < 32 - 6; col++) {
uint16_t index = (row >> 3) * 32 + col;
uint16_t tile = pnt[2 * index] + (pnt[2 * index + 1] << 8);
uint16_t pattern = tile & 0x01FF;
bool palette = tile & 0x0800;
bool priority = tile & 0x1000;
bool vflip = tile & 0x0400;
bool hflip = tile & 0x0200;

uint8_t offy = vflip ? (7 - row % 8) : (row % 8);
uint8_t *pixels = &vdp->vram[pattern * 32 + 4 * offy];
uint8_t bp0 = pixels[0], bp1 = pixels[1],
bp2 = pixels[2], bp3 = pixels[3];

uint8_t idx, i, offx;
uint16_t color;

for (i = 0; i < 8; i++) {
idx = ((bp0 >> i) & 1) +
(((bp1 >> i) & 1) << 1) +
(((bp2 >> i) & 1) << 2) +
(((bp3 >> i) & 1) << 3);
color = vdp->cram[2 * idx] + (vdp->cram[2 * idx + 1] << 8);
offx = hflip ? (col * 8 + (7 - i)) : (col * 8 + i);
draw_pixel(vdp->v_counter, offx, color);
}
}
}

/*
Draw sprites in the current scanline.
*/
static void draw_sprites(VDP *vdp)
{
uint8_t *sat = vdp->vram + get_sat_base(vdp);
uint8_t spritebuf[8], nsprites = 0, i;

for (i = 0; i < 64; i++) {
uint8_t y = sat[i] - 1;
if (vdp->v_counter >= y && vdp->v_counter < y + 8) {
DEBUG("sprite draw!!!")
// TODO
}
}
}

/*
Draw the current scanline.
*/
static void draw_scanline(VDP *vdp)
{
draw_background(vdp);
draw_sprites(vdp);
}

/*
Advance the V counter for the next scanline.
*/
static void advance_scanline(VDP *vdp)
@@ -114,15 +200,12 @@ static void advance_scanline(VDP *vdp)
}

/*
Simulate one scanline within the VDP.

TODO: elaborate
Simulate one line within the VDP.
*/
void vdp_simulate_line(VDP *vdp)
{
if (vdp->v_counter >= 0x18 && vdp->v_counter < 0xA8) {
// TODO: draw current line
}
if (vdp->v_counter >= 0x18 && vdp->v_counter < 0xA8)
draw_scanline(vdp);
if (vdp->v_counter == 0xC0)
vdp->stat_int = true;
advance_scanline(vdp);
@@ -277,4 +360,36 @@ void vdp_dump_registers(const VDP *vdp)
DEBUG("- %04X %04X %04X %04X %04X %04X %04X %04X",
w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7])
}

return;

DEBUG("Dumping PNT:")
for (uint16_t i = 0; i < 28 * 32; i += 32) {
uint16_t w[32];
for (uint8_t j = 0; j < 32; j++)
w[j] = vdp->vram[get_pnt_base(vdp) + 2 * (i + j)] +
(vdp->vram[get_pnt_base(vdp) + 2 * (i + j) + 1] << 8);

DEBUG("- %03X %03X %03X %03X %03X %03X %03X %03X"
" %03X %03X %03X %03X %03X %03X %03X %03X"
" %03X %03X %03X %03X %03X %03X %03X %03X"
" %03X %03X %03X %03X %03X %03X %03X %03X",
w[0x00], w[0x01], w[0x02], w[0x03], w[0x04], w[0x05], w[0x06], w[0x07],
w[0x08], w[0x09], w[0x0A], w[0x0B], w[0x0C], w[0x0D], w[0x0E], w[0x0F],
w[0x10], w[0x11], w[0x12], w[0x13], w[0x14], w[0x15], w[0x16], w[0x17],
w[0x18], w[0x19], w[0x1A], w[0x1B], w[0x1C], w[0x1D], w[0x1E], w[0x1F])
}

DEBUG("Dumping PGT:")
for (uint16_t i = 0; i < /* 512 */ 16; i++) {
uint32_t w[8];
for (uint8_t j = 0; j < 8; j++)
w[j] = vdp->vram[32 * i + 4 * j] +
(vdp->vram[32 * i + 4 * j + 1] << 8) +
(vdp->vram[32 * i + 4 * j + 2] << 16) +
(vdp->vram[32 * i + 4 * j + 3] << 24);

DEBUG("- 0x%04X: %08X %08X %08X %08X %08X %08X %08X %08X", i,
w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7])
}
}

Loading…
Cancel
Save