gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

ASM > Rotate/Scale sprite code to asm

#166085 - headspin - Mon Jan 26, 2009 10:42 am

I am trying to convert the following code from this website

Code:
s16 s = -SIN[angle & 0x1FF] >> 4;
s16 c = COS[angle & 0x1FF] >> 4;

spriteRotation[index].hdx = c;
spriteRotation[index].hdy = -s;
spriteRotation[index].vdx = s;
spriteRotation[index].vdy = c;


And here is my current "translation" to arm asm.

Code:
ldr r0, =SIN_bin            @ Load the address of our SIN table
ldr r1, =COS_bin            @ Load the address of our COS table
ldr r2, =angle               @ Load the address of angle
ldrh r3, [r2]               @ Load r3 with the value of angle
add r3, #1                  @ Add one to angle
cmp r3, #512               @ Compare our angle to 512
movpl r3, #0               @ If the angle is greater than 512 then set it to zero
strh r3, [r2]               @ Write it back to angle
ldr r4, =0x1FF               @ Load our mask to r4
and r3, r4                  @ And our mask with our angle
lsl r3, #1                  @ Multiply by 2? (16 bit SIN data?)
add r0, r3                  @ Add our offset to our SIN table
add r1, r3                  @ Add our offset to our COS table
ldrsh r2, [r0]               @ Now read the SIN table
ldrsh r3, [r1]               @ Now read the COS table
asr r2, #4                  @ Right shift the SIN value 4 bits
mov r6, r2                  @ Make a copy of our SIN value (-SIN[angle & 0x1FF] >> 4)
rsb r2, r2, #0               @ Reverse subtract to make it negative (r2=#0 - r2)
asr r3, #4                  @ Right shift the COS value 4 bits  (c = COS[angle & 0x1FF] >> 4)
ldr r4, =OBJ_ROTATION_HDX(0)   @ This is the HDX address of the sprite
ldr r5, =OBJ_ROTATION_HDY(0)   @ This is the HDY address of the sprite
strh r3, [r4]               @ Write our COS value to HDX (hdx = c)
strh r6, [r5]               @ Write our SIN value to HDY (hdy = -s)
ldr r4, =OBJ_ROTATION_VDX(0)   @ This is the VDX address of the sprite
ldr r5, =OBJ_ROTATION_VDY(0)   @ This is the VDY address of the sprite
strh r2, [r4]               @ Write our SIN value to VDX (vdx = s)
strh r3, [r5]               @ Write our COS value to VDY (vdy = c)


I am using the same SIN.bin and COS.bin from the old libnds (located in libnds\source\arm9) I ran a bin2s and included them in my project. I have no idea if the values are half word in size or not but thats what I've assumed in the code.

I also am also not sure how to make a value negative as in the C example, again I'm guessing it's setting the MSB.

All I'm getting is the sprite turns into the shape of a line and is really slowly moving. Obviously there is a bug in the code somewhere. Can you see it?
_________________
Warhawk DS | Manic Miner: The Lost Levels | The Detective Game


Last edited by headspin on Mon Jan 26, 2009 12:59 pm; edited 4 times in total

#166089 - FluBBa - Mon Jan 26, 2009 11:36 am

I guess the reason why you would use asm is becuase you want to optimise the code... adding extra code when converting to asm kind of defeats the purpose, doesn't it?
Skip the "cmp #512" as it's even wrong, you'd need a movpl instead of movgt.
use rsb (reverse subtract) to negate a number like this, "rsb r2,r2,#0", which means r2=#0 - r2.
_________________
I probably suck, my not is a programmer.

#166090 - headspin - Mon Jan 26, 2009 12:18 pm

Thanks FluBBa. Actually it's not for optimizing but just for the challenge. I'm sure a C compiler can create better code than I can at the moment. But I'm doing this to learn arm and for fun. I can always optimize it a bit later when I learn more of the instruction set.

I've updated my first post with your code changes and now the sprite starts to rotate correctly but when it goes past the 90 degree position it disappears. Any clue why?
_________________
Warhawk DS | Manic Miner: The Lost Levels | The Detective Game

#166091 - Cearn - Mon Jan 26, 2009 12:40 pm

A basic rotation function would look like this. It's untested, but the principles are there. I wouldn't be surprised if the compiler comes up with pretty much the same thing.
Code:
@ void objRotate(int mtxIndex, int angle)
    .align
    .thumb_func
    .global objRotate
objRotate:
    @ Get correct matrix offset and set-up lookup
    ldr     r2, =oamBuffer
    mov     r2, r2, #5
    add     r0, r2                  @ r0= &oamBuffer[4*mtxIndex]
    ldr     r2, =SIN_bin
   
    @ Set cross-diagonals to sines.
    lsl     r3, r1, #(32-9)         @ - r3= (angle%512)*2
    lsr     r3, r3, #(32-8)         @ /
    ldrsh   r3, [r2, r3]            @ NOTE: signed load
    asr     r3, r3, #4              @ NOTE: asr, not lsr
   
    strh    r3, [r2, #22]           @ mtx.pc =  sin(a)
    neg     r3, r3
    strh    r3, [r2, #14]           @ mtx.pb = -sin(a)
   
    @ Set diagonals to cosines.
    add     r3, r1, #0x80           @ \_
    lsl     r3, r3, #(32-9)         @ - r3= ((angle+512/4)%512)*2
    lsr     r3, r3, #(32-8)         @ /
    ldrsh   r3, [r2, r3]
    asr     r3, r3, #4
   
    strh    r3, [r2, #6]            @ mtx.pa= cos(a)
    strh    r3, [r2, #30]           @ mtx.pd= cos(a)

Note a couple of things.
First, signed vs unsigned shifts and loads. Since these are really signed data, you need the signed versions. Unsigned can make things go wonky when you start shifting. This is possibly why things disappear after 90 degrees.

Second, where possible use indexed addressing modes. This can save you a lot of address loads. The affine matrices are interlaced with the normal object attributes at a distance of 32 bytes. The matrix elements start at 6 and then offsets of 8.

You can also get the cosine via the sine lut via cos(a) = sin(a+½π).

If you're learning ARM asm, create some functions in C and compile with -save-temps. This will give you the assembly for the C code. Though the compiler at times uses more registers than necessary or adds superfluous mov/cmp instructions, it does know a few tricks that you may not have thought of.

#166092 - headspin - Mon Jan 26, 2009 1:00 pm

Thanks Cearn ldrsh did the trick :)

I also appreciate your other tips especially viewing the compiled C assembly.
_________________
Warhawk DS | Manic Miner: The Lost Levels | The Detective Game