git.y1.nz

gbdk-2020

GameBoy Development Kit
download: https://git.y1.nz/archives/gbdk.tar.gz
README | Files | Log | Refs | LICENSE

commit be52e43d7ec853505f6466cf50f9e5897e3ae3be
parent 4f90a5eb8353537bfbc0547db239519cc7d0505d
Author: Toxa <56631470+untoxa@users.noreply.github.com>
Date:   Mon, 21 Nov 2022 21:33:18 +0400

Merge pull request #455 from michel-iwaniec/nes_sprite_flipping

NES: Add metasprite flipping support
Diffstat:
Mgbdk-lib/examples/cross-platform/metasprites/src/metasprites.c43++++++++++++++++++++++++++++++++++---------
Dgbdk-lib/examples/gb/metasprites/Makefile36------------------------------------
Dgbdk-lib/examples/gb/metasprites/Readme.md20--------------------
Dgbdk-lib/examples/gb/metasprites/metasprites.c153-------------------------------------------------------------------------------
Dgbdk-lib/examples/gb/metasprites/sprite.png0
Mgbdk-lib/include/gb/gb.h8++++++++
Mgbdk-lib/include/msx/msx.h8++++++++
Mgbdk-lib/include/nes/nes.h8++++++++
Mgbdk-lib/include/sms/sms.h8++++++++
Mgbdk-lib/libc/targets/mos6502/nes/metasprites.s143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
10 files changed, 198 insertions(+), 229 deletions(-)

diff --git a/gbdk-lib/examples/cross-platform/metasprites/src/metasprites.c b/gbdk-lib/examples/cross-platform/metasprites/src/metasprites.c @@ -1,3 +1,5 @@ +#include <stdint.h> + #include <gbdk/platform.h> #include <gbdk/metasprites.h> @@ -26,7 +28,7 @@ uint16_t PosX, PosY; int16_t SpdX, SpdY; uint8_t PosF; uint8_t hide, jitter; -uint8_t idx; +uint8_t idx, rot; // main funxction void main(void) { @@ -59,7 +61,7 @@ void main(void) { PosX = PosY = 96 << 4; SpdX = SpdY = 0; - hide = 0; jitter = 0; idx = 0; + hide = 0; jitter = 0; idx = 0; rot = 0; while(1) { // poll joypads @@ -100,18 +102,41 @@ void main(void) { jitter = 10; } + // Press SELECT button to cycle metasprite through Normal/Flip-Y/Flip-XY/Flip-X + if ((joypads.joy0 & J_SELECT) && (!jitter) && (!hide)) { + rot++; rot &= 3; + jitter = 20; + } + // Hide/Animate/Flip input throttling if (jitter) jitter--; PosX += SpdX, PosY += SpdY; uint8_t hiwater = 0; - - // Hide the metasprite or move it + + // NOTE: In a real game it would be better to only call the move_metasprite..() + // functions if something changed (such as movement or rotation). That + // reduces CPU usage on frames that don't need updates. + // + // In this example they are called every frame to simplify the example code + + // Hide the metasprite or move it & apply any rotation settings if (hide) hide_metasprite(sprite_metasprites[idx], SPR_NUM_START); else - hiwater = move_metasprite(sprite_metasprites[idx], TILE_NUM_START, SPR_NUM_START, (PosX >> 4), (PosY >> 4)); + switch (rot) { +#if HARDWARE_SPRITE_CAN_FLIP_V + case 1: hiwater = move_metasprite_hflip(sprite_metasprites[idx], TILE_NUM_START, SPR_NUM_START, (PosX >> 4), (PosY >> 4)); break; +#endif +#if HARDWARE_SPRITE_CAN_FLIP_H && HARDWARE_SPRITE_CAN_FLIP_V + case 2: hiwater = move_metasprite_hvflip(sprite_metasprites[idx], TILE_NUM_START, SPR_NUM_START, (PosX >> 4), (PosY >> 4)); break; +#endif +#if HARDWARE_SPRITE_CAN_FLIP_H + case 3: hiwater = move_metasprite_vflip(sprite_metasprites[idx], TILE_NUM_START, SPR_NUM_START, (PosX >> 4), (PosY >> 4)); break; +#endif + default: hiwater = move_metasprite(sprite_metasprites[idx], TILE_NUM_START, SPR_NUM_START, (PosX >> 4), (PosY >> 4)); break; + }; // Hide rest of the hardware sprites, because amount of sprites differ between animation frames. hide_sprites_range(hiwater, MAX_HARDWARE_SPRITES); @@ -119,16 +144,16 @@ void main(void) { // Y Axis: update velocity (reduce speed) if no U/D button pressed if (!(PosF & ACC_Y)) { if (SpdY != 0) { - if (SpdY < 0) SpdY++; - else SpdY --; + if (SpdY > 0) SpdY--; + else SpdY ++; } } // X Axis: update velocity (reduce speed) if no L/R button pressed if (!(PosF & ACC_X)) { if (SpdX != 0) { - if (SpdX < 0) SpdX++; - else SpdX --; + if (SpdX > 0) SpdX--; + else SpdX ++; } } diff --git a/gbdk-lib/examples/gb/metasprites/Makefile b/gbdk-lib/examples/gb/metasprites/Makefile @@ -1,36 +0,0 @@ -LCC = ../../../bin/lcc -PNG2ASSET = ../../../bin/png2asset - -CFLAGS = - -# Output name for compiled ROM -BINS = metasprites.gb - -# Add entries here to have them converted into metasprites -PNGSOURCES = sprite.png -PNG_CSOURCES = $(PNGSOURCES:%.png=%.c) -PNG_CHEADERS = $(PNGSOURCES:%.png=%.h) - -# List of all C source files except those generated by png2asset -CSOURCES = $(filter-out $(PNGSOURCES:%.png=%.c), $(wildcard *.c)) - -all: $(BINS) - -compile.bat: Makefile - @echo "REM Automatically generated from Makefile" > compile.bat - @make -sn | sed y/\\//\\\\/ | grep -v make >> compile.bat - -# Use png2asset to convert the png into C formatted metasprite data -# -sh 48 : Sets sprite height to 48 (width remains automatic) -# -spr8x16 : Use 8x16 hardware sprites -# -c ... : Set C output file -%.c: %.png - $(PNG2ASSET) $< -sh 48 -spr8x16 -c $@ - -# Compile all C sources, including converted png metasprites -$(BINS): $(CSOURCES) $(PNG_CSOURCES) - $(LCC) $(CFLAGS) -o $(BINS) $(CSOURCES) $(PNG_CSOURCES) - - -clean: - rm -f *.o *.lst *.map *.gb *.ihx *.sym *.cdb *.adb *.asm $(PNG_CHEADERS) $(PNG_CSOURCES) diff --git a/gbdk-lib/examples/gb/metasprites/Readme.md b/gbdk-lib/examples/gb/metasprites/Readme.md @@ -1,20 +0,0 @@ - -Metasprite Example -================== - -Demonstrates using the metasprite features to move and animate a large sprite. - -* Press A button to show / hide the metasprite -* Press B button to cycle through the metasprite animations -* Press SELECT button to cycle the metasprite through Normal / Flip-Y / Flip-XY / Flip-X -* Up / Down / Left / Right to move the metasprite - -In this example the move_metasprite...() functions are called every -frame to simplify the example code, regardless of whether the updates -are needed or not. - -In a real game it would be better to only call them if something changed -(such as movement or rotation) since that reduces CPU usage on frames where -the updates aren't required. - - diff --git a/gbdk-lib/examples/gb/metasprites/metasprites.c b/gbdk-lib/examples/gb/metasprites/metasprites.c @@ -1,153 +0,0 @@ -#include <stdint.h> - -#include <gbdk/platform.h> -#include <gbdk/metasprites.h> - -#include "sprite.h" - -const unsigned char pattern[] = {0x80,0x80,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x02,0x02,0x01,0x01}; - -joypads_t joypads; - -#define ACC_X 1 -#define ACC_Y 2 - -// The metasprite will be built starting with hardware sprite zero (the first) -#define SPR_NUM_START 0 - -// Metasprite tiles are loaded into VRAM starting at tile number 0 -#define TILE_NUM_START 0 - -// sprite coords -uint16_t PosX, PosY; -int16_t SpdX, SpdY; -uint8_t PosF; -uint8_t hide, jitter; -uint8_t idx, rot; - -// main funxction -void main(void) { - // init palettes - BGP_REG = OBP0_REG = 0xE4; - OBP1_REG = 0xE0; - - // Fill the screen background with a single tile pattern - fill_bkg_rect(0, 0, 20, 18, 0); - set_bkg_data(0, 1, pattern); - - // Load metasprite tile data into VRAM - set_sprite_data(TILE_NUM_START, sizeof(sprite_tiles) >> 4, sprite_tiles); - - // show bkg and sprites - SHOW_BKG; SHOW_SPRITES; - - // Check what size hardware sprite the metasprite is using (from sprite.h) - #if sprite_TILE_H == 16 - SPRITES_8x16; - #else - SPRITES_8x8; - #endif - - // init 1 joypad - joypad_init(1, &joypads); - - // Set initial position, zero out speed - PosX = PosY = 64 << 4; - SpdX = SpdY = 0; - - hide = 0; jitter = 0; idx = 0; rot = 0; - - while(1) { - // poll joypads - joypad_ex(&joypads); - - PosF = 0; - // game object - if (joypads.joy0 & J_UP) { - SpdY -= 2; - if (SpdY < -32) SpdY = -32; - PosF |= ACC_Y; - } else if (joypads.joy0 & J_DOWN) { - SpdY += 2; - if (SpdY > 32) SpdY = 32; - PosF |= ACC_Y; - } - - if (joypads.joy0 & J_LEFT) { - SpdX -= 2; - if (SpdX < -32) SpdX = -32; - PosF |= ACC_X; - } else if (joypads.joy0 & J_RIGHT) { - SpdX += 2; - if (SpdX > 32) SpdX = 32; - PosF |= ACC_X; - } - - - // Press A button to show/hide metasprite - if ((joypads.joy0 & J_A) && (!jitter)) { - hide = (!hide); - jitter = 20; - } - - // Press B button to cycle through metasprite animations - if ((joypads.joy0 & J_B) && (!jitter) && (!hide)) { - idx++; if (idx >= (sizeof(sprite_metasprites) >> 1)) idx = 0; - jitter = 10; - } - - // Press SELECT button to cycle metasprite through Normal/Flip-Y/Flip-XY/Flip-X - if ((joypads.joy0 & J_SELECT) && (!jitter) && (!hide)) { - rot++; rot &= 3; - jitter = 20; - } - - // Hide/Animate/Flip input throttling - if (jitter) jitter--; - - PosX += SpdX, PosY += SpdY; - - uint8_t hiwater = 0; - - // NOTE: In a real game it would be better to only call the move_metasprite..() - // functions if something changed (such as movement or rotation). That - // reduces CPU usage on frames that don't need updates. - // - // In this example they are called every frame to simplify the example code - - // Hide the metasprite or move it & apply any rotation settings - if (hide) - hide_metasprite(sprite_metasprites[idx], SPR_NUM_START); - else - switch (rot) { - case 0: hiwater = move_metasprite (sprite_metasprites[idx], TILE_NUM_START, SPR_NUM_START, (PosX >> 4), (PosY >> 4)); break; - case 1: hiwater = move_metasprite_hflip (sprite_metasprites[idx], TILE_NUM_START, SPR_NUM_START, (PosX >> 4), (PosY >> 4)); break; - case 2: hiwater = move_metasprite_hvflip(sprite_metasprites[idx], TILE_NUM_START, SPR_NUM_START, (PosX >> 4), (PosY >> 4)); break; - case 3: hiwater = move_metasprite_vflip (sprite_metasprites[idx], TILE_NUM_START, SPR_NUM_START, (PosX >> 4), (PosY >> 4)); break; - }; - - // Hide rest of the hardware sprites, because amount of sprites differ between animation frames. - hide_sprites_range(hiwater, 40); - - // Y Axis: update velocity (reduce speed) if no U/D button pressed - if (!(PosF & ACC_Y)) { - if (SpdY != 0) { - if (SpdY > 0) SpdY--; - else SpdY ++; - } - } - - // X Axis: update velocity (reduce speed) if no L/R button pressed - if (!(PosF & ACC_X)) { - if (SpdX != 0) { - if (SpdX > 0) SpdX--; - else SpdX ++; - } - } - - - // wait for VBlank to slow down everything and reduce cpu use when idle - wait_vbl_done(); - } -} - diff --git a/gbdk-lib/examples/gb/metasprites/sprite.png b/gbdk-lib/examples/gb/metasprites/sprite.png Binary files differ. diff --git a/gbdk-lib/include/gb/gb.h b/gbdk-lib/include/gb/gb.h @@ -1576,6 +1576,14 @@ __REG _shadow_OAM_base; */ #define MAX_HARDWARE_SPRITES 40 +/** True if sprite hardware can flip sprites horizontally +*/ +#define HARDWARE_SPRITE_CAN_FLIP_H 1 + +/** True if sprite hardware can flip sprites vertically +*/ +#define HARDWARE_SPRITE_CAN_FLIP_V 1 + /** Enable OAM DMA copy each VBlank and set it to transfer any 256-byte aligned array */ inline void SET_SHADOW_OAM_ADDRESS(void * address) { diff --git a/gbdk-lib/include/msx/msx.h b/gbdk-lib/include/msx/msx.h @@ -627,6 +627,14 @@ extern volatile uint8_t _shadow_OAM_OFF; */ #define MAX_HARDWARE_SPRITES 32 +/** True if sprite hardware can flip sprites horizontally +*/ +#define HARDWARE_SPRITE_CAN_FLIP_H 0 + +/** True if sprite hardware can flip sprites vertically +*/ +#define HARDWARE_SPRITE_CAN_FLIP_V 0 + /** Sets address of 256-byte aligned array of shadow OAM to be transferred on each VBlank */ inline void SET_SHADOW_OAM_ADDRESS(void * address) { diff --git a/gbdk-lib/include/nes/nes.h b/gbdk-lib/include/nes/nes.h @@ -700,6 +700,14 @@ extern uint8_t _shadow_OAM_base; */ #define MAX_HARDWARE_SPRITES 64 +/** True if sprite hardware can flip sprites horizontally +*/ +#define HARDWARE_SPRITE_CAN_FLIP_H 1 + +/** True if sprite hardware can flip sprites vertically +*/ +#define HARDWARE_SPRITE_CAN_FLIP_V 1 + /** Enable OAM DMA copy each VBlank and set it to transfer any 256-byte aligned array */ inline void SET_SHADOW_OAM_ADDRESS(void * address) { diff --git a/gbdk-lib/include/sms/sms.h b/gbdk-lib/include/sms/sms.h @@ -658,6 +658,14 @@ extern volatile uint8_t _shadow_OAM_OFF; */ #define MAX_HARDWARE_SPRITES 64 +/** True if sprite hardware can flip sprites horizontally +*/ +#define HARDWARE_SPRITE_CAN_FLIP_H 0 + +/** True if sprite hardware can flip sprites vertically +*/ +#define HARDWARE_SPRITE_CAN_FLIP_V 0 + /** Sets address of 256-byte aligned array of shadow OAM to be transferred on each VBlank */ inline void SET_SHADOW_OAM_ADDRESS(void * address) { diff --git a/gbdk-lib/libc/targets/mos6502/nes/metasprites.s b/gbdk-lib/libc/targets/mos6502/nes/metasprites.s @@ -6,6 +6,9 @@ .area OSEG (PAG, OVR) ___current_metasprite:: .ds 2 ___current_base_tile:: .ds 1 + ___move_metasprite_hflip_PARM_3:: + ___move_metasprite_vflip_PARM_3:: + ___move_metasprite_hvflip_PARM_3:: ___move_metasprite_PARM_3:: .ds 2 .area _INITIALIZED @@ -16,11 +19,11 @@ .area _HOME -; uint8_t __move_metasprite(uint8_t id, uint8_t x, uint8_t y) .define xPos ".tmp" .define yPos "___move_metasprite_PARM_3" .define id ".tmp+1" -___move_metasprite:: + +.move_metasprite_prologue: sta *id stx xPos asl @@ -37,6 +40,20 @@ ___move_metasprite:: ora *___current_base_tile sta *___current_base_tile ldy #0 + rts + +.move_metasprite_epilogue: + ; Return number of hardware sprites used + txa + lsr + lsr + sec + sbc *id + rts + +; uint8_t __move_metasprite(uint8_t id, uint8_t x, uint8_t y) +___move_metasprite:: + jsr .move_metasprite_prologue ___move_metasprite_loop: lda [*___current_metasprite],y ; dy iny @@ -46,10 +63,10 @@ ___move_metasprite_loop: adc *yPos sta *yPos sta _shadow_OAM+OAM_POS_Y,x - lda [*___current_metasprite],y ; dx - iny + lda *xPos clc - adc *xPos + adc [*___current_metasprite],y ; dx + iny sta *xPos sta _shadow_OAM+OAM_POS_X,x lda [*___current_metasprite],y ; tile index @@ -67,10 +84,114 @@ ___move_metasprite_loop: inx bne ___move_metasprite_loop ___move_metasprite_end: - ; Return number of hardware sprites used - txa - lsr - lsr + jmp .move_metasprite_epilogue + +; uint8_t __move_metasprite_vflip(uint8_t id, uint8_t x, uint8_t y) +___move_metasprite_vflip:: + jsr .move_metasprite_prologue +___move_metasprite_vflip_loop: + lda [*___current_metasprite],y ; dy + iny + cmp #0x80 + beq ___move_metasprite_vflip_end + clc + adc *yPos + sta *yPos + sta _shadow_OAM+OAM_POS_Y,x + lda *xPos sec - sbc *id - rts + sbc [*___current_metasprite],y ; dx + iny + sta *xPos + sta _shadow_OAM+OAM_POS_X,x + lda [*___current_metasprite],y ; tile index + iny + clc + adc *___current_base_tile + sta _shadow_OAM+OAM_TILE_INDEX,x + lda [*___current_metasprite],y ; props + eor #OAMF_XFLIP + iny + ; TODO: Handle attributes in png2asset + sta _shadow_OAM+OAM_ATTRIBUTES,x + inx + inx + inx + inx + bne ___move_metasprite_vflip_loop +___move_metasprite_vflip_end: + jmp .move_metasprite_epilogue + +; uint8_t __move_metasprite_hflip(uint8_t id, uint8_t x, uint8_t y) +___move_metasprite_hflip:: + jsr .move_metasprite_prologue +___move_metasprite_hflip_loop: + lda [*___current_metasprite],y ; dy + iny + cmp #0x80 + beq ___move_metasprite_hflip_end + eor #0xFF + sec + adc *yPos + sta *yPos + sta _shadow_OAM+OAM_POS_Y,x + lda *xPos + clc + adc [*___current_metasprite],y ; dx + iny + sta *xPos + sta _shadow_OAM+OAM_POS_X,x + lda [*___current_metasprite],y ; tile index + iny + clc + adc *___current_base_tile + sta _shadow_OAM+OAM_TILE_INDEX,x + lda [*___current_metasprite],y ; props + eor #OAMF_YFLIP + iny + ; TODO: Handle attributes in png2asset + sta _shadow_OAM+OAM_ATTRIBUTES,x + inx + inx + inx + inx + bne ___move_metasprite_hflip_loop +___move_metasprite_hflip_end: + jmp .move_metasprite_epilogue + +; uint8_t __move_metasprite_hvflip(uint8_t id, uint8_t x, uint8_t y) +___move_metasprite_hvflip:: + jsr .move_metasprite_prologue +___move_metasprite_hvflip_loop: + lda [*___current_metasprite],y ; dy + iny + cmp #0x80 + beq ___move_metasprite_hvflip_end + eor #0xFF + sec + adc *yPos + sta *yPos + sta _shadow_OAM+OAM_POS_Y,x + lda *xPos + sec + sbc [*___current_metasprite],y ; dx + iny + sta *xPos + sta _shadow_OAM+OAM_POS_X,x + lda [*___current_metasprite],y ; tile index + iny + clc + adc *___current_base_tile + sta _shadow_OAM+OAM_TILE_INDEX,x + lda [*___current_metasprite],y ; props + eor #OAMF_YFLIP+OAMF_XFLIP + iny + ; TODO: Handle attributes in png2asset + sta _shadow_OAM+OAM_ATTRIBUTES,x + inx + inx + inx + inx + bne ___move_metasprite_hvflip_loop +___move_metasprite_hvflip_end: + jmp .move_metasprite_epilogue

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.