Browse Source

Implement some missing graphics features (fixes #4)

* Sprite collision flag
* Background tile priority flag
* Display blank flag
develop
Ben Kurtovic 6 years ago
parent
commit
e8fe5e4797
2 changed files with 59 additions and 12 deletions
  1. +3
    -1
      src/emulator.c
  2. +56
    -11
      src/vdp.c

+ 3
- 1
src/emulator.c View File

@@ -39,6 +39,8 @@ static void setup_graphics(bool fullscreen, unsigned scale)
if (SDL_Init(SDL_INIT_VIDEO) < 0) if (SDL_Init(SDL_INIT_VIDEO) < 0)
FATAL("SDL failed to initialize: %s", SDL_GetError()); FATAL("SDL failed to initialize: %s", SDL_GetError());


SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");

uint32_t flags; uint32_t flags;
if (fullscreen) if (fullscreen)
flags = SDL_WINDOW_FULLSCREEN_DESKTOP; flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
@@ -64,7 +66,7 @@ static void setup_graphics(bool fullscreen, unsigned scale)
sizeof(uint32_t) * GG_SCREEN_WIDTH * GG_SCREEN_HEIGHT); sizeof(uint32_t) * GG_SCREEN_WIDTH * GG_SCREEN_HEIGHT);


SDL_RenderSetLogicalSize(emu.renderer, GG_SCREEN_WIDTH, GG_SCREEN_HEIGHT); SDL_RenderSetLogicalSize(emu.renderer, GG_SCREEN_WIDTH, GG_SCREEN_HEIGHT);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
SDL_SetTextureBlendMode(emu.texture, SDL_BLENDMODE_BLEND);
SDL_SetWindowTitle(emu.window, "crater"); SDL_SetWindowTitle(emu.window, "crater");
SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
SDL_GL_SetSwapInterval(1); // Vsync SDL_GL_SetSwapInterval(1); // Vsync


+ 56
- 11
src/vdp.c View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2017 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#include <string.h> #include <string.h>
@@ -18,6 +18,9 @@
#define CODE_REG_WRITE 2 #define CODE_REG_WRITE 2
#define CODE_CRAM_WRITE 3 #define CODE_CRAM_WRITE 3


#define COLBUF_BG_PRIORITY 0x10
#define COLBUF_OPAQUE_SPRITE 0x20

/* /*
Initialize the Video Display Processor (VDP). Initialize the Video Display Processor (VDP).


@@ -90,6 +93,14 @@ static bool should_frame_interrupt(const VDP *vdp)
} }


/* /*
Return whether the display should be visible or completely blank.
*/
static bool is_display_visible(const VDP *vdp)
{
return vdp->regs[0x01] & 0x40;
}

/*
Get the height of all sprites in patterns (1 pattern = 8x8 pixels). Get the height of all sprites in patterns (1 pattern = 8x8 pixels).
*/ */
static uint8_t get_sprite_height(const VDP *vdp) static uint8_t get_sprite_height(const VDP *vdp)
@@ -180,24 +191,41 @@ static uint16_t get_color(const VDP *vdp, uint8_t index, bool palette)
} }


/* /*
Toggle visibility of the display.

This sets the alpha channel of every pixel to be 0xFF (if true)
or 0x00 (if false).
*/
static void toggle_display_visibility(VDP *vdp, bool visible)
{
if (!vdp->pixels)
return;

uint8_t a = visible ? 0xFF : 0x00;
for (size_t i = 0; i < 160 * 144; i++)
vdp->pixels[i] = (a << 24) | (vdp->pixels[i] & 0x00FFFFFF);
}

/*
Draw a pixel onto our pixel array at the given coordinates. Draw a pixel onto our pixel array at the given coordinates.


The color should be in BGR444 format, as returned by get_color(). The color should be in BGR444 format, as returned by get_color().
*/ */
static void draw_pixel(VDP *vdp, uint8_t y, uint8_t x, uint16_t color) static void draw_pixel(VDP *vdp, uint8_t y, uint8_t x, uint16_t color)
{ {
uint8_t a = is_display_visible(vdp) ? 0xFF : 0x00;
uint8_t r = 0x11 * (color & 0x000F); uint8_t r = 0x11 * (color & 0x000F);
uint8_t g = 0x11 * ((color & 0x00F0) >> 4); uint8_t g = 0x11 * ((color & 0x00F0) >> 4);
uint8_t b = 0x11 * ((color & 0x0F00) >> 8); uint8_t b = 0x11 * ((color & 0x0F00) >> 8);


uint32_t argb = (0xFF << 24) + (r << 16) + (g << 8) + b;
uint32_t argb = (a << 24) + (r << 16) + (g << 8) + b;
vdp->pixels[y * 160 + x] = argb; vdp->pixels[y * 160 + x] = argb;
} }


/* /*
Draw the background of the current scanline. Draw the background of the current scanline.
*/ */
static void draw_background(VDP *vdp)
static void draw_background(VDP *vdp, uint8_t *colbuf)
{ {
uint8_t src_row = (vdp->v_counter + get_bg_vscroll(vdp)) % (28 << 3); uint8_t src_row = (vdp->v_counter + get_bg_vscroll(vdp)) % (28 << 3);
uint8_t dst_row = vdp->v_counter - 0x18; uint8_t dst_row = vdp->v_counter - 0x18;
@@ -216,8 +244,6 @@ static void draw_background(VDP *vdp)
bool vflip = tile & 0x0400; bool vflip = tile & 0x0400;
bool hflip = tile & 0x0200; bool hflip = tile & 0x0200;


(void) priority; // TODO

uint8_t vshift = vflip ? (7 - src_row % 8) : (src_row % 8), hshift; uint8_t vshift = vflip ? (7 - src_row % 8) : (src_row % 8), hshift;
uint8_t pixel, index; uint8_t pixel, index;
int16_t dst_col; int16_t dst_col;
@@ -232,6 +258,9 @@ static void draw_background(VDP *vdp)
index = read_pattern(vdp, pattern, vshift, hshift); index = read_pattern(vdp, pattern, vshift, hshift);
color = get_color(vdp, index, palette); color = get_color(vdp, index, palette);
draw_pixel(vdp, dst_row, dst_col, color); draw_pixel(vdp, dst_row, dst_col, color);

if (priority && index != 0)
colbuf[dst_col] |= COLBUF_BG_PRIORITY;
} }
} }
} }
@@ -239,7 +268,7 @@ static void draw_background(VDP *vdp)
/* /*
Draw sprites in the current scanline. Draw sprites in the current scanline.
*/ */
static void draw_sprites(VDP *vdp)
static void draw_sprites(VDP *vdp, uint8_t *colbuf)
{ {
uint8_t *sat = vdp->vram + get_sat_base(vdp); uint8_t *sat = vdp->vram + get_sat_base(vdp);
uint8_t spritebuf[8], nsprites = 0, i; uint8_t spritebuf[8], nsprites = 0, i;
@@ -258,8 +287,6 @@ static void draw_sprites(VDP *vdp)
} }
} }


// TODO: collisions

uint8_t dst_row = vdp->v_counter - 0x18; uint8_t dst_row = vdp->v_counter - 0x18;


while (nsprites-- > 0) { while (nsprites-- > 0) {
@@ -288,11 +315,18 @@ static void draw_sprites(VDP *vdp)
dst_col = x + pixel - (6 << 3); dst_col = x + pixel - (6 << 3);
if (dst_col < 0 || dst_col >= 160) if (dst_col < 0 || dst_col >= 160)
continue; continue;
if (colbuf[dst_col] & COLBUF_BG_PRIORITY)
continue;


index = read_pattern(vdp, pattern, vshift, pixel); index = read_pattern(vdp, pattern, vshift, pixel);
if (index == 0) if (index == 0)
continue; continue;


if (colbuf[dst_col] & COLBUF_OPAQUE_SPRITE)
vdp->flags |= FLAG_SPR_COL;
else
colbuf[dst_col] |= COLBUF_OPAQUE_SPRITE;

color = get_color(vdp, index, 1); color = get_color(vdp, index, 1);
draw_pixel(vdp, dst_row, dst_col, color); draw_pixel(vdp, dst_row, dst_col, color);
} }
@@ -307,8 +341,9 @@ static void draw_scanline(VDP *vdp)
if (!vdp->pixels) if (!vdp->pixels)
return; return;


draw_background(vdp);
draw_sprites(vdp);
uint8_t colbuf[160] = {0x00};
draw_background(vdp, colbuf);
draw_sprites(vdp, colbuf);
} }


/* /*
@@ -396,6 +431,16 @@ uint8_t vdp_read_data(VDP *vdp)
} }


/* /*
Set the given VDP register.
*/
static void write_reg(VDP *vdp, uint8_t reg, uint8_t byte)
{
if (reg == 0x01 && (vdp->regs[reg] & 0x40) != (byte & 0x40))
toggle_display_visibility(vdp, byte & 0x40);
vdp->regs[reg] = byte;
}

/*
Write a byte into the VDP's control port. Write a byte into the VDP's control port.


Depending on the status of the control flag, this will either update the Depending on the status of the control flag, this will either update the
@@ -425,7 +470,7 @@ void vdp_write_control(VDP *vdp, uint8_t byte)
} else if (vdp->control_code == CODE_REG_WRITE) { } else if (vdp->control_code == CODE_REG_WRITE) {
uint8_t reg = byte & 0x0F; uint8_t reg = byte & 0x0F;
if (reg <= VDP_REGS) if (reg <= VDP_REGS)
vdp->regs[reg] = vdp->control_addr & 0xFF;
write_reg(vdp, reg, vdp->control_addr & 0xFF);
} }
} }




Loading…
Cancel
Save