summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/cx4fn.hxx
blob: 60b0adff0e49eff48cf924ff459ddb976be9466b (plain) (tree)
1
2
3
4
5
6
7
8
                   
                               




                                                                            
                                                           



                                                                            
                
                                                                                                          






                                            
                                       






                                                           

                                                                           


                                                           

                                                                             


                                                          

                                                                             

               

                                                                                             

 
                                     





















                                                                              
                                        






                                                           

                                                                           


                                                           

                                                                             


                                                          

                                                                             

               

                                                                  

 
                                                     
 





                                          


                                                       
                                                   
                                                          
                 
                                               
                                                                 

                                                                           



                                                           

                                                                                 



                                                           

                                                                              

                                                   

                                                                          













                                                       



                                                              
                                                                                                                 
 
                  

                               

                                    








                                         

                                   





                                      



                                           
                              

                                   





                                                                        

                                                                                                                                          















                                                             
                                                
 

                           

                                    

                                          
 

                                                
 




                              

                          

                                           











                                  
                                    

                      
                                    



                                         

                                       



                                         
                                       

                      
                                       



                                         

                                       



                      



                                                                                              


                              
                                                                    




















                                                                                
                                                                          



































                                                                       
// license:GPL-2.0+
// copyright-holders:byuu, Nach
/***************************************************************************

    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 <cmath>
#define CX4_Tan(a) (CX4_CosTable[a] ? ((((int32_t)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_t)(cx4.c4x * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95);
	cx4.C4WFYVal = (int16_t)(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_t)(cx4.c4x * cx4.C4WFScale / 0x100);
	cx4.C4WFYVal = (int16_t)(cx4.c4y * cx4.C4WFScale / 0x100);
}

static void CX4_C4DrawWireFrame(address_space &space)
{
	uint32_t line = CX4_readl(0x1f80);
	uint32_t point1, point2;
	int16_t X1, Y1, Z1;
	int16_t X2, Y2, Z2;
	uint8_t Color;
	int32_t i;

	for(i = cx4.ram[0x0295]; i > 0; i--, line += 5)
	{
		if(space.read_byte(line) == 0xff &&
			space.read_byte(line + 1) == 0xff)
		{
			int32_t 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_t X1, int32_t Y1, int16_t Z1, int32_t X2, int32_t Y2, int16_t Z2, uint8_t Color)
{
	int32_t i;

	//Transform coordinates
	cx4.C4WFXVal  = (int16_t)X1;
	cx4.C4WFYVal  = (int16_t)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_t)X2;
	cx4.C4WFYVal = (int16_t)Y2;
	cx4.C4WFZVal = Z2;
	CX4_C4TransfWireFrame2();
	X2 = (cx4.C4WFXVal + 48) << 8;
	Y2 = (cx4.C4WFYVal + 48) << 8;

	//Get line info
	cx4.C4WFXVal  = (int16_t)(X1 >> 8);
	cx4.C4WFYVal  = (int16_t)(Y1 >> 8);
	cx4.C4WFX2Val = (int16_t)(X2 >> 8);
	cx4.C4WFY2Val = (int16_t)(Y2 >> 8);
	CX4_C4CalcWireFrame();
	X2 = (int16_t)cx4.C4WFXVal;
	Y2 = (int16_t)cx4.C4WFYVal;

	//Render line
	for(i = cx4.C4WFDist ? cx4.C4WFDist : 1; i > 0; i--)
	{
		if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000)
		{
			uint16_t addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
			uint8_t 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_t A, B, C, D;
	int32_t x, y;

	//Calculate Pixel Resolution
	uint8_t w = CX4_read(0x1f89) & ~7;
	uint8_t h = CX4_read(0x1f8c) & ~7;

	int32_t Cx = (int16_t)CX4_readw(0x1f83);
	int32_t Cy = (int16_t)CX4_readw(0x1f86);

	int32_t LineX, LineY;
	uint32_t X, Y;
	uint8_t byte;
	int32_t outidx = 0;
	uint8_t bit    = 0x80;

	//Calculate matrix
	int32_t XScale = CX4_readw(0x1f8f);
	int32_t YScale = CX4_readw(0x1f92);

	if(XScale & 0x8000)
	{
		XScale = 0x7fff;
	}
	if(YScale & 0x8000)
	{
		YScale = 0x7fff;
	}

	if(CX4_readw(0x1f80) == 0)
	{ //no rotation
		A = (int16_t)XScale;
		B = 0;
		C = 0;
		D = (int16_t)YScale;
	}
	else if(CX4_readw(0x1f80) == 128)
	{ //90 degree rotation
		A = 0;
		B = (int16_t)(-YScale);
		C = (int16_t)XScale;
		D = 0;
	}
	else if(CX4_readw(0x1f80) == 256)
	{ //180 degree rotation
		A = (int16_t)(-XScale);
		B = 0;
		C = 0;
		D = (int16_t)(-YScale);
	}
	else if(CX4_readw(0x1f80) == 384)
	{ //270 degree rotation
		A = 0;
		B = (int16_t)YScale;
		C = (int16_t)(-XScale);
		D = 0;
	}
	else
	{
		A = (int16_t)  CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15);
		B = (int16_t)(-CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15));
		C = (int16_t)  CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15);
		D = (int16_t)  CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15);
	}

	//Clear the output RAM
	memset(cx4.ram, 0, (w + row_padding / 4) * unsigned(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_t 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;
	}
}