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 > Problem with BG rotation - FIXED

#101583 - Omegas - Wed Sep 06, 2006 7:09 pm

I'm trying to rotate a 256x256 exrot background around the center of the screen (x=128, y=96). The BG_Rotation libnds example looks like it's trying to accomplish this so I took the code and tried it with my own images. I soon noticed that the rotation seems to be off-center for some reason. To confirm this I made a test background that has a dot in the middle and a crosshair showing where the rotation center should be. You can download this test at http://www.vilminko.net/henri/nds/rot_test.zip. The code is taken from the rotation example, I just added the crosshair image on BG2. Use L/R to rotate the image and you'll see that the center of rotation lies a dozen pixels down and left from the middle point of the screen.

Please don't tell me to read the Tonc chapter about affine transformations... That's what I did first and didn't find anything useful about rotating and scrolling backgrounds at the same time. I would appreciate it if someone could tell me how this bit is derived though:

Code:
BG3_CX = (scrollX<<8) - rcX * (c - s);
BG3_CY = (scrollY<<8) - rcY * (s + c);


(s and c being the sine and the cosine of the current rotation angle and rcX, rcY the coordinates the image should rotate about)


Last edited by Omegas on Thu Sep 07, 2006 3:16 pm; edited 1 time in total

#101595 - Cearn - Wed Sep 06, 2006 8:21 pm

Omegas wrote:
Please don't tell me to read the Tonc chapter about affine transformations... That's what I did first and didn't find anything useful about rotating and scrolling backgrounds at the same time

As tonc does indeed cover the rotation and scaling at the same time, I'm afraid I'm going to have to insist :P
tonc: affine bgs, eq 4 is exactly what you need to do.

The problem is that the libnds example was wrong to begin with: the matrix multiplication was incorrect. It should have been
Code:
      BG3_CX = (scrollX<<8) - (rcX * c - rcY*s);
      BG3_CY = (scrollY<<8) - (rcX * s + rcY*c);

This is p0 - P?q0; what the example did was p0 - q0^T ? P. These are not the same operation.

Hmm, maybe this explains why the #defines of the matrix are transposed too ...


ETA: also, use ints (s32/u32) as local variables; while the slowness of non-ints will not be a limiting factor here, it seems quite silly to actually make your code slower when there's absolutely no reason to.

#101696 - Omegas - Thu Sep 07, 2006 3:09 pm

Cearn wrote:

As tonc does indeed cover the rotation and scaling at the same time, I'm afraid I'm going to have to insist :P
tonc: affine bgs, eq 4 is exactly what you need to do.


Eh, I guess I have to read my copy of Tonc more carefully next time... :) But I have to thank you as I got it solved now. This is how I did it:

Code:

   // set up a rotation matrix
   // (see TONC chapter on affine transformations)
   u32 xdx = ( c * scaleX ) >> 8;
   u32 xdy = (-s * scaleX ) >> 8;
   u32 ydx = ( s * scaleY ) >> 8;
   u32 ydy = ( c * scaleY ) >> 8;
      
   // set the translation registers
   BG3_XDX = xdx;
   BG3_XDY = xdy;
   BG3_YDX = ydx;
   BG3_YDY = ydy;
      
   // set the scroll registers
   // (see the TONC chapter about positioning and transforming affine backgrounds)
   BG3_CX = (scrollX<<8) - (xdx * rcX + xdy * rcY);
   BG3_CY = (scrollY<<8) - (ydx * rcX + ydy * rcY);


Your version was good but it didn't account for the scaling factors scaleX and scaleY. This could probably be optimized too but at least it's working properly now. :)

#101702 - gmiller - Thu Sep 07, 2006 3:19 pm

I make my students in my GBA class read tonc and cowbite so they will know how to do this. Thanks Cearn ....

#101708 - Cearn - Thu Sep 07, 2006 3:43 pm

Omegas wrote:
Your version was good but it didn't account for the scaling factors scaleX and scaleY. This could probably be optimized too but at least it's working properly now. :)
Should have noticed that one, sorry about that. Also, this probably cannot be optimized further; not unless you want to lose generality anyway.

Omegas wrote:
Code:

   // set up a rotation matrix
   // (see TONC chapter on affine transformations)
   u32 xdx = ( c * scaleX ) >> 8;
   u32 xdy = (-s * scaleX ) >> 8;
   u32 ydx = ( s * scaleY ) >> 8;
   u32 ydy = ( c * scaleY ) >> 8;

These should be signed, not unsigned integers.
Also, just as a general comment, be aware that the mathematical convention for vector notation is vector-name_vector-elements:
v = (vx, vy, vz). This seems to be reversed in libgba's affine matrix definitions: its xdy is actually the x element of the dy vector. Be aware of this when you try to compare the operations with mathematical texts.

gmiller wrote:
I make my students in my GBA class read tonc and cowbite so they will know how to do this. Thanks Cearn ....
CowBite suffers from the problem as most other documents on the affine matrix: it uses a transposed (or even inverted) version of the matrix. It also lists the elements as having a separate signbit (1.7.8 format), which is also incorrect: these are simple integers in 2s complement, not a derivative of floating point numbers.

#101713 - gmiller - Thu Sep 07, 2006 4:20 pm

Cearn wrote:
Quote:

CowBite suffers from the problem as most other documents on the affine matrix: it uses a transposed (or even inverted) version of the matrix. It also lists the elements as having a separate signbit (1.7.8 format), which is also incorrect: these are simple integers in 2s complement, not a derivative of floating point numbers.


Yes it sufferes more than that but to put is all together I do not rely on only one source. Most the of documents have errors in them so I use what is available and then try to point out the problems.

#101714 - gmiller - Thu Sep 07, 2006 4:24 pm

We have also added a whole section on fixed point math avoiding the inferred sign magnitude representation and pointing out that it is just 2's complement and what is requred when doing add and subtract as well as the results when doing multiply and divide.