changeset 22:407725d9a02f

Implemented sprite drawing. Added small sprite example.
author Michael Pavone <pavone@retrodev.com>
date Wed, 30 Mar 2016 19:55:48 -0700
parents 91ded3b12d96
children a085f17b79e9
files sprites.s16 src/vdp.c src/vdp.h
diffstat 3 files changed, 222 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sprites.s16	Wed Mar 30 19:55:48 2016 -0700
@@ -0,0 +1,143 @@
+
+	;write palette entries to CRAM
+	ldim 0, r0
+	ldimh $FF, r0
+	outi 14, r0
+	ldim colors, r0
+	ldimh colors, r0
+	ldim $80, r1
+	ldimh $0, r1
+	ldim 0, r2
+cloop:
+	ld16 r0, r2, r3
+	outi 15, r3
+	addi 2, r2
+	cmp r1, r2
+	bne cloop
+	
+	;write tile to VRAM
+	ldim 0, r2
+	outi 14, r2
+	ldim tile, r0
+	ldim $A0, r1
+	ldimh $0, r1
+tloop:
+	ld16 r0, r2, r3
+	outi 15, r3
+	addi 2, r2
+	cmp r1, r2
+	bne tloop
+	
+	;write name table entries to VRAM
+	ldim 0, r2
+	ldimh $60, r2
+	outi 14, r2
+	;current entry
+	ldim 0, r0
+	;increment
+	ldimh $8, r2
+	;counter
+	ldim $00, r1
+	ldimh $7, r1
+nloop:
+	outi 15, r0
+	add r2, r0, r0
+	addi -1, r1
+	bne nloop
+	
+	;setup writes to sprite list
+	ldim 0, r0
+	ldimh $FE, r0
+	outi 14, r0
+	
+	;write first sprite
+	ldim $15, r0
+	ldimh $35, r0
+	outi 15, r0
+	ldim 1, r1
+	ldimh $84, r1
+	outi 15, r1
+	
+	;write second sprite
+	ldim $8A, r0
+	ldimh $8A, r0
+	outi 15, r0
+	ldimh $A4, r1
+	outi 15, r1
+	
+	
+	;write vscroll register
+	ldim $0, r0
+	ldimh $E6, r0
+	outi $C, r0
+	;write hscroll register to enable display
+	ldimh $80, r0
+	outi $D, r0
+forever:
+	bra forever
+tile:
+	dc.l $000FFFFF
+	dc.l $E111EEEE
+	dc.l $DD222DDD
+	dc.l $CCC333CC
+	dc.l $BBBB444B
+	dc.l $AAAAA555
+	dc.l $99996669
+	dc.l $88877788
+	
+	dc.l $00000088
+	dc.l $00000889
+	dc.l $0000889A
+	dc.l $000889AB
+	dc.l $00889ABC
+	dc.l $0889ABCD
+	dc.l $889ABCDE
+	dc.l $889ABCEF
+	
+	dc.l $889ABCEF
+	dc.l $889ABCDE
+	dc.l $0889ABCD
+	dc.l $00889ABC
+	dc.l $000889AB
+	dc.l $0000889A
+	dc.l $00000889
+	dc.l $00000088
+	
+	dc.l $88000000
+	dc.l $98800000
+	dc.l $A9880000
+	dc.l $BA988000
+	dc.l $CBA98800
+	dc.l $DCBA9880
+	dc.l $EDCBA988
+	dc.l $FECBA988
+	
+	dc.l $FECBA988
+	dc.l $EDCBA988
+	dc.l $DCBA9880
+	dc.l $CBA98800
+	dc.l $BA988000
+	dc.l $A9880000
+	dc.l $98800000
+	dc.l $88000000
+colors:
+	dc.w $0000, $0001, $0002, $0003
+	dc.w $0004, $0005, $0006, $0007
+	dc.w $0008, $0009, $000A, $000B
+	dc.w $000C, $000D, $000E, $000F
+	
+	dc.w $0000, $0010, $0020, $0030
+	dc.w $0040, $0050, $0060, $0070
+	dc.w $0080, $0090, $00A0, $00B0
+	dc.w $00C0, $00D0, $00E0, $00F0
+	
+	dc.w $0000, $0100, $0200, $0300
+	dc.w $0400, $0500, $0600, $0700
+	dc.w $0800, $0900, $0A00, $0B00
+	dc.w $0C00, $0D00, $0E00, $0F00
+	
+	dc.w $0000, $0111, $0222, $0333
+	dc.w $0444, $0555, $0666, $0777
+	dc.w $0888, $0999, $0AAA, $0BBB
+	dc.w $0CCC, $0DDD, $0EEE, $0FFF
+
--- a/src/vdp.c	Tue Mar 29 19:59:26 2016 -0700
+++ b/src/vdp.c	Wed Mar 30 19:55:48 2016 -0700
@@ -41,6 +41,9 @@
 						context->readbuffer = context->linebuffers + 328;
 					}
 					context->draw_dest = 0;
+					//enable sprite scanning
+					context->status |= VDP_STATUS_SPRITE_SCAN;
+					context->current_draw = 0;
 				}
 				if (context->draw_counter) {
 					context->draw_counter--;
@@ -70,9 +73,67 @@
 					context->draw_counter = 2;
 					//TODO: handle horizontal flip
 				}
-				//TODO: Scan sprite table
+				if (context->status & VDP_STATUS_SPRITE_SCAN) {
+					context->status |= VDP_STATUS_SRAM;
+					uint16_t pos = context->sram[context->hcounter];
+					uint16_t y = pos & 0xFF;
+					uint16_t x = pos >> 8;
+					uint16_t atts = context->sram[context->hcounter+1];
+					x |= atts << 2 & 0x100;
+					if (x | y) {
+						uint16_t size = atts & 0x400 ? 16 : 8;
+						if (context->vcounter >= y && context->vcounter < y + size) {
+							uint16_t address = (atts & 0x3F) * 16;
+							if (atts & 0x1000) {
+								address += (size-1) * 2 - (context->vcounter - y) * 2;
+							} else {
+								address += (context->vcounter - y) * 2;
+							}
+							context->sprite_draws[context->current_draw].source = address;
+							context->sprite_draws[context->current_draw].x = x;
+							context->sprite_draws[context->current_draw].hflip = (atts & 0x800) != 0;
+							context->sprite_draws[context->current_draw].palpriority = 0x80 | (atts >> 9 & 0x50);
+							context->current_draw++;
+							if (size == 16) {
+								context->sprite_draws[context->current_draw].source = address + 32;
+								context->sprite_draws[context->current_draw].x = x + 8;
+								context->sprite_draws[context->current_draw].hflip = (atts & 0x800) != 0;
+								context->sprite_draws[context->current_draw].palpriority = 0x80 | (atts >> 9 & 0x50);
+							}
+							context->current_draw++;
+							if (context->current_draw == 40) {
+								//no more rendering capacity
+								context->status &= ~VDP_STATUS_SPRITE_SCAN;
+								context->current_draw = 0;
+							}
+						}
+					} else {
+						//hit sprite list terminator
+						context->status &= ~VDP_STATUS_SPRITE_SCAN;
+						context->current_draw = 0;
+					}
+				}
 			} else {
-				//TODO: Render sprites
+				sprite_draw *draw = context->sprite_draws + (context->current_draw >> 1);
+				if (draw->palpriority) {
+					context->status |= VDP_STATUS_VRAM;
+					uint16_t pixels = context->vram[draw->source + (context->current_draw & 1)];
+					uint16_t x = draw->x - 16 + (context->hscroll & 7);
+					for (int i = 0; i < 4; i++, x++)
+					{
+						//TODO: handle horizontal flip
+						uint8_t pixel = (pixels >> ((3-i) * 4)) & 0xF;
+						if (pixel && x < 328 && ((draw->palpriority & 0x40) || !(context->drawbuffer[x] & 0x40))) {
+							context->drawbuffer[x] = pixel | draw->palpriority;
+						}
+					}
+					if (context->current_draw & 1) {
+						draw->palpriority = 0;
+					} else {
+						draw->x += 4;
+					}
+				}
+				context->current_draw++;
 			}
 		}
 		//Draw to framebuffer
--- a/src/vdp.h	Tue Mar 29 19:59:26 2016 -0700
+++ b/src/vdp.h	Wed Mar 30 19:55:48 2016 -0700
@@ -2,6 +2,13 @@
 #define VDP_H_
 
 typedef struct {
+	uint16_t source;
+	uint16_t x;
+	uint8_t  hflip;
+	uint8_t  palpriority;
+} sprite_draw;
+
+typedef struct {
 	uint16_t *framebuffer;
 	uint8_t  *drawbuffer;
 	uint8_t  *readbuffer;
@@ -22,14 +29,18 @@
 	uint16_t draw_source;
 	uint16_t draw_dest;
 	
+	
 	uint16_t vram[32*512];
 	uint8_t  linebuffers[328*2];
 	uint16_t sram[64*2];
 	uint16_t cram[64];
 	
+	sprite_draw sprite_draws[40];
+	
 	uint8_t  fifo_dest;
 	uint8_t  draw_counter;
 	uint8_t  palpriority;
+	uint8_t  current_draw;
 } vdp;
 
 enum {
@@ -39,10 +50,11 @@
 	FIFO_DEST_CRAM
 };
 
-#define VDP_STATUS_FIFO    1
-#define VDP_STATUS_VRAM    2
-#define VDP_STATUS_SRAM    4
-#define VDP_STATUS_ENABLED 8
+#define VDP_STATUS_FIFO        1
+#define VDP_STATUS_VRAM        2
+#define VDP_STATUS_SRAM        4
+#define VDP_STATUS_ENABLED     8
+#define VDP_STATUS_SPRITE_SCAN 16
 
 void vdp_init(vdp *context, uint32_t clock_div);
 void vdp_run(vdp *context, uint32_t target);