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.

DS development > Rotating background around the center

#115702 - HyperHacker - Thu Jan 18, 2007 1:54 pm

From what I've read about the GBA, its affine backgrounds would rotate around their center. However, when I use rotation on the DS, they rotate around the top left corner. How can I rotate them around the center instead?
_________________
I'm a PSP hacker now, but I still <3 DS.


Last edited by HyperHacker on Mon Jan 22, 2007 7:02 am; edited 2 times in total

#115811 - tepples - Fri Jan 19, 2007 7:27 am

Affine backgrounds always rotate about the top left corner. You'll need to move the top left corner so as to make them appear to rotate about the center. To rotate where the texel (scrollX, scrollY) is placed at pixel (centerX, centerY), once you've computed the rotation matrix, try something like this:
Code:
x_origin = scrollX - centerX * pa - centerY * pb;
y_origin = scrollY - centerX * pc - centerY * pd;

EDIT: corrected y_origin formula
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Tue Jan 23, 2007 2:38 am; edited 1 time in total

#116127 - HyperHacker - Mon Jan 22, 2007 4:11 am

I'm not sure I understand you. How do I move the top left corner? I was thinking of a method along the lines of turning BG wrap on, and "rotate" the image (much like one "rotates" a byte), so that EG instead of this, I have this, which would tile the same way. Seems a bit of a hack though; is this what you meant?
_________________
I'm a PSP hacker now, but I still <3 DS.

#116128 - tepples - Mon Jan 22, 2007 4:30 am

There are six values in the struct that defines an affine matrix. PA, PB, PC, PD, X origin, Y origin. To make a background rotate about a point other than the top left corner of the screen, you set the values of X origin and Y origin as needed based on PA, PB, PC, and PD.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#116129 - HyperHacker - Mon Jan 22, 2007 6:06 am

OK, well that's not entirely working:
Code:
i = fixed2int(fixed_mult(Rot, float2fixed(1.4222222))); //convert 360ths to 512ths
if(i >= 512) i = 512; else if(i < 0) i = 0;

BGMatrix[0][0] = fixed_div(COS[i], Zoom) >> 4; //convert 12bit fraction to 8bit
BGMatrix[0][1] = fixed_div(-SIN[i], Zoom) >> 4;
BGMatrix[1][0] = fixed_div(SIN[i], Zoom) >> 4;
BGMatrix[1][1] = fixed_div(COS[i], Zoom) >> 4;
BG3_CX = (XPos - 128 * BGMatrix[0][0] - 96 * BGMatrix[0][1]) << 8;
BG3_CY = (YPos - 128 * BGMatrix[1][0] - 96 * BGMatrix[1][1]) << 8;

BG3_XDX = BGMatrix[0][0];
BG3_XDY = BGMatrix[0][1];
BG3_YDX = BGMatrix[1][0];
BG3_YDY = BGMatrix[1][1];

I tried 128,96 as the center point (center of the screen) and 256,256 (center of the background which is 512x512), in either case the image just jumps around the screen randomly as it rotates. Adjusting Zoom (1.0 by default) also causes this. It rotates just fine around 0,0 if I don't adjust BG3_CX or BG3_CY.

When you say this:
Code:
x_origin = scrollX - centerX * pa - centerY * pb;
y_origin = scrollX - centerX * pc - centerY * pd;

I assume you meant y_origin = scrollY?


[edit] Nevermind! Just had to kill the "<< 8" writing to BG3_Cx, since the values were already fixed point. Doh!

(For those just tuning in, yes, centerX and centerY are screen coords, not BG coords.)


[whee more editing] OK, I had to make a few tweaks to get scrolling working. Otherwise the image's top left corner would be in the center of the screen and the center point would move as I scrolled. This resolves the problem, so the image starts in the corner of the screen like normal and always rotates around the center of the screen no matter the scroll position:
Code:
BG3_CX = ((XPos << 8) - 128 * BGMatrix[0][0] - 96 * BGMatrix[0][1]) + (128 << 8);
BG3_CY = ((YPos << 8) - 128 * BGMatrix[1][0] - 96 * BGMatrix[1][1]) + (96 << 8);


Also, refresh my memory, how do I go about compensating for the rotation when scrolling? As it is now, if the image is rotated 90?, then when I adjust the X position, it moves up and down instead of left and right. I did this once before to implement a proper camera system in 3D, but I didn't really understand what I'd done very well (just tinkering and hey it works). I understand you multiply through the matrix? EG TrueScrollX = BGMatrix[?][?] * ScrollX? Hopefully I can work this out tomorrow, right now I need to sleep.

Thanks for the help BTW. I should have paid more attention in math class, maybe then all this matrix stuff wouldn't be such a pain for me. >_>
_________________
I'm a PSP hacker now, but I still <3 DS.


Last edited by HyperHacker on Mon Jan 22, 2007 7:20 am; edited 3 times in total

#116199 - tepples - Tue Jan 23, 2007 2:41 am

HyperHacker wrote:
Also, refresh my memory, how do I go about compensating for the rotation when scrolling? As it is now, if the image is rotated 90?, then when I adjust the X position, it moves up and down instead of left and right.

How are you currently implementing your character's motion on the map?

Try adding (PA, PC) to the camera position when the player presses right, and add (PB, PD) to the camera position when the player presses down.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#116206 - HyperHacker - Tue Jan 23, 2007 4:37 am

There is no character. This is just a demo; all it does is scroll a bitmap around. It's to show off the NDS Motion Card, so there isn't really an up/down/left/right but rather an X and Y acceleration.

[edit] I adapted the code I used in my 3D camera system (just removed the Z axis references):
Code:
BGMatrix[0][0] = fixed_div(COS[i], Zoom) >> 4; //convert 12bit fraction to 8bit
BGMatrix[0][1] = fixed_div(-SIN[i], Zoom) >> 4;
BGMatrix[1][0] = fixed_div(SIN[i], Zoom) >> 4;
BGMatrix[1][1] = fixed_div(COS[i], Zoom) >> 4;

XPos += ((XAcc / XYSpeedFactor) * BGMatrix[0][0]) + ((YAcc / XYSpeedFactor) * BGMatrix[0][1]);
YPos -= ((XAcc / XYSpeedFactor) * BGMatrix[1][0]) + ((YAcc / XYSpeedFactor) * BGMatrix[1][1]);

BG3_CX = ((XPos << 8) - 128 * BGMatrix[0][0] - 96 * BGMatrix[0][1]) + (128 << 8);
BG3_CY = ((YPos << 8) - 128 * BGMatrix[1][0] - 96 * BGMatrix[1][1]) + (96 << 8);

It seems right, but since I don't have the motion card right now it'd be quite difficult to test. Does it look right to you? (The use of -= for YPos is intentional, as the sensor's X axis is the same as the screen's, but its Y axis is inverse to the screen's.)

XAcc and YAcc are the acceleration values returned from the sensor, XYSpeedFactor is a constant (currently 64) simply there to slow down the motion to a reasonable rate (else the image would be jumping all over the place just from the slight jitter from holding it in your hand).
_________________
I'm a PSP hacker now, but I still <3 DS.

#116217 - tepples - Tue Jan 23, 2007 7:25 am

When you divide by SpeedFactor, it may be better to multiply before dividing so that as much precision remains in the numbers as long as possible.

Does your code work with the acceleration controlled by touch? If so, it should work with the accelerometer.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.