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.

Coding > MODE 7 using MODE_2, BG3 with ROTBG_SIZE_256x256

#22058 - Mr. GBA - Sat Jun 12, 2004 6:08 pm

Hi,

I'm trying mode 7 using MODE2 with BG 3, ROTBG_SIZE_256x256 & BG_COLOR_256.

I think I have the correct code placed in the HBLANK interrupt, but I'm not getting the right result. The following code is from the HBLANK interrupt.

/* do something */
int center_y; //these are the points around which the the screen rotates
int center_x;
int tempS = SIN[angle];//some temps to hold the sine cos values so we eliminate all those table acceses
int tempC = COS[angle];//actualy only need to do this once per frame so we could store then in a global
//and calc durring the vblank if we wanted

int zoom;

zoom = (height*div[REG_VCOUNT])>>16; //div is fixed 16.16 height is fixed 24.8 so I end up with 8.24..
//so I shift away 16 bits to give me a zoom that is fixed 24.8
//you may notice that I still have some distortion at the bottom of the screen
//this can probably be fixed by keeping some of the presision in the
//value and shifting later

center_y = (180 * zoom)>>2; //set for the center of the screen in the x direction and slightlu
center_x = (120 * zoom)>>2; //bellow the screen for the Y (about were the observer would be standing)

REG_BG3X = (((ScaleX)-center_y*tempS-center_x*tempC))>>14; //x and y are the background scroll factors
REG_BG3Y = (((ScaleY)-center_y*tempC+center_x*tempS))>>14;

REG_BG3PA = (tempC*zoom)>>16; //cos&sin are LUTs that are .8 fixed numbers
REG_BG3PB = (tempS*zoom)>>16; //zoom is also fixed
REG_BG3PC = (-tempS*zoom)>>16;
REG_BG3PD = (tempC*zoom)>>16;


The angle variable is incremented and decremented in the keypad functions.

I would be much obliged if someone could help me figure out how to get mode seven working.

Thanks.
_________________
my dev/business site:

http://codebytesdev.afraid.org

#22067 - dagamer34 - Sat Jun 12, 2004 10:38 pm

Could you tell us what kind of result you are getting and where you got the code from (it looks familiar)?

Try changing this line:
Code:

zoom = (height*div[REG_VCOUNT])>>16; //div is fixed 16.16 height is fixed 24.8 so I end up with 8.24..

If my set-up is just like yours, then my Mode7 rotation function works by shifting the final zoom 8 bits instead of 16. Or maybe I'm completely wrong, who knows. If you'd like, I can send you a copy of my Mode 7 example, although it has my library stuff in there which might be a little hard to read.

Check out Cearn's tutorials over the subject if you need some help. They're on the main site.
_________________
Little kids and Playstation 2's don't mix. :(

#22079 - Mr. GBA - Sun Jun 13, 2004 12:46 am

The result I get shows the background tiles only in the left hand portion of the screen only. Also the tiled background looks very small, like tiny little dots.

I've tried right shifting the zoom by 8 instead of 16 and a similar result transpired.

I would really appreciate it if you (dagamer34) could post your mode 7 code.

BTW, I got the code from Devoto's mode 7 tut.

Thanks.
_________________
my dev/business site:

http://codebytesdev.afraid.org

#22082 - Mr. GBA - Sun Jun 13, 2004 2:10 am

OK guys, I'm really stuck and it's 2 AM in the morning.

I've put my project up on my home server at http://82.44.76.14/bgcounter.zip

Hopefully someone will be able to correct my mode 7 project.

The project uses gcc (devkitadv).

Thanks. :)Zzzzzzzzzz
_________________
my dev/business site:

http://codebytesdev.afraid.org

#22088 - dagamer34 - Sun Jun 13, 2004 3:33 am

I have found 1 thing so far and that is none of your registers are declared volatile. There seems to be something else causing the problem though, so I'll keep looking into it.
_________________
Little kids and Playstation 2's don't mix. :(

#22106 - Cearn - Sun Jun 13, 2004 2:57 pm

With this much bitshifting going on you need to be really careful with where the fixed point is; write down a list of variables and their fixed points and trace where the point goes after each statement. The mode 7 sections on my site should show how to do this as well as other mode 7 niceties (and not so niceties).

#22109 - Mr. GBA - Sun Jun 13, 2004 3:37 pm

I've got a mode 7 effect, but without using the registers REG_BG3X REG_BG3Y. The background appears to curve to the left. The REG_BG3X & REG_BG3Y registers are used to define the location of the pixel at 0,0 (so Cowbite Spec claims).
Could anyone of you masters tell me a bit more about these registers.

Thanks.
(BTW, I really appreciate the help I've received so far. If I can be of service to anybody, don't hesitate to ask).
_________________
my dev/business site:

http://codebytesdev.afraid.org

#22179 - Cearn - Mon Jun 14, 2004 9:48 am

in bgcounter.cpp
Code:

    //sine cos LUT
    for(int loop = 0; loop < 360; loop++)
    {
        SIN[loop] = (FIXED)((RADIAN(loop)) * (float)(1<<16));  //sin and cos are computed and cast to fixed
        COS[loop] = (FIXED)((RADIAN(loop)) * (float)(1<<16));
    }

Dude ... please tell me this was an accident. Lie if you have to. Something like the cat jumped on your keyboard, messed up and quit the editor before you could assess the damage.
(if you don't get it take a good hard look at the code)

Code:

    div[loop] = (FIXED)( (float)( (1<<16)/loop) ); //our fixed point divide table is 8.24 (24 bits of fraction)

This is of course .16 bits fraction (and I wonder what happens when loop=0). With the current set of parentheses the casts to FIXED and float are completely superfluous (not a bug per se, but still wasteful).

Also, the keyboard and VBlank interrupts won't work with what you have now. I'll explain later.

Code:

REG_IE |= INT_HBLANK |INT_KEYBOARD;   // Enable V-Blank IRQ.
REG_DISPSTAT |= 0x10 |BIT12;    // Enable Display V-Blank IRQ also.

This does not set the V-blank IRQ. In fact, it doesn't even set the
keyboard IRQ. For the VBlank IRQ, you need to set REG_IE, bit 0 and
REG_DISPSTAT, bit 3. For the keyboard IRQ, you need REG_IE, bit 12
(which is INT_KEYBOARD) and unless I'm mistaken you also need to set REG_P1CNT, bit 14. Try
Code:

REG_IE |= INT_HBLANK | INT_VBLANK | INT_KEYBOARD;
REG_DISPSTAT |= 0x18; // Hblank and Vblank
REG_P1CNT |= 1<<14;


And to get a nicer looking mode 7, try this:
Code:

    // make sure cc and ss are .8 fixed numbers;
    // do an extra shift if you have to (and preferably outside the isr)
    FIXED cc = COS[angle];
    FIXED ss = SIN[angle];

    FIXED lam = (height*DIV[REG_VCOUNT]) >> 8;  // .12
    FIXED lcc= lam*cc>>5;             // .15
    FIXED lss= lam*ss>>5;             // .15

    // horizontal scale and offset (convert to .8 in the process)
    REG_BG2PA= lcc>>7;
    REG_BG2X= pos_x - 120*(lcc>>7) + ((D*lss)>>7);

    // vertical scale and offset
    REG_BG2PC= lss>>7;
    REG_BG2Y= pos_z - 120*(lss>>7) - ((D*lcc)>>7);

Note that you multiply with 120 after the down-shift to .8 fixed. This is important. I've also renamed ScaleX and ScaleY to pos_x and pos_z, since they have nothing to do with scaling (left over from earlier code?). D is the focus length; D=128 is standard I believe.
Now, if you use this you'll still probably see nothing because you're at the top left corner of the map, looking away from the map try setting pos_x= 128<<8 and pos_z= 256<<8. Or set the WRAP_AROUND flag in REG_BGxCNT, that still won't give you a clue as to where you are on the map if it's symmetrical, but at least you'll see something.


Last edited by Cearn on Wed Jun 16, 2004 12:01 pm; edited 1 time in total

#22191 - Mr. GBA - Mon Jun 14, 2004 2:33 pm

VERY VERY VERY NICE!!! CEARN!!!

I very much like the look of your suggested mode 7. It's way more realisitc than Dovoto's, which is where I got that dreadful SIN & COS LUT (that somehow works!).

I'm a semi-perfectionist so, I need to parse every line of code to avoid feeling like a hopeless loser. Please correct me where I am wrong.

*Variables cc & ss are obviously references to SIN & COS values (which both have the same value in accordance to my screwed up LUT).
FIXED cc = COS[angle];
FIXED ss = SIN[angle];

*Variable lam is the projected Y value that intersects through the projection plane. This will later act as the centre for rotation, I think.
FIXED lcc= lam*cc>>5; // .15

*Variable lcc is the value that the background will be sheared towards relative to the top left corner in the x direction.
FIXED lcc= lam*cc>>5; // .15

*Variable lss ] is the value that the background will be sheared towards relative to the top left corner in the x direction. Why REG_BG2PA is used twice I'll never know :(.
FIXED lss= lam*ss>>5; // .15

*This is where we do the actual rotation.
REG_BG2PA= lcc>>7;

* Ok, this is where I get lost because I'm not entirely sure of the purpose of REG_BG2X. Anyway, I think this is where we set the orientation of the X scrolling action. I think we minus the centre of the screen (120)*lcc from pos_x (current position) because this will give us ? and why the hell does D come into it. :(. Please help me understand what is going on here.
REG_BG2X= pos_x - 120*(lcc>>7) + ((D*lss)>>7);
REG_BG2Y= pos_z - 120*(lss>>7) - ((D*lcc)>>7);

OK then. Ceran, that is all that I can rendition from your mode 7, which must be pretty way off :( I would be much obliged if you could explain to me where I'm going wrong, particularly REG_BG2X & REG_BG2Y.

BTW, thanks for the keyboard interrupt code (which is the now the least of my worries).

Thanks in advance.
_________________
my dev/business site:

http://codebytesdev.afraid.org

#22194 - Cearn - Mon Jun 14, 2004 3:03 pm

For code and documentation,
http://user.chem.tue.nl/jakvijn/tonc/

lambda is a scaling factor; in principle it's lam=z/D, but in the special case of a pitch-less environment, it's also lam=height/scanline

variables lcc and lss are simply lam*cosine and lam*sine, respectively. I used temporaries because they're used more than once, that's all.

REG_BG2PA is used twice because I screwed up in copy-pasting. The second one should be REG_BG2PC. Hey, everyone makes stupid C&P errors occasionally. (EDIT: is fixed now in previously given code). REG_BG2PB and REG_BG2PD are unnecessary because effectively ignored when you're changing REG_BG2DY every scanline. (look it up in GBATek, internal registers)

I'm working on a full description of the mode 7 process (with variable pitch, horizon lines, variable pitch), but it'll take some time to get it in a user-friendly form. Well, I suppose that what I have now is user-friendly, it's just particular about who its friends are ;)


Last edited by Cearn on Wed Jun 16, 2004 12:02 pm; edited 1 time in total

#22199 - Mr. GBA - Mon Jun 14, 2004 4:22 pm

Thanks for the explanation.
However, there is one matter that needs clearing up. How are REG_BG3X & REG_BG3Y calculated. Could you please tell me if these registers refer to pixel pos 0,0 on the actual screen or if it alternates for each individual scanline.
_________________
my dev/business site:

http://codebytesdev.afraid.org

#22201 - Cearn - Mon Jun 14, 2004 5:06 pm

Without any scaling or rotation, dx= (REG_BGxDX, REG_BGxDY) contain the coordinates (in .8 fixed format) of the map that are put at the origin of the screen. However, when you write to REG_BGxDY in an HBlank, the left of the current line will count as the origin, instead of the top-left of the screen. For example, if you do
Code:

REG_BG2DY = 0

each scanline, the first line of the map will appear on all scanlines.

As for how you calculate the values of dx, the GBA uses the following equation
P ? q = p - dx.
where:
P the affine matrix (goes into REG_BGxPA-REG_BGxPD)
q= (qx, qy) an arbitrary screen point
p= (px, py) an arbitrary map point
dx= (REG_BGxDX, REG_BGxDY)

For any given subject, you should try to write down the necessary transformation and then try to cram it into the form of the equation given above. For rotation phi around a given point r, that'd simply mean P= R(phi) and dx= r - P?r. For mode 7, it's something trickier depending on how your camera is orientated. I've just uploaded a file called m7theory.zip, you could take a look at it, but I warn you that there's a lot of math involved.

#22219 - Mr. GBA - Tue Jun 15, 2004 12:11 am

Thanks alot Cearn. Everything thus far has been understood and now I'm working on a full 360 degree rotation of the backgorund in mode 7. I'm still reading your tutorials, especially .mode7 theory.
_________________
my dev/business site:

http://codebytesdev.afraid.org