changeset 2204:dc4268a778bc

Implement Mode 4 sprite zooming
author Michael Pavone <pavone@retrodev.com>
date Mon, 22 Aug 2022 23:21:16 -0700
parents 9826d50061a0
children 90297f1fb3fe
files vdp.c vdp.h
diffstat 2 files changed, 37 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/vdp.c	Mon Aug 22 22:59:42 2022 -0700
+++ b/vdp.c	Mon Aug 22 23:21:16 2022 -0700
@@ -392,6 +392,10 @@
 static void render_sprite_cells_mode4(vdp_context * context)
 {
 	if (context->sprite_index >= context->sprite_draws) {
+		uint8_t zoom = context->type != VDP_GENESIS && (context->regs[REG_MODE_2] & BIT_SPRITE_ZM);
+		if (context->type == VDP_SMS && context->sprite_index < 4) {
+			zoom = 0;
+		}
 		sprite_draw * d = context->sprite_draw_list + context->sprite_index;
 		uint32_t pixels = planar_to_chunky[context->fetch_tmp[0]] << 1;
 		pixels |= planar_to_chunky[context->fetch_tmp[1]];
@@ -411,6 +415,19 @@
 			} else {
 				context->linebuf[x] = pixels >> i & 0xF;
 			}
+			if (zoom) {
+				x++;
+				if (context->linebuf[x] && (pixels >> i & 0xF)) {
+					if (
+						((context->regs[REG_MODE_1] & BIT_SPRITE_8PX) && x > 8)
+						|| ((!(context->regs[REG_MODE_1] & BIT_SPRITE_8PX)) && x < 256)
+					) {
+						context->flags2 |= FLAG2_SPRITE_COLLIDE;
+					}
+				} else {
+					context->linebuf[x] = pixels >> i & 0xF;
+				}
+			}
 		}
 		context->sprite_index--;
 	}
@@ -683,12 +700,20 @@
 		uint32_t sat_address = mode4_address_map[(context->regs[REG_SAT] << 7 & 0x3F00) + context->sprite_index];
 		uint32_t y = context->vdpmem[sat_address+1];
 		uint32_t size = (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) ? 16 : 8;
+		uint32_t ysize = size;
+		uint8_t zoom = context->type != VDP_GENESIS && (context->regs[REG_MODE_2] & BIT_SPRITE_ZM);
+		if (context->type == VDP_SMS && context->slot_counter <= 4) {
+			zoom = 0;
+		}
+		if (zoom) {
+			ysize *= 2;
+		}
 
 		if (y == 0xd0) {
 			context->sprite_index = MAX_SPRITES_FRAME_H32;
 			return;
 		} else {
-			if (y <= line && line < (y + size)) {
+			if (y <= line && line < (y + ysize)) {
 				if (!context->slot_counter) {
 					context->sprite_index = MAX_SPRITES_FRAME_H32;
 					context->flags |= FLAG_DOT_OFLOW;
@@ -707,7 +732,7 @@
 				context->sprite_index = MAX_SPRITES_FRAME_H32;
 				return;
 			} else {
-				if (y <= line && line < (y + size)) {
+				if (y <= line && line < (y + ysize)) {
 					if (!context->slot_counter) {
 						context->sprite_index = MAX_SPRITES_FRAME_H32;
 						context->flags |= FLAG_DOT_OFLOW;
@@ -788,11 +813,19 @@
 		uint32_t address = (context->regs[REG_SAT] << 7 & 0x3F00) + 0x80 + context->sprite_info_list[context->cur_slot].index * 2;
 		address = mode4_address_map[address];
 		--context->sprite_draws;
+		uint8_t zoom = context->type != VDP_GENESIS && (context->regs[REG_MODE_2] & BIT_SPRITE_ZM);
+		if (context->type == VDP_SMS && context->sprite_draws < 4) {
+			zoom = 0;
+		}
 		uint32_t tile_address = context->vdpmem[address] * 32 + (context->regs[REG_STILE_BASE] << 11 & 0x2000);
 		if (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) {
 			tile_address &= ~32;
 		}
-		tile_address += (context->vcounter - context->sprite_info_list[context->cur_slot].y)* 4;
+		uint16_t y_diff = context->vcounter - context->sprite_info_list[context->cur_slot].y;
+		if (zoom) {
+			y_diff >>= 1;
+		}
+		tile_address += y_diff * 4;
 		context->sprite_draw_list[context->sprite_draws].x_pos = context->vdpmem[address + 1];
 		context->sprite_draw_list[context->sprite_draws].address = tile_address;
 		context->cur_slot--;
--- a/vdp.h	Mon Aug 22 22:59:42 2022 -0700
+++ b/vdp.h	Mon Aug 22 23:21:16 2022 -0700
@@ -116,6 +116,7 @@
 #define BIT_PAL        0x08
 #define BIT_MODE_5     0x04
 #define BIT_SPRITE_SZ  0x02
+#define BIT_SPRITE_ZM  0x01
 
 //Mode reg 3
 #define BIT_EINT_EN    0x08