Day 13 - Sprite Effects!




What Sprite Effects Exactly?


	Well, since you asked so nicely, we will cover the following: Vertical and 
Horizontal Flip, Mosaic, and rotation and scaling. With rotation, however, I don't
cover SIN() and COS(), so we'll just discuss where and what to put in the
rotational/scaling data and leave you to figure the rest out. I may discuss making
a table of the values for the rotation array, but this is alittle out of the current
topic.

Flip Flags

This is so simple, I'm not even going to give a full code file example. The Vertical Flip Flag is bit#12 (starting from #0 on right) in Attribute 0. So for our flipping pleasure, the defines in sprites.h, which you should have already, that we care about here are: -VERTICAL_FLIP -HORIZONTAL_FLIP The Horizontal Flip Flag is bit#13 in Attribute 0. To toggle the flip flag, you want to grab the first 32bits of a sprite's OAM Entry into a register and EORing (same as XOR) the register with either VERTICAL_FLIP or HORIZONTAL_FLIP. Alright, some code: ldr r2,=OAM ldr r3,[r2] ; load r3 from memory, [] in a load statement mean "from memory". ; the above will load r3 with Attribute 0 and Attribute 1. both because CPU registers are 32bit ; and OAM attributes are 16bit. eor r3,r3,VERTICAL_FLIP ; XORs r3 with VERTICAL_FLIP and puts the value in r3. ; EOR and XOR are the same, just remember that the asm instruction is called EOR. str r3,[r2] ; store the modified Attributes back to OAM. That code toggles the Vertical Flip Flag, if you wanted to toggle the Horizontal Flip... well... I hope you get the idea.

Mosaic

The Mosaic Register is at 0x400004C, please redownload screen.h for the new functionality. The register is 16bits, bits#15-12 are vertical mosaic and bits#11-8 are horizontal mosaic. Mosaic, if you didn't know already, makes your sprite look blocky. The other bits are for the background. Other than setting REG_MOSAIC, we also need to set the Mosaic Flag in Attribute 0. Toggle it by replacing VERTICAL FLIP, with MOSAIC in the previous code. Note that you can OR them together with the | (pipe) symbol. Here's the previous example modified: ;set the mosaic register ldr r4,=REG_MOSAIC ldr r3,=0x1200 ; 1 for horizontal, 2 for vertical, none for background. str r3,[r4] ; store it. ldr r2,=OAM ldr r3,[r2] ; load r3 from memory, [] in a load statement mean "from memory". ; the above will load r3 with Attribute 0 and Attribute 1. both because CPU registers are 32bit ; and OAM attributes are 16bit. eor r3,r3,MOSAIC ; XORs r3 with MOSAIC and puts the value in r3. ; EOR and XOR are the same, just remember that the asm instruction is called EOR. str r3,[r2] ; store the modified Attributes back to OAM. And boom! You get a MOSAICaded sprite.

Rotation (Insert triumphant melody here!)

I hope you've atleast read Day 3 of the C tutorial at ThePernProject.COM because if you haven't, this is going to be aLOT harder. Go read it now. ... ... Go read it again. :) ... ... Think you understand? If you don't it's ok, because I'm going to try to explain it anyway. To start out, there's something called Rotation Data. Now in Rotation Data there are 4 16bit "spots" in each entry in Rotation Data memory. Got that? Good. Rotation Data is in OAM. What, you ask, isn't the sprite attributes in OAM? And I answer: yes. Remember what happened to Attribute 3? We never used any Attribute 3's. Well here's a little hint: Rotation Data is the Attribute 3s throughout OAM. Just to clarify, Attribute 3 has nothing to do with an individual sprite. Here's a little diagram mapping OAM to Rotation Data Entries and the pa,pb,pc,pd that ThePernProject Day 3 talks about: Sprite 0 Att#0 Sprite 0 Att#1 Sprite 0 Att#2 Sprite 0 Att#3 - Rotation Data Entry #0 - 16bit "spot"#1 - pa Sprite 1 Att#0 Sprite 1 Att#1 Sprite 1 Att#2 Sprite 1 Att#3 - Rotation Data Entry #0 - 16bit "spot"#2 - pb Sprite 2 Att#0 Sprite 2 Att#1 Sprite 2 Att#2 Sprite 2 Att#3 - Rotation Data Entry #0 - 16bit "spot"#3 - pc Sprite 3 Att#0 Sprite 3 Att#1 Sprite 3 Att#2 Sprite 3 Att#3 - Rotation Data Entry #0 - 16bit "spot"#4 - pd Sprite 4 Att#0 Sprite 4 Att#1 Sprite 4 Att#2 Sprite 4 Att#3 - Rotation Data Entry #1 - 16bit "spot"#1 - pa Sprite 5 Att#0 Sprite 5 Att#1 Sprite 5 Att#2 Sprite 5 Att#3 - Rotation Data Entry #1 - 16bit "spot"#2 - pb Sprite 6 Att#0 Sprite 6 Att#1 Sprite 6 Att#2 Sprite 6 Att#3 - Rotation Data Entry #1 - 16bit "spot"#3 - pc Sprite 7 Att#0 Sprite 7 Att#1 Sprite 7 Att#2 Sprite 7 Att#3 - Rotation Data Entry #1 - 16bit "spot"#4 - pd ---- Continues in shown pattern throughout OAM ---- I realize that the diagram is big, but I hope it illustrates well the layout of Rotation Data. Note that any sprite can use any Rotation Data Entry. There are 32 Rotation Data Entries, so 32 sprites can be rotated/scaled. So just what do we put in each 16bit "spot" (pa,pb,pc,pd) in the Rotation Data? Well, ThePernProject gives us some very nice equations just to make it hard for us to do the calculations in assembly (kidding!...), they are: spot 1 - pa needs to be the COSine of the angle. spot 2 - pb needs to be the SINe of the angle. spot 3 - pc needs to be the NEGATIVE SINe of the angle. spot 4 - pd needs to be the COSine of the angle. There is another part to it, but that's for scaling which we'll cover another day. Notice that spot 3 needs to be the negative sine of the angle, this is what makes rotation so hard (for me anyway). Because to effectively set Rotation Data Spots, we need to grab Attributes 2 and 3 of some sprite. Clear Attribute 3 (by ANDing), the Rotation Data Spot. And set the new value (by ORing). Remember, these are 16bit numbers, so if we just set Attribute 3 with the right value, we would accidentally zero out Attribute 2. To help us out I've make several (alot actually) new defines in sprites.h, so I suggest you download this new one. The defines are for the Rotation data (obviously) and look like PA_0, PB_0, PC_0, PD_0. Replace the '0' with the number of the rotation data entry that you want to use. Keep in mind that as of 10/26/2002, I've only finished doing defines up to (and including) PD_19. Also, to make this easier as we just want to learn how to rotate sprites, we won't guard against zeroing out Attribute 2, I'll have to write a day on masking bytes. Instead, we'll just use sprite #0 and rotation data entry #0. This way we can zero out Attribute 2 because Attribute 2 will actually supposed to be 0.

Let's Get Coding!

I hope you still have your sprit.asm from Day 5, also keep it because we most likely will use it alot from now on. Let's see some code! ;;--- CODE START ---;; @include screen.h ; we need this. @include dma.h ; the DMA stuff. @include keypad.h @include sprites.h b start @include sprit.asm start ldr r1,=REG_DISPCNT ldr r2,=(MODE_1|BG2_ENABLE|OBJ_ENABLE|OBJ_MAP_1D) str r2,[r1] ldr r1,=REG_DMA3SAD ldr r2,=pallete str r2,[r1] ldr r1,=REG_DMA3DAD ldr r2,=OBJPAL str r2,[r1] ldr r1,=REG_DMA3CNT ldr r2,=(128|DMA_32NOW) str r2,[r1] ldr r1,=REG_DMA3SAD ldr r2,=obj str r2,[r1] ldr r1,=REG_DMA3DAD ldr r2,=CHARMEM str r2,[r1] ldr r1,=REG_DMA3CNT ldr r2,=(512|DMA_32NOW) str r2,[r1] ;;--- STOP COPYING ---;; You should be able to understand what is going on up there by now, if I get enough email of people saying that they don't, maybe I'll add comments. ;;--- CODE CONTINUE ---;; ldr r1,=OAM ldr r2,=((SQUARE|COLOR_256|30))|((SIZE_32|(0<<9)|10)<<16) str r2,[r1] ;;--- STOP COPYING ---;; Here notice the new part italicaded. The number of the rotation data gets shifted over 9 to get it in the right spot. We are using rotation data entry #0. ;;--- CODE CONTINUE ---;; ldr r1,=PA_0 ; store will be in PA ldr r2,=70<<16 ; COS(45 degrees) = 0.70, in first byte of part of register that str r2,[r1] ; Working with fixed point numbers in rotation data. ldr r1,=PB_0 ; store will be in PB ldr r2,=70<<16 ; SIN(45 degrees) = 0.70 also. same as the other one. str r2,[r1] ldr r1,=PC_0 ; store will be in PC ldr r2,=0 ; Negative SIN(45 degrees) = -0.70 sub r2,r2,70 ; subtract 70 from 0 to get a negative and mov r2,r2,lsl 16 ; shift to get just the important 16bits. str r2,[r1] ldr r1,=PD_0 ; store will be in PD ldr r2,=70<<16 ; COS(45 degrees) = 0.70 again, there's two COSes. str r2,[r1] ; store to attributes#2&3 of sprite 3. ;;--- STOP COPYING ---;; Note that we are working with 16bit fixed numbers, so we need those 3 shifts by 16 not only to get it in the right part of the register that'll end up in the right part of memory, we do it also because the 70 is 0.70 and needs to be in the decimal (fraction) part of the number. ;;--- CODE CONTINUE ---;; infin ldr r1,=KEYS ; first 3 lines check if A is down. ldr r1,[r1] ; these lines toggle rotation and the size ands r1,r1,#KEY_A ; double flag. ldreq r1,=OAM ; hit A quickly (just once) to toggle the two flags. ldreq r2,[r1] ; get attributes 0&1 of our sprite. eoreq r2,r2,#(ROTATION_FLAG|SIZE_DOUBLE) ; toggle the flag bits with XOR (eor is the instruction for XORing) streq r2,[r1] ; note that the last 4 lines only run if A is down. b infin ;;--- END OF SOURCE FILE/ STOP COPYING ---;; Assemble and run! I hope you get it. I'm not sure why the sprite also scales by like 4. I ran ThePernProject's C code and got the same result, maybe the well known equations are incorrect?

Day In Review

I'm glad I got this done, it was fun. Oooh 13 is lucky now, what do ya know? Hehe. See ya. Have fun!, -Mike H a.k.a GbaGuy
Intro - Day 14
"Time for a Spot commercial... WOOF!... Thank you, Spot!" -My dad.

Patater GBAGuy Mirror
Contact