#include <stdio.h>
#include <types.h>
#include "rdpdump.h"

ulong 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_TMptr;				// Pointer in RDRAM of the current RDP texture map
uchar RDP_TMformat;				// Format (RGBA, YUV, CI, etc) of the current RDP texture map
uchar RDP_TMsize;				// Size (bit depth) of the current RDP texture map
ulong RDP_TMxsize, RDP_TMysize; // X and Y size (in pixels) of the current RDP texture map

ulong RDP_TRx1, RDP_TRy1;       // Top left screen coordinate of the current textured rectangle
ulong RDP_TRx2, RDP_TRy2;		// Bottom right screen coordinate of the current textured rectangle
ulong RDP_TRcmd0, RDP_TRcmd1, RDP_TRtile;

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_TLUTcount;			// Number of entries in the current palette.  (Theoretical max is 256.)

ulong RDP_SCx1, RDP_SCy1;       // Top left screen coordinate of the current scissor
ulong RDP_SCx2, RDP_SCy2;       // Bottom right screen coordinate of the current scissor

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

bool RDP_inTexRect;
FILE *fp;

char *formatLUT[5] = {
    "G_IM_FMT_RGBA",
    "G_IM_FMT_YUV",
    "G_IM_FMT_CI",
    "G_IM_FMT_IA",
    "G_IM_FMT_I"
};

char *sizeLUT[4] = {
    "G_IM_SIZ_4b",
    "G_IM_SIZ_8b",
    "G_IM_SIZ_16b",
    "G_IM_SIZ_32b"
};

char *cycleLUT[4] = {
    "G_CYC_1CYCLE",
    "G_CYC_2CYCLE",
    "G_CYC_COPY",
    "G_CYC_FILL"
};

char *tileLUT[8] = {
    "G_TX_RENDERTILE",
    "???",
    "???",
    "???",
    "???",
    "???",
    "???",
    "G_TX_LOADTILE"
};

void main(int argc, char **argv)
{
    FILE *ip;
    char buf[8];

    if (argc < 3)
    {
        printf("Usage: RDPDUMP <infile> <outfile>\n");
        return;
    }

    ip = fopen(argv[1], "rb");
    if (ip == NULL)
    {
        printf("Can't open %s!\n", argv[1]);
        return;
    }

    fp = fopen(argv[2], "wb");
    if (fp == NULL)
    {
        printf("Can't open %s!\n", argv[2]);
        return;
    }

    InitRDP();

    for (;;)
    {
        fread(buf, 1, 8, ip);
        if (feof(ip))
        {
            printf("Done!\n");
            fclose(ip);
            fclose(fp);
            return;
        }

        RDP_cmd[0] = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
        RDP_cmd[1] = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
        DoRDPEmulation();
    }
}

void InitRDP(void)
{
	RDP_FBformat = 0;
	RDP_FBsize   = 0;
	RDP_FBwidth  = 0;
	RDP_FBptr    = 0;

	RDP_inTexRect = FALSE;
}

void DoRDPEmulation(void)
{
	uchar cmd;

	// Check to see if this is the second half of G_TEXRECT...
	if (RDP_inTexRect)
	{
		RDP_TexRect_Continue();
		return;
	}

	// Nope, so grab the command and execute it.
	cmd = RDP_cmd[0] >> 24;
	if (cmd < 0xC0)
	{
		RDP_Unknown();
		return;
	}

	RDPCommandTable[cmd - 0xC0]();
}

void RDP_Unknown(void)
{
    fprintf(fp, "%08X %08X                    %02X: Unknown\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_NoOp(void)					// 0xC0
{
    fprintf(fp, "%08X %08X                    %02X: NoOp\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_TriFill(void)				// 0xC8
{
    fprintf(fp, "%08X %08X                    %02X: TriFill\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_TriFillZBuf(void)			// 0xC9
{
    fprintf(fp, "%08X %08X                    %02X: TriFillZBuf\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_TriTxtr(void)				// 0xCA
{
    fprintf(fp, "%08X %08X                    %02X: TriTxtr\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_TriTxtrZBuf(void)			// 0xCB
{
    fprintf(fp, "%08X %08X                    %02X: TriTxtrZBuf\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_TriShade(void)				// 0xCC
{
    fprintf(fp, "%08X %08X                    %02X: TriShade\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_TriShadeZBuf(void)			// 0xCD
{
    fprintf(fp, "%08X %08X                    %02X: TriShadeZBuf\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_TriShadeTxtr(void)			// 0xCE
{
    fprintf(fp, "%08X %08X                    %02X: TriShadeTxtr\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_TriShadeTxtrZBuf(void)		// 0xCF
{
    fprintf(fp, "%08X %08X                    %02X: TriShadeTxtrZBuf\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

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

	RDP_TRx2   = (RDP_cmd[0] & 0x00FFF000) >> 14;		// Truncate off .2 bit fractional and flip points
	RDP_TRy2   = (RDP_cmd[0] & 0x00000FFF) >> 2;
	RDP_TRx1   = (RDP_cmd[1] & 0x00FFF000) >> 14;
	RDP_TRy1   = (RDP_cmd[1] & 0x00000FFF) >> 2;
    RDP_TRtile = (RDP_cmd[1] & 0x07000000) >> 24;

    RDP_TRcmd0 = RDP_cmd[0];
    RDP_TRcmd1 = RDP_cmd[1];
}

void RDP_TexRect_Continue(void)		// 0xE4 [continued]
{
	ulong u, v, du, dv, temp;
	ulong srcptr, destptr, len;
	ushort col, yidx;
	uchar tidx;
	int x, y;

	RDP_inTexRect = FALSE;

	u  = (RDP_cmd[0] & 0xFFFF0000) >> 21;
	v  = (RDP_cmd[0] & 0x0000FFFF) >> 5;
	du = (RDP_cmd[1] & 0xFFFF0000) >> 26;
	dv = (RDP_cmd[1] & 0x0000FFFF) >> 10;

    fprintf(fp, "%08X %08X %08X %08X  %02X: TexRect -\n", RDP_TRcmd0, RDP_TRcmd1, RDP_cmd[0], RDP_cmd[1], RDP_TRcmd0 >> 24);
    fprintf(fp, "                                         x1=%d  y1=%d  tile=%d (%s)\n", RDP_TRx1, RDP_TRy1, RDP_TRtile, tileLUT[RDP_TRtile]);
    fprintf(fp, "                                         x2=%d  y2=%d\n", RDP_TRx2, RDP_TRy2);
    fprintf(fp, "                                         u=%d  v=%d  du=%d  dv=%d\n\n", u, v, du, dv);
}

void RDP_TexRectFlip(void)			// 0xE5
{
    fprintf(fp, "%08X %08X                    %02X: TexRectFlip\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_LoadSync(void)				// 0xE6
{
    fprintf(fp, "%08X %08X                    %02X: RDP Load Sync\n\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_PipeSync(void)				// 0xE7
{
    fprintf(fp, "%08X %08X                    %02X: RDP Pipe Sync\n\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_TileSync(void)				// 0xE8
{
    fprintf(fp, "%08X %08X                    %02X: RDP Tile Sync\n\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_FullSync(void)				// 0xE9
{
    fprintf(fp, "%08X %08X                    %02X: RDP Full Sync\n\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetKeyGB(void)				// 0xEA
{
    fprintf(fp, "%08X %08X                    %02X: SetKey GB\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetKeyR(void)				// 0xEB
{
    fprintf(fp, "%08X %08X                    %02X: SetKey R\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetConvert(void)			// 0xEC
{
    fprintf(fp, "%08X %08X                    %02X: Set Convert\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetScissor(void)			// 0xED
{
    RDP_SCx1 = (RDP_cmd[0] & 0x00FFF000) >> 14;
    RDP_SCy1 = (RDP_cmd[0] & 0x00000FFF) >> 2;
    RDP_SCx2 = (RDP_cmd[1] & 0x00FFF000) >> 14;
    RDP_SCy2 = (RDP_cmd[1] & 0x00000FFF) >> 2;

    fprintf(fp, "%08X %08X                    %02X: Set Scissor -\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
    fprintf(fp, "                                         x1=%d  y1=%d  x2=%d  y2=%d\n\n", RDP_SCx1, RDP_SCy1, RDP_SCx2, RDP_SCy2);
}

void RDP_SetPrimDepth(void)			// 0xEE
{
    fprintf(fp, "%08X %08X                    %02X: Set PrimDepth\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetOtherMode(void)			// 0xEF
{
    int cycle;

    cycle = (RDP_cmd[0] & 0x00300000) >> 20;

    fprintf(fp, "%08X %08X                    %02X: Set Other Mode -\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
    fprintf(fp, "                                         cycle=%d (%s)\n\n", cycle, cycleLUT[cycle]);
}

void RDP_LoadTLUT(void)				// 0xF0
{
    int count, tile;

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

    fprintf(fp, "%08X %08X                    %02X: Load TLUT (palette) -\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
    fprintf(fp, "                                         tile=%d (%s)  count=%d\n\n", tile, tileLUT[tile], count);
}

void RDP_SetTileSize(void)			// 0xF2
{
    ulong sl, tl, tile, sh, th;

    sl   = (RDP_cmd[0] & 0x00FFF000) >> 14;
    tl   = (RDP_cmd[0] & 0x00000FFF) >> 2;
    tile = (RDP_cmd[1] & 0x07000000) >> 24;
	sh   = (RDP_cmd[1] & 0x00FFF000) >> 14;
	th   = (RDP_cmd[1] & 0x00000FFF) >> 2;

    fprintf(fp, "%08X %08X                    %02X: Set Tile Size -\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
    fprintf(fp, "                                         u1=%d  v1=%d  tile=%d (%s)\n", sl, tl, tile, tileLUT[tile]);
    fprintf(fp, "                                         u2=%d  v2=%d\n\n", sh, th);
}

void RDP_LoadBlock(void)			// 0xF3
{
    ulong uls, ult, tile, lrs, dxt;

    uls  = (RDP_cmd[0] & 0x00FFF000) >> 14;
    ult  = (RDP_cmd[0] & 0x00000FFF) >> 2;
    tile = (RDP_cmd[1] & 0x07000000) >> 24;
	lrs  = (RDP_cmd[1] & 0x00FFF000) >> 14;
	dxt  = (RDP_cmd[1] & 0x00000FFF) >> 2;

    fprintf(fp, "%08X %08X                    %02X: Load Block -\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
    fprintf(fp, "                                         uls=%d  ult=%d  tile=%d (%s)\n", uls, ult, tile, tileLUT[tile]);
    fprintf(fp, "                                         lrs=%d  dxt=%d\n\n", lrs, dxt);
}

void RDP_LoadTile(void)				// 0xF4
{
    ulong sl, tl, tile, sh, th;

    sl   = (RDP_cmd[0] & 0x00FFF000) >> 14;
    tl   = (RDP_cmd[0] & 0x00000FFF) >> 2;
    tile = (RDP_cmd[1] & 0x07000000) >> 24;
	sh   = (RDP_cmd[1] & 0x00FFF000) >> 14;
	th   = (RDP_cmd[1] & 0x00000FFF) >> 2;

    fprintf(fp, "%08X %08X                    %02X: Load Tile -\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
    fprintf(fp, "                                         x1=%d  y1=%d  tile=%d (%s)\n", sl, tl, tile, tileLUT[tile]);
    fprintf(fp, "                                         x2=%d  y2=%d\n\n", sh, th);
}

void RDP_SetTile(void)				// 0xF5
{
    ulong fmt, siz, line, tmem, tile, palette;
    ulong ct, mt, maskt, shiftt;
    ulong cs, ms, masks, shifts;

    fmt     = (RDP_cmd[0] & 0x00E00000) >> 21;
    siz     = (RDP_cmd[0] & 0x00180000) >> 19;
    line    = (RDP_cmd[0] & 0x0003FE00) >> 9;
    tmem    = (RDP_cmd[0] & 0x000001FF);
    tile    = (RDP_cmd[1] & 0x07000000) >> 24;
    palette = (RDP_cmd[1] & 0x00F00000) >> 20;
    ct      = (RDP_cmd[1] & 0x00080000) >> 19;
    mt      = (RDP_cmd[1] & 0x00040000) >> 18;
    maskt   = (RDP_cmd[1] & 0x0003C000) >> 14;
    shiftt  = (RDP_cmd[1] & 0x00003C00) >> 10;
    cs      = (RDP_cmd[1] & 0x00000200) >> 9;
    ms      = (RDP_cmd[1] & 0x00000100) >> 8;
    masks   = (RDP_cmd[1] & 0x000000F0) >> 4;
    shifts  = (RDP_cmd[1] & 0x0000000F);

    fprintf(fp, "%08X %08X                    %02X: Set Tile -\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
    fprintf(fp, "                                         fmt=%d (%s)\n", fmt, formatLUT[fmt]);
    fprintf(fp, "                                         siz=%d (%s)  line?=%d\n", siz, sizeLUT[siz], line);
    fprintf(fp, "                                         tmem=%d  tile=%d (%s)\n", tmem, tile, tileLUT[tile]);
    fprintf(fp, "                                         palette?=%d\n", palette);
    fprintf(fp, "                                         ct?=%d  mt?=%d  maskt?=%d  shiftt?=%d\n", ct, mt, maskt, shiftt);
    fprintf(fp, "                                         cs?=%d  ms?=%d  masks?=%d  shifts?=%d\n\n", cs, ms, masks, shifts);
}

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

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

    fprintf(fp, "%08X %08X                    %02X: Fill Rectangle\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

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

    fprintf(fp, "%08X %08X                    %02X: Set Fill Color\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetFogColor(void)			// 0xF8
{
    fprintf(fp, "%08X %08X                    %02X: Set Fog Color\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetBlendColor(void)		// 0xF9
{
    fprintf(fp, "%08X %08X                    %02X: Set Blend Color\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetPrimColor(void)			// 0xFA
{
    fprintf(fp, "%08X %08X                    %02X: Set Prim Color\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetEnvColor(void)			// 0xFB
{
    fprintf(fp, "%08X %08X                    %02X: Set Env Color\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetCombine(void)			// 0xFC
{
    fprintf(fp, "%08X %08X                    %02X: Set Combine\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

void RDP_SetTImg(void)				// 0xFD
{
	RDP_TMformat = (RDP_cmd[0] & 0x00E00000) >> 21;
	RDP_TMsize   = (RDP_cmd[0] & 0x00180000) >> 19;
	RDP_TMptr    = RDP_cmd[1];

    fprintf(fp, "\n");
    fprintf(fp, "----------------------------------------------------------------------------\n");
    fprintf(fp, "\n");
    fprintf(fp, "%08X %08X                    %02X: Set TImg (texture map) -\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
    fprintf(fp, "                                         fmt=%d (%s)\n", RDP_TMformat, formatLUT[RDP_TMformat]);
    fprintf(fp, "                                         siz=%d (%s)\n", RDP_TMsize, sizeLUT[RDP_TMsize]);
    fprintf(fp, "                                         tmap=%08X\n\n", RDP_TMptr);
}

void RDP_SetZImg(void)				// 0xFE
{
    fprintf(fp, "%08X %08X                    %02X: Set ZImg (Z-buffer)\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
}

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];

    fprintf(fp, "%08X %08X                    %02X: Set CImg (frame buffer) -\n", RDP_cmd[0], RDP_cmd[1], RDP_cmd[0] >> 24);
    fprintf(fp, "                                         fmt=%d (%s)\n", RDP_FBformat, formatLUT[RDP_FBformat]);
    fprintf(fp, "                                         siz=%d (%s)  width=%d\n", RDP_FBsize, sizeLUT[RDP_FBsize], RDP_FBwidth);
    fprintf(fp, "                                         framebuf=%08X\n\n", RDP_FBptr);
}

