Mode 7 - Wikipedia

I recently(ish) went 10 rounds with trying to get a Mode 7 implementation using a SpriteBatch in Monogame. On the face of it, it sounded entirely simple.

I decided that my knowledge wasn’t quite there and figured it was a problem most easily solved by using textured geometry and making a game that was 3D pretending to be 2D.

But, thought that I’d throw this out to the community here - has anyone seen or done anything like this? I was looking at using it to create textured floors/ceilings in a Ray Casting engine… but I’ve also got a bit of a desire to create a Mario Kart / F-Zero clone of old at some point.

Thanks!

1 Like

Remember seeing it once but that was a long time ago…

I converted the first bit of code from the linked page below to C#…

```
// Using System.Numerics.FixedPoint static class
using static System.Numerics.FixedPoint;
// Constants and fields declaration for 3D graphics camera position and distances
private Vector3 _camPos; // camera position
private const int M7D = 3000; // fixed point multiplication factor for horizontal distance
private const int LuDiv = 65536; // fixed point representation for 1.0
// Method implementation for Mode7 affine 3D projection on background 2
void M7HblA()
{
// Variable declaration for intermediate calculations
int lam, xs, ys;
// Calculate pseudo-distance between camera and screen
lam = (int)(_camPos.Y * LuDiv / GraphicsDevice.Viewport.Height * 256 >> 8);
// Calculate coefficients for affine transformation
xs = 120 * lam; // horizontal scaling factor
ys = M7D * lam; // vertical scaling factor
// Look up local sine and cosine values
var cosf = (fixed) (_gCosf * 256);
var sinf = (fixed) (_gSinf * 256);
// Compute scale and rotation components of affine transformation matrix
REG_BG2PA = (cosf * lam >> 8).IntValue(); // horizontal scale
REG_BG2PC = (sinf * lam >> 8).IntValue(); // vertical scale and rotation
// Apply translation and scaling to initial camera position
REG_BG2X = (int)(_camPos.X - (xs * cosf - ys * sinf) / 256); // horizontal translation
REG_BG2Y = (int)(_camPos.Z - (xs * sinf + ys * cosf) / 256); // vertical translation
}
```

But this should help you get going:

Tonc: Mode 7 Part 1 (coranac.com)

EDIT

Updated code with comments

1 Like

Thanks @MrValentine!

Bookmarking this resource - hopefully get a chance to have another shot at it this weekend

1 Like

This is not a simple problem in modern times.

The SNES and all non-HDMI consoles wrote each pixel color to VRAM or directly timed to the output (ATARI 2600, C64, Apple II…). This was called racing the scan-line.

Memory latency has increased with higher clock rates. The channel widths have increased, leading to higher throughput. Reading and writing any values smaller than 64 bits incurs a performance penalty.

Mode 7 requires a non-linear UV texture mapping, since the texture sampler linearly interpolates between vertices, a custom solution is required.

So there are two modern solutions:

**Best Solution:** Write a custom pixel shader to address the non-linearity by transforming the UV inputs of the texture sampler call.

Or:

Pre-Compute the transformed textures.(not a good idea due to storage and memory size requirements)

And one classic solution(sits between the above solutions):

Use `Texture.GetData()`

and `Texture.SetData()`

to use the data array to manually set each pixel.

Pin the data and use pointer arithmetic in an unsafe context to ensure the calculations complete in a timely manner.

See https://github.com/MonoGame/MonoGame/blob/b21463b419e55b4c898030fc22bee77dabb11210/MonoGame.Framework/Graphics/DefaultColorProcessors.cs#L28 as an example of pinning and modifying texture data in an unsafe context.

**This method would provide the closest technique to the original implementation.**

My last suggestion would be to implement full 3D and reverse engineer a series of de-projection matrices for each object space’s Z axis. The implementation is well beyond the scope of this response.

1 Like

A little update…

I’ve finally sat down with this puzzle again with a little more knowledge and am close to a solution now using some Matrix Transformations and Render Targets.

This link has been pretty useful too: Game Components Affine and Non-Affine Transforms in Windows Phone 7 (c-sharpcorner.com)

Hopefully I’ll close in on getting it just how I’d like it when I get another spare hour or so.

2 Likes

And after just a little more effort I’ve reached enough of a solution that I *think* I’ve got the starting place for projects along these lines:

MattDrivenDev/MonoGameMode7: A simple (don’t ask about the matrix math!) SNES-style Mode7 camera for a sprite-based MonoGame game. (github.com)

4 Likes