Language…
23 users online: Aclais,  Ahrion, Batata Douce, crm0622,  Eden_, Ekimnoid, Gamet2004, Golden Yoshi, Hidincuzimsmokin, koffe190,  MarioFanGamer, masl, Mischievous Marc, neidoodle, Rauf, RZRider, Scags, schema_tuna, shaoshao, sinseiga, StarWolf3000, sugarfish456, TheXander - Guests: 263 - Bots: 261
Users: 64,795 (2,376 active)
Latest user: mathew

Graphics routine coding question.

I apologize in advance this is a lot of reading.

I am reading MarioFanGamer's sprite coding tutorial and simplifying it for my own comprehension. I have run into a confusing part of the Graphics routine coding which talks about OAM tile size and $0460,y

"Y: OAM tile size. Usually, you don't need to store to $0460,y because the tile size routine already does it for you if desired. In Y for this routine, 0x00 means only 8x8 tiles and 0x02 means only 16x16 tiles. If you want to set the tile size manually, just load any negative value like 0xFF into Y and obviously, set the values (either 0x00 or 0x02) to $0460,y. Keep in mind that the tile size index is four times than the OAM index so you have to LSR the index twice."


My question comes in as this, if i were wanting to make a (24x24 or 48x48) sprite how would this portion of code be written?


Code
LDA #$00	; Tile to draw - 1
LDY #$02	; 16x16 sprite
JSL $01B7B3


I was thinking a 24x24 sprite would be LDY #$04 and a 48x48 would be LDY #$08 but im unsure as it only refers to 00 being 8x8 and 02 being 16x16 nothing higher is mentioned.


and if i were to manually set the tile size using $0460,y how would I write that into the routine? its written in a way that sounds like i would write it like this.

Code
LDA #$00	; Tile to draw - 1
LDY #$FF	; 16x16 sprite
STY $0460,y
JSL $01B7B3
Bit 1 clear or set (with the result being $00 or $02) tells the SNES graphics chip if the tile should be "small" or "large" respectively. The SNES supports any two sizes out of 8x8, 16x16, 32x32, and 64x64. However, SMW always uses 8x8 and 16x16, so "small" means 8x8, and "large" means 16x16.

If you want to make a 24x24 sprite, you have to use some combination of 8x8 and 16x16 tiles arranged in a way to get what you want. Exactly how will usually involve some sort of tradeoff -- number of OAM slots vs. space in the gfx file, etc.

For example, you could use a 16x16 tile in the upper left, and then pad that with 5 8x8 tiles to the right and below (in which case, you'd have mixed tile sizes and need to set them yourself). Or you could use 4 16x16 tiles that overlap (in which case, all the tiles would be 16x16, so you can let the Finish routine set them) -- note: here, the order you place them is important -- tiles in lower OAM slots will be shown on top of tiles in higher slots.

---
Edit: more stuff I forgot to add that addresses more of the question:

Quote
and if i were to manually set the tile size using $0460,y how would I write that into the routine? its written in a way that sounds like i would write it like this.

Code
LDA #$00	; Tile to draw - 1
LDY #$FF	; 16x16 sprite
STY $0460,y
JSL $01B7B3



Generally, you'll be setting the tile size as you go, along with setting the tile number, properties, and x & y. If Y holds the OAM offset, then something like:

Code
TYA
LSR #2
TAY

LDA #$02
STA $0460|!addr,y

TYA
ASL #2
TAY


will set the current slot to 16x16. There may be some little optimizations you can do here, but that's the general idea. You'd do this for each tile (with STZ $0460|!addr,y in the middle instead if this one is 8x8).

And then only at the end would you call %FinishOAMWrite().
a few points of clarity for my stupid brain.

you mentioned the Snes supports any two sizes out of 8x8, 16x16, 32x32, and 64x64 for tile sizes, but smw always uses 8x8 or 16x16 but if i were doing a tile size of 32x32 or 64x64 i COULD use
Code
LDY #$02	; 16x16 sprite
and have it set to a higher number such as #$06 (idk the exact number at the moment) if the sprite is 32x32 and is layed out together in its final form in the gfx file.

Originally posted by Fernap
Generally, you'll be setting the tile size as you go, along with setting the tile number, properties, and x & y. If Y holds the OAM offset, then something like:

Code
TYA
LSR #2
TAY

LDA #$02
STA $0460|!addr,y

TYA
ASL #2
TAY


will set the current slot to 16x16. There may be some little optimizations you can do here, but that's the general idea. You'd do this for each tile (with STZ $0460|!addr,y in the middle instead if this one is 8x8).

And then only at the end would you call %FinishOAMWrite().



#smw{o_O?} if i were doing 48x48 which is 9 16x16 tiles i would white the above code 9 times one for each individual 16x16 tile, how do i write that code multiple times? is it just me taking
Code
TYA
LSR #2
TAY

LDA #$02
STA $0460|!addr,y

TYA
ASL #2
TAY
and then replicating
Code
LDA #$02
STA $0460|!addr,y

TYA
ASL #2
TAY
?

also arithmetic shift and logical shift i kind of understand, its the offset and because it is shift #2 it would be two 8x8s to make a 16x16 tile? not sue on this, its my guess.



This is the Code from the tutorial looking at: it makes a blue mushroom in the tutorial
Code
print "MAIN ",pc
	JSR Graphics
print "INIT ",pc
RTL

Graphics:
	%GetDrawInfo()

	LDA $00
	STA $0300,y	; X position
	LDA $01
	STA $0301,y	; Y position
	LDA #$24
	STA $0302,y	; Tile number
	LDA $15F6,x                The YXPPCCCT properties for the sprites are stored in $15F6,x (palette and tile page stored from the CFG editor but you can overwrite them)
	ORA $64                    the default priority (actually properties but only the priority bits are stored there) for the current level mode is $64.
	STA $0303,y	; Properties

	LDA #$00	; Tile to draw - 1
	LDY #$02	; 16x16 sprite
	JSL $01B7B3
RTS


in VSC at the end i changed
Code
LDA #$00	; Tile to draw - 1
LDY #$02	; 16x16 sprite
JSL $01B7B3
to
Code
LDA #$2F    ;Tiles to draw -1 2F=47+1=48
LDY #$FF
and after LDY #$FF i should add repeatedly for however many tiles (in this case 9 16x16)?
Code
TYA
LSR #2
TAY

LDA #$02
STA $0460|!addr,y

TYA
ASL #2
TAY
Nooo!!! You're not exactly on the right track there.

First, I think it's best that you forget for now that the SNES can draw anything that's not exactly 8x8 and 16x16 tiles. This is a global setting which SMW has it set so only 8x8 and 16x16 tiles are possible. In this part of the code,

Code
LDA #$00	; Tile to draw - 1
LDY #$02	; 16x16 sprite
JSL $01B7B3

the subroutine will take what you load into y and only read bit 1: common inputs are #$00 = %00000000, bit 1 clear, or #$02 = %00000010, bit 1 set. This bit will determine whether the tile you're drawing is 8x8 (bit 1 clear) or 16x16 (bit 1 set). Therefore, it's helpless to have anything other than #$00 or #$02 (or #$FF, which won't set any sizes within the routine) there.


As Fernap said, drawing a sprite bigger than 16x16 requires you to draw multiple tiles in multiple OAM slots in different positions. So for example, a 32x32 sprite is actually made of 4 16x16 tiles (so 4 OAM slots are taken).

I suggest that you don't get too ahead of yourself, as the point you're in in the tutorial only covers the basic case of how to draw a tile in one OAM slot. Later on (part 4.2.4 and onwards), it'll be taught how to draw in multiple slots, and then how to create a loop to do so, how to offset the position of each of them appropriately, etc. It is quite more complex than the one tile case, but I'm sure you can figure it out with reading and practice (and feel free to ask if you can't, of course).
It's easily the best thing I've done
So why the empty numb?
fair enough, im not really pushing myself too far with the more advanced coding stuff mostly writing complex values in a second asm just to test my math and keep up with it for later, hence the complex questions, im aware it gets pretty complex with what i have planned in the future. im simplifying the tutorial a bit to make it easier for me to understand.

for now, i must return to my homeworld, and continue practicing my coding. i will return to post here, or maybe ill ask around if i find more things im confused by.
What purpose does a colon serve when used like this?
Code
PHB : PHK : PLB

ive seen a few colons and havent Yet figured out the purpose overall i am understanding most of what i see in the tutorial codes
The main purpose of it is to set the data bank or DBR to the current bank. The idea is that the SNES uses a 24-bit address bus but the data bank allows you to leave it out and only write out 16 of the 24 bits. Compare:
Code
	; DBR = $90

	; Long addressing
	LDA $908420

	; Short addressing
	LDA $8420

Both codes are algorithmically equivalent but the latter is faster to access and take up less space, making it preferable when you need to access a lot of tables in ROM of a certain bank, particularly tables assigned in the same bank of the same code such as sprite code.

The problem is that jumping doesn't change the data bank and thus must be changed manually. A traditional method to set the DBR to the current bank is by pushing the program bank first (that's the PHK opcode) and then pulling the data bank (PLB), of course preserving the current DBR as well (PHB) which at the end gets restored before the return (PLB again). This happens extremely often in sprites where ROM tables have to access very often:
Code
	PHB
	PHK
	PLB
	JSR SprMainCode
	PLB
	RTL


Edit: Nevermind, I can't read.


Originally posted by Flamesofshadow
What purpose does a colon serve when used like this?

To be clear, the colon when used like that functions like a new line character. It's used to combine multiple lines into a single line of text, for visual clarity purposes. For instance, this:
Code
	LDA #$14
	STA $00
	LDA #$25
	STA $01

and this:
Code
	LDA #$14 : STA $00
	LDA #$25 : STA $01

would be equivalent.

You often see it with that PHB : PHK : PLB set of lines, since they're commonly used for wrappers as MFG described, and combining them like that just makes it more clear that they're related to each other.

Professional frame-by-frame time wizard. YouTube - Twitter - SMW Glitch List - SMW Randomizer
Ah ok so my initial idea for it was correct then
Does anyone have a more proper but easy to understand for my caveman brain solution to this issue?

I had to add two offsets for y tiles because there was something wrong with the code making it work improperly (the head and body tiles were taking up the same place, or the body was in the ground. this is what I ended up doing to fix it, and I know it likely isn't the proper solution.

Code
LDA $01
CLC : ADC #$F0	; Add Y ofset
STA $0301,y	; Y position
CLC : ADC #$10	; Add Y ofset
STA $0305,y	; Y position 2





Here is the unedited code from section 4.2.4 of MarioFanGamer's sprite coding tutorial https://www.smwcentral.net/?p=viewthread&t=92218

https://media.smwcentral.net/MarioFanGamer/SpriteCreationTut/tut8.asm
The only reason that solution wouldn't be proper is: you're taking $01 (origin ypos), subtracting 0x10 from it (or adding 0xF0 as you wrote) to draw the first tile, then adding 0x10 back for the second tile, which brings you back to the original value. You could draw the tile that's in the origin first and be spared from the second operation:

Code
LDA $01
STA $0305,y
SEC : SBC #$10	;equivalent to adding #$F0, more intuitive this way imo
STA $0301,y

Otherwise, this code is perfectly fine! Since you're only dealing with two tiles, making a table isn't really worth it, and this is the faster way to do it as well.
It's easily the best thing I've done
So why the empty numb?
Ah ok, i just wanted to make sure as i want the code to be as clean as possible and was thinking doing that in that way might have been the messy way.

I know When it comes to larger sprites which have multiple tiles i will end up needing a table for most of the displacements because it will get really messy otherwise.
I got to Part 5: Advanced sprite creation. Section 5.1 Extra whatever

is about Extra Property Bytes, Extra Bytes and the Extra Bit.


this area is not the most explanatory in terms of how to use the different Bytes and Bits, also the linked source code is actually unavailable.


the current question is, Which of those would I need for a sprite which has three sizes (small, medium, large)? my thought is extra bytes as the cfg editor shows options for up to 12 and as I would need 3 it is the type i would need.

extra bit would be if I want the sprite moving left or right when spawned (0/not set is left, 1/set is right)
You're treating the extra bytes as a binary option i.e. on and off. No, these are whole bytes i.e. you can easily use AND #$03 of the first extra byte to determine the size. The other two bytes would be wasted space in that case.

The extra bit thing is correction, though.
would I need multiple AND to branch to the different code for each of the 3 sizes? from my understanding this looks right but i want to make sure.

Code
LDA $AB40
AND #$01
BEQ !define1 ;small
AND#$02
BEQ !define2 ;Medium
AND#$03
BEQ !define3 ;Large


To be clear, AND is a binary operation and is usually used to check whether particular bits are set. When you want to check specific values as opposed to bits, you would use CMP instead.

There's a few other issues in this code as well. One is that the extra property bytes are in $7FAB40 (not $AB40), and you need to use the full address there; also it's a table, so you need to index it by X too. You also probably don't want to have your branches be to defines, and instead use normal labels. So you could do something like this:

Code
	LDA !extra_byte_1,x	; you can use this built-in PIXI define instead of the address
	BEQ Small
	CMP #$01
	BEQ Medium
	CMP #$02
	BEQ Large
	; code if not 00/01/02

Small:
	RTS

Medium:
	RTS

Large:
	RTS


Professional frame-by-frame time wizard. YouTube - Twitter - SMW Glitch List - SMW Randomizer
Flamesofshadow, I'm guessing that you thought that LDA $AB40 would read $7FAB40. Ersanio has a simplified version of the memory map in his tutorial: https://ersanio.gitbook.io/assembly-for-the-snes/the-fundamentals/memory

In the top left, for banks $00-$3F, $7E0000-$7E1FFF is mirrored to $0000-$1FFF. This is why (typically) LDA $1234 reads memory (WRAM). To read $7FAB40, you should use a 3-byte address (LDA !extra_byte_1,x in Thomas' code). (Also note $7E vs $7F; WRAM occupies two banks)
Originally posted by thomas
Code
LDA !extra_byte_1,x	; you can use this built-in PIXI define instead of the address
	BEQ Small
	CMP #$01
	BEQ Medium
	CMP #$02
	BEQ Large
	; code if not 00/01/02

Small:
	RTS

Medium:
	RTS

Large:
	RTS



I've been trying out a few things the past few days when I'm actually able to focus, had partial but very glitchy success with one method but I don't like the results and it's unplayable with the glitchiness of the sprite.


Where is the best place to put that code? I'm trying it in different places and methods, but due to some of the routines being so long, the branches can't reach (mostly the routines for the large grrrol) and that's a hassle.






I've also been going over the tutorial to try to retain what information i know and figure out what i don't, section Part 4.2.5: Complicated graphics routine mentions some stuff that i want to clarify for myself.

1. it mentions using scratch RAM for drawing tiles in a loop, in the source code for that section https://media.smwcentral.net/MarioFanGamer/SpriteCreationTut/tut9.asm the scratch ram is $04 which i think is 7E0004 because 7E0000 is scratch ram? what are the value limits for scratch ram if it is 7E0000.
Originally posted by Flamesofshadow
Originally posted by thomas
Code
LDA !extra_byte_1,x	; you can use this built-in PIXI define instead of the address
	BEQ Small
	CMP #$01
	BEQ Medium
	CMP #$02
	BEQ Large
	; code if not 00/01/02

Small:
	RTS

Medium:
	RTS

Large:
	RTS



I've been trying out a few things the past few days when I'm actually able to focus, had partial but very glitchy success with one method but I don't like the results and it's unplayable with the glitchiness of the sprite.


Where is the best place to put that code? I'm trying it in different places and methods, but due to some of the routines being so long, the branches can't reach (mostly the routines for the large grrrol) and that's a hassle.

To be fair, it can be hard to see where exactly the problem is arising when we can't see the code nor how glitchy the sprite is.

On a side note: You can also use JSR (Label,x) which is extremely helpful when you have multiple states or get into the range issue like in your case:
Code
	LDA !extra_byte_1,x
	AND #$03
	ASL		; I forgot this one pre-edit.
	TAX
	JSR (CodePtrs,x)
	; Other stuff

CodePtrs:
dw Small
dw Medium
dw Large
; Note that a value of 3 will crash the game
; but that one is an invalid option anyway and
; can be specified in a readme if public.

Small:
RTS

Medium:
RTS

Large:
RTS

This by the way is where the suggestion to use AND #$03 is coming from.

Keep in mind that you have to restore X to make the code work. I use TXY before the jump and then execute TYX within the subroutines, though when both registers are used, you can simply load from $15E9 instead.

Originally posted by Flamesofshadow
I've also been going over the tutorial to try to retain what information i know and figure out what i don't, section Part 4.2.5: Complicated graphics routine mentions some stuff that i want to clarify for myself.

1. it mentions using scratch RAM for drawing tiles in a loop, in the source code for that section https://media.smwcentral.net/MarioFanGamer/SpriteCreationTut/tut9.asm the scratch ram is $04 which i think is 7E0004 because 7E0000 is scratch ram? what are the value limits for scratch ram if it is 7E0000.

The reason why I chose $04 and not $00 for the tile index is because $00 is already used for the positon relative to the screen and doing so will overwrite it, something you want to avoid. Other then that, the limit of $00 is the same as for $04.
ill test out that code and see what i can do with it. as for my broken glitchy code, i didn't post it because i know its badly done, and I'm sure the issue is OAM or just the sheer amount of tiles, if Mario looks right he and the sprite vanish, if he looks left the sprite appears and is reading the wrong tiles so yea its just messed up but i didn't expect it to work, just tested it to find if my branches could reach