mirror of https://github.com/bsnes-emu/bsnes.git
252 lines
7.1 KiB
C++
Executable File
252 lines
7.1 KiB
C++
Executable File
#ifdef CX4_CPP
|
|
|
|
#include <math.h>
|
|
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
|
|
#define sar(b, n) ((b) >> (n))
|
|
#ifdef PI
|
|
#undef PI
|
|
#endif
|
|
#define PI 3.1415926535897932384626433832795
|
|
|
|
//Wireframe Helpers
|
|
void Cx4::C4TransfWireFrame() {
|
|
double c4x = (double)C4WFXVal;
|
|
double c4y = (double)C4WFYVal;
|
|
double c4z = (double)C4WFZVal - 0x95;
|
|
double tanval, c4x2, c4y2, c4z2;
|
|
|
|
//Rotate X
|
|
tanval = -(double)C4WFX2Val * PI * 2 / 128;
|
|
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
|
|
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
|
|
|
|
//Rotate Y
|
|
tanval = -(double)C4WFY2Val * PI * 2 / 128;
|
|
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
|
|
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
|
|
|
|
//Rotate Z
|
|
tanval = -(double)C4WFDist * PI * 2 / 128;
|
|
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
|
|
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
|
|
|
|
//Scale
|
|
C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
|
|
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
|
|
}
|
|
|
|
void Cx4::C4CalcWireFrame() {
|
|
C4WFXVal = C4WFX2Val - C4WFXVal;
|
|
C4WFYVal = C4WFY2Val - C4WFYVal;
|
|
|
|
if(abs(C4WFXVal) > abs(C4WFYVal)) {
|
|
C4WFDist = abs(C4WFXVal) + 1;
|
|
C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
|
|
C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
|
|
} else if(C4WFYVal != 0) {
|
|
C4WFDist = abs(C4WFYVal) + 1;
|
|
C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
|
|
C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
|
|
} else {
|
|
C4WFDist = 0;
|
|
}
|
|
}
|
|
|
|
void Cx4::C4TransfWireFrame2() {
|
|
double c4x = (double)C4WFXVal;
|
|
double c4y = (double)C4WFYVal;
|
|
double c4z = (double)C4WFZVal;
|
|
double tanval, c4x2, c4y2, c4z2;
|
|
|
|
//Rotate X
|
|
tanval = -(double)C4WFX2Val * PI * 2 / 128;
|
|
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
|
|
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
|
|
|
|
//Rotate Y
|
|
tanval = -(double)C4WFY2Val * PI * 2 / 128;
|
|
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
|
|
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
|
|
|
|
//Rotate Z
|
|
tanval = -(double)C4WFDist * PI * 2 / 128;
|
|
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
|
|
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
|
|
|
|
//Scale
|
|
C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
|
|
C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
|
|
}
|
|
|
|
void Cx4::C4DrawWireFrame() {
|
|
uint32 line = readl(0x1f80);
|
|
uint32 point1, point2;
|
|
int16 X1, Y1, Z1;
|
|
int16 X2, Y2, Z2;
|
|
uint8 Color;
|
|
|
|
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
|
|
if(bus.read(line) == 0xff && bus.read(line + 1) == 0xff) {
|
|
int32 tmp = line - 5;
|
|
while(bus.read(tmp + 2) == 0xff && bus.read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
|
|
point1 = (read(0x1f82) << 16) | (bus.read(tmp + 2) << 8) | bus.read(tmp + 3);
|
|
} else {
|
|
point1 = (read(0x1f82) << 16) | (bus.read(line) << 8) | bus.read(line + 1);
|
|
}
|
|
point2 = (read(0x1f82) << 16) | (bus.read(line + 2) << 8) | bus.read(line + 3);
|
|
|
|
X1=(bus.read(point1 + 0) << 8) | bus.read(point1 + 1);
|
|
Y1=(bus.read(point1 + 2) << 8) | bus.read(point1 + 3);
|
|
Z1=(bus.read(point1 + 4) << 8) | bus.read(point1 + 5);
|
|
X2=(bus.read(point2 + 0) << 8) | bus.read(point2 + 1);
|
|
Y2=(bus.read(point2 + 2) << 8) | bus.read(point2 + 3);
|
|
Z2=(bus.read(point2 + 4) << 8) | bus.read(point2 + 5);
|
|
Color = bus.read(line + 4);
|
|
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
|
|
}
|
|
}
|
|
|
|
void Cx4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
|
|
//Transform coordinates
|
|
C4WFXVal = (int16)X1;
|
|
C4WFYVal = (int16)Y1;
|
|
C4WFZVal = Z1;
|
|
C4WFScale = read(0x1f90);
|
|
C4WFX2Val = read(0x1f86);
|
|
C4WFY2Val = read(0x1f87);
|
|
C4WFDist = read(0x1f88);
|
|
C4TransfWireFrame2();
|
|
X1 = (C4WFXVal + 48) << 8;
|
|
Y1 = (C4WFYVal + 48) << 8;
|
|
|
|
C4WFXVal = (int16)X2;
|
|
C4WFYVal = (int16)Y2;
|
|
C4WFZVal = Z2;
|
|
C4TransfWireFrame2();
|
|
X2 = (C4WFXVal + 48) << 8;
|
|
Y2 = (C4WFYVal + 48) << 8;
|
|
|
|
//Get line info
|
|
C4WFXVal = (int16)(X1 >> 8);
|
|
C4WFYVal = (int16)(Y1 >> 8);
|
|
C4WFX2Val = (int16)(X2 >> 8);
|
|
C4WFY2Val = (int16)(Y2 >> 8);
|
|
C4CalcWireFrame();
|
|
X2 = (int16)C4WFXVal;
|
|
Y2 = (int16)C4WFYVal;
|
|
|
|
//Render line
|
|
for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
|
|
if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
|
|
uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
|
|
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
|
|
ram[addr + 0x300] &= ~bit;
|
|
ram[addr + 0x301] &= ~bit;
|
|
if(Color & 1) ram[addr + 0x300] |= bit;
|
|
if(Color & 2) ram[addr + 0x301] |= bit;
|
|
}
|
|
X1 += X2;
|
|
Y1 += Y2;
|
|
}
|
|
}
|
|
|
|
void Cx4::C4DoScaleRotate(int row_padding) {
|
|
int16 A, B, C, D;
|
|
|
|
//Calculate matrix
|
|
int32 XScale = readw(0x1f8f);
|
|
int32 YScale = readw(0x1f92);
|
|
|
|
if(XScale & 0x8000)XScale = 0x7fff;
|
|
if(YScale & 0x8000)YScale = 0x7fff;
|
|
|
|
if(readw(0x1f80) == 0) { //no rotation
|
|
A = (int16)XScale;
|
|
B = 0;
|
|
C = 0;
|
|
D = (int16)YScale;
|
|
} else if(readw(0x1f80) == 128) { //90 degree rotation
|
|
A = 0;
|
|
B = (int16)(-YScale);
|
|
C = (int16)XScale;
|
|
D = 0;
|
|
} else if(readw(0x1f80) == 256) { //180 degree rotation
|
|
A = (int16)(-XScale);
|
|
B = 0;
|
|
C = 0;
|
|
D = (int16)(-YScale);
|
|
} else if(readw(0x1f80) == 384) { //270 degree rotation
|
|
A = 0;
|
|
B = (int16)YScale;
|
|
C = (int16)(-XScale);
|
|
D = 0;
|
|
} else {
|
|
A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
|
|
B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
|
|
C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
|
|
D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
|
|
}
|
|
|
|
//Calculate Pixel Resolution
|
|
uint8 w = read(0x1f89) & ~7;
|
|
uint8 h = read(0x1f8c) & ~7;
|
|
|
|
//Clear the output RAM
|
|
memset(ram, 0, (w + row_padding / 4) * h / 2);
|
|
|
|
int32 Cx = (int16)readw(0x1f83);
|
|
int32 Cy = (int16)readw(0x1f86);
|
|
|
|
//Calculate start position (i.e. (Ox, Oy) = (0, 0))
|
|
//The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
|
|
//the function. We do Cx*A etc normally because the matrix parameters
|
|
//already have the fractional parts.
|
|
int32 LineX = (Cx << 12) - Cx * A - Cx * B;
|
|
int32 LineY = (Cy << 12) - Cy * C - Cy * D;
|
|
|
|
//Start loop
|
|
uint32 X, Y;
|
|
uint8 byte;
|
|
int32 outidx = 0;
|
|
uint8 bit = 0x80;
|
|
|
|
for(int32 y = 0; y < h; y++) {
|
|
X = LineX;
|
|
Y = LineY;
|
|
for(int32 x = 0; x < w; x++) {
|
|
if((X >> 12) >= w || (Y >> 12) >= h) {
|
|
byte = 0;
|
|
} else {
|
|
uint32 addr = (Y >> 12) * w + (X >> 12);
|
|
byte = read(0x600 + (addr >> 1));
|
|
if(addr & 1) { byte >>= 4; }
|
|
}
|
|
|
|
//De-bitplanify
|
|
if(byte & 1) ram[outidx ] |= bit;
|
|
if(byte & 2) ram[outidx + 1] |= bit;
|
|
if(byte & 4) ram[outidx + 16] |= bit;
|
|
if(byte & 8) ram[outidx + 17] |= bit;
|
|
|
|
bit >>= 1;
|
|
if(!bit) {
|
|
bit = 0x80;
|
|
outidx += 32;
|
|
}
|
|
|
|
X += A; //Add 1 to output x => add an A and a C
|
|
Y += C;
|
|
}
|
|
outidx += 2 + row_padding;
|
|
if(outidx & 0x10) {
|
|
outidx &= ~0x10;
|
|
} else {
|
|
outidx -= w * 4 + row_padding;
|
|
}
|
|
LineX += B; //Add 1 to output y => add a B and a D
|
|
LineY += D;
|
|
}
|
|
}
|
|
|
|
#endif
|