Bug when I display two 32x32 sprites

Discussion of hardware and software development for Super NES and Super Famicom.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
freeman.pixelz
Posts: 4
Joined: Wed Dec 30, 2020 1:52 pm

Bug when I display two 32x32 sprites

Post by freeman.pixelz » Fri Jan 01, 2021 4:26 am

Hello,

I started to read tutorials here:
https://wiki.superfamicom.org/

I have an issue when I try to display 2 sprites on the screen. How can I set a different position to the second sprite?

This is the source code:
https://www.dropbox.com/s/n7tbnwk7bgcr8 ... e.zip?dl=0

This is the main code:

Code: Select all

Start:
    InitSNES    ; Clear registers, etc.

    rep #$10
    sep #$20

    lda #%00001001
    sta $2105

    ; Blue Background
    stz $2121
    lda #$40
    sta $2122
    sta $2122
    
    ; Load Palette for our tiles
    LoadPalette PaletteConsole, 128, 16     ; Sprite Palettes start at color 128
    LoadPalette PaletteBike, 128, 16     ; Sprite Palettes start at color 128

    ; Load Tile data to VRAM
    LoadBlockToVRAM SpriteConsole, $0000, $0800 ; First sprite
    LoadBlockToVRAM SpriteBike, $0100, $0800 ; Second sprite

    jsr SpriteInit
    
    ; First Sprite Position
    lda #($80-16)
    sta $0000
    lda #(224/2 - 16)
    sta $0001
    stz $0002
    lda #%01110000
    sta $0003
    ;lda #%11000000
    ;sta $0100
    lda #%01010100
    sta $0200
    
    ; Second Sprite Position
    ; ???
    
    ; Setup Video modes and other stuff, then turn on the screen
    jsr SetupVideo

    lda #$80
    sta $4200       ; Enable NMI


Infinity:
    Stall
    jmp Infinity    ; bwa hahahahaha
Screenshot:
https://ibb.co/TbjQZ8Z

Oziphantom
Posts: 1077
Joined: Tue Feb 07, 2017 2:03 am

Re: Bug when I display two 32x32 sprites

Post by Oziphantom » Fri Jan 01, 2021 4:53 am

LoadBlockToVRAM SpriteConsole, $0000, $0800 ; First sprite
LoadBlockToVRAM SpriteBike, $0100, $0800 ; Second sprite

so lets look at what these functions do as a graph

Code: Select all

 000 100 200 300 400 500 600 700 800 900 A00
|   |   |   |   |   |   |   |   |   |   |
*********************************         first load
    *********************************     second load
    
    
how sprites are stored in VRAM for 32x32
AAAABBBBCCCCDDDD
AAAABBBBCCCCDDDD
AAAABBBBCCCCDDDD
AAAABBBBCCCCDDDD
EEEEFFFFGGGGHHHH
EEEEFFFFGGGGHHHH
EEEEFFFFGGGGHHHH
EEEEFFFFGGGGHHHH
so you can't load in two 32x32 sprites with a single block DMA as you are doing. As in when you load the second sprite B it will overwrite all the AAAA parts from the 2nd line onewards, which is what you are seeing. Either combine both sprites into a single block in tools, or you will need to do 4 DMAs at specific offsets to copy in just the sprite data.

freeman.pixelz
Posts: 4
Joined: Wed Dec 30, 2020 1:52 pm

Re: Bug when I display two 32x32 sprites

Post by freeman.pixelz » Fri Jan 01, 2021 6:40 am

Thank you. So I forgot to take the first sprite size in consideration. Is this code correct?

Code: Select all

; Load Tile data to VRAM
    LoadBlockToVRAM SpriteConsole, $0000, $0800 ; First sprite
    LoadBlockToVRAM SpriteBike, $0800, $0800 ; Second sprite
What about the second sprite position? How can I set a position to the second sprite?

freeman.pixelz
Posts: 4
Joined: Wed Dec 30, 2020 1:52 pm

Re: Bug when I display two 32x32 sprites

Post by freeman.pixelz » Fri Jan 01, 2021 7:18 am

I tried this but the second sprite is not displayed:

Code: Select all

;============================================================================
; Includes
;============================================================================

;== Include MemoryMap, Vector Table, and HeaderInfo ==
.INCLUDE "header.inc"

;== Include SNES Initialization routines ==
.INCLUDE "init.inc"
.INCLUDE "LoadGraphics.asm"

.define SpriteConsoleAddress $0000
.define SpriteBikeAddress $0800

;== EQUates ==
.EQU PalNum $0000       ; Use some RAM

;============================================================================
; Main Code
;============================================================================

.MACRO Stall
    .REPT 3
        WAI
    .ENDR
.ENDM

.BANK 0 SLOT 0
.ORG 0
.SECTION "MainCode"

Start:
    InitSNES    ; Clear registers, etc.

    rep #$10
    sep #$20

    lda #%00001001
    sta $2105

    ; Blue Background
    stz $2121
    lda #$40
    sta $2122
    sta $2122
    
    ; Load Palette for our tiles
    LoadPalette PaletteConsole, 128, 16     ; Sprite Palettes start at color 128
    LoadPalette PaletteBike, 128, 16     ; Sprite Palettes start at color 128

    ; Load Tile data to VRAM
    LoadBlockToVRAM SpriteConsole, SpriteConsoleAddress, $0800 ; First sprite
    LoadBlockToVRAM SpriteBike, SpriteBikeAddress, $0800 ; Second sprite

    jsr SpriteInit
    
    ; First Sprite Position
    lda #($80-16)
    sta SpriteConsoleAddress+$0000
    lda #(224/2 - 16)
    sta SpriteConsoleAddress+$0001
    stz SpriteConsoleAddress+$0002
    lda #%01110000
    sta SpriteConsoleAddress+$0003
    ;lda #%11000000
    ;sta $0100
    lda #%01010100
    sta SpriteConsoleAddress+$0200
    
    ; Second Sprite Position
    lda #($80-16)
    sta SpriteBikeAddress+$0000
    lda #(76/2 - 16)
    sta SpriteBikeAddress+$0001
    stz SpriteBikeAddress+$0002
    lda #%01110000
    sta SpriteBikeAddress+$0003
    lda #%01010100
    sta SpriteBikeAddress+$0200
    
    ; Setup Video modes and other stuff, then turn on the screen
    jsr SetupVideo

    lda #$80
    sta $4200       ; Enable NMI


Infinity:
    jmp Infinity    ; bwa hahahahaha

User avatar
dougeff
Posts: 2817
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Bug when I display two 32x32 sprites

Post by dougeff » Fri Jan 01, 2021 11:37 am

SpriteConsoleAddress and SpriteBikeAddress are PPU address, not OAM (sprite memory) addresses.

I don't see any code (like s DMA) to send anything to the OAM memory.

Typically, you would set aside a 544 byte ($220) area in the CPU RAM as a buffer and then copy it all to the OAM with a DMA.
Last edited by dougeff on Sat Jan 02, 2021 9:21 am, edited 1 time in total.
nesdoug.com -- blog/tutorial on programming for the NES

User avatar
dougeff
Posts: 2817
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Bug when I display two 32x32 sprites

Post by dougeff » Fri Jan 01, 2021 11:53 am

So the OAM is split into a low table (512 bytes) and a high table (32 bytes).

low table = 4 bytes per Sprite
x, y, tile #, attributes

high table = 2 bits per Sprite
sx (size, x 9th bit)

If you have the first Sprite's tiles at $0000 and the 2nd Sprite's tiles at $800... it is $20 bytes per 4bpp sprite tile, so the tile number for the 2nd sprites should be $800/$20 = $40.

my code for transferring from OAM BUFFER to the OAM is like this (with A in 8 bit and XY in 16 bit mode)

ldx #$0000
stx oam_addr_L ;$2102 (and 2103)

stz $4300 ; transfer mode 0 = 1 register write once
lda #4 ;$2104 oam data
sta $4301 ; destination, oam data
ldx #.loword(OAM_BUFFER)
stx $4302 ; source
lda #^OAM_BUFFER
sta $4304 ; bank
ldx #544
stx $4305 ; length
lda #1
sta $420b ; start dma, channel 0

...

If you want to skip the DMA, you can transfer the bytes directly to the OAM DATA register, first set an address (with A in 8 bit and XY in 16 bit)

ldx #$0000
stx $2102

then send 1 byte at a time

lda #sprite1.x
sta $2104
lda #sprite1.y
sta $2104
lda #sprite1.tile
sta $2104
etc...

then the high table, set address

ldx #$0200
stx $2102
lda #sprites1234.high_table_bits
sta $2104

but I'm not 100% sure this works. haven't tested it personally.
nesdoug.com -- blog/tutorial on programming for the NES

freeman.pixelz
Posts: 4
Joined: Wed Dec 30, 2020 1:52 pm

Re: Bug when I display two 32x32 sprites

Post by freeman.pixelz » Fri Jan 01, 2021 12:38 pm

Actually this is the code of SetupVideo, the first sprite is transferred to OAM. I must do the same for the second sprite then.

Code: Select all

SetupVideo:
    php
    
    rep #$10
    sep #$20
    
    stz $2102
    stz $2103
    
    ;*********transfer sprite data

    stz $2102        ; set OAM address to 0
    stz $2103

    LDY #$0400
    STY $4300        ; CPU -> PPU, auto increment, write 1 reg, $2104 (OAM Write)
    stz $4302
    stz $4303        ; source offset
    LDY #$0220
    STY $4305        ; number of bytes to transfer
    LDA #$7E
    STA $4304        ; bank address = $7E  (work RAM)
    LDA #$01
    STA $420B        ;start DMA transfer
    
    lda #%10100000
    sta $2101

    lda #%00010000            ; Enable BG1
    sta $212C
    
    lda #$0F
    sta $2100           ; Turn on screen, full Brightness

    plp
    rts

User avatar
dougeff
Posts: 2817
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Bug when I display two 32x32 sprites

Post by dougeff » Fri Jan 01, 2021 1:33 pm

LDY #$0220 ;size of DMA transfer
STY $4305

This is copying all 128 sprites.

stz $4302
stz $4303

from $0000 RAM, using that as the OAM Buffer.

So, you just need to write your sprite variables to 0000-0007, then call the DMA code.

JSR SetupVideo

(poorly named subroutine, should be called SpriteDMA or something).
nesdoug.com -- blog/tutorial on programming for the NES

Post Reply