Browse Source

Implement some missing graphics features (fixes #4)

* Sprite collision flag
* Background tile priority flag
* Display blank flag
develop
Ben Kurtovic 2 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)
39 39
     if (SDL_Init(SDL_INIT_VIDEO) < 0)
40 40
         FATAL("SDL failed to initialize: %s", SDL_GetError());
41 41
 
42
+    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
43
+
42 44
     uint32_t flags;
43 45
     if (fullscreen)
44 46
         flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
@@ -64,7 +66,7 @@ static void setup_graphics(bool fullscreen, unsigned scale)
64 66
         sizeof(uint32_t) * GG_SCREEN_WIDTH * GG_SCREEN_HEIGHT);
65 67
 
66 68
     SDL_RenderSetLogicalSize(emu.renderer, GG_SCREEN_WIDTH, GG_SCREEN_HEIGHT);
67
-    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
69
+    SDL_SetTextureBlendMode(emu.texture, SDL_BLENDMODE_BLEND);
68 70
     SDL_SetWindowTitle(emu.window, "crater");
69 71
     SDL_ShowCursor(SDL_DISABLE);
70 72
     SDL_GL_SetSwapInterval(1);  // Vsync

+ 56
- 11
src/vdp.c View File

@@ -1,4 +1,4 @@
1
-/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
1
+/* Copyright (C) 2014-2017 Ben Kurtovic <ben.kurtovic@gmail.com>
2 2
    Released under the terms of the MIT License. See LICENSE for details. */
3 3
 
4 4
 #include <string.h>
@@ -18,6 +18,9 @@
18 18
 #define CODE_REG_WRITE  2
19 19
 #define CODE_CRAM_WRITE 3
20 20
 
21
+#define COLBUF_BG_PRIORITY   0x10
22
+#define COLBUF_OPAQUE_SPRITE 0x20
23
+
21 24
 /*
22 25
     Initialize the Video Display Processor (VDP).
23 26
 
@@ -90,6 +93,14 @@ static bool should_frame_interrupt(const VDP *vdp)
90 93
 }
91 94
 
92 95
 /*
96
+    Return whether the display should be visible or completely blank.
97
+*/
98
+static bool is_display_visible(const VDP *vdp)
99
+{
100
+    return vdp->regs[0x01] & 0x40;
101
+}
102
+
103
+/*
93 104
     Get the height of all sprites in patterns (1 pattern = 8x8 pixels).
94 105
 */
95 106
 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)
180 191
 }
181 192
 
182 193
 /*
194
+    Toggle visibility of the display.
195
+
196
+    This sets the alpha channel of every pixel to be 0xFF (if true)
197
+    or 0x00 (if false).
198
+*/
199
+static void toggle_display_visibility(VDP *vdp, bool visible)
200
+{
201
+    if (!vdp->pixels)
202
+        return;
203
+
204
+    uint8_t a = visible ? 0xFF : 0x00;
205
+    for (size_t i = 0; i < 160 * 144; i++)
206
+        vdp->pixels[i] = (a << 24) | (vdp->pixels[i] & 0x00FFFFFF);
207
+}
208
+
209
+/*
183 210
     Draw a pixel onto our pixel array at the given coordinates.
184 211
 
185 212
     The color should be in BGR444 format, as returned by get_color().
186 213
 */
187 214
 static void draw_pixel(VDP *vdp, uint8_t y, uint8_t x, uint16_t color)
188 215
 {
216
+    uint8_t a = is_display_visible(vdp) ? 0xFF : 0x00;
189 217
     uint8_t r = 0x11 *  (color & 0x000F);
190 218
     uint8_t g = 0x11 * ((color & 0x00F0) >> 4);
191 219
     uint8_t b = 0x11 * ((color & 0x0F00) >> 8);
192 220
 
193
-    uint32_t argb = (0xFF << 24) + (r << 16) + (g << 8) + b;
221
+    uint32_t argb = (a << 24) + (r << 16) + (g << 8) + b;
194 222
     vdp->pixels[y * 160 + x] = argb;
195 223
 }
196 224
 
197 225
 /*
198 226
     Draw the background of the current scanline.
199 227
 */
200
-static void draw_background(VDP *vdp)
228
+static void draw_background(VDP *vdp, uint8_t *colbuf)
201 229
 {
202 230
     uint8_t src_row = (vdp->v_counter + get_bg_vscroll(vdp)) % (28 << 3);
203 231
     uint8_t dst_row = vdp->v_counter - 0x18;
@@ -216,8 +244,6 @@ static void draw_background(VDP *vdp)
216 244
         bool     vflip    = tile & 0x0400;
217 245
         bool     hflip    = tile & 0x0200;
218 246
 
219
-        (void) priority;  // TODO
220
-
221 247
         uint8_t vshift = vflip ? (7 - src_row % 8) : (src_row % 8), hshift;
222 248
         uint8_t pixel, index;
223 249
         int16_t dst_col;
@@ -232,6 +258,9 @@ static void draw_background(VDP *vdp)
232 258
             index = read_pattern(vdp, pattern, vshift, hshift);
233 259
             color = get_color(vdp, index, palette);
234 260
             draw_pixel(vdp, dst_row, dst_col, color);
261
+
262
+            if (priority && index != 0)
263
+                colbuf[dst_col] |= COLBUF_BG_PRIORITY;
235 264
         }
236 265
     }
237 266
 }
@@ -239,7 +268,7 @@ static void draw_background(VDP *vdp)
239 268
 /*
240 269
     Draw sprites in the current scanline.
241 270
 */
242
-static void draw_sprites(VDP *vdp)
271
+static void draw_sprites(VDP *vdp, uint8_t *colbuf)
243 272
 {
244 273
     uint8_t *sat = vdp->vram + get_sat_base(vdp);
245 274
     uint8_t spritebuf[8], nsprites = 0, i;
@@ -258,8 +287,6 @@ static void draw_sprites(VDP *vdp)
258 287
         }
259 288
     }
260 289
 
261
-    // TODO: collisions
262
-
263 290
     uint8_t dst_row = vdp->v_counter - 0x18;
264 291
 
265 292
     while (nsprites-- > 0) {
@@ -288,11 +315,18 @@ static void draw_sprites(VDP *vdp)
288 315
             dst_col = x + pixel - (6 << 3);
289 316
             if (dst_col < 0 || dst_col >= 160)
290 317
                 continue;
318
+            if (colbuf[dst_col] & COLBUF_BG_PRIORITY)
319
+                continue;
291 320
 
292 321
             index = read_pattern(vdp, pattern, vshift, pixel);
293 322
             if (index == 0)
294 323
                 continue;
295 324
 
325
+            if (colbuf[dst_col] & COLBUF_OPAQUE_SPRITE)
326
+                vdp->flags |= FLAG_SPR_COL;
327
+            else
328
+                colbuf[dst_col] |= COLBUF_OPAQUE_SPRITE;
329
+
296 330
             color = get_color(vdp, index, 1);
297 331
             draw_pixel(vdp, dst_row, dst_col, color);
298 332
         }
@@ -307,8 +341,9 @@ static void draw_scanline(VDP *vdp)
307 341
     if (!vdp->pixels)
308 342
         return;
309 343
 
310
-    draw_background(vdp);
311
-    draw_sprites(vdp);
344
+    uint8_t colbuf[160] = {0x00};
345
+    draw_background(vdp, colbuf);
346
+    draw_sprites(vdp, colbuf);
312 347
 }
313 348
 
314 349
 /*
@@ -396,6 +431,16 @@ uint8_t vdp_read_data(VDP *vdp)
396 431
 }
397 432
 
398 433
 /*
434
+    Set the given VDP register.
435
+*/
436
+static void write_reg(VDP *vdp, uint8_t reg, uint8_t byte)
437
+{
438
+    if (reg == 0x01 && (vdp->regs[reg] & 0x40) != (byte & 0x40))
439
+        toggle_display_visibility(vdp, byte & 0x40);
440
+    vdp->regs[reg] = byte;
441
+}
442
+
443
+/*
399 444
     Write a byte into the VDP's control port.
400 445
 
401 446
     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)
425 470
     } else if (vdp->control_code == CODE_REG_WRITE) {
426 471
         uint8_t reg = byte & 0x0F;
427 472
         if (reg <= VDP_REGS)
428
-            vdp->regs[reg] = vdp->control_addr & 0xFF;
473
+            write_reg(vdp, reg, vdp->control_addr & 0xFF);
429 474
     }
430 475
 }
431 476
 

Loading…
Cancel
Save