//
// Project UnReality: The First Nintendo 64 Emulator
// Copyright (C) 1997-1998, Cold Fusion Entertainment
// All rights reserved
//
// This source code is unpublished propietary information of Cold Fusion Entertainment.  No portion of this software
// may be disclosed to any third party or copied or duplicated in any form, in whole or in part, without the prior
// written consent of Cold Fusion Entertainment.
// 

//
// $Log: rdp.cpp $
// Revision 1.6  1998/05/24 05:59:02  BREAKPOINT
// Fixed lots of bugs, implemented multiple tile sets, added initial decoding for RSP set other mode, and created a function table
// for Textured Rectangle drawing.
// Revision 1.5  1998/05/23 15:42:25  BREAKPOINT
// Fixed up processing of RDP commands, and corrected sprite drawing routines.
// Revision 1.4  1998/05/18 01:27:41  BREAKPOINT
// Added RDP dumper, and fixed minor bug in TexRect.
// Revision 1.3  1998/05/16 02:50:44  BREAKPOINT
// Fixed small bug in RDP where initializing would (potentially) execute an unknown RDP command.
// Revision 1.2  1998/05/14 20:12:32  BREAKPOINT
// Added transparency/alpha blending, and fill color/draw filled rectangle.
// Revision 1.1  1998/05/14 01:24:28  BREAKPOINT
// Initial revision
//

static char *rcsid = "$Id: rdp.cpp 1.6 1998/05/24 05:59:02 BREAKPOINT Exp $";

//---------------------------------------------------------------------------------------------------------------------

#define NO_EXTERN_RDP
#include <types.h>
#include "rdp.h"
#include "emu.h"
#include "mmio.h"
#include "unreal.h"
#include "r4300i.h"

#include "inline.cpp"

ulong RDP_offs, RDP_cmd[2];
uchar RDP_FBformat;				// Format of the RDP's frame buffer
uchar RDP_FBsize;				// Size (bit depth) of the RDP's frame buffer
ulong RDP_FBwidth;				// X size (in pixels) of the RDP's frame buffer
ulong RDP_FBptr;				// Pointer in RDRAM of the RDP's frame buffer

ulong RDP_TIptr;				// Pointer in RDRAM to the current texture image (holder for TLUT)
uchar RDP_TIformat;				// Format of the current texture image (holder for TLUT)
uchar RDP_TIsize;				// Size (bit depth) of the current texture image (holder for TLUT)

RDP_TileDef RDP_TM[8];			// Tile definitions for all 8 texture maps

int RDP_TRtile;					// Tile index to use for the current textured rectangle
Fixed32 RDP_TRx1, RDP_TRy1;		// Top left screen coordinate of the current textured rectangle
Fixed32 RDP_TRx2, RDP_TRy2;		// Bottom right screen coordinate of the current textured rectangle

ulong RDP_TLUTptr;				// Pointer in RDRAM to the current palette to use for texture lookup
uchar RDP_TLUTformat;			// Format of the current palette
uchar RDP_TLUTsize;				// Size (bit depth) of the current palette

ulong RDP_COLfill;				// The current fill color for the RDP (2x 16 bit RGBA)

int RDP_OMcycle;				// Current cycle mode for the RDP

bool RDP_inTexRect;

//#define RDP_DUMPER
#ifdef RDP_DUMPER

void DumpRDP(void)
{
	FILE *fp;
	static int count = 0;
	char buf[256];
	uchar cmd;

	sprintf(buf, "RDP%05d.DMP", count);

	fp = fopen(buf, "r+b");
	if (fp == NULL) fp = fopen(buf, "wb");
	fseek(fp, 0, 2);

	buf[0] = RDP_cmd[0] >> 24;
	buf[1] = RDP_cmd[0] >> 16;
	buf[2] = RDP_cmd[0] >> 8;
	buf[3] = RDP_cmd[0];
	buf[4] = RDP_cmd[1] >> 24;
	buf[5] = RDP_cmd[1] >> 16;
	buf[6] = RDP_cmd[1] >> 8;
	buf[7] = RDP_cmd[1];
	fwrite(buf, 1, 8, fp);

	if ((RDP_cmd[0] >> 24) == 0xE9) count++;
	fclose(fp);
}

#endif

void InitRDP(void)
{
	RDP_inTexRect = FALSE;
}

void DoRDPEmulation(void)
{
	uchar cmd;

	// Check first to see if this was an RDP display list init (start == end).  If so, don't do anything...
	if (dpcreg.start == dpcreg.end) return;

	// Note we're using the RSP's memory calls... the RDP emulation is secretly hidden in the RSP's emulation code.
	RDP_offs   = dpcreg.end - 0x08;
	RDP_cmd[0] = RSP_Read32(RDP_offs);
	RDP_cmd[1] = RSP_Read32(RDP_offs + 0x04);

	// Check to see if this is the second half of G_TEXRECT...
	if (RDP_inTexRect)
		RDP_TexRect_Continue();
	else
	{
		// Nope, so grab the command and execute it.
		cmd = RDP_cmd[0] >> 24;

		if (cmd < 0xC0)
			RDP_Unknown();
		else
			RDPCommandTable[cmd - 0xC0]();
	}

#ifdef RDP_DUMPER
	DumpRDP();
#endif

	// Advance 'current' pointer.
	dpcreg.current = dpcreg.end;
}

void RDP_Unknown(void)
{
//	MessageBox(NULL, "Unknown RDP command!", NULL, MB_OK);
}

void RDP_NoOp(void)					// 0xC0
{
	// Do nothing!
}

void RDP_TriFill(void)				// 0xC8
{
}

void RDP_TriFillZBuf(void)			// 0xC9
{
}

void RDP_TriTxtr(void)				// 0xCA
{
}

void RDP_TriTxtrZBuf(void)			// 0xCB
{
}

void RDP_TriShade(void)				// 0xCC
{
}

void RDP_TriShadeZBuf(void)			// 0xCD
{
}

void RDP_TriShadeTxtr(void)			// 0xCE
{
}

void RDP_TriShadeTxtrZBuf(void)		// 0xCF
{
}

void RDP_TexRect(void)				// 0xE4
{
	RDP_inTexRect = TRUE;

	RDP_TRx2 = S10p2_TO_FIXED((RDP_cmd[0] & 0x00FFF000) >> 12);
	RDP_TRy2 = S10p2_TO_FIXED((RDP_cmd[0] & 0x00000FFF));
	RDP_TRx1 = S10p2_TO_FIXED((RDP_cmd[1] & 0x00FFF000) >> 12);
	RDP_TRy1 = S10p2_TO_FIXED((RDP_cmd[1] & 0x00000FFF));

    RDP_TRtile = (RDP_cmd[1] & 0x07000000) >> 24;
}

void RDP_TexRect_Continue(void)		// 0xE4 [continued]
{
	Fixed32 u, v, du, dv;

	RDP_inTexRect = FALSE;
	u  = S5p10_TO_FIXED((RDP_cmd[0] & 0xFFFF0000) >> 16);
	v  = S5p10_TO_FIXED((RDP_cmd[0] & 0x0000FFFF));
	du = S5p10_TO_FIXED((RDP_cmd[1] & 0xFFFF0000) >> 16);
	dv = S5p10_TO_FIXED((RDP_cmd[1] & 0x0000FFFF));

	// Fixup delta U if in COPY mode.
	if (RDP_OMcycle == G_CYC_COPY) du >>= 2;

	// Blast the rectangle...
	RDP_DrawTexRect[RDP_FBsize - 2][RDP_TM[RDP_TRtile].format][RDP_TM[RDP_TRtile].size](u, v, du, dv);
}

void RDP_TexRectFlip(void)			// 0xE5
{
}

void RDP_LoadSync(void)				// 0xE6
{
}

void RDP_PipeSync(void)				// 0xE7
{
}

void RDP_TileSync(void)				// 0xE8
{
}

void RDP_FullSync(void)				// 0xE9
{
    // Stop the R4300i so we can add an event to the heap...
    running = FALSE;
    WaitForSingleObject(hDebugEvent, INFINITE);

	// Generate an RDP interrupt!
	EventAdd_DP();

    // Fire the R4300i back up.
    running = TRUE;
    SetEvent(hRunEvent);
}

void RDP_SetKeyGB(void)				// 0xEA
{
}

void RDP_SetKeyR(void)				// 0xEB
{
}

void RDP_SetConvert(void)			// 0xEC
{
}

void RDP_SetScissor(void)			// 0xED
{
}

void RDP_SetPrimDepth(void)			// 0xEE
{
}

void RDP_SetOtherMode(void)			// 0xEF
{
	RDP_OMcycle = (RDP_cmd[0] & 0x00300000) >> 20;
}

void RDP_LoadTLUT(void)				// 0xF0
{
	// Load texture lookup table (for palettes).  Use current texture map pointer for the TLUT information.
	RDP_TLUTptr    = RDP_TIptr;
	RDP_TLUTformat = RDP_TIformat;
	RDP_TLUTsize   = RDP_TIsize;
}

void RDP_SetTileSize(void)			// 0xF2
{
	int tile;

	tile = (RDP_cmd[1] & 0x07000000) >> 24;
	RDP_TM[tile].u1 = S10p2_TO_FIXED((RDP_cmd[0] & 0x00FFF000) >> 12);
	RDP_TM[tile].v1 = S10p2_TO_FIXED((RDP_cmd[0] & 0x00000FFF));
	RDP_TM[tile].u2 = S10p2_TO_FIXED((RDP_cmd[1] & 0x00FFF000) >> 12);
	RDP_TM[tile].v2 = S10p2_TO_FIXED((RDP_cmd[1] & 0x00000FFF));
}

void RDP_LoadBlock(void)			// 0xF3
{
}

void RDP_LoadTile(void)				// 0xF4
{
}

void RDP_SetTile(void)				// 0xF5
{
	int tile;

    tile = (RDP_cmd[1] & 0x07000000) >> 24;

    RDP_TM[tile].format   = ((RDP_cmd[0] & 0x00E00000) >> 21);
    RDP_TM[tile].size     = ((RDP_cmd[0] & 0x00180000) >> 19);
    RDP_TM[tile].xsize    = ((RDP_cmd[0] & 0x0003FE00) >>  9) << 3;
    RDP_TM[tile].offset   = ((RDP_cmd[0] & 0x000001FF)      ) << 3;
    RDP_TM[tile].palette  = ((RDP_cmd[1] & 0x00F00000) >> 20);
    RDP_TM[tile].clamp_u  = ((RDP_cmd[1] & 0x00000200) >>  9);
    RDP_TM[tile].clamp_v  = ((RDP_cmd[1] & 0x00080000) >> 19);
    RDP_TM[tile].mirror_u = ((RDP_cmd[1] & 0x00000100) >>  8);
    RDP_TM[tile].mirror_v = ((RDP_cmd[1] & 0x00040000) >> 18);
    RDP_TM[tile].wrap_u   = 1 << ((RDP_cmd[1] & 0x000000F0) >>  4);
	RDP_TM[tile].wrap_v   = 1 << ((RDP_cmd[1] & 0x0003C000) >> 14);

	// Check for clamping if wraps are zero.
	if ((RDP_TM[tile].wrap_u == 0) && (RDP_TM[tile].wrap_v == 0))
	{
		RDP_TM[tile].clamp_u = TRUE;
		RDP_TM[tile].clamp_v = TRUE;
	}

//    shiftt = ((RDP_cmd[1] & 0x00003C00) >> 10);
//    shifts = ((RDP_cmd[1] & 0x0000000F));
}

void RDP_FillRect(void)				// 0xF6
{
	int x1, y1, x2, y2;
	ulong xlen, ylen;
	ulong destptr, x;

	// Extract coordinates.
	x1 = ROUND_FIXED_TO_INT(S10p2_TO_FIXED((RDP_cmd[1] & 0x00FFF000) >> 12));
	y1 = ROUND_FIXED_TO_INT(S10p2_TO_FIXED((RDP_cmd[1] & 0x00000FFF)));
	x2 = ROUND_FIXED_TO_INT(S10p2_TO_FIXED((RDP_cmd[0] & 0x00FFF000) >> 12));
	y2 = ROUND_FIXED_TO_INT(S10p2_TO_FIXED((RDP_cmd[0] & 0x00000FFF)));

	// Calculate lengths.
	xlen = (x2 - x1) + 1;
	ylen = (y2 - y1) + 1;

	// If drawing to a 16-bit CFB, only fill half as many X's...
	if (RDP_FBwidth == G_IM_SIZ_16b) xlen >>= 1;

	// Blast out the rectangle...
	while (ylen--)
	{
		destptr = RDP_FBptr + (((RDP_FBwidth * y1) + x1) * RDP_FBsize);

		x = xlen;
		while (x--)
		{
			RSP_Write32(destptr, RDP_COLfill);
			destptr += 4;
		}

		y1++;
	}
}

void RDP_SetFillColor(void)			// 0xF7
{
	RDP_COLfill = RDP_cmd[1];
}

void RDP_SetFogColor(void)			// 0xF8
{
}

void RDP_SetBlendColor(void)		// 0xF9
{
}

void RDP_SetPrimColor(void)			// 0xFA
{
}

void RDP_SetEnvColor(void)			// 0xFB
{
}

void RDP_SetCombine(void)			// 0xFC
{
}

void RDP_SetTImg(void)				// 0xFD
{
	RDP_TIformat = (RDP_cmd[0] & 0x00E00000) >> 21;
	RDP_TIsize   = (RDP_cmd[0] & 0x00180000) >> 19;
	RDP_TIptr    = RDP_cmd[1];
}

void RDP_SetZImg(void)				// 0xFE
{
}

void RDP_SetCImg(void)				// 0xFF
{
	RDP_FBformat = (RDP_cmd[0] & 0x00E00000) >> 21;
	RDP_FBsize   = (RDP_cmd[0] & 0x00180000) >> 19;
	RDP_FBwidth  = (RDP_cmd[0] & 0x00000FFF) + 1;
	RDP_FBptr    = RDP_cmd[1];
}

// *******************************************************************************************************
// *******************************************************************************************************
//
//                                     Textured Rectangle Drawing
//
// *******************************************************************************************************
// *******************************************************************************************************

void DTR16_RGBA16(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
	ulong base_src, base_dest;
	Fixed32 srcptr, my_srcptr, srcptr_du, srcptr_dv, maxsrcptr_u, maxsrcptr_v, maxsrcptr_u_add;
	ulong destptr, my_destptr, destptr_du, destptr_dv;
	RDP_TileDef *tile_ptr;
	int xlen, ylen, my_xlen;
	ushort col;

	// Get a pointer to the current tile descriptor.
	tile_ptr = &RDP_TM[RDP_TRtile];

	// Setup initial source and destination base values (for quick adding later).
	base_src  = RDP_TIptr + tile_ptr->offset;
	base_dest = RDP_FBptr + (((RDP_FBwidth * ROUND_FIXED_TO_INT(RDP_TRy1)) + ROUND_FIXED_TO_INT(RDP_TRx1)) << 1);

	// Setup initial pointers.
	srcptr  = FixedMul(INT_TO_FIXED(tile_ptr->xsize), v) + FixedMul(u, INT_TO_FIXED(2));
	destptr = 0;

	// Fixup U and Vs to match clamped values (if applicable).
	if (tile_ptr->clamp_u)
	{
		if (u > tile_ptr->u1) u = tile_ptr->u1;
		maxsrcptr_u_add = INT_TO_FIXED(ROUND_FIXED_TO_INT(tile_ptr->u2) * 2);		// *2 for 16-bit CFB.
	}

	if (tile_ptr->clamp_v)
	{
		if (v > tile_ptr->v1) v = tile_ptr->v1;
		maxsrcptr_v = srcptr + INT_TO_FIXED(tile_ptr->xsize * ROUND_FIXED_TO_INT(tile_ptr->v2));
	}

	// Finally, setup lengths and deltas.
	xlen = (ROUND_FIXED_TO_INT(RDP_TRx2 - RDP_TRx1)) + 1;
	ylen = (ROUND_FIXED_TO_INT(RDP_TRy2 - RDP_TRy1)) + 1;

	srcptr_du  = FixedMul(du, INT_TO_FIXED(2));
	srcptr_dv  = FixedMul(INT_TO_FIXED(tile_ptr->xsize), dv);
	destptr_du = 2;
	destptr_dv = RDP_FBwidth << 1;

	// Draw it!
	while (ylen--)
	{
		my_xlen     = xlen;
		my_srcptr   = srcptr;
		my_destptr  = destptr;
		maxsrcptr_u = srcptr + maxsrcptr_u_add;

		while (my_xlen--)
		{
			// Read 16 bit texel.
			col = RSP_Read16(base_src + FIXED_TO_INT(my_srcptr));

			// Blast out color to frame buffer only if this texel has its alpha bit set.
			if (col & 1) RSP_Write16(base_dest + my_destptr, col);

			// Increment pointers.
			my_srcptr  += srcptr_du;
			my_destptr += destptr_du;

			// Check clamping.
			if ((tile_ptr->clamp_u) && (my_srcptr > maxsrcptr_u)) my_srcptr = maxsrcptr_u;
		}

		srcptr  += srcptr_dv;
		destptr += destptr_dv;

		// Check clamping.
		if ((tile_ptr->clamp_v) && (srcptr > maxsrcptr_v)) srcptr = maxsrcptr_v;
	}
}

void DTR16_RGBA32(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR16_YUV16(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR16_YUV32(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR16_CI(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
	ulong base_src, base_dest;
	Fixed32 srcptr, my_srcptr, srcptr_du, srcptr_dv, maxsrcptr_u, maxsrcptr_v, maxsrcptr_u_add;
	ulong destptr, my_destptr, destptr_du, destptr_dv;
	RDP_TileDef *tile_ptr;
	int xlen, ylen, my_xlen;
	ushort col;
	uchar tidx;

/*******************************
  Right now, only 8 bit CI is supported... this needs to be able to do 4 bit CI as well, and the
  switch() below is ugly -- it should be replaced with a nice function pointer array.
********************************/

	// Get a pointer to the current tile descriptor.
	tile_ptr = &RDP_TM[RDP_TRtile];

	// Setup initial source and destination base values (for quick adding later).
	base_src  = RDP_TIptr + tile_ptr->offset;
	base_dest = RDP_FBptr + (((RDP_FBwidth * ROUND_FIXED_TO_INT(RDP_TRy1)) + ROUND_FIXED_TO_INT(RDP_TRx1)) << 1);

	// Setup initial pointers.
	srcptr  = FixedMul(INT_TO_FIXED(tile_ptr->xsize), v) + u;
	destptr = 0;

	// Fixup U and Vs to match clamped values (if applicable).
	if (tile_ptr->clamp_u)
	{
		if (u > tile_ptr->u1) u = tile_ptr->u1;
		maxsrcptr_u_add = INT_TO_FIXED(ROUND_FIXED_TO_INT(tile_ptr->u2));
	}

	if (tile_ptr->clamp_v)
	{
		if (v > tile_ptr->v1) v = tile_ptr->v1;
		maxsrcptr_v = srcptr + INT_TO_FIXED(tile_ptr->xsize * ROUND_FIXED_TO_INT(tile_ptr->v2));
	}

	// Finally, setup lengths and deltas.
	xlen = (ROUND_FIXED_TO_INT(RDP_TRx2 - RDP_TRx1)) + 1;
	ylen = (ROUND_FIXED_TO_INT(RDP_TRy2 - RDP_TRy1)) + 1;

	srcptr_du  = du;
	srcptr_dv  = FixedMul(INT_TO_FIXED(tile_ptr->xsize), dv);
	destptr_du = 2;
	destptr_dv = RDP_FBwidth << 1;

	// Draw it!
	switch (RDP_TLUTsize)
	{
		case G_IM_SIZ_16b:
			while (ylen--)
			{
				my_xlen     = xlen;
				my_srcptr   = srcptr;
				my_destptr  = destptr;
				maxsrcptr_u = srcptr + maxsrcptr_u_add;

				while (my_xlen--)
				{
					// Read 8 bit texel.
					tidx = RSP_Read8(base_src + FIXED_TO_INT(my_srcptr));

					// Lookup texel into a 16 bit RGBA TLUT.
					col = RSP_Read16(RDP_TLUTptr + (tidx << 1));

					// Blast out color to frame buffer only if this texel has its alpha bit set.
					if (col & 1) RSP_Write16(base_dest + my_destptr, col);

					// Increment pointers.
					my_srcptr  += srcptr_du;
					my_destptr += destptr_du;

					// Check clamping.
					if ((tile_ptr->clamp_u) && (my_srcptr > maxsrcptr_u)) my_srcptr = maxsrcptr_u;
				}

				srcptr  += srcptr_dv;
				destptr += destptr_dv;

				// Check clamping.
				if ((tile_ptr->clamp_v) && (srcptr > maxsrcptr_v)) srcptr = maxsrcptr_v;
			}
			break;

		case G_IM_SIZ_32b:
			break;
	}
}

void DTR16_IA(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR16_I(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR32_RGBA16(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR32_RGBA32(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR32_YUV16(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR32_YUV32(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR32_CI(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR32_IA(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}

void DTR32_I(Fixed32 u, Fixed32 v, Fixed32 du, Fixed32 dv)
{
}
