Neo Geo Tiles Covered Up?

Discussion of development of software for any "obsolete" computer or video game system. See the WSdev wiki and ObscureDev wiki for more information on certain platforms.
Post Reply
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Neo Geo Tiles Covered Up?

Post by puppydrum64 »

EDIT: It works now if I make the tilemap start at an index lower than everything else. I read the wiki and couldn't find that info anywhere :oops:

I was curious about Neo Geo programming and decided to give it a go using the Chibiakumas tutorial. Their message board is mostly dead sadly so I doubt I'd get a good answer there, so I'm asking here. The problem I'm having is with tilemaps. My tilemap works just fine, I used the same code from the tutorial found here: https://www.chibiakumas.com/68000/platf ... #LessonP26

By itself, the tilemap works perfectly. There's just one major problem: it gets drawn over top of any sprite EXCEPT sprite 0. Scaling the shrink factor of the tilemap reveals the hidden sprites underneath. Sprite 0 gets drawn on top of everything regardless.

In my test rom, sprite 0 is the aiming sight, sprite 1 is the gun (it's the BFG from Doom, I only drew the leftmost strip just to see if it would appear) and sprites 32 and onward are the tilemap. The tilemap is made of the anchor sprite (the leftmost strip) and 39 more strips chained to the anchor sprite. I'm fairly new to NEOGEO programming but I have a basic idea of how to draw something to the screen properly. I just don't understand why this doesn't seem to work correctly, I should be nowhere near the sprite limit (either per-scanline or total sprites)


neogeo_tile_coverup1.PNG
neogeo_tile_coverup2.PNG
The source code for all this is a bit lengthy but I can provide it as well. Most of it is irrelevant to the problem I'm having. I'll try to cut what I can.

Main Document:

Code: Select all

;UNCOMMENT ONLY ONE OF THESE AT A TIME! ENSURES COMPATIBILITY BETWEEN HARDWARE.
;NEOGEO_MVS equ 1
NEOGEO_AES equ 1

;CREDITS:
;CHIBIAKUMAS.COM
;Neo-Geo Graphic Tool Suite by evobboy
;YY-CHR
;NEOGEODEV WIKI


; Source code based on the work from www.chibiakumas.com
	include "\SrcALL\BasicMacros.asm"		;Needed for Monitor
	include "\SrcNEO\NEOGEO_Macros.asm"

; USER RAM: $100000 THRU $10F2FF
flag_VBlank	equ  $10F2FF  		;(byte) vblank flag in ram

Sprite00_X			equ $100000					;Aiming sight X pos			(WORD)
Sprite00_X2 		equ Sprite00_X+2			;							(WORD)
Sprite00_Y			equ	Sprite00_X+4			;Aiming sight Y pos			(WORD)
Sprite00_Y2 		equ Sprite00_X+6			;							(WORD)
Sprite00_Shrink 	equ Sprite00_X+8			;Aiming sight shrink factor	(WORD)

tempByte0			equ $10000A					;general purpose temp storage (BYTE)
tempByte1			equ tempByte0+1				;general purpose temp storage (BYTE)
tempByte2			equ tempByte1+1				;general purpose temp storage (BYTE)
tempByte3			equ tempByte2+1				;general purpose temp storage (BYTE)

looptemp			equ tempByte3+1				;temp loop counter	(BYTE)

;these can be used as a word or long, but in doing so you will clobber anything else stored in them.
;Example: move.l d0,tempByte0 will split d0 into 4 bytes, storing the first in temp0, the second in temp1, etc.

AimingSensitivity equ $100034	;The speed at which your cursor moves. 
								;Ranges from 1 to 8,Not implemented yet (BYTE)


;Even though this processor works with longs and words, each individual memory address only holds 8 bits.
;Moving a long into GameFlags00 for example would clobber the next three memory addresses.


Cursor_X 		equ  $101000		;Cursor Position for writing text		(BYTE)
Cursor_Y 		equ  $101001		;Cursor Position for writing text		(BYTE)
score_ones		equ	 $101002		;Ones digit of score					(BYTE)
score_tens		equ  $101003		;Tens digit of score					(BYTE)
score_100		equ  $101004		;Hundreds digit of score				(BYTE)
score_1000		equ  $101005		;Thousands digit of score				(BYTE)
score_10000 	equ  $101006		;Ten-Thousands digit of score			(BYTE)
score_100000	equ  $101007		;Hundred-Thousands digit of score		(BYTE)

AlienShrink		equ	 $10100A		;alien's shrink factor - for anchor sprite.	  (WORD)
AlienShrink2	equ	 $10100C		;alien's shrink factor - for chained sprites. (WORD)
TilemapShrink	equ	 $10100E		;tilemap's shrink factor.						(WORD)
;GAME CONSTANTS:
TOTAL_MAX_PALETTES equ 4			;how many palettes your game has (max 256)


; MEMORY MAPPED PORTS
;Hard DIPs:
DIPSW_SETTINGS  equ 0
DIPSW_CHUTES    equ 1
DIPSW_CTRL      equ 2
DIPSW_ID0       equ 3
DIPSW_ID1       equ 4
DIPSW_MULTI     equ 5
DIPSW_FREEPLAY  equ 6
DIPSW_FREEZE    equ 7

;VRAM zones:
SCB1            equ $0000   ;Sprite tilemaps
FIXMAP          equ $7000
SCB2            equ $8000   ;Sprite shrink values
SCB3            equ $8200   ;Sprite Y positions, heights and flags
SCB4            equ $8400   ;Sprite X positions

;Basic colors:
BLACK           equ $8000
MIDRED          equ $4700
RED             equ $4F00
MIDGREEN        equ $2070
GREEN           equ $20F0
MIDBLUE         equ $1007
BLUE            equ $100F
MIDYELLOW       equ $6770
YELLOW          equ $6FF0
MIDMAGENTA      equ $5707
MAGENTA         equ $5F0F
MIDCYAN         equ $3077
CYAN            equ $30FF
ORANGE          equ $6F70
MIDGREY         equ $7777
WHITE           equ $7FFF

;Zones:
RAMSTART        equ $100000   ;68k work RAM
PALETTES        equ $400000   ;Palette RAM
BACKDROP        equ PALETTES+(16*2*256)-2
MEMCARD         equ $800000   ;Memory card
SYSROM          equ $C00000   ;System ROM

;Registers:
REG_P1CNT       equ $300000
REG_DIPSW       equ $300001   ;Dipswitches/Watchdog
REG_SOUND       equ $320000   ;Z80 I/O
REG_STATUS_A    equ $320001
REG_P2CNT       equ $340000
REG_STATUS_B    equ $380000
REG_POUTPUT     equ $380001   	;Joypad port outputs
REG_SLOT        equ $380021   	;Slot select

REG_NOSHADOW    equ $3A0001   	;Video output normal/dark
REG_SHADOW      equ $3A0011
REG_BRDFIX      equ $3A000B   	;Use embedded fix tileset
REG_CRTFIX      equ $3A001B   	;Use game fix tileset
REG_PALBANK1    equ $3A000F  	;Use palette bank 1
REG_PALBANK0    equ $3A001F   	;Use palette bank 0 (default)

REG_VRAMADDR    equ $3C0000	  	;Tell this WHERE to draw (equivalent of $2006 on NES)
REG_VRAMRW      equ $3C0002	 	;Tell this WHAT to draw (equivalent of $2007 on NES)
REG_VRAMMOD     equ $3C0004
REG_LSPCMODE    equ $3C0006
REG_TIMERHIGH   equ $3C0008
REG_TIMERLOW    equ $3C000A
REG_IRQACK      equ $3C000C
REG_TIMERSTOP   equ $3C000E

;System ROM calls:
SYS_INT1          equ $C00438
SYS_RETURN        equ $C00444
SYS_IO            equ $C0044A
SYS_CREDIT_CHECK  equ $C00450
SYS_CREDIT_DOWN   equ $C00456
SYS_READ_CALENDAR equ $C0045C   ;MVS only
SYS_CARD          equ $C00468
SYS_CARD_ERROR    equ $C0046E
SYS_HOWTOPLAY     equ $C00474   ;MVS only
SYS_FIX_CLEAR     equ $C004C2
SYS_LSP_1ST       equ $C004C8   ;Clear sprites
SYS_MESS_OUT      equ $C004CE

;RAM locations:
BIOS_SYSTEM_MODE  equ $10FD80
BIOS_MVS_FLAG     equ $10FD82
BIOS_COUNTRY_CODE equ $10FD83
BIOS_GAME_DIP     equ $10FD84   ;Start of soft DIPs settings (up to $10FD93)

;Set by SYS_IO:
BIOS_P1STATUS   equ $10FD94
BIOS_P1PREVIOUS equ $10FD95
BIOS_P1CURRENT  equ $10FD96
BIOS_P1CHANGE   equ $10FD97
BIOS_P1REPEAT   equ $10FD98
BIOS_P1TIMER    equ $10FD99

BIOS_P2STATUS   equ $10FD9A
BIOS_P2PREVIOUS equ $10FD9B
BIOS_P2CURRENT  equ $10FD9C
BIOS_P2CHANGE   equ $10FD9D
BIOS_P2REPEAT   equ $10FD9E
BIOS_P2TIMER    equ $10FD99

BIOS_STATCURNT    equ $10FDAC
BIOS_STATCHANGE   equ $10FDAD
BIOS_USER_REQUEST equ $10FDAE
BIOS_USER_MODE    equ $10FDAF
BIOS_START_FLAG   equ $10FDB4
BIOS_MESS_POINT   equ $10FDBE
BIOS_MESS_BUSY    equ $10FDC2

;Memory card:
BIOS_CRDF       equ $10FDC4   ;Byte: function to perform when calling BIOSF_CRDACCESS
BIOS_CRDRESULT  equ $10FDC6   ;Byte: 00 on success, else 80+ and encodes the error
BIOS_CRDPTR     equ $10FDC8   ;Longword: pointer to read from/write to
BIOS_CRDSIZE    equ $10FDCC   ;Word: how much data to read/write from/to card
BIOS_CRDNGH     equ $10FDCE   ;Word: usually game NGH. Unique identifier for the game that owns the save file
BIOS_CRDFILE    equ $10FDD0   ;Word: each NGH has up to 16 save files associated with

;Calendar, MVS only (in BCD, USES YOUR COMPUTER'S CALENDAR IF RUNNING ON MAME)
BIOS_YEAR       equ $10FDD2   ;Last 2 digits of year
BIOS_MONTH      equ $10FDD3
BIOS_DAY        equ $10FDD4
BIOS_WEEKDAY    equ $10FDD5   ;Sunday = 0, Monday = 1 ... Saturday = 6
BIOS_HOUR       equ $10FDD6   ;24 hour time, load as long to get minute and second in subsequent bytes.	
BIOS_MINUTE     equ $10FDD7
BIOS_SECOND     equ $10FDD8

BIOS_SELECT_TIMER equ $10FDDA   ;Byte: game start countdown
BIOS_DEVMODE      equ $10FE80   ;Byte: non-zero for developer mode

;Upload system ROM call:
BIOS_UPDEST     equ $10FEF4   ;Longword
BIOS_UPSRC      equ $10FEF8   ;Longword
BIOS_UPSIZE     equ $10FEFC   ;Longword
BIOS_UPZONE     equ $10FEDA   ;Byte: zone (0=PRG, 1=FIX, 2=SPR, 3=Z80, 4=PCM, 5=PAT)
BIOS_UPBANK     equ $10FEDB   ;Byte: bank

SOUND_STOP      equ $D00046

;Button definitions:
CNT_UP	        equ 0
CNT_DOWN		equ 1
CNT_LEFT		equ 2
CNT_RIGHT		equ 3
CNT_A	        equ 4
CNT_B	        equ 5
CNT_C	        equ 6
CNT_D	        equ 7
CNT_START1      equ 0
CNT_SELECT1     equ 1
CNT_START2      equ 2
CNT_SELECT2     equ 3

;-------------------------------------------------------------------------
;	CARTRIDGE HEADER
;-------------------------------------------------------------------------
; This Header is based on the work from 
; "Neo-Geo Assembly Programming for the Absolute Beginner" by freem
; http://ajworld.net/neogeodev/beginner/

; Traps
	dc.l	$0010F300		; Initial Supervisor Stack Pointer (SSP)
	dc.l	$00C00402		; Initial PC			(BIOS $C00402)
	dc.l	$00C00408		; Bus error/Monitor		(BIOS $C00408)
	dc.l	$00C0040E		; Address error			(BIOS $C0040E)
	dc.l	$00C00414		; Illegal Instruction	(BIOS $C00414)
	dc.l	$00C00426		; Divide by 0
	dc.l	$00C00426		; CHK Instruction
	dc.l	$00C00426		; TRAPV Instruction
	dc.l	$00C0041A		; Privilege Violation	(BIOS $C0041A)
	dc.l	$00C00420		; Trace					(BIOS $C00420)
	dc.l	$00C00426		; Line 1010 Emulator
	dc.l	$00C00426		; Line 1111 Emulator
	dc.l	$00C00426		; Reserved
	dc.l	$00C00426		; Reserved
	dc.l	$00C00426		; Reserved
	dc.l	$00C0042C		; Uninitialized Interrupt Vector

	dc.l	$00C00426		; Reserved
	dc.l	$00C00426		; Reserved
	dc.l	$00C00426		; Reserved
	dc.l	$00C00426		; Reserved
	dc.l	$00C00426		; Reserved
	dc.l	$00C00426		; Reserved
	dc.l	$00C00426		; Reserved
	dc.l	$00C00426		; Reserved
	dc.l	$00C00432		; Spurious Interrupt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 									Interrupts
	dc.l	VBlank			; Level 1 interrupt (VBlank)
	dc.l	IRQ2			; Level 2 interrupt (HBlank)
	dc.l	IRQ3			; Level 3 interrupt
	dc.l	$00000000		; Level 4 interrupt
	dc.l	$00000000		; Level 5 interrupt
	dc.l	$00000000		; Level 6 interrupt
	dc.l	$00000000		; Level 7 interrupt (NMI)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;									 Traps
	dc.l	$FFFFFFFF		; TRAP #0 Instruction
	dc.l	$FFFFFFFF		; TRAP #1 Instruction
	dc.l	$FFFFFFFF		; TRAP #2 Instruction
	dc.l	$FFFFFFFF		; TRAP #3 Instruction
	dc.l	$FFFFFFFF		; TRAP #4 Instruction
	dc.l	$FFFFFFFF		; TRAP #5 Instruction
	dc.l	$FFFFFFFF		; TRAP #6 Instruction
	dc.l	$FFFFFFFF		; TRAP #7 Instruction
	dc.l	$FFFFFFFF		; TRAP #8 Instruction
	dc.l	$FFFFFFFF		; TRAP #9 Instruction
	dc.l	$FFFFFFFF		; TRAP #10 Instruction
	dc.l	$FFFFFFFF		; TRAP #11 Instruction
	dc.l	$FFFFFFFF		; TRAP #12 Instruction
	dc.l	$FFFFFFFF		; TRAP #13 Instruction
	dc.l	$FFFFFFFF		; TRAP #14 Instruction
	dc.l	$FFFFFFFF		; TRAP #15 Instruction
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	dc.l	$FFFFFFFF		; Reserved
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;							Cart Header
	dc.b "NEO-GEO"
	dc.b $00 			;System Version (0=cart; 1/2 are used for CD games)
	dc.w $0FFF 			;NGH number ($0000 is prohibited)
	dc.l $00080000 		;game prog size in bytes (4Mbits/512KB)
	dc.l $00108000 		;pointer to backup RAM block (first two bytes are debug dips)
	dc.w $0000 			;game save size in bytes
	dc.b $02 			;Eye catcher anim flag (0=BIOS,1=game,2=nothing)
	dc.b $00 			;Sprite bank for eyecatch if done by BIOS
	dc.l softDips_All  	;Software dips for Japan
	dc.l softDips_All   ;Software dips for USA
	dc.l softDips_All 	;Software dips for Europe
	jmp USER 			; $122
	jmp PLAYER_START 	; $128
	jmp DEMO_END 		; $12E
	jmp COIN_SOUND 		; $134

	dc.l $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
	dc.l $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
	dc.l $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
	dc.l $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
	dc.l $FFFFFFFF,$FFFFFFFF

	;org $00000182
	dc.l TRAP_CODE 				;pointer to TRAP_CODE

	; security code required by Neo-Geo games
TRAP_CODE:
	dc.l $76004A6D,$0A146600,$003C206D,$0A043E2D
	dc.l $0A0813C0,$00300001,$32100C01,$00FF671A
	dc.l $30280002,$B02D0ACE,$66103028,$0004B02D
	dc.l $0ACF6606,$B22D0AD0,$67085088,$51CFFFD4
	dc.l $36074E75,$206D0A04,$3E2D0A08,$3210E049
	dc.l $0C0100FF,$671A3010,$B02D0ACE,$66123028
	dc.l $0002E048,$B02D0ACF,$6606B22D,$0AD06708
	dc.l $588851CF,$FFD83607
	dc.w $4E75
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 				Software Dip Switches (a.k.a. "soft dip")
softDips_All:
	dc.b "EXAMPLE SET A   " 		; Game Name
	dc.w $FFFF 						; Special Option 1
	dc.w $FFFF 						; Special Option 2
	dc.b $FF 						; Special Option 3
	dc.b $FF 						; Special Option 4
	dc.b $02 						; Option 1: 2 choices, default #0
	dc.b $00,$00,$00,$00,$00,$00,$00,$00,$00 ; filler
	dc.b "OPTION 1A   " 			; Option 1 description
	dc.b "CHOICE1 A   " 			; Option choices
	dc.b "CHOICE2 A   "

	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 									USER
; Needs to perform actions according to the value in BIOS_USER_REQUEST.
; Must jump back to SYSTEM_RETURN at the end so the BIOS can have control.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

USER:	
	move.b	d0,$300001			;Kick watchdog
	lea		$10F300,sp			;Set stack pointer to BIOS_WORKRAM
	move.w	#0,$3C0006			;LSPC_MODE - Disable auto-animation, timer interrupts
									;set auto-anim speed to 0 frames
	move.w	#7,$3C000C			;LSPC_IRQ_ACK - acknowledge all IRQs

	move.w	#$2000,sr			; Enable VBlank interrupt, go Supervisor

	; Handle user request
	moveq	#0,d0
	move.b	($10FDAE).l,d0		;BIOS_USER_REQUEST
	lsl.b	#2,d0				; shift value left to get offset into table
	lea		cmds_USER_REQUEST,a0
	movea.l	(a0,d0),a0
	jsr		(a0)
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 							BIOS_USER_REQUEST commands

cmds_USER_REQUEST:
	dc.l	userReq_StartupInit	; Command 0 (Initialize)
	dc.l	userReq_StartupInit	; Command 1 (Custom eyecatch)
	dc.l	userReq_Game		; Command 2 (Demo Game/Game)
	dc.l	userReq_Game		; Command 3 (Title Display)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 							userReq_StartupInit

userReq_StartupInit:
	KickWatchdog
	jmp		$C00444			;SYSTEM_RETURN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
;				Handle Interrupts and system events	
	
PLAYER_START:					;Player pressed start on title
	KickWatchdog
	rts
	
COIN_SOUND:					
DEMO_END:						
	rts

VBlank:
	btst	#7,$10FD80			;BIOS_SYSTEM_MODE - check if the BIOS wants to run its vblank
	bne		gamevbl
	jmp		$C00438				;SYSTEM_INT1 - run BIOS vblank
gamevbl:						;run the game's vblank
	movem.l d0-d7/a0-a6,-(sp)	;save registers
		move.w	#4,$3C000C		;LSPC_IRQ_ACK - acknowledge the vblank interrupt
		KickWatchdog
		jsr		$C0044A 		;"Call SYSTEM_IO every 1/60 second."
		jsr		$C004CE			;Puzzle Bobble calls MESS_OUT just after SYSTEM_IO
		move.b	#0,flag_VBlank	;clear vblank flag so waitVBlank knows to stop
	movem.l (sp)+,d0-d7/a0-a6	;restore registers
	rte

IRQ2:
	move.w	#2,$3C000C			;LSPC_IRQ_ACK - ack. interrupt #2 (HBlank)
	KickWatchdog
	rte
IRQ3:
	move.w  #1,$3C000C			;LSPC_IRQ_ACK - acknowledge interrupt 3
	KickWatchdog
	rte
	 	
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 							UserReq_Game

userReq_Game:

	
; YOUR ACTUAL GAME CODE GOES HERE - EVERYTHING ABOVE IS REQUIRED BY THE SYSTEM.


	;        -RGB			;Color Num:
	move.w #$0000,$401FFE	;0 - Background color
	move.l #4,AimingSensitivity
	move.w #$1000,$3C0006		;set auto-animation speed to 8 frames.
	
	
Setup_HOWTOPLAY:				;The "HOW TO PLAY" screen from NAM 1975. Duplicated here for testing purposes only.
								;Will modify to show this game's controls instead.
								
	ifd NEOGEO_MVS				;NOT AVAILABLE ON NEOGEO AES
	;this is getting annoying so i'll set my system to aes to skip it for now.
	MOVE.L #$00000200,$10F300	;All buttons released
	MOVE.L #$000001FF,$10F304	;All arrows highlighted
	MOVE.L #$0010F3E2,$10F308	;MESS_OUT
	MOVE.W #$0004,$10F30C		;Wait 4 frames
	MOVE.L #$0000000C,$10F30E	;Init loop counter to 12
	MOVE.L #$00000100,$10F312	;All arrows cleared
	MOVE.L #$00000000,$10F316	;Wait...
	MOVE.W #$0008,$10F31A		;...8 frames
	MOVE.L #$000000FF,$10F31C	;Loop back (blink all arrows 12 times.)
	MOVE.L #$00000201,$10F320	;A button is pressed.
	MOVE.L #$00000100,$10F324	;All arrows cleared.
	MOVE.L #$0010F418,$10F328	;MESS_OUT
	MOVE.W #$0004,$10F32C		;Wait 4 frames
	MOVE.L #$0000000C,$10F32E	;Init loop counter to 12
	MOVE.L #$00000200,$10F332	;All buttons released
	MOVE.L #$00000000,$10F336	;Wait...
	MOVE.W #$0008,$10F33A		;...8 frames
	MOVE.L #$00000201,$10F33C	;A button is pressed.
	MOVE.L #$00000000,$10F340	;Wait...
	MOVE.W #$0008,$10F344		;...8 frames
	MOVE.L #$000000FF,$10F346	;Loop back (blink A Button 12 times)
	
	JSR SYS_HOWTOPLAY
	endif	
	
	ClearFixLayer
	
	
	
	;This system bios call loads its own palettes over top of yours so you
	;need to reload your palettes after it's done!
	
Prep_VRAM:


	
	jsr LoadPalettes		;callee preserved. No need to back up regs.
	
	LEA TestData2,A0
	MOVE.W #$0000,D1
	JSR CreateSprites 		;gun
	
	LEA TestData,A0
	MOVE.W #$0001,D1
	JSR CreateSprites		;aiming sight
	
	
	
	MOVE.W #$077F,TilemapShrink
	JSR DefineTilemap
	;BUG: Any sprite other than Sprite 0 is shown BEHIND the tilemap!
	

	

;--------------------------------------------------------------------------
	
inf:	
	KickWatchdog
	jsr HandleControls
	jmp inf
	
	
;---------------------------------------------------------------------
; SUBROUTINES
;---------------------------------------------------------------------
	include "NEOGEO_Subroutines.asm"
	;include "\SrcALL\Multiplatform_BCD.asm"
	include "CreateSprites.asm"
	include "tilemap2.asm"

;-------------------------------------------------------------------------
; DEBUG TOOLS CREATED BY KEITH OF CHIBIAKUMAS.COM
;-------------------------------------------------------------------------

ShowDebugScreen:
	CLR.B (Cursor_X)		;RESET DEBUG SCREEN DRAWING CURSORS TO ZERO
	CLR.B (Cursor_Y)
	
	lea Message,a3
	jsr PrintString			;Show String Message
	
	
	
	
	jsr NewLine			;Move down a line
    
	

	
	jsr Monitor			;Show Registers

	jsr Monitor_MemDump	;Dump 6 lines from  $00010000
	dc.l $101000
	dc.w $6
	
	jsr NewLine
	jsr NewLine
	lea InsertCoinMessage,a3
	jsr PrintString
	RTS
	
	
PrintString:
	move.b (a3)+,d0			;Read a character in from A3
	cmp.b #255,d0
	beq PrintString_Done	;Return on 255
	jsr PrintChar			;Print the Character
	bra PrintString
PrintString_Done:		
	rts
	
NewLine:
	addq.b #1,(Cursor_Y)	;Inc Ypos
	clr.b (Cursor_X)		;Zero Xpos
	rts	
	
	
PrintChar:
	moveM.l d0-d7/a0-a7,-(sp)
		and #$FF,d0
		sub #32,d0				;First character in font is CHR(32)
		
;VRAM address = $7000 + (Ypos * 32) + Xpos

		Move.L  #$7000,d5		;Tilemap base $7000
		clr.L d4
		Move.B (Cursor_X),D4
		rol.L #5,D4				;X*32
		add.L D4,D5
		
		clr.L d4
		Move.B (Cursor_Y),D4
		
		add #2,d4				;NEO doesn't recommend using top 2 columns
		add.L D4,D5
		
			;	PTTT - P=Palette T=TileNum
		add.w #$1800,d0			;Tile Num (Palette 1 - Tile $800+)
		
		move.w d5,$3C0000 		;VRAM Address
		move.w d0,$3C0002		;VRAM Write (tile data)
		
		addq.b #1,(Cursor_X)	;INC Xpos
		cmp.b #39,(Cursor_X)	;At end of line?
		bls nextpixel_Xok
		jsr NewLine				;NewLine!
nextpixel_Xok:
	moveM.l (sp)+,d0-d7/a0-a7
	rts

	
	include "\SrcALL\Multiplatform_Monitor.asm"
;--------------------------------------------------------------------------
; CONTROLLER INPUT
;--------------------------------------------------------------------------
	include "controller.asm"

;--------------------------------------------------------------------------
;	DATA TABLES ETC
;--------------------------------------------------------------------------
Message:    dc.b 'DEBUG SCREEN',255
	even
	
InsertCoinMessage:	dc.b 'INSERT COIN...',255
	EVEN

;SPRITE SHEETS

TilemapCompressed:
	;not used but the label was retained to prevent the assembler from rejecting my code for now.
	
;PALETTES
Palette_1:	  ; PALETTE 1 - WE DON'T MESS WITH PALETTE ZERO.
    dc.w $0FFF; ;0  -RGB	transparent
    dc.w $0808; ;1  -RGB	dark magenta
    dc.w $00FF; ;2  -RGB	cyan
    dc.w $0FFF; ;3  -RGB	white
    dc.w $0F0F; ;4  -RGB	bright magenta
    dc.w $0FF0; ;5  -RGB	bright yellow
    dc.w $033D; ;6  -RGB	navy blue
    dc.w $0AAA; ;7  -RGB	light gray
    dc.w $0E76; ;8  -RGB
    dc.w $0EA5; ;9  -RGB
    dc.w $0FF4; ;10 -RGB
    dc.w $0A2A; ;11 -RGB
    dc.w $0F0F; ;12 -RGB
    dc.w $003D; ;13 -RGB
    dc.w $036B; ;14 -RGB
    dc.w $00DF; ;15 -RGB
	
Palette_2:
    dc.w $0333; ;0  -RGB
    dc.w $0444; ;1  -RGB
    dc.w $0555; ;2  -RGB
    dc.w $0FFF; ;3  -RGB
    dc.w $0FFF; ;4  -RGB
    dc.w $0286; ;5  -RGB
    dc.w $03D3; ;6  -RGB
    dc.w $0E33; ;7  -RGB
    dc.w $0E76; ;8  -RGB
    dc.w $0EA5; ;9  -RGB
    dc.w $0FF4; ;10 -RGB
    dc.w $0A2A; ;11 -RGB
    dc.w $0F0F; ;12 -RGB
    dc.w $003D; ;13 -RGB
    dc.w $036B; ;14 -RGB
    dc.w $00DF; ;15 -RGB

Palette_3		
    dc.w $0F00; ;0  -RGB
    dc.w $00F0; ;0  -RGB
    dc.w $000F; ;0  -RGB
	dc.w $0F00; ;0  -RGB
    dc.w $00F0; ;0  -RGB
    dc.w $00F0; ;0  -RGB
    dc.w $0F00; ;0  -RGB
    dc.w $00F0; ;0  -RGB
    dc.w $000F; ;0  -RGB
    dc.w $0F00; ;0  -RGB
    dc.w $00F0; ;0  -RGB
    dc.w $000F; ;0  -RGB
    dc.w $0F00; ;0  -RGB
    dc.w $00F0; ;0  -RGB
    dc.w $000F; ;0  -RGB
    dc.w $0F00; ;0  -RGB
	
Palette_4:	
    dc.w $0FFF; ;0  -RGB
    dc.w $0EEE; ;1  -RGB
    dc.w $0DDD; ;2  -RGB
    dc.w $0FF0; ;3  -RGB
    dc.w $0BBB; ;4  -RGB
    dc.w $0AAA; ;5  -RGB
    dc.w $0999; ;6  -RGB
    dc.w $0888; ;7  -RGB
    dc.w $0777; ;8  -RGB
    dc.w $0666; ;9  -RGB
    dc.w $0555; ;10 -RGB
    dc.w $0444; ;11 -RGB
    dc.w $0333; ;12 -RGB
    dc.w $0222; ;13 -RGB
    dc.w $0111; ;14 -RGB
    dc.w $0000; ;15 -RGB

;EOF
tilemap2.asm:

Code: Select all

;;;;;;;;;;;; DEFINE TILEMAP ;;;;;;;;;;;;;;;;;;;;;;;;

DefineTilemap:

	MOVE.W #$8020,D7	;ATTRIBS ADDR
	MOVE.W #$0800,D6	;TILE ADDR		LOWER NUMBER SPRITES ARE DRAWN ON TOP OF HIGHER ONES SO WE NEED THIS TO BE A HIGH NUMBER.
	
	MOVE.W (TilemapShrink),D5	;SHRINK FACTOR (50%)
	
	MOVE.L #30,D4		;SPRITE WIDTH
	MOVE.L #27,D2		;SPRITE HEIGHT
	
;DEFINE ANCHOR SPRITE

	MOVE.W D7,$3C0000	;SET VRAMADDR TO $8000
	MOVE.W D5,$3C0002	;STORE SHRINK FACTOR INTO $8000
	
	ADD.W #$200,D7		;D7 NOW POINTS TO Y POS DESTINATION
	
	MOVE.W D7,$3C0000	;SET VRAMADDR TO $8200
	MOVE.W #$F821,D0	;Y POS OF $F8 AND SPRITE HEIGHT OF 33 WHICH FILLS WHOLE SCREEN
	MOVE.W D0,$3C0002	;STORE Y POS AND SPRITE HEIGHT INTO $8200
	
	ADD.W #$200,D7		;D7 NOW POINTS TO X POS DESTINATION
	
	MOVE.W D7,$3C0000		;SET VRAMADDR TO $8400
	MOVE.W #$0400,$3C0002	;STORE X POS IN $8400
	
	SUB.W #$400,D7			;RESET D7 BACK TO $8000
	
;;;;;TILES

SpriteLoop:
	move.l d2,d3			;SET UP LOOP COUNTER. THIS WAY WE CAN PRESERVE D2.
TileLoop:
	MOVE.W D6,$3C0000		;SET VRAMADDR TO SPRITE ZERO'S ADDRESS ($0000)
	MOVE.W #$2010,$3C0002	
	
	ADDQ.W #1,D6			;INCREMENT D6 TO POINT TO SPRITE ZERO'S ATTRIB DATA
	
	MOVE.W D6,$3C0000		;SET VRAMADDR TO SPRITE ZERO'S ATTRIB ($0001)
	MOVE.W #$0100,$3C0002	;SEND PALETTE DATA TO THE DESTINATION ADDR.
	
	ADDQ.W #1,D6
	
	DBRA D3,TileLoop
	
;At this point the anchor sprite is finished.
;CHAINED SPRITE

	AND.W #%1111111111000000,D6	;RESET D6 TO THE NEAREST MULTIPLE OF $40
	ADD.W #$40,D6				;ADD $40 TO REACH NEXT SPRITE ADDR
	ADD.W #$001,D7				;NEXT SPRITE ADDR FOR SHRINK/X/Y
	
	MOVE.W D7,$3C0000
	MOVE.W D5,$3C0002
	
	ADD.W #$200,D7
	
	MOVE.W D7,$3C0000
	MOVE.W #$0040,$3C0002	;THIS IS A CHAINED SPRITE.
	
	ADD.W #$200,D7
	
	MOVE.W D7,$3C0000
	MOVE.W #$0000,$3C0002	;X POS IS IGNORED FOR CHAINED SPRITES.
	
	SUB.W #$400,D7
	
	DBRA D4,SpriteLoop

	JMP inf
;Set tilenumbers!
	
	move.l #0,d2			;y pos
	lea TileMap,a6			;get tilemap data to write to screen.
TileNextY:
	move.l #0,d1
TileNextX:
	clr.l d0
	move.b (a6)+,d0
	add.l #$200C,d0
	
	jsr SetTile
	
	addq.l #1,d1
	cmp #40,d1
	bne TileNextX
	addq.l #1,d2
	cmp #26,d2
	bne TileNextY

	RTS
	
SetTile:
	movem.l d1-d2,-(sp)		;tileXY (d1,d2)=d0
		rol.w #6,d1			;xpos * 64
		rol.w #1,d2			;ypos * 2
		add.w d2,d1			;tile address
		add.w #$800,d1		;where bkgd sprites start
		move.w d1,$3C0000
		move.w d0,$3C0002
	movem.l (sp)+,d1-d2
	rts
	
TileMap:	;decimal 40 wide, decimal 26 tall
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	
	dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
	dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
	dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
	dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
	dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
	dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
	dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
	dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
	
	dc.b 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
	dc.b 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
CreateSprites.asm

Code: Select all

; PROBLEM: WE HAVE MORE PARAMETERS FOR CREATING SPRITE DATA THAN WE HAVE
; DATA REGISTERS ON THE 68000.

; POSSIBLE SOLUTIONS: TAKING A PAGE FROM CHIBIAKUMAS BOOK, WE USE
; A SIMILAR METHOD TO HOW KEITH SETS UP THE SEGA GENESIS VDP SETTINGS.
; ORGANIZE THE DATA REGS BETTER TO MAKE IT MORE READABLE.
CreateSprites:
	
	;INPUT: MOVE.W SPRITE ID NO.,D1 (0 THRU DECIMAL 379)
	;INPUT: LEA TestData,a0
	
	MOVE.L D1,-(SP)
	ADD.W #$8000,D1		;ADD $8000 TO D1 TO GET DESTINATION FOR SHRINK FACTOR
	
	MOVE.W (A0)+,D2		;LOAD SHRINK FACTOR INTO D2
	
	MOVE.W D1,$3C0000	;WHERE TO WRITE DATA ($8000+SPRITENUM)
	MOVE.W D2,$3C0002	;WHAT DATA TO WRITE	 (SHRINK FACTOR)
	
	ADD.W #$200,D1		;ADD $200 TO D1 TO GET DESTINATION FOR Y POS
	MOVE.W (A0)+,D2		;LOAD Y POS INTO D2

	MOVE.W (A0)+,D3		;LOAD SPRITE HEIGHT DATA INTO D3
	OR.W D3,D2			;COMBINE SPRITE HEIGHT WITH Y POS.	;DO NOT RE-USE D3, I WILL CHECK IT LATER
	MOVE.W (A0)+,D0		;LOAD CHAIN BIT INTO D0
	OR.W D0,D2			;COMBINE CHAIN BIT WITH Y POS.		;DO NOT RE-USE D0, I WILL CHECK IT LATER
	
	MOVE.W D1,$3C0000	;WHERE TO WRITE DATA ($8200+SPRITENUM)
	MOVE.W D2,$3C0002	;WHAT DATA TO WRITE
	
	ADD.W #$200,D1		;ADD $200 TO D1 TO GET DESTINATION FOR X POS
	
	; AND #$0040,D3			;IS THERE A CHAIN BIT?
	; BNE skipXpos			;X POS IS IGNORED FOR CHAINED SPRITES
	; FOR NOW WE WILL WRITE AN X POS VALUE TO $8400 EVEN IF THE SPRITE IS CHAINED BUT WE'LL TRY THIS LATER.
	
	MOVE.W (A0)+,D2		;LOAD X POS INTO D2
	
	MOVE.W D1,$3C0000	;WHERE TO WRITE DATA ($8400+SPRITENUM)
	MOVE.W D2,$3C0002	;WHAT DATA TO WRITE
skipXpos:
	MOVE.L (SP)+,D1		;POP D1

	MOVE.W D1,D4		;COPY D1 TO D4 SINCE WE WILL MESS WITH THAT VALUE.
	ROL.L #6,D4			;MULTIPLY SPRITE NUMBER BY $40 FOR TILE AND ATTRIB USE.
	
	MOVE.W D3,D2		;WE NO LONGER NEED D2 SO COPY THE SPRITE SIZE TO IT TO USE AS A LOOP COUNTER.
	SUBQ.W #1,D2		;SUBTRACT 1 TO FIX EXTRA TILE BUG
loop_CreateSprites:		;LOOP BEGINS HERE

	MOVE.W (A0)+,D7		;LOAD TILE ID NO. INTO D7
	MOVE.W D4,$3C0000	;WHERE TO WRITE THE TILE ID DATA (SPRITENUM*$40)
	MOVE.W D7,$3C0002	;WHAT DATA TO WRITE (THE TILE ID DATA)
	
	ADDQ.L #1,D4		;INCREMENT D4 BY 1 SINCE THAT'S WHERE PALETTE/ATTRIB DATA GOES.
	
	MOVE.W (A0)+,D5		;LOAD PALETTE DATA INTO D5
	ROL.L #8,D5			;SHIFT PALETTE DATA INTO TOP BYTE WHERE IT BELONGS
	MOVE.W (A0)+,D6		;LOAD ANIM/FLIP DATA INTO D6
	OR.W D6,D5			;MERGE ANIM/FLIP DATA WITH PALETTE DATA
	
	MOVE.W D4,$3C0000	;WHERE TO WRITE PALETTE DATA ((SPRITENUM*$40)+1)
	MOVE.W D5,$3C0002	;WHAT DATA TO WRITE (MERGED PALETTE/ANIM/FLIP DATA)
	
	ADDQ.L #1,D4		;INCREMENT D4 BY 1 TO POINT TO NEXT TILE'S TILE ID DESTINATION. (IF ANY)
	
	;NOW REPEAT FOR EACH TILE IN THE SPRITE.
	;BUG: NUMBER OF TILES EQUALS SPRITE HEIGHT +1, UNLESS SPRITE HEIGHT IS ZERO THEN NO SPRITE IS DRAWN.
	;WHETHER I USE DBRA OR DBEQ SEEMS TO MAKE NO DIFFERENCE.
	
	dbeq D2,loop_CreateSprites	;uses sprite size as a loop counter since other tiles only need
								;tile ID and attrib. data.
	Debug
	RTS
TestData:		
	;TILE 0
	
	DC.W $0FFF	;SHRINK FACTOR  WRITE TO $8000 + SPRITE NUMBER
	DC.W $C200	;Y POS			WRITE TO $8200 + SPRITE NUMBER
	DC.W $0001	;SPRITE HEIGHT	WRITE TO $8200 + SPRITE NUMBER (OR'D WITH Y POS)
	DC.W $0000	;CHAIN BIT		WRITE TO $8200 + SPRITE NUMBER (OR'D WITH Y POS)
	DC.W $5000	;X POS			WRITE TO $8400 + SPRITE NUMBER
	DC.W $2000	;TILE ID NO.	WRITE TO (SPRITE NUMBER*40)
	DC.W $0001	;PALETTE DATA	WRITE TO (SPRITE NUMBER*$40)+1
	DC.W $0004	;ANIM/FLIP		WRITE TO (SPRITE NUMBER*$40)+1 (OR'D WITH PALETTE)
	
	
TestData2:		
	;TILE 0

	DC.W $0FFF	;SHRINK FACTOR  WRITE TO $8000 + SPRITE NUMBER
	DC.W $C200	;Y POS			WRITE TO $8200 + SPRITE NUMBER
	DC.W $0005	;SPRITE HEIGHT	WRITE TO $8200 + SPRITE NUMBER (OR'D WITH Y POS)
	DC.W $0000	;CHAIN BIT		WRITE TO $8200 + SPRITE NUMBER (OR'D WITH Y POS)
	DC.W $5000	;X POS			WRITE TO $8400 + SPRITE NUMBER
	DC.W $2018	;TILE ID NO.	WRITE TO (SPRITE NUMBER*40)
	DC.W $0002	;PALETTE DATA	WRITE TO (SPRITE NUMBER*$40)+1
	DC.W $0000	;ANIM/FLIP		WRITE TO (SPRITE NUMBER*$40)+1 (OR'D WITH PALETTE)
	
	DC.W $2020,$0002,$0000		;TILE 1		ID, PAL, ANIM/FLIP
	DC.W $2028,$0002,$0000		;TILE 2
	DC.W $2030,$0002,$0000		;TILE 3
	DC.W $2038,$0002,$0000		;TILE 4
	DC.W $201D,$0002,$0000		;TILE 5
	DC.W $201E,$0002,$0000		;TILE 6
	DC.W $200D,$0002,$0000		;TILE 7
	DC.W $200D,$0001,$0000		;TILE 8
	DC.W $200D,$0001,$0000		;TILE 9
	DC.W $200D,$0001,$0000		;TILE 10
	DC.W $200D,$0001,$0000		;TILE 11
	DC.W $200D,$0001,$0000		;TILE 12
	DC.W $200D,$0001,$0000		;TILE 13
	DC.W $200D,$0001,$0000		;TILE 14
	DC.W $200D,$0001,$0000		;TILE 15
	DC.W $200D,$0001,$0000		;TILE 16
	DC.W $200D,$0001,$0000		;TILE 17
	DC.W $200D,$0001,$0000		;TILE 18
	DC.W $200D,$0001,$0000		;TILE 19
	DC.W $200D,$0001,$0000		;TILE 20
	DC.W $200D,$0001,$0000		;TILE 21
	DC.W $200D,$0001,$0000		;TILE 22
	DC.W $200D,$0001,$0000		;TILE 23
	DC.W $200D,$0001,$0000		;TILE 24
	DC.W $200D,$0001,$0000		;TILE 25
	DC.W $200D,$0001,$0000		;TILE 26
	DC.W $200D,$0001,$0000		;TILE 27
	DC.W $200D,$0001,$0000		;TILE 28
	EVEN
User avatar
Gilbert
Posts: 564
Joined: Sun Dec 12, 2010 10:27 pm
Location: Hong Kong
Contact:

Re: Neo Geo Tiles Covered Up?

Post by Gilbert »

puppydrum64 wrote: Mon Jun 07, 2021 4:51 pm EDIT: It works now if I make the tilemap start at an index lower than everything else. I read the wiki and couldn't find that info anywhere :oops:
I don't know much about Neo Geo, but as the system (almost) does not have any background layer, a "tile map" is just an array of sprites (I think I've read something about it being able to chain a number of sprites so you do not need to move each individual tile sprite one by one, which is sort of a remedy to the "no background" problem), so it makes sense just to change their sprite indices as most systems determine sprite priorities by their order.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Neo Geo Tiles Covered Up?

Post by puppydrum64 »

Gilbert wrote: Mon Jun 07, 2021 10:28 pm
puppydrum64 wrote: Mon Jun 07, 2021 4:51 pm EDIT: It works now if I make the tilemap start at an index lower than everything else. I read the wiki and couldn't find that info anywhere :oops:
I don't know much about Neo Geo, but as the system (almost) does not have any background layer, a "tile map" is just an array of sprites (I think I've read something about it being able to chain a number of sprites so you do not need to move each individual tile sprite one by one, which is sort of a remedy to the "no background" problem), so it makes sense just to change their sprite indices as most systems determine sprite priorities by their order.
You are correct, that's exactly how it works.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Neo Geo Tiles Covered Up?

Post by puppydrum64 »

I'm trying to improve the sprite drawing code by allowing passing of certain parameters such as the sprite we want to draw, the base sprite number, width, etc. This all works fine and dandy for sprites that are one tile wide. Once chaining gets involved it all breaks down. My code is a bit messy, I'm new to the 68000 and I'm used to 6502 which only has 3 registers to work with. Trying to keep track of 8 different registers and what's in them is very confusing, so I've done my best to use a LOT of comments to explain everything as best as I can.

Code: Select all

; PROBLEM: WE HAVE MORE PARAMETERS FOR CREATING SPRITE DATA THAN WE HAVE
; DATA REGISTERS ON THE 68000.

; POSSIBLE SOLUTIONS: TAKING A PAGE FROM CHIBIAKUMAS BOOK, WE USE
; A SIMILAR METHOD TO HOW KEITH SETS UP THE SEGA GENESIS VDP SETTINGS.
; ORGANIZE THE DATA REGS BETTER TO MAKE IT MORE READABLE.

	

	
	;USAGE OF REGS:
	;D0 = NUMBER OF SPRITES IN OBJECT
	;D1 = SPRITENUM, GETS PUSHED ONTO STACK THEN MODIFIED INTO SCB2+ OFFSET
	;D2 = SHRINK FACTOR, YPOS, XPOS. AFTER THE FIRST PART OF THE SUBROUTINE THIS BECOMES A LOOP COUNTER (WORKING SPRITE HEIGHT)
	;D3 = SPRITE HEIGHT
	;D4 = SCB1 OFFSET
	;D5 = PALETTE DATA		;NOT NEEDED UNTIL SCB1 LOOP
	;D6 = ANIM/FLIP DATA	;NOT NEEDED UNTIL SCB1 LOOP
	;D7 = TILE ID NO.		;NOT NEEDED UNTIL SCB1 LOOP
	
	;A0 = SOURCE OF SPRITE DATA.
	
	
	; PREP (DO THIS PRIOR TO THE CALL)
	; LEA TestData,A0
	; MOVE.L SPRITENUM,D1
	; MOVE.L SPRITE_WIDTH,D0
	
	
CreateSprites:
	MOVE.W (A0)+,D2		;LOAD SHRINK FACTOR INTO D2
	MOVE.L D2,-(SP)
		MOVE.L D1,-(SP)
			ADD.W #$8000,D1		;ADD $8000 TO D1 TO GET DESTINATION FOR SHRINK FACTOR
			

			
			MOVE.W D1,$3C0000	;WHERE TO WRITE DATA ($8000+SPRITENUM)
			MOVE.W D2,$3C0002	;WHAT DATA TO WRITE	 (SHRINK FACTOR)
			
			ADD.W #$200,D1		;ADD $200 TO D1 TO GET DESTINATION FOR Y POS
			MOVE.W (A0)+,D2		;LOAD Y POS INTO D2

			MOVE.W (A0)+,D3		;LOAD SPRITE HEIGHT DATA INTO D3
			OR.W D3,D2			;COMBINE SPRITE HEIGHT WITH Y POS.	;DO NOT RE-USE D3, I WILL CHECK IT LATER
			MOVE.W (A0)+,D0		;LOAD CHAIN BIT INTO D0
			OR.W D0,D2			;COMBINE CHAIN BIT WITH Y POS.		;DO NOT RE-USE D0, I WILL CHECK IT LATER
			
			MOVE.W D1,$3C0000	;WHERE TO WRITE DATA ($8200+SPRITENUM)
			MOVE.W D2,$3C0002	;WHAT DATA TO WRITE
			
			ADD.W #$200,D1		;ADD $200 TO D1 TO GET DESTINATION FOR X POS
			
			MOVE.W (A0)+,D2		;LOAD X POS INTO D2
			
			MOVE.W D1,$3C0000	;WHERE TO WRITE DATA ($8400+SPRITENUM)
			MOVE.W D2,$3C0002	;WHAT DATA TO WRITE

		;WE ARE DONE WITH SCB2 THRU SCB4 FOR THE ANCHOR SPRITE.
		;WE NO LONGER NEED 
;HANDLE CHAINED SPRITES.
			MOVE.L D0,D5		;BACKUP SPRITE WIDTH SO WE CAN USE IT AS A LOOP COUNTER.
		MOVE.L (SP)+,D1			;POP D1 TO RESTORE ORIGINAL SPRITENUM.
	MOVE.L (SP)+,D2				;POP D2 TO RESTORE SHRINK FACTOR. WE'LL NEED IT FOR THE FIRST TILE OF THE CHAINED SPRITES.
	MOVE.L D1,D6				;COPY SPRITENUM TO D6 SINCE WE'LL BE USING IT AS WE INCREMENT THROUGH THE CHAINED SPRITES.
	MOVE.L D1,-(SP)				;PUSH D1 ONTO STACK AGAIN TO PRESERVE ORIGINAL SPRITENUM.
		
		cmp.w #1,d5					;if there is only one sprite in the object we don't have any chained sprites.
		BEQ skipchainedsprites
		
		;DATA REG USAGE:
		;D0 = PRESERVED SPRITE WIDTH (WE WON'T USE THIS IN THIS LOOP)
		;D1 = PRESERVED ANCHOR SPRITENUM (WE WON'T USE THIS IN THIS LOOP)
		;D2 = SHRINK FACTOR OF CHAINED SPRITES.
		;D3 = SPRITE HEIGHT
		;D4 = UNUSED
		;D5 = SPRITE WIDTH
		;D6 = CURRENT CHAINED SPRITE SPRITENUM
		;D7 = UNUSED
		
		
loop_ChainedSprites:
		ADDQ.L #1,D6			;INCREMENT WORKING SPRITENUM SINCE THE CHAINED SPRITE MUST BE ONE AFTER THE PREVIOUS.
		MOVE.L D6,-(SP)			;PUSH D6 ONTO STACK SINCE WE'RE ABOUT TO FIDDLE WITH IT.
			ADD.W $8000,D6			;ADD $8000 TO GET SCB2 OFFSET
			
			MOVE.W D6,$3C0000		;VRAMADDR = SCB2 (SHRINK FACTOR DESTINATION)
			MOVE.W D2,$3C0002		;SHRINK FACTOR (IS CONSTANT AMONG ALL CHAINED SPRITES.)
			
			ADD.W $0200,D6			;ADJUST D6 TO SCB3 OFFSET.
			
			MOVE.W $0040,D4			;STORE CHAIN BIT IN D4. CHAIN BIT OVERRIDES ALL OTHER YPOS DATA.
			MOVE.W D6,$3C0000		;VRAMADDR = SCB3 (CHAIN BIT DESTINATION)
			MOVE.W D4,$3C0002		;THIS IS A CHAINED SPRITE. YPOS IS IGNORED.
			
			ADD.W $0200,D6
			MOVE.W D6,$3C0000		;VRAMADDR = SCB4 (XPOS)
			MOVE.W D4,$3C0000		;X POS IS IGNORED SO IT DOESN'T MATTER WHAT WE WRITE HERE.
		MOVE.L (SP)+,D6			;POP D6 OFF OF STACK. IT IS RESET FOR THE NEXT CHAINED SPRITE.
		DBEQ D5,loop_ChainedSprites
		
		
		
skipchainedsprites:		
		
	;NOW ALL WE HAVE LEFT IS SCB1 DATA (TILE ID + ATTRIBS.)
	;WE CAN CLEAR ALL DATA REGS NOW EXCEPT D0,D1,D3. THIS WILL SIMPLIFY THE DEBUG PROCESS AT THE COST OF POTENTIALLY WASTED CPU CYCLES AND ROM SPACE.
	
		CLR.L D2
		CLR.L D4
		CLR.L D5
		CLR.L D6
		CLR.L D7
	
	MOVE.L (SP)+,D1		;POP D1 TO RESTORE ORIGINAL SPRITENUM.
	
	MOVE.W D1,D4		;COPY D1 TO D4 SINCE WE WILL MESS WITH THAT VALUE.
	ROL.L #6,D4			;MULTIPLY SPRITE NUMBER BY $40 FOR TILE AND ATTRIB USE.
	
	MOVE.W D3,D2		;WE NO LONGER NEED D2 SO COPY THE SPRITE SIZE TO IT TO USE AS A LOOP COUNTER.
	SUBQ.W #1,D2		;SUBTRACT 1 TO FIX EXTRA TILE BUG
	
	MOVE.W D0,D5
	
	;DATA REG USAGE:
	;D0 = PRESERVED SPRITE WIDTH 
	;D1 = PRESERVED ANCHOR SPRITENUM
	;D2 = LOOP COUNTER FOR SPRITE HEIGHT
	;D3 = PRESERVED SPRITE HEIGHT	(NOT USED IN THIS LOOP)
	;D4 = SCB1 OFFSET BASED ON ANCHOR SPRITENUM.
	;D5 = LOOP COUNTER FOR SPRITE WIDTH
	;D6 = ANIM/FLIP DATA
	;D7 = TILE ID, THEN PALETTE DATA.
	
	
loop_SCB1:				;BUG: WORKS FOR ANCHOR SPRITE BUT NOT FOR CHAINED SPRITES.

	MOVE.W (A0)+,D7		;LOAD TILE ID NO. INTO D7
	; pushall
	; Debug
	; popall
	MOVE.W D4,$3C0000	;WHERE TO WRITE THE TILE ID DATA (SPRITENUM*$40)
	MOVE.W D7,$3C0002	;WHAT DATA TO WRITE (THE TILE ID DATA)
	
	ADDQ.L #1,D4		;INCREMENT D4 BY 1 SINCE THAT'S WHERE PALETTE/ATTRIB DATA GOES.
	
	MOVE.W (A0)+,D7		;LOAD PALETTE DATA INTO D7
	ROL.L #8,D7			;SHIFT PALETTE DATA INTO TOP BYTE WHERE IT BELONGS
	MOVE.W (A0)+,D6		;LOAD ANIM/FLIP DATA INTO D6
	OR.W D6,D7			;MERGE ANIM/FLIP DATA WITH PALETTE DATA
	
	MOVE.W D4,$3C0000	;WHERE TO WRITE PALETTE DATA ((SPRITENUM*$40)+1)
	MOVE.W D7,$3C0002	;WHAT DATA TO WRITE (MERGED PALETTE/ANIM/FLIP DATA)
	
	ADDQ.L #1,D4		;INCREMENT D4 BY 1 TO POINT TO NEXT TILE'S TILE ID DESTINATION. (IF ANY)
	
	;NOW REPEAT FOR EACH TILE IN THE SPRITE.

	
	dbeq D2,loop_SCB1	;uses sprite size as a loop counter
	
	;NOW WE REPEAT FOR EACH SPRITE IN THE OBJECT.
	;FIRST, RESET D2.
	
	
	;SOURCE OF THE BUG IS SOMEWHERE IN HERE.
	;BUG: DOESN'T ACTUALLY DRAW THE CHAINED SPRITES, JUST THE ANCHOR.
	;ALSO SOMETIMES DRAWING MORE THAN 2 SPRITES CAUSES NONE OF THEM TO SHOW.
	
	MOVE.L D3,D2		;RESTORES D2 TO EQUAL ORIGINAL SPRITE HEIGHT.
	SUBQ.W #1,D2		;SUBTRACT 1 TO FIX EXTRA TILE BUG
	
	; NEXT, COUNT HOW MANY SPRITES IN THE OBJECT WE HAVE FINISHED. EACH TIME WE GET HERE IS ONE SPRITE FINISHED.
	; THEN ADJUST OUR SCB1 OFFSET ACCORDINGLY. 
	
	AND.W #%1111111111000000,D4	;RESET D4 TO THE NEAREST MULTIPLE OF $40
	ADD.W #$40,D4				;ADD $40 TO REACH NEXT SPRITE ADDR

	DBEQ d5,loop_SCB1			;MY GUESS IS THAT I'M LOOPING OUT OF BOUNDS SOMEHOW.
	RTS
TestData:		
	;TILE 0
	
	DC.W $0FFF	;SHRINK FACTOR  WRITE TO $8000 + SPRITE NUMBER
	DC.W $C200	;Y POS			WRITE TO $8200 + SPRITE NUMBER
	DC.W $0001	;SPRITE HEIGHT	WRITE TO $8200 + SPRITE NUMBER (OR'D WITH Y POS)
	DC.W $0000	;CHAIN BIT		WRITE TO $8200 + SPRITE NUMBER (OR'D WITH Y POS)
	DC.W $5000	;X POS			WRITE TO $8400 + SPRITE NUMBER
	DC.W $2000	;TILE ID NO.	WRITE TO (SPRITE NUMBER*40)
	DC.W $0001	;PALETTE DATA	WRITE TO (SPRITE NUMBER*$40)+1
	DC.W $0004	;ANIM/FLIP		WRITE TO (SPRITE NUMBER*$40)+1 (OR'D WITH PALETTE)
	
	
TestData2:		
	;TILE 0

	DC.W $0FFF	;SHRINK FACTOR  WRITE TO $8000 + SPRITE NUMBER
	DC.W $C200	;Y POS			WRITE TO $8200 + SPRITE NUMBER
	DC.W $0005	;SPRITE HEIGHT	WRITE TO $8200 + SPRITE NUMBER (OR'D WITH Y POS)
	DC.W $0000	;CHAIN BIT		WRITE TO $8200 + SPRITE NUMBER (OR'D WITH Y POS)
	DC.W $5000	;X POS			WRITE TO $8400 + SPRITE NUMBER
	DC.W $2018	;TILE ID NO.	WRITE TO (SPRITE NUMBER*40)
	DC.W $0002	;PALETTE DATA	WRITE TO (SPRITE NUMBER*$40)+1
	DC.W $0000	;ANIM/FLIP		WRITE TO (SPRITE NUMBER*$40)+1 (OR'D WITH PALETTE)
	DC.W $2020,$0002,$0000		;TILE 1		ID, PAL, ANIM/FLIP
	DC.W $2028,$0002,$0000		;TILE 2
	DC.W $2030,$0002,$0000		;TILE 3
	DC.W $2038,$0002,$0000		;TILE 4
	DC.W $2019,$0002,$0000		;TILE 5
	DC.W $2021,$0002,$0000		;TILE 6
	DC.W $2029,$0002,$0000		;TILE 7
	DC.W $2031,$0001,$0000		;TILE 8
	DC.W $2039,$0001,$0000		;TILE 9
	DC.W $2031,$0001,$0000		;TILE 10
	DC.W $2039,$0001,$0000		;TILE 11
	DC.W $200D,$0001,$0000		;TILE 12
	DC.W $200D,$0001,$0000		;TILE 13
	DC.W $200D,$0001,$0000		;TILE 14
	DC.W $200D,$0001,$0000		;TILE 15
	DC.W $200D,$0001,$0000		;TILE 16
	DC.W $200D,$0001,$0000		;TILE 17
	DC.W $200D,$0001,$0000		;TILE 18
	DC.W $200D,$0001,$0000		;TILE 19
	DC.W $200D,$0001,$0000		;TILE 20
	DC.W $200D,$0001,$0000		;TILE 21
	DC.W $200D,$0001,$0000		;TILE 22
	DC.W $200D,$0001,$0000		;TILE 23
	DC.W $200D,$0001,$0000		;TILE 24
	DC.W $200D,$0001,$0000		;TILE 25
	DC.W $200D,$0001,$0000		;TILE 26
	DC.W $200D,$0001,$0000		;TILE 27
	DC.W $200D,$0001,$0000		;TILE 28

TestData3:
	DC.W $0FFF
	DC.W $F400
	DC.W $0004
	DC.W $0400
	DC.W $2004,$0001,$0000
	DC.W $2005,$0001,$0000
	DC.W $2006,$0001,$0000
	DC.W $2007,$0001,$0000
	DC.W $2008,$0001,$0000
	DC.W $2009,$0001,$0000
	DC.W $200A,$0001,$0000
	DC.W $200B,$0001,$0000
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Neo Geo Tiles Covered Up?

Post by puppydrum64 »

Code: Select all

;INPUT:
;D0 = BASE SPRITENUM
;D2 = NUMBER OF SPRITES PER OBJECT
;D4 = NUMBER OF TILES PER SPRITE
CreateSprite:
	MOVE.L D0,D1				;BACKUP SPRITENUM
	MOVE.L D2,D3				;BACKUP SPRITES PER OBJECT
	ADD.W #$8000,D1				;ADD $8000 TO GET SCB2 OFFSET
	MOVE.W #$200,$3C0004		;SET VRAM TO INC BY $200
	MOVE.W D1,$3C0000			;SET VRAMADDR TO SCB2
	MOVE.L A0,-(SP)				;BACKUP EFFECTIVE ADDRESS
		MOVE.W (A0)+,$3C0002	;STORE SHRINK FACTOR
		MOVE.W (A0)+,$3C0002	;STORE Y POS AND SPRITE HEIGHT
		MOVE.W (A0)+,$3C0002	;STORE X POS
	MOVE.L (SP)+,A0				;RESTORE EFFECTIVE ADDRESS
	SUB.W #$8000,D1				;RESTORE ORIGINAL SPRITENUM
	SUBQ.L #1,D3				;WE'VE SET UP THE ANCHOR SPRITE SO ADJUST OUR LOOP COUNTER.
LOOP_CHAIN_SCB2:
	ADD.W #$8001,D1				;ADD $8001 TO GET SCB2 ADDR OF NEXT SPRITENUM
	MOVE.W D1,$3C0000			;SET VRAMADDR TO SCB2 OFFSET OF NEXT SPRITENUM
	MOVE.W (A0),$3C0002			;LOAD JUST THE SHRINK FACTOR (DO NOT INCREMENT A0)
	MOVE.W #$0040,$3C0002		;STORE CHAIN BIT IN SCB3
	MOVE.W #$0000,$3C0002		;DUMMY WRITE TO SCB4
	SUB.W #$8000,D1				;GET WORKING SPRITENUM BACK
	DBEQ D3,LOOP_CHAIN_SCB2		;REPEAT UNTIL ALL SPRITES ARE SETUP

	MOVE.W #1,$3C0004			;RETURN VRAM INC TO 1

	MOVE.L D0,D1				;BACKUP SPRITENUM
	MOVE.L D2,D3				;BACKUP SPRITES PER OBJECT
	MOVE.L D4,D5				;BACKUP TILES PER SPRITE
	ROL.L #6,D1					;MULTIPLY SPRITENUM BY 64 TO GET SCB1 ADDR.
	MOVE.L D1,D6				;BACKUP SCB1 ADDRESS
	
LOOP_SPRITE:
	MOVE.W D6,$3C0000			;SET VRAMADDR TO 64*SPRITENUM
LOOP_TILE:
	MOVE.W (A1)+,$3C0002		;SEND TILE DATA TO SCB1
	MOVE.W (A2)+,$3C0002		;SEND PALETTE DATA TO SCB1
	DBEQ D5,LOOP_TILE			;REPEAT UNTIL ALL TILES IN THIS SPRITE ARE DONE.
	
	MOVE.L D4,D5				;RESET LOOP COUNTER
	
	;BUG: EACH CHAINED SPRITE IS OFFSET BY ONE TILE MORE THAN THE LAST. THIS RESULTS IN TILES GETTING SKIPPED.
	;THIS IS SO CLOSE TO WORKING! JUST A LITTLE MORE EFFORT AND IT WILL WORK AT LAST!
	
	ADD.W #$0042,D6				;ADD 64 TO GET SCB1 OFFSET FOR NEXT SPRITENUM.
	DBEQ D3,LOOP_SPRITE			;REPEAT UNTIL ALL SPRITES IN THE OBJECT ARE DONE.
	
	rts


TestData00:
	DC.W $0FFF,$F404,$0400
TestData01:
	DC.W $2004,$2005,$2006,$2007
	DC.W $2008,$2009,$200A,$200B
	DC.W $2004,$2005,$2006,$2007
	DC.W $2008,$2009,$200A,$200B
	DC.W $2004,$2005,$2006,$2007
	DC.W $2008,$2009,$200A,$200B
	DC.W $2004,$2005,$2006,$2007
	DC.W $2008,$2009,$200A,$200B
TestData02:
	DC.W $0100,$0100,$0100,$0100
	DC.W $0100,$0100,$0100,$0100
	DC.W $0100,$0100,$0100,$0100
	DC.W $0100,$0100,$0100,$0100
This improved version almost works but there is a sort of "compounding" offset of tiles getting skipped. If I set D6 to increment by $42 rather than $40 it's a little easier to see what's happening:
tile_stairstep_neogeo.PNG
tile_stairstep_neogeo.PNG (10.83 KiB) Viewed 4882 times
I still don't see the flaw in my loop logic however.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Neo Geo Tiles Covered Up?

Post by puppydrum64 »

I fixed it now, just had to subtract 1 from the number of tiles per sprite. This code has been tested with sprites of many shapes and sizes, and works for all of them. Feel free to use it if you wish. Giving credit is appreciated but not needed.

Code: Select all

;INPUT:
;A0 = SHRINK,Y,X
;A1 = TILE ID CHART
;A2 = PALETTE/ANIM/FLIP

;D0 = BASE SPRITENUM
;D2 = NUMBER OF SPRITES PER OBJECT
;D4 = NUMBER OF TILES PER SPRITE
CreateSprite:
	MOVE.L D0,D1				;BACKUP SPRITENUM
	MOVE.L D2,D3				;BACKUP SPRITES PER OBJECT
	
	ADD.W #$8000,D1				;ADD $8000 TO GET SCB2 OFFSET
	MOVE.W #$200,$3C0004		;SET VRAM TO INC BY $200
	MOVE.W D1,$3C0000			;SET VRAMADDR TO SCB2
	
	MOVE.L A0,-(SP)				;BACKUP EFFECTIVE ADDRESS
		MOVE.W (A0)+,$3C0002	;STORE SHRINK FACTOR
		
		MOVE.W (A0)+,D7			;GET Y POS
		OR.L D4,D7				;MIX IN SPRITE HEIGHT DATA
		MOVE.W D7,$3C0002		;STORE Y POS AND SPRITE HEIGHT
		
		MOVE.W (A0)+,$3C0002	;STORE X POS
	MOVE.L (SP)+,A0				;RESTORE EFFECTIVE ADDRESS
	
	SUB.W #$8000,D1				;RESTORE ORIGINAL SPRITENUM
	SUBQ.L #1,D3				;WE'VE SET UP THE ANCHOR SPRITE SO ADJUST OUR LOOP COUNTER.
	
LOOP_CHAIN_SCB2:
	ADD.W #$8001,D1				;ADD $8001 TO GET SCB2 ADDR OF NEXT SPRITENUM
	MOVE.W D1,$3C0000			;SET VRAMADDR TO SCB2 OFFSET OF NEXT SPRITENUM
	MOVE.W (A0),$3C0002			;LOAD JUST THE SHRINK FACTOR (DO NOT INCREMENT A0)
	MOVE.W #$0040,$3C0002		;STORE CHAIN BIT IN SCB3
	MOVE.W #$0000,$3C0002		;DUMMY WRITE TO SCB4
	SUB.W #$8000,D1				;GET WORKING SPRITENUM BACK
	DBEQ D3,LOOP_CHAIN_SCB2		;REPEAT UNTIL ALL SPRITES ARE SETUP

	MOVE.W #1,$3C0004			;RETURN VRAM INC TO 1

	MOVE.L D0,D1				;RESTORE SPRITENUM
	MOVE.L D2,D3				;RESTORE SPRITES PER OBJECT
	MOVE.L D4,D5				;BACKUP TILES PER SPRITE
	ROL.L #6,D1					;MULTIPLY SPRITENUM BY 64 TO GET SCB1 ADDR.
	MOVE.L D1,D6				;BACKUP SCB1 ADDRESS
	SUBQ.L #1,D5				;NEEDED TO PREVENT SKIPPING TILES
	

LOOP_SPRITE:
	MOVE.W D6,$3C0000			;SET VRAMADDR TO 64*SPRITENUM
LOOP_TILE:
	MOVE.W (A1)+,$3C0002		;SEND TILE DATA TO SCB1
	MOVE.W (A2)+,$3C0002		;SEND PALETTE DATA TO SCB1
	DBEQ D5,LOOP_TILE			;REPEAT UNTIL ALL TILES IN THIS SPRITE ARE DONE.
	
	MOVE.L D4,D5				;RESET LOOP COUNTER
	SUBQ.L #1,D5				;NEEDED TO PREVENT SKIPPING TILES
	
	
	MOVE.W D6,$3C0000
	ADD.W #$0040,D6				;ADD 64 TO GET SCB1 OFFSET FOR NEXT SPRITENUM.

	DBEQ D3,LOOP_SPRITE			;REPEAT UNTIL ALL SPRITES IN THE OBJECT ARE DONE.
	
	rts
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Neo Geo Tiles Covered Up?

Post by puppydrum64 »

Any idea about what causes these animation glitches? I see them a lot even on sprites that aren't supposed to be animated. I think it has something to do with overlapping sprites (even though their sprite numbers don't conflict with each other, I made sure of that)
NeoOne
Posts: 3
Joined: Sat Jul 22, 2023 8:52 am

Re: Neo Geo Tiles Covered Up?

Post by NeoOne »

puppydrum64 wrote: Mon Jun 07, 2021 4:51 pm EDIT: It works now if I make the tilemap start at an index lower than everything else. I read the wiki and couldn't find that info anywhere :oops:

By itself, the tilemap works perfectly. There's just one major problem: it gets drawn over top of any sprite EXCEPT sprite 0. Scaling the shrink factor of the tilemap reveals the hidden sprites underneath. Sprite 0 gets drawn on top of everything regardless.
I saw this post when I was searching for Neo Geo stuff last night and wanted to say that you aren't meant to use sprite 0! It's used by the graphics system to pad out the display list for each line of the screen. The Neo Geo can display a maximum of 96 sprites per line and if you use less than that - it fills the spaces in the display list with repeated sprite 0's. Sprite 0 should always be set to transparent for this reason.

Also as you found out : the sprites are numbered by priority so sprites with a lower number will always be drawn behind sprites with a higher number.

Program looks good though! Wish I could code well in 68000
User avatar
dink
Posts: 157
Joined: Sun Jan 12, 2020 8:42 pm

Re: Neo Geo Tiles Covered Up?

Post by dink »

Howdy,
A bit off topic, but regarding sprite 0 and a (non)bug in a game on Neo Geo CD: Shinsetsu Samurai Spirits: Bushidō Retsuden... which is quite interesting

So, the game uses sprite 0 to display the message window, which gets drawn over by the scene. The only reason you see this is because it gets redrawn by the hw again at the end of the sprite list.

So, here's 2 images - first: game as normal, second: spritelist artificially filled up so that sprite 0 doesn't get displayed at the end of the list.

best regards,
- dink
Attachments
ssrpg_normal.png
ssrpg_normal.png (17.74 KiB) Viewed 2205 times
ssrpg_no_end_sprite0.png
ssrpg_no_end_sprite0.png (18.03 KiB) Viewed 2205 times
NeoOne
Posts: 3
Joined: Sat Jul 22, 2023 8:52 am

Re: Neo Geo Tiles Covered Up?

Post by NeoOne »

dink wrote: Sun Jul 23, 2023 6:33 am Howdy,
A bit off topic, but regarding sprite 0 and a (non)bug in a game on Neo Geo CD: Shinsetsu Samurai Spirits: Bushidō Retsuden... which is quite interesting

So, the game uses sprite 0 to display the message window, which gets drawn over by the scene. The only reason you see this is because it gets redrawn by the hw again at the end of the sprite list.

So, here's 2 images - first: game as normal, second: spritelist artificially filled up so that sprite 0 doesn't get displayed at the end of the list.

best regards,
- dink
That's interesting. I wonder why they did that? Maybe if you set the "sticky" bit of sprite 1 it joins to sprite 0 and you can use that to change sprite priority and push the message window to the front? Normally you can't change sprite priority on the Neo Geo and you have to "copy" one sprite to another if you want to do that
Post Reply