/*----------------------------------------------------------------------------------*/
#define _KM_USE_VERTEX_MACRO_L4_
#include <shinobi.h>
#include <kamui2.h>
#include <km2util.h>
#include <string.h>
#include <stdlib.h>
#include "dispstrex.h"
#include "command.h"
#include "km2kamuix.h"

extern const unsigned char character[];

static KMSTRIPHEAD kmiStripHead16;
static PROCESSHANDLE hProcessDp;
static KMSURFACEDESC sTexSurface;
static DWORD VMAP[80][30];
static void *pMem;
static DWORD cnt;
static DWORD busy;
static int Size;
static int Type;
static PDS_PERIPHERAL *per;

static void Dump( DWORD adrs, int line, int type );
static void DpMessage(PKMVOID hProcess, PDCXMESSAGE pMessage );
/*----------------------------------------------------------------------------------*/
void DpCommand(int argc, char *argv[])
{
	KMSTRIPCONTEXT kmiContext16;

	if (busy) return;

	if (argc==1) {
		PRINTOUT(("ld <filename>\n"));
		return;
	}
	Size = fsGetFileSize( argv[1] );
	if (Size==0) {
		PRINTOUT(("%s is not found.\n", argv[1]));
		return;
	}

	busy = 1;
	pMem = syMalloc(Size);
	fsLoadFile( argv[1], pMem, Size );

	kmCreateTextureSurface(
		&sTexSurface,
		128,128,
		KM_TEXTURE_ARGB1555 | KM_TEXTURE_VQ
	);
	kmLoadTexture(
		&sTexSurface,
		&character
	);

	memset(&kmiContext16,0,sizeof(KMSTRIPCONTEXT));
	kmiContext16.nSize = sizeof(kmiContext16);
	kmiContext16.StripControl.nListType								= KM_TRANS_POLYGON;
	kmiContext16.StripControl.nUserClipMode	 						= KM_USERCLIP_INSIDE;
	kmiContext16.StripControl.nShadowMode		 					= KM_NORMAL_POLYGON;
	kmiContext16.StripControl.bOffset								= KM_FALSE;
 	kmiContext16.StripControl.bGouraud		 						= KM_TRUE;
	kmiContext16.ObjectControl.nDepthCompare			 			= KM_ALWAYS;
	kmiContext16.ObjectControl.nCullingMode			 				= KM_NOCULLING;
	kmiContext16.ObjectControl.bZWriteDisable						= KM_FALSE;
	kmiContext16.ObjectControl.bDCalcControl			 			= KM_FALSE;
	kmiContext16.type.splite.Base.dwPacked							= 0xffffffff;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].nSRCBlendingMode		= KM_SRCALPHA;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].nDSTBlendingMode		= KM_INVSRCALPHA;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].bSRCSelect			= KM_FALSE;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].bDSTSelect			= KM_FALSE;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].nFogMode				= KM_NOFOG;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].bColorClamp			= KM_FALSE;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].bUseAlpha			= KM_TRUE;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].bIgnoreTextureAlpha	= KM_FALSE;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].nFlipUV				= KM_NOFLIP;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].nClampUV				= KM_CLAMP_UV;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].nFilterMode			= KM_POINT_SAMPLE;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].bSuperSampleMode		= KM_FALSE;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].dwMipmapAdjust		= KM_MIPMAP_D_ADJUST_1_00;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].nTextureShadingMode	= KM_MODULATE;
	kmiContext16.ImageControl[KM_IMAGE_PARAM1].pTextureSurfaceDesc	= &sTexSurface;
	kmGenerateStripHead16( &kmiStripHead16,&kmiContext16 );

	SetWindowArea(hProcessDp, 20, 40, 77*7, 30*9);
	ActivateProcess(hProcessDp);

	cnt = 0;
}
/*----------------------------------------------------------------------------------*/
static KMDWORD UV16(KMBYTE cx, KMBYTE cy)
{
	KMFLOAT x,y;
	union {
		KMFLOAT f[2];
		KMWORD  f16[4];
	} f;

	f.f[0] = (KMFLOAT)cx / 16.f;
	f.f[1] = (KMFLOAT)cy / 16.f;

	return ((f.f16[1]<<16) | f.f16[3]);
}
/*----------------------------------------------------------------------------------*/
void DpCommandExec(PKMVERTEXBUFFDESC pBufferDesc)
{
	KMINT32		x, y;
	KMINT32		nChar;
	KMDWORD		uv1, uv2, uv3;
	float		XPos,YPos;
	KMRECT		Rect;
	float		Width,Height;
	float		Left,Top;

	if (per->on & PDD_DGT_KU) if (cnt<=16) cnt=0; else cnt-=16;
	if (per->on & PDD_DGT_KD) if (cnt>=Size-16) cnt=Size-16; else cnt+=16;
	if (per->on & PDD_DGT_KL) if (cnt<=256) cnt=0; else cnt-=256;
	if (per->on & PDD_DGT_KR) if (cnt>=Size-256) cnt=Size-256; else cnt+=256;
	if (per->press & PDD_DGT_TA) Type=(Type+1)%3;


	Dump( (DWORD)pMem+cnt, 30, Type);

	GetClientRect(hProcessDp, &Rect);
	Left  = (float)Rect.nXmin;
	Top   = (float)Rect.nYmin;
	Width = (float)(Rect.nXmax - Rect.nXmin);
	Height= (float)(Rect.nYmax - Rect.nYmin);

	kmxxGetCurrentPtr(pBufferDesc);
	kmxxStartStrip(pBufferDesc,&kmiStripHead16);

	for(y = 0; y < 30; y++) {
		for(x = 0; x < 77; x++) {
			nChar = VMAP[x][y];
			if(nChar!=' ' && nChar!='\0') {
				XPos = x * 7;
				YPos = y * 9;

				uv1 = UV16(nChar%16  , nChar/16  );
				uv2 = UV16(nChar%16+1, nChar/16  );
				uv3 = UV16(nChar%16+1, nChar/16+1);

				kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
									Left + XPos, 		Top + YPos,		256.0f,
									Left + XPos + 8,	Top + YPos,		256.0f,
									Left + XPos + 8,	Top + YPos + 8,	256.0f,
									Left + XPos,		Top + YPos + 8,
									uv1, uv2, uv3
								);
				kmEndStrip( pBufferDesc );
			}
		}
	}

	kmxxReleaseCurrentPtr(pBufferDesc);

	if (per->press & PDD_DGT_TB) {
		killProcess( hProcessDp );
	}
}
/*----------------------------------------------------------------------------------*/
void InitDpCommand(void)
{
	hProcessDp = RegisterCommand(
		DpCommand,
		(PKMCALLBACKFUNC)DpCommandExec,
		NULL,
		"dp",
		PROCESSTYPE_W_DRAW
	);

	SetMessageCallback( hProcessDp, DpMessage );

	per = pdGetPeripheral(PDD_PORT_A0);
	busy = 0;
	Type = 0;
}
/*----------------------------------------------------------------------------------*/
void Dump( DWORD adrs, int line, int type )
{
	int i,j,n;
	char *P;
	unsigned char st0[10];
	unsigned char st1[10];
	unsigned char hex[16];
	char buf[256];

	kmyZeroMemory( VMAP, 80*30*4 );
	switch (Type) {
	case 0:
		sprintf(buf, " ADDRESS  +0 +1 +2 +3 +4 +5 +6 +7  +8 +9 +A +B +C +D +E +F  01234567 89ABCDEF");
		n = 77;
		break;
	case 1:
		sprintf(buf, " ADDRESS   +0   +2   +4   +6    +8   +A   +C   +E   01234567 89ABCDEF");
		n = 69;
		break;
	case 2:
		sprintf(buf, " ADDRESS     +0       +4        +8       +C     01234567 89ABCDEF");
		n = 65;
		break;
	}

	for(j=0; j<n; j++) VMAP[j][0] = buf[j];

	P = (char*)adrs;
	for(i=1; i<line; i++) {
		for(j=0; j<16; j++) hex[j] = *P++;

		for(j=0; j<8; j++) {
			if (hex[j  ]) st0[j] = hex[j  ]; else st0[j] = 0xff;
			if (hex[j+8]) st1[j] = hex[j+8]; else st1[j] = 0xff;
		}

		switch (Type) {
		case 0:
			sprintf(buf, "$%08x %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x                   ",
				adrs-(DWORD)pMem,
				hex[0],hex[1],hex[ 2],hex[ 3],hex[ 4],hex[ 5],hex[ 6],hex[ 7],
				hex[8],hex[9],hex[10],hex[11],hex[12],hex[13],hex[14],hex[15]
			);
			break;
		case 1:
			sprintf(buf, "$%08x %02x%02x %02x%02x %02x%02x %02x%02x  %02x%02x %02x%02x %02x%02x %02x%02x                   ",
				adrs-(DWORD)pMem,
				hex[1],hex[0],hex[ 3],hex[ 2],hex[ 5],hex[ 4],hex[ 7],hex[ 6],
				hex[9],hex[8],hex[11],hex[10],hex[13],hex[12],hex[15],hex[14]
			);
			break;
		case 2:
			sprintf(buf, "$%08x %02x%02x%02x%02x %02x%02x%02x%02x  %02x%02x%02x%02x %02x%02x%02x%02x                   ",
				adrs-(DWORD)pMem,
				hex[ 3],hex[ 2],hex[ 1],hex[ 0],hex[ 7],hex[ 6],hex[ 5],hex[ 4],
				hex[11],hex[10],hex[ 9],hex[ 8],hex[15],hex[14],hex[13],hex[12]
			);
			break;
		}

		for(j=0; j<8; j++) {
			buf[n-17+j] = st0[j];
			buf[n- 8+j] = st1[j];
		}

		for(j=0; j<n; j++) VMAP[j][i] = buf[j];

		adrs+=16;
	}
}
/*----------------------------------------------------------------------------------*/
void DpMessage(PKMVOID hProcess, PDCXMESSAGE pMessage )
{
	switch (pMessage->eType) {
	case DCXMESSAGE_DESTROY_WINDOW:
		syFree( pMem );
		kmFreeTexture( &sTexSurface );
		busy = 0;
		break;
	case DCXMESSAGE_DISPLAY_HELP:
		strcpy( pMessage->pContext, "File Dump Utility" );
		break;
	}
}
/*----------------------------------------------------------------------------------*/