Browse Source

Implement some missing graphics features (fixes #4)

* Sprite collision flag
* Background tile priority flag
* Display blank flag
develop
Ben Kurtovic 3 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)
FATAL("SDL failed to initialize: %s", SDL_GetError());

SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");

uint32_t flags;
if (fullscreen)
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);

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_ShowCursor(SDL_DISABLE);
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. */

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

#define COLBUF_BG_PRIORITY 0x10
#define COLBUF_OPAQUE_SPRITE 0x20

/*
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).
*/
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.

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)
{
uint8_t a = is_display_visible(vdp) ? 0xFF : 0x00;
uint8_t r = 0x11 * (color & 0x000F);
uint8_t g = 0x11 * ((color & 0x00F0) >> 4);
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;
}

/*
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 dst_row = vdp->v_counter - 0x18;
@@ -216,8 +244,6 @@ static void draw_background(VDP *vdp)
bool vflip = tile & 0x0400;
bool hflip = tile & 0x0200;

(void) priority; // TODO

uint8_t vshift = vflip ? (7 - src_row % 8) : (src_row % 8), hshift;
uint8_t pixel, index;
int16_t dst_col;
@@ -232,6 +258,9 @@ static void draw_background(VDP *vdp)
index = read_pattern(vdp, pattern, vshift, hshift);
color = get_color(vdp, index, palette);
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.
*/
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 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;

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

index = read_pattern(vdp, pattern, vshift, pixel);
if (index == 0)
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);
draw_pixel(vdp, dst_row, dst_col, color);
}
@@ -307,8 +341,9 @@ static void draw_scanline(VDP *vdp)
if (!vdp->pixels)
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.

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) {
uint8_t reg = byte & 0x0F;
if (reg <= VDP_REGS)
vdp->regs[reg] = vdp->control_addr & 0xFF;
write_reg(vdp, reg, vdp->control_addr & 0xFF);
}
}


Loading…
Cancel
Save