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 > Mode7 background coordinates

#11115 - poslundc - Fri Sep 26, 2003 6:09 am

I did the Pern tutorial on Mode7 which was all well and good, but I decided I wanted to have control over the vertical angle of the camera, which meant I couldn't use the simple division method used in Pern.

So I started fooling around with raycasting... I think I've got the basic principle but I'm at my wits end trying to get it to work properly with the scale/rotate hardware. Here's a diagram of what I'm trying to do:

[Images not permitted - Click here to view it]

(In case it isn't clear, the horizontal line on the bottom is the background I'm trying to render, and the vertical line at the right is the perpendicular height (z) to the camera, which has an angle theta that measures the vertical swivel.)

My basic strategy is to cast a ray from the top to the bottom of the viewport (160 pixels). I calculate the length of the ray (which is in pixels) then divide by the pixel-distance from the camera to the viewport (which I have precalculated from a fixed field-of-vision) to get what I believe is the proper scaling value.

I think I am correct so far... anyway, I can't seem to calculate the proper x and y scroll-coordinate for each scanline. I figure that since it scales from the upper-left origin, I would need to shrink my x and y coordinates by the same factor that I am scaling the image.

In other words:
new_x = camera_x / zoom_factor
new_y = (camera_y + current scanline) / zoom_factor

... But no matter how many variations I've tried on this theme, the image always winds up terribly warped.

Here's the code I call every frame to calculate the new register values (data types and variable names are pretty obvious):

Code:

slice = gCamera.fov / 160;

for (i = 0; i < 160; i++)
{
   angle = gCamera.theta + (gCamera.fov >> 1) - (i * slice);
   if (angle < 0)
      angle += (360 << 8);
   dist = ((gCamera.z << 16) / gCosLUT[angle >> 8]);
   zoom = dist / 172; // precaluclated pixel-distance to viewport

   cX = ((gCamera.x << 8) / zoom);
   cY = (((gCamera.y + (i << 8)) << 8) / zoom);

   bgTransform[i].pa = zoom;
   bgTransform[i].pb = 0;
   bgTransform[i].pc = 0;
   bgTransform[i].pd = zoom;
   bgTransform[i].x = cX;
   bgTransform[i].y = cY;
}


(I realize that this code is sub-optimal, but I'm shooting for correctness at this point rather than efficiency.)

If anyone can suggest to me what I'm doing wrong, it would be greatly appreciated!

Thanks,

Dan.

#11134 - poslundc - Sat Sep 27, 2003 2:46 am

It's okay, I finally figured it out.

... but not until after wading through a sea of utter heck figuring out how to properly use those scroll registers.

In case anyone cares, the trick was figuring out that the hardware will automatigically scale the location you provide on the map so that it appears at the origin of the viewport (ie. at 0,0 on the screen). Which meant I had to incorporate that scaling into any offset I wanted to provide.

Somebody might consider making a tutorial that explains raycasting for Mode7, with less detail on the geometry and more explaining how to adapt the technique (which is already well-enough documented) to the GBA's hardware. All of the tutorials I've found are either do Mode7 at a more elementary level (such as the Pern demo) or focus too much on the mathematics of 3D and not enough on the science of GBA.

I would probably be willing to do so, if there is a demand for it.

Dan.