/*************************************************************************** cx4fn.c Code based on original work by zsKnight, anomie and Nach. This implementation is based on C++ "cx4*.cpp" by byuu. (up to date with source v 0.49). ***************************************************************************/ #include #define CX4_Tan(a) (CX4_CosTable[a] ? ((((INT32)CX4_SinTable[a]) << 16) / CX4_CosTable[a]) : 0x80000000) #define CX4_sar(b, n) ((b) >> (n)) #ifdef PI #undef PI #endif #define PI 3.1415926535897932384626433832795 //Wireframe Helpers static void CX4_C4TransfWireFrame(void) { cx4.c4x = (double)cx4.C4WFXVal; cx4.c4y = (double)cx4.C4WFYVal; cx4.c4z = (double)cx4.C4WFZVal - 0x95; //Rotate X cx4.tanval = -(double)cx4.C4WFX2Val * PI * 2 / 128; cx4.c4y2 = cx4.c4y * cos(cx4.tanval) - cx4.c4z * sin(cx4.tanval); cx4.c4z2 = cx4.c4y * sin(cx4.tanval) + cx4.c4z * cos(cx4.tanval); //Rotate Y cx4.tanval = -(double)cx4.C4WFY2Val * PI * 2 / 128; cx4.c4x2 = cx4.c4x * cos(cx4.tanval) + cx4.c4z2 * sin(cx4.tanval); cx4.c4z = cx4.c4x * -sin(cx4.tanval) + cx4.c4z2 * cos(cx4.tanval); //Rotate Z cx4.tanval = -(double)cx4.C4WFDist * PI * 2 / 128; cx4.c4x = cx4.c4x2 * cos(cx4.tanval) - cx4.c4y2 * sin(cx4.tanval); cx4.c4y = cx4.c4x2 * sin(cx4.tanval) + cx4.c4y2 * cos(cx4.tanval); //Scale cx4.C4WFXVal = (INT16)(cx4.c4x * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95); cx4.C4WFYVal = (INT16)(cx4.c4y * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95); } static void CX4_C4CalcWireFrame(void) { cx4.C4WFXVal = cx4.C4WFX2Val - cx4.C4WFXVal; cx4.C4WFYVal = cx4.C4WFY2Val - cx4.C4WFYVal; if(abs(cx4.C4WFXVal) > abs(cx4.C4WFYVal)) { cx4.C4WFDist = abs(cx4.C4WFXVal) + 1; cx4.C4WFYVal = (256 * (long)cx4.C4WFYVal) / abs(cx4.C4WFXVal); cx4.C4WFXVal = (cx4.C4WFXVal < 0) ? -256 : 256; } else if(cx4.C4WFYVal != 0) { cx4.C4WFDist = abs(cx4.C4WFYVal) + 1; cx4.C4WFXVal = (256 * (long)cx4.C4WFXVal) / abs(cx4.C4WFYVal); cx4.C4WFYVal = (cx4.C4WFYVal < 0) ? -256 : 256; } else { cx4.C4WFDist = 0; } } static void CX4_C4TransfWireFrame2(void) { cx4.c4x = (double)cx4.C4WFXVal; cx4.c4y = (double)cx4.C4WFYVal; cx4.c4z = (double)cx4.C4WFZVal; //Rotate X cx4.tanval = -(double)cx4.C4WFX2Val * PI * 2 / 128; cx4.c4y2 = cx4.c4y * cos(cx4.tanval) - cx4.c4z * sin(cx4.tanval); cx4.c4z2 = cx4.c4y * sin(cx4.tanval) + cx4.c4z * cos(cx4.tanval); //Rotate Y cx4.tanval = -(double)cx4.C4WFY2Val * PI * 2 / 128; cx4.c4x2 = cx4.c4x * cos(cx4.tanval) + cx4.c4z2 * sin(cx4.tanval); cx4.c4z = cx4.c4x * -sin(cx4.tanval) + cx4.c4z2 * cos(cx4.tanval); //Rotate Z cx4.tanval = -(double)cx4.C4WFDist * PI * 2 / 128; cx4.c4x = cx4.c4x2 * cos(cx4.tanval) - cx4.c4y2 * sin(cx4.tanval); cx4.c4y = cx4.c4x2 * sin(cx4.tanval) + cx4.c4y2 * cos(cx4.tanval); //Scale cx4.C4WFXVal = (INT16)(cx4.c4x * cx4.C4WFScale / 0x100); cx4.C4WFYVal = (INT16)(cx4.c4y * cx4.C4WFScale / 0x100); } static void CX4_C4DrawWireFrame(running_machine &machine) { UINT32 line = CX4_readl(0x1f80); UINT32 point1, point2; INT16 X1, Y1, Z1; INT16 X2, Y2, Z2; UINT8 Color; INT32 i; address_space &space = machine.device("maincpu")->space(AS_PROGRAM); for(i = cx4.ram[0x0295]; i > 0; i--, line += 5) { if(space.read_byte(line) == 0xff && space.read_byte(line + 1) == 0xff) { INT32 tmp = line - 5; while(space.read_byte(tmp + 2) == 0xff && space.read_byte(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; } point1 = (CX4_read(0x1f82) << 16) | (space.read_byte(tmp + 2) << 8) | space.read_byte(tmp + 3); } else { point1 = (CX4_read(0x1f82) << 16) | (space.read_byte(line) << 8) | space.read_byte(line + 1); } point2 = (CX4_read(0x1f82) << 16) | (space.read_byte(line + 2) << 8) | space.read_byte(line + 3); X1=(space.read_byte(point1 + 0) << 8) | space.read_byte(point1 + 1); Y1=(space.read_byte(point1 + 2) << 8) | space.read_byte(point1 + 3); Z1=(space.read_byte(point1 + 4) << 8) | space.read_byte(point1 + 5); X2=(space.read_byte(point2 + 0) << 8) | space.read_byte(point2 + 1); Y2=(space.read_byte(point2 + 2) << 8) | space.read_byte(point2 + 3); Z2=(space.read_byte(point2 + 4) << 8) | space.read_byte(point2 + 5); Color = space.read_byte(line + 4); CX4_C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color); } } static void CX4_C4DrawLine(INT32 X1, INT32 Y1, INT16 Z1, INT32 X2, INT32 Y2, INT16 Z2, UINT8 Color) { INT32 i; //Transform coordinates cx4.C4WFXVal = (INT16)X1; cx4.C4WFYVal = (INT16)Y1; cx4.C4WFZVal = Z1; cx4.C4WFScale = CX4_read(0x1f90); cx4.C4WFX2Val = CX4_read(0x1f86); cx4.C4WFY2Val = CX4_read(0x1f87); cx4.C4WFDist = CX4_read(0x1f88); CX4_C4TransfWireFrame2(); X1 = (cx4.C4WFXVal + 48) << 8; Y1 = (cx4.C4WFYVal + 48) << 8; cx4.C4WFXVal = (INT16)X2; cx4.C4WFYVal = (INT16)Y2; cx4.C4WFZVal = Z2; CX4_C4TransfWireFrame2(); X2 = (cx4.C4WFXVal + 48) << 8; Y2 = (cx4.C4WFYVal + 48) << 8; //Get line info cx4.C4WFXVal = (INT16)(X1 >> 8); cx4.C4WFYVal = (INT16)(Y1 >> 8); cx4.C4WFX2Val = (INT16)(X2 >> 8); cx4.C4WFY2Val = (INT16)(Y2 >> 8); CX4_C4CalcWireFrame(); X2 = (INT16)cx4.C4WFXVal; Y2 = (INT16)cx4.C4WFYVal; //Render line for(i = cx4.C4WFDist ? cx4.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); cx4.ram[addr + 0x300] &= ~bit; cx4.ram[addr + 0x301] &= ~bit; if(Color & 1) { cx4.ram[addr + 0x300] |= bit; } if(Color & 2) { cx4.ram[addr + 0x301] |= bit; } } X1 += X2; Y1 += Y2; } } static void CX4_C4DoScaleRotate(int row_padding) { INT16 A, B, C, D; INT32 x, y; //Calculate Pixel Resolution UINT8 w = CX4_read(0x1f89) & ~7; UINT8 h = CX4_read(0x1f8c) & ~7; INT32 Cx = (INT16)CX4_readw(0x1f83); INT32 Cy = (INT16)CX4_readw(0x1f86); INT32 LineX, LineY; UINT32 X, Y; UINT8 byte; INT32 outidx = 0; UINT8 bit = 0x80; //Calculate matrix INT32 XScale = CX4_readw(0x1f8f); INT32 YScale = CX4_readw(0x1f92); if(XScale & 0x8000) { XScale = 0x7fff; } if(YScale & 0x8000) { YScale = 0x7fff; } if(CX4_readw(0x1f80) == 0) { //no rotation A = (INT16)XScale; B = 0; C = 0; D = (INT16)YScale; } else if(CX4_readw(0x1f80) == 128) { //90 degree rotation A = 0; B = (INT16)(-YScale); C = (INT16)XScale; D = 0; } else if(CX4_readw(0x1f80) == 256) { //180 degree rotation A = (INT16)(-XScale); B = 0; C = 0; D = (INT16)(-YScale); } else if(CX4_readw(0x1f80) == 384) { //270 degree rotation A = 0; B = (INT16)YScale; C = (INT16)(-XScale); D = 0; } else { A = (INT16) CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15); B = (INT16)(-CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15)); C = (INT16) CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15); D = (INT16) CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15); } //Clear the output RAM memset(cx4.ram, 0, (w + row_padding / 4) * h / 2); //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. LineX = (Cx << 12) - Cx * A - Cx * B; LineY = (Cy << 12) - Cy * C - Cy * D; //Start loop for(y = 0; y < h; y++) { X = LineX; Y = LineY; for(x = 0; x < w; x++) { if((X >> 12) >= w || (Y >> 12) >= h) { byte = 0; } else { UINT32 addr = (Y >> 12) * w + (X >> 12); byte = CX4_read(0x600 + (addr >> 1)); if(addr & 1) { byte >>= 4; } } //De-bitplanify if(byte & 1) { cx4.ram[outidx ] |= bit; } if(byte & 2) { cx4.ram[outidx + 1] |= bit; } if(byte & 4) { cx4.ram[outidx + 16] |= bit; } if(byte & 8) { cx4.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; } }