# 3D affine transformation (rotation) mimicking Mode 7, Java 2D

I watched videos of games using mode 7 like Outrun or Space Harrier and I want to make a game which imitates this classic graphic. I was inspired by Notch's Prelude Of The Chambered too.

After experimenting with pseudo 3D solutions from here StackOverflow and reading about 3D computer graphic I tried to make my own Mode 7 implementation with 3D affine transformations. (I've read here on stackoverflow too that using matrices and transformations is better than use pseudo 3d technics.)

A came up with this solution, but it doesn't work perfectly:

void mode7() {
// width and height of texture
int texW = 1024, texH = 1024;
// ... of screen
int screenW = 800, screenH = 800;

// precalculated values
int scrWH = (int) (screenW * screenH);
int imgWH = (int) (texW * texH);

// center of perspective projection -- the point I look at
int toCenterOffsetX = screenW >> 1;
int toCenterOffsetY = screenH >> 1;

// depth
float z = 1f;

int textureIndex;
int screenIndex;

double tempX, tempY, tempZ;

// screen coordinates
double screenX, screenY, screenZ;
// after perspective division
int perX, perY;

// scale
//float scale = 2f;

for(int pixelY = toCenterOffsetY; pixelY < screenH; pixelY++) {
for(int pixelX = 0; pixelX < screenW; pixelX++) {
// z
screenZ = z;

// translating to center
screenY = pixelY - (texH >> 1);
screenX = pixelX - (texW >> 1);

// transformation

// rotating -- glitch like graphic somehow
//screenX = tempX;
//screenY = tempY;

// 3D Rx
//               | x |
//               | y |
//               | z |
// ----------------------------------------------
// | 1  0    0   | 1 * x + 0 * y + 0 * z     = x'
// | 0  cos -sin | 0 * x + cos * y - sin * z = y'
// | 0  sin  cos | 0 * x + sin * y + cos * z = z'
tempX = screenX * 1 + 0 * screenY + 0 * screenZ;
tempY = screenX * 0 + screenY * Math.cos(rotX*RAD) - screenZ * Math.sin(rotX*RAD);
tempZ = screenX * 0 + screenY * Math.sin(rotX*RAD) + screenZ * Math.cos(rotX*RAD);

// rotating
screenX = tempX;
screenY = tempY;

// translating back
screenY = (float) tempY; // + (texH >> 1);
screenX = (float) tempX; // + (texW >> 1);

// perspective divison and set horizon
perX = (int) (screenX / tempZ) + toCenterOffsetX;
perY = (int) (screenY / tempZ) + toCenterOffsetY;

// index
//pixelX *= scale; // not working, blank blue screen
//pixelY *= scale;

// removing gaps with nearest neighbour like scaling
//pixelX *= texW / (texW / tempZ);
//pixelY *= texH / (texH / tempZ);
// simplified
//pixelX *= tempZ;
//pixelY *= tempZ; // not working...even one frame won't be drawn, just white screen

textureIndex = (int) ( pixelY * texW + pixelX );

screenIndex = (int) ( perY * screenW + perX );

// write pixels
if( (textureIndex >= 0 && textureIndex < imgWH) &&
(screenIndex >= 0 && screenIndex < scrWH)
) {
output[screenIndex] = input[textureIndex];
}
}
}
}


If I'm right, then I should use something similar to the nearest neighbour scaling to remove the gaps.

Games like Outrun doesn't have a huge map eg. 3000 x 3000 (I think) but it'll take minutes to drive through the picture. I first used a 64 * 64 texture for this but ther results were almost exactly the same. How could I make the map scaled to the proper size?

I leave the optimizations for later.

The input / output arrays are due to the DataBufferInt and getRGB(x, y, w, h... stuff I used to avoid setRGB and other slow methods.

I don't ask for exact, full solutions, I ask for some hints, guides, or mathematical explanations.

I'd like to learn enough so I can create a simple 3D game like Notch did. I know he's already had years of experience of game programming but I hope it's something I can learn without 10+ year of game programming.

Here are the results and the used texture: