#include <shinobi.h>
#include <kamui2.h>
#include <km2util.h>
#include <string.h>
#include "dispstrex.h"
#include "command.h"
#include "cursor.h"
#include "waku.h"

#define _KM_USE_VERTEX_MACRO_L4_	/***/
#include <km2kamuix.h>

extern int BGID;
extern int BGLOOP;
extern KMSURFACEDESC gTextureList[];
extern void SetBackground (PKMSURFACEDESC TextureID);

#define FRAMESIZEX 4
#define FRAMESIZEY 4
#define FRAMEXGAP 2
#define TITLESIZE 16

COMMANDCONTROL Command;

static char *argv[16];
static float ConsolePosX;
static float ConsolePosY;
static KMUINT32 ConsoleSizeX;
static KMUINT32 ConsoleSizeY;

static KMSTRIPHEAD StripHead16;
static KMSTRIPHEAD StripHead01;
static KMSTRIPHEAD StripHead03;
static int InvalidateCount;
static KMBOOLEAN bProcessExecute = FALSE;
static PROCESSHANDLE hConsole, hInvalidate, hPS;

KMSURFACEDESC WhiteTexDesc, FrameTexDesc;
KMDWORD CmdWhiteTex[32] = {
	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
};

extern void	InitStripContext01( PKMSTRIPCONTEXT pStripContext, PKMSTRIPHEAD	pStripHead);
extern void	InitStripContext03( PKMSTRIPCONTEXT pStripContext, PKMSTRIPHEAD	pStripHead, PKMSURFACEDESC pTextureDesc);


/*
	CONSOLE
*/
void ConsoleCommand(int argc, char *argv[])
{
	PRINTOUT(("DC-X Command Console Ver. 1.00\n"))
}

void ConsoleDraw(PKMVERTEXBUFFDESC pBufferDesc)
{
	KMRECT Rect;
	GetClientRect((PROCESSHANDLE)hConsole, &Rect);
	ConsolePosX = Rect.nXmin;
	ConsolePosY = Rect.nYmin;
	txt_SetDisplayPos(ConsolePosX, ConsolePosY, ConsoleSizeX, ConsoleSizeY);
	txt_DispScreen(pBufferDesc);
}

/*
	InvalidateWindow
*/
void InvalidateWindowCommand(int argc, char *argv[])
{
	PRINTOUT(("Invalidate Windows\n"))
	ActivateProcess(hInvalidate);
	InvalidateCount = 1;
}

void InvalidateWindowDraw(PKMVERTEXBUFFDESC pBufferDesc)
{
	kmxxGetCurrentPtr(pBufferDesc);
	if (BGID==-1) {
		kmxxStartStrip(pBufferDesc, &StripHead01);
		kmxxSetVertex_1(KM_VERTEXPARAM_NORMAL		,   0.f, 480.f , 300.0f, 1.0f, 0.0f, 0.5f, 0.0f);
		kmxxSetVertex_1(KM_VERTEXPARAM_NORMAL		,   0.f,   0.f , 300.0f, 1.0f, 0.0f, 0.1f, 0.0f);
		kmxxSetVertex_1(KM_VERTEXPARAM_NORMAL		, 640.f, 480.f , 300.0f, 1.0f, 0.0f, 0.8f, 0.0f);
		kmxxSetVertex_1(KM_VERTEXPARAM_ENDOFSTRIP	, 640.f,   0.f , 300.0f, 1.0f, 0.0f, 0.2f, 0.0f);
	} else {
		KMSTRIPCONTEXT CTX;

		InitStripContext03( &CTX, &StripHead03, &gTextureList[BGID]);
		kmxxStartStrip(pBufferDesc, &StripHead03);
		if (BGLOOP) {
			float x,y;
			x = 640.f / gTextureList[BGID].u0.Width;
			y = 480.f / gTextureList[BGID].u1.Height;
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL		,   0.f,   0.f, 300.f, 0.f,0.f, 0xffffffff, 0x00000000);
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL		,   0.f, 480.f, 300.f, 0.f,y  , 0xffffffff, 0x00000000);
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL		, 640.f,   0.f, 300.f, x  ,0.f, 0xffffffff, 0x00000000);
			kmxxSetVertex_3(KM_VERTEXPARAM_ENDOFSTRIP	, 640.f, 480.f, 300.f, x  ,y  , 0xffffffff, 0x00000000);
		} else {
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL		,   0.f,   0.f, 300.f, 0.f,0.f, 0xffffffff, 0x00000000);
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL		,   0.f, 480.f, 300.f, 0.f,1.f, 0xffffffff, 0x00000000);
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL		, 640.f,   0.f, 300.f, 1.f,0.f, 0xffffffff, 0x00000000);
			kmxxSetVertex_3(KM_VERTEXPARAM_ENDOFSTRIP	, 640.f, 480.f, 300.f, 1.f,1.f, 0xffffffff, 0x00000000);
		}
	}
	kmxxReleaseCurrentPtr(pBufferDesc);

	InvalidateCount--;
	if(InvalidateCount < 0) SuspendProcess(hInvalidate);
}

void Invalidate(void)
{
	ActivateProcess(hInvalidate);
	InvalidateCount = 1;
}

/*
 	Process Status (PS)
*/
void PSCommand(int argc, char *argv[])
{
	PCOMMANDSTRUCT pCurrent, pLastDraw;
	KMRECT Rect;
	int CommandType, DispOn;
	char pstat[16], ptype[16];

	CommandType = DispOn = 0;

	if(strcmp(argv[1], "-H") == 0 || strcmp(argv[1], "-h") == 0)
	{
		/* Help Window*/
		PRINTOUT(("ps [flag]\n"));
		PRINTOUT(("flag:\n"));
		PRINTOUT(("-all : All Process Display\n"));
		PRINTOUT(("-act: Active Process Display\n"));
		PRINTOUT(("-sus: Suspended Process Display\n"));
		PRINTOUT(("-pn[num]: Process Status num = ID \n"));
		return;
	}

	if(argc == 1)
	{
		CommandType = 0;
	}
	else
	{
		if(strcmp(argv[1], "-all") == 0 || strcmp(argv[1], "-ALL") == 0) CommandType = 0;
		if(strcmp(argv[1], "-act") == 0 || strcmp(argv[1], "-ACT") == 0) CommandType = 1;
		if(strcmp(argv[1], "-sus") == 0 || strcmp(argv[1], "-SUS") == 0) CommandType = 2;
	}

	PRINTOUT(("  ID          Name      Type  Status\n"));
	PRINTOUT(("------------------------------------\n"));
	pCurrent = Command.RegistTop;
	do
	{
		if(pCurrent->pProcess)
		{
			DispOn = 0;
			switch(CommandType)
			{
				case 0:
				{
					DispOn = 1;
					break;
				}
				case 1:
				{
					if(pCurrent->Attrib == PROCESSSTATE_ACTIVE) DispOn = 1;
					break;
				}
				case 2:
				{
					if(pCurrent->Attrib == PROCESSSTATE_SUSPEND) DispOn = 1;
					break;
				}
			}

			if(pCurrent->Attrib == PROCESSSTATE_ACTIVE)
				strcpy(pstat, "active");
			else
				strcpy(pstat, "suspend");

			if(pCurrent->ProcessType == PROCESSTYPE_W_DRAW)
				strcpy(ptype, "Draw");
			else
				strcpy(ptype, "NoDraw");

			if(DispOn) PRINTOUT(("%8X  %10s  %6s  %7s\n", (KMDWORD)pCurrent, pCurrent->CommandName, ptype, pstat));
		}
	}while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);
}
/*
*	Process Kill
*/
void KillCommand(int argc, char *argv[])
{
	PROCESSHANDLE hProcess;
	KMDWORD nID;
	int ret;

	if(argc == 1)
	{
		PRINTOUT(("Usage: kill ProcessID\n"));
	}

	sscanf(argv[1], "%x", &nID);
	hProcess = (PROCESSHANDLE)nID;
	ret = killProcess(hProcess);
	if(ret == 0)
	{
		PRINTOUT(("Cannot Find Process ID = %X\n", nID));
	}
}

/*+++++++++++++++++++++

----------------------*/
void InitializeCommand()
{
	int i;
	KMSTRIPCONTEXT		StripContext16;
	KMSTRIPCONTEXT		StripContext01;
	KMPACKEDARGB		BaseColor;
	BaseColor.dwPacked = 0xFFFFFFFF;

	Command.RegistTop 			= NULL;
	Command.nRegistratedCommand = 0;
	for(i = 0; i < 16; i++)
	{
		argv[i] = (char *)syMalloc(256);
	}

	ConsolePosX 	= 200.0f;
	ConsolePosY 	= 26.0f;
	ConsoleSizeX 	= 320;
	ConsoleSizeY 	= 450;

	hInvalidate = RegisterCommand(	InvalidateWindowCommand,
									(PKMCALLBACKFUNC)InvalidateWindowDraw, NULL,
									"invalidate",
									PROCESSTYPE_W_DRAW);

	hConsole = RegisterCommand(		ConsoleCommand,
									(PKMCALLBACKFUNC)ConsoleDraw, NULL,
									"console",
									PROCESSTYPE_W_DRAW);		/* Draw Command あり */

	hPS		= RegisterCommand(		PSCommand,
									NULL, NULL,
									"ps",
									PROCESSTYPE_WO_DRAW);

			  RegisterCommand(		KillCommand,
									NULL, NULL,
									"kill",
									PROCESSTYPE_WO_DRAW);

	SetWindowArea(hConsole, ConsolePosX, ConsolePosY, ConsoleSizeX, ConsoleSizeY);

	txt_SetDisplayPos(ConsolePosX, ConsolePosY, ConsoleSizeX, ConsoleSizeY);

	kmCreateTextureSurface(		&WhiteTexDesc, 					/* Null texture Surafce Desc */
								8, 8,							/* U, V Size */
								KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565
							);

	kmCreateTextureSurface(		&FrameTexDesc, 					/* Null texture Surafce Desc */
								64, 64,							/* U, V Size */
								KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565
							);

    kmLoadTexture( &WhiteTexDesc, CmdWhiteTex );
	kmLoadTexture( &FrameTexDesc, &waku[0x10]);

	memset(&StripHead16 , 0, sizeof(StripHead16));
	memset(&StripContext16,0,sizeof(KMSTRIPCONTEXT));

	StripContext16.nSize = sizeof(StripContext16);
	StripContext16.StripControl.nListType							= KM_OPAQUE_POLYGON;
	StripContext16.StripControl.nUserClipMode	 					= KM_USERCLIP_DISABLE;
	StripContext16.StripControl.nShadowMode		 					= KM_NORMAL_POLYGON;
	StripContext16.StripControl.bOffset								= KM_FALSE;
 	StripContext16.StripControl.bGouraud		 					= KM_TRUE;
	StripContext16.ObjectControl.nDepthCompare			 			= KM_GREATER;
	StripContext16.ObjectControl.nCullingMode			 			= KM_NOCULLING;
	StripContext16.ObjectControl.bZWriteDisable						= KM_FALSE;
	StripContext16.ObjectControl.bDCalcControl			 			= KM_FALSE;
	StripContext16.type.splite.Base									= BaseColor;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].nSRCBlendingMode	= KM_SRCALPHA;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].nDSTBlendingMode	= KM_INVSRCALPHA;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].bSRCSelect			= KM_FALSE;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].bDSTSelect			= KM_FALSE;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].nFogMode			= KM_NOFOG;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].bColorClamp		= KM_FALSE;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].bUseAlpha			= KM_TRUE;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].bIgnoreTextureAlpha= KM_FALSE;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].nFlipUV			= KM_NOFLIP;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].nClampUV			= KM_CLAMP_UV;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].nFilterMode		= KM_POINT_SAMPLE;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].bSuperSampleMode	= KM_FALSE;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].dwMipmapAdjust		= KM_MIPMAP_D_ADJUST_1_00;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].nTextureShadingMode= KM_MODULATE;
	StripContext16.ImageControl[KM_IMAGE_PARAM1].pTextureSurfaceDesc= &FrameTexDesc;

	kmGenerateStripHead16( &StripHead16, &StripContext16 );
	InitStripContext01( &StripContext01, &StripHead01);

	ActivateProcess(hInvalidate);
	ActivateProcess(hConsole);
	InvalidateCount = 1;
}

void MoveCurrentWindow(int dx, int dy)
{
	PCOMMANDSTRUCT pCurrent, pLastDraw;
	KMRECT Rect;
	int XSize,YSize;

	pCurrent = Command.RegistTop;
	pLastDraw = NULL;
	do
	{
		if( pCurrent->ProcessType == PROCESSTYPE_W_DRAW)
		{
			if(pCurrent->Attrib == PROCESSSTATE_ACTIVE && pCurrent != (PCOMMANDSTRUCT)hInvalidate)
			{
				pLastDraw = pCurrent;
			}
		}
	}while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);

	if(!pLastDraw) return;
	GetClientRect((PROCESSHANDLE)pLastDraw, &Rect);
	XSize = Rect.nXmax - Rect.nXmin; YSize = Rect.nYmax - Rect.nYmin;
	SetWindowArea((PROCESSHANDLE)pLastDraw, Rect.nXmin + dx, Rect.nYmin + dy, XSize, YSize );
	Invalidate();
}

void SetWindowArea(PROCESSHANDLE hProcess, int OrgX, int OrgY, int XSize, int YSize)
{
	PCOMMANDSTRUCT pCommand = (PCOMMANDSTRUCT)hProcess;

	pCommand->Client.nXmin	= OrgX - FRAMESIZEX - FRAMEXGAP;
	pCommand->Client.nYmin	= OrgY - FRAMESIZEY - TITLESIZE;
	pCommand->Client.nXmax	= OrgX + XSize 		+ FRAMESIZEX;
	pCommand->Client.nYmax	= OrgY + YSize 		+ FRAMESIZEY;

	pCommand->Clipper.nXmin	= (pCommand->Client.nXmin > 0  ) ? pCommand->Client.nXmin : 0;
	pCommand->Clipper.nYmin	= (pCommand->Client.nYmin > 0  ) ? pCommand->Client.nYmin : 0;
	pCommand->Clipper.nXmax	= (pCommand->Client.nXmax < 639) ? pCommand->Client.nXmax : 639;
	pCommand->Clipper.nYmax	= (pCommand->Client.nYmax < 479) ? pCommand->Client.nYmax : 479;
}

PROCESSHANDLE RegisterCommand(		PCOMMANDFUNC pFunc,
									PKMCALLBACKFUNC pProcess,
									PKMVOID pData,
									char* pszName,
									PROCESSTYPE ProcessType)
{
	PCOMMANDSTRUCT pNewCommand, pCurrent;

	pNewCommand = (PCOMMANDSTRUCT)syMalloc(sizeof(COMMANDSTRUCT));
	if(pNewCommand == NULL ) return NULL;

	pNewCommand->pCommand 		= pFunc;
	pNewCommand->pProcess 		= pProcess;
	pNewCommand->pMessage		= NULL;		/* DefaultはMessageコールバックNULL */
	pNewCommand->pData			= pData;
	pNewCommand->Attrib			= PROCESSSTATE_SUSPEND;
	pNewCommand->ProcessType	= ProcessType;
	pNewCommand->IsLastDraw		= FALSE;

	pNewCommand->Client.nXmin	= 0;
	pNewCommand->Client.nXmax	= 639;
	pNewCommand->Client.nYmin	= 0;
	pNewCommand->Client.nYmax	= 479;
	pNewCommand->Clipper.nXmin	= 0;
	pNewCommand->Clipper.nXmax	= 639;
	pNewCommand->Clipper.nYmin	= 0;
	pNewCommand->Clipper.nYmax	= 479;

	strcpy(pNewCommand->CommandName, pszName);

	/*
	 * 	  Concatinate Command to Tail Queue
	 */
	if(Command.nRegistratedCommand == 0)
	{
		pNewCommand->pPrev = NULL;
		pNewCommand->pNext = NULL;
		Command.RegistTop = pNewCommand;
	}
	else
	{
		pCurrent = Command.RegistTop;
		while(pCurrent->pNext) pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext;
		pCurrent->pNext 	= (PKMVOID)pNewCommand;
		pNewCommand->pPrev 	= (PKMVOID)pCurrent;
		pNewCommand->pNext	= NULL;
	}

	Command.nRegistratedCommand++;
	return (PROCESSHANDLE)pNewCommand;
}

int ChangeLastDraw2TopDraw(void)
{
	PCOMMANDSTRUCT pCurrent, pFirstDraw, pLastDraw;
	KMDWORD	DrawProcessCount = 0;

	if(bProcessExecute) return FALSE;
	pCurrent = Command.RegistTop;
	pFirstDraw = NULL;
	pLastDraw = NULL;
	do
	{
		if( pCurrent->ProcessType == PROCESSTYPE_W_DRAW)
		{
			pCurrent->IsLastDraw = FALSE;
			if(pCurrent->Attrib == PROCESSSTATE_ACTIVE)
			{
				if(!pFirstDraw) pFirstDraw = pCurrent;
				pLastDraw = pCurrent;
			}
			DrawProcessCount++;
		}
	}while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);

	if(DrawProcessCount <= 1)
	{
		if(pLastDraw) pLastDraw->IsLastDraw = TRUE;
		return 0;
	}

	ChangeProcessPriority((PROCESSHANDLE)pLastDraw, PROCESS_PRIORITY_TOP_OF_DRAW);
	/* InvalidateがTopに来るようにする */
	ChangeProcessPriority( hInvalidate, PROCESS_PRIORITY_TOP_OF_DRAW);
}

int SetMessageCallback(	PROCESSHANDLE hProcess, PMESSAGECALLBACKFUNC pFunc)
{
	PCOMMANDSTRUCT pCommand;

	pCommand = (PCOMMANDSTRUCT)hProcess;
	pCommand->pMessage = pFunc;

	return 1;
}

int killProcess(PROCESSHANDLE hProcess)
{
	PCOMMANDSTRUCT pCurrent;
	DCXMESSAGE mes;

	pCurrent = Command.RegistTop;
	do
	{
		if((KMDWORD)pCurrent == (KMDWORD)hProcess)
		{
			mes.eType    = DCXMESSAGE_DESTROY_WINDOW;
			mes.pContext = NULL;

			if(pCurrent->pMessage) (pCurrent->pMessage)(hProcess, &mes);
			SuspendProcess(hProcess);
			Invalidate();
			return 1;
		}
	}while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);

	return 0;
}

int ActivateProcess(PROCESSHANDLE hProcess)
{
	PCOMMANDSTRUCT pCurrent, pLastDraw;

	((PCOMMANDSTRUCT)hProcess)->Attrib = PROCESSSTATE_ACTIVE;

	/* Search Tail Command of Draw */
	pCurrent = Command.RegistTop;
	pLastDraw = NULL;
	do
	{
		if( pCurrent->ProcessType == PROCESSTYPE_W_DRAW)
		{
			pCurrent->IsLastDraw = FALSE;
			if(pCurrent->Attrib == PROCESSSTATE_ACTIVE)
			{
				pLastDraw = pCurrent;
			}
		}
	}while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);

	if(pLastDraw) pLastDraw->IsLastDraw = TRUE;

	return 0;
}

int SuspendProcess(PROCESSHANDLE hProcess)
{
	PCOMMANDSTRUCT pCurrent, pLastDraw;

	((PCOMMANDSTRUCT)hProcess)->Attrib = PROCESSSTATE_SUSPEND;

	/* Search Tail Command of Draw */
	pCurrent = Command.RegistTop;
	pLastDraw = NULL;
	do
	{
		if( pCurrent->ProcessType == PROCESSTYPE_W_DRAW)
		{
			pCurrent->IsLastDraw = FALSE;
			if(pCurrent->Attrib == PROCESSSTATE_ACTIVE)
			{
				pLastDraw = pCurrent;
			}
		}
	}while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);

	if(pLastDraw) pLastDraw->IsLastDraw = TRUE;

	return 0;
}

int ExecuteCommand(char *pszCommandLine)
{
	PCOMMANDSTRUCT pCommand;
	int argc;
	char *pCurrent;
	if (*pszCommandLine == '\0') return -1;	/* NULL COMMAND */

	for(argc = 0; argc < 16; argc++)
	{
		*argv[argc] = '\0';
	}

	argc = 0;
	pCurrent = strtok(pszCommandLine," ");
	strcpy(argv[argc], pCurrent);				/* argv[0] is command name */
	argc++;
	while((pCurrent = strtok(NULL," ")) != NULL)
	{
		strcpy(argv[argc], pCurrent);
		argc++;
		if(argc > 15) break;
	}

	pCommand = Command.RegistTop;
	do
	{
		if(strcmp(pCommand->CommandName, argv[0]) == 0)
		{
			(pCommand->pCommand)(argc, &argv[0]);
			return argc;
		}
	}while((pCommand = (PCOMMANDSTRUCT)pCommand->pNext) != NULL);

	PRINTOUT(("Command is not found\n"));
	return -2;
}

void SetClipper(PCOMMANDSTRUCT pCommand, PKMVERTEXBUFFDESC pBufferDesc)
{
	KMRECT TileClip;

	/* Pixel Clipping Mask */
	/* Tile Clipping Mask */
	TileClip.nXmin = (pCommand->Clipper.nXmin / 32);
	TileClip.nYmin = (pCommand->Clipper.nYmin / 32);
	TileClip.nXmax = ((pCommand->Clipper.nXmax) / 32);
	TileClip.nYmax = ((pCommand->Clipper.nYmax) / 32);

	kmSetPixelClipping( pCommand->Clipper.nXmin,
						pCommand->Clipper.nYmin,
						pCommand->Clipper.nXmax,
						pCommand->Clipper.nYmax);

	kmSetRegionClipping(TileClip.nXmin,
						TileClip.nYmin,
						TileClip.nXmax,
						TileClip.nYmax);


	kmSetUserClipping(	pBufferDesc,
						KM_USERCLIP_DISABLE,
						KM_OPAQUE_POLYGON,
						&TileClip);

	kmSetUserClipping(	pBufferDesc,
						KM_USERCLIP_DISABLE,
						KM_TRANS_POLYGON,
						&TileClip );

	kmSetUserClipping(	pBufferDesc,
						KM_USERCLIP_DISABLE,
						KM_PUNCHTHROUGH_POLYGON,
						&TileClip );
}

int GetClientRect(PROCESSHANDLE hProcess , PKMRECT pRect)
{
	PCOMMANDSTRUCT pCommand = (PCOMMANDSTRUCT)hProcess;

	pRect->nXmin = pCommand->Client.nXmin + FRAMESIZEX + FRAMEXGAP;
	pRect->nYmin = pCommand->Client.nYmin + FRAMESIZEY + TITLESIZE;
	pRect->nXmax = pCommand->Client.nXmax - FRAMESIZEX;
	pRect->nYmax = pCommand->Client.nYmax - FRAMESIZEY;

	return 0;
}
#pragma inline(ConvUV16)
KMDWORD ConvUV16(float fu, float fv)
{
	union {
		KMFLOAT f[2];
		KMWORD  f16[4];
	} f;

	f.f[0] = fu/64.0f;
	f.f[1] = fv/64.0f;

	return ((f.f16[1]<<16) | f.f16[3]);
}

void FrameDraw(PCOMMANDSTRUCT pCommand, PKMVERTEXBUFFDESC pBufferDesc, KMBOOLEAN bIsLast)
{
	KMPACKEDARGB FrameColor;
	KMDWORD uv1, uv2, uv3;

	if(bIsLast)
		FrameColor.dwPacked = 0xFFFFFFFF;
	else
		FrameColor.dwPacked = 0xFFC0C0C0;

	kmChangeStripSpriteBaseColor(&StripHead16, FrameColor);
	kmxxGetCurrentPtr(pBufferDesc);
	kmxxStartStrip(pBufferDesc,&StripHead16);

	/* 上の横線 */
	uv1 = ConvUV16( 0.0f, 0.0f);
	uv2 = ConvUV16( 4.0f, 0.0f);
	uv3 = ConvUV16( 4.0f, 3.0f);
	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmin		, pCommand->Client.nYmin, 				256.0f,
						pCommand->Client.nXmin + 16	,	pCommand->Client.nYmin,					256.0f,
						pCommand->Client.nXmin + 16	,	pCommand->Client.nYmin + FRAMESIZEY,	256.0f,
						pCommand->Client.nXmin		,	pCommand->Client.nYmin + FRAMESIZEY,
						uv1, uv2, uv3
						);

	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmin + 17, pCommand->Client.nYmin, 				256.0f,
						pCommand->Client.nXmax - 17, pCommand->Client.nYmin,					256.0f,
						pCommand->Client.nXmax - 17, pCommand->Client.nYmin + FRAMESIZEY,	256.0f,
						pCommand->Client.nXmin + 17, pCommand->Client.nYmin + FRAMESIZEY,
						uv1, uv2, uv3
						);

	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmax - 16	, pCommand->Client.nYmin, 				256.0f,
						pCommand->Client.nXmax		,	pCommand->Client.nYmin,					256.0f,
						pCommand->Client.nXmax		,	pCommand->Client.nYmin + FRAMESIZEY,	256.0f,
						pCommand->Client.nXmax - 16	,	pCommand->Client.nYmin + FRAMESIZEY,
						uv1, uv2, uv3
						);

	/* 下の横線 */
	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmin, pCommand->Client.nYmax - FRAMESIZEY, 				256.0f,
						pCommand->Client.nXmin + 16,	pCommand->Client.nYmax - FRAMESIZEY,					256.0f,
						pCommand->Client.nXmin + 16,	pCommand->Client.nYmax,	256.0f,
						pCommand->Client.nXmin,	pCommand->Client.nYmax,
						uv1, uv2, uv3
						);

	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmin + 17, pCommand->Client.nYmax - FRAMESIZEY, 				256.0f,
						pCommand->Client.nXmax - 17,	pCommand->Client.nYmax - FRAMESIZEY,					256.0f,
						pCommand->Client.nXmax - 17,	pCommand->Client.nYmax,	256.0f,
						pCommand->Client.nXmin + 17,	pCommand->Client.nYmax,
						uv1, uv2, uv3
						);

	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmax - 16, pCommand->Client.nYmax - FRAMESIZEY, 				256.0f,
						pCommand->Client.nXmax,	pCommand->Client.nYmax - FRAMESIZEY,					256.0f,
						pCommand->Client.nXmax,	pCommand->Client.nYmax,	256.0f,
						pCommand->Client.nXmax - 16, pCommand->Client.nYmax,
						uv1, uv2, uv3
						);

	/* 右の縦線 */
	uv1 = ConvUV16(61.0f, 0.0f);
	uv2 = ConvUV16(64.0f, 0.0f);
	uv3 = ConvUV16(64.0f, 4.0f);
	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmax - FRAMESIZEX	, pCommand->Client.nYmin, 		256.0f,
						pCommand->Client.nXmax				, pCommand->Client.nYmin,		256.0f,
						pCommand->Client.nXmax				, pCommand->Client.nYmin + 16,	256.0f,
						pCommand->Client.nXmax - FRAMESIZEX , pCommand->Client.nYmin + 16,
						uv1, uv2, uv3
						);

	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmax - FRAMESIZEX, pCommand->Client.nYmin + 17, 	256.0f,
						pCommand->Client.nXmax			   , pCommand->Client.nYmin + 17,	256.0f,
						pCommand->Client.nXmax			   , pCommand->Client.nYmax - 17,	256.0f,
						pCommand->Client.nXmax - FRAMESIZEX, pCommand->Client.nYmax - 17,
						uv1, uv2, uv3
						);

	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmax - FRAMESIZEX, pCommand->Client.nYmax - 16, 	256.0f,
						pCommand->Client.nXmax,	pCommand->Client.nYmax - 16,				256.0f,
						pCommand->Client.nXmax,	pCommand->Client.nYmax,						256.0f,
						pCommand->Client.nXmax - FRAMESIZEX,	pCommand->Client.nYmax,
						uv1, uv2, uv3
						);

	/* 左の縦線 */
	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmin				, pCommand->Client.nYmin, 	256.0f,
						pCommand->Client.nXmin + FRAMESIZEX	, pCommand->Client.nYmin,	256.0f,
						pCommand->Client.nXmin + FRAMESIZEX	, pCommand->Client.nYmin + 16,	256.0f,
						pCommand->Client.nXmin				, pCommand->Client.nYmin + 16,
						uv1, uv2, uv3
						);
	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmin				, pCommand->Client.nYmin + 17, 	256.0f,
						pCommand->Client.nXmin + FRAMESIZEX	, pCommand->Client.nYmin + 17,	256.0f,
						pCommand->Client.nXmin + FRAMESIZEX	, pCommand->Client.nYmax - 17,	256.0f,
						pCommand->Client.nXmin				, pCommand->Client.nYmax - 17,
						uv1, uv2, uv3
						);
	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmin				, pCommand->Client.nYmax - 16, 	256.0f,
						pCommand->Client.nXmin + FRAMESIZEX	, pCommand->Client.nYmax - 16,	256.0f,
						pCommand->Client.nXmin + FRAMESIZEX	, pCommand->Client.nYmax,	256.0f,
						pCommand->Client.nXmin				, pCommand->Client.nYmax,
						uv1, uv2, uv3
						);

	/* NameBox */
	uv1 = ConvUV16( 8.0f,59.0);
	uv2 = ConvUV16(56.0f,59.0);
	uv3 = ConvUV16(56.0f,64.0 - 16.0f);
	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmin + FRAMESIZEX + 1 + 17 	, pCommand->Client.nYmin + FRAMESIZEY + 1			, 	256.0f,
						pCommand->Client.nXmax - FRAMESIZEX - 1 - 17 	, pCommand->Client.nYmin + FRAMESIZEY + 1			,	256.0f,
						pCommand->Client.nXmax - FRAMESIZEX - 1 - 17 	, pCommand->Client.nYmin + FRAMESIZEY + TITLESIZE	,	256.0f,
						pCommand->Client.nXmin + FRAMESIZEX + 1 + 17 	, pCommand->Client.nYmin + FRAMESIZEY + TITLESIZE,
						uv1, uv2, uv3
						);

	/* Control Box  */
	uv1 = ConvUV16( 8.0f,64.0 - 20.0f);
	uv2 = ConvUV16(21.0f,64.0 - 20.0f);
	uv3 = ConvUV16(21.0f,64.0 - 32.0f);
	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmin + FRAMESIZEX + 1 , pCommand->Client.nYmin + FRAMESIZEY + 1		, 	256.0f,
						pCommand->Client.nXmin + FRAMESIZEX + 1 + 16 , pCommand->Client.nYmin + FRAMESIZEY + 1		,	256.0f,
						pCommand->Client.nXmin + FRAMESIZEX + 1 + 16 , pCommand->Client.nYmin + FRAMESIZEY + TITLESIZE,	256.0f,
						pCommand->Client.nXmin + FRAMESIZEX + 1 , pCommand->Client.nYmin + FRAMESIZEY + TITLESIZE,
						uv1, uv2, uv3
					);
	/* Control Box  */
	uv1 = ConvUV16(25.0f,64.0 - 22.0f);
	uv2 = ConvUV16(36.0f,64.0 - 22.0f);
	uv3 = ConvUV16(36.0f,64.0 - 32.0f);
	kmxxSetVertex_16(	KM_VERTEXPARAM_ENDOFSTRIP,
						pCommand->Client.nXmax - FRAMESIZEX - 1 - 16, pCommand->Client.nYmin + FRAMESIZEY + 1		, 	256.0f,
						pCommand->Client.nXmax - FRAMESIZEX - 1 	, pCommand->Client.nYmin + FRAMESIZEY + 1		,	256.0f,
						pCommand->Client.nXmax - FRAMESIZEX - 1		, pCommand->Client.nYmin + FRAMESIZEY + TITLESIZE,	256.0f,
						pCommand->Client.nXmax - FRAMESIZEX - 1 - 16, pCommand->Client.nYmin + FRAMESIZEY + TITLESIZE,
						uv1, uv2, uv3
					);

	kmxxReleaseCurrentPtr(pBufferDesc);
}

KMBOOLEAN ChangeProcessPriority(PROCESSHANDLE hProcess, PROCESSPRIORITY Priority)
{
	PCOMMANDSTRUCT pCurrent, pInsertProcess, pTargetProcess;

	KMBOOLEAN bInsertBefore;
	/* If this function is called inside of Process, it fail */
	if(bProcessExecute) return FALSE;

	/* pTargetProcess .... プライオリティを変更するプロセス
	   pInsertProcess .... pTargetProcessを挿入するプロセス（このプロセスの前か後に挿入)
	*/

	pTargetProcess 	= (PCOMMANDSTRUCT)hProcess;
	pCurrent 		= Command.RegistTop;
	pInsertProcess 	= NULL;

	switch(Priority)
	{
		case PROCESS_PRIORITY_CRITICAL:
		{
			pInsertProcess = Command.RegistTop;		/* Topに持ってくる */
			bInsertBefore = TRUE;
			break;
		}
		case PROCESS_PRIORITY_TOP_OF_DRAW:
		{
			do
			{
				if(pCurrent->ProcessType == PROCESSTYPE_W_DRAW)
				{
					pInsertProcess = pCurrent;
					break;
				}
			}while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);
			bInsertBefore = TRUE;
			break;
		}
		case PROCESS_PRIORITY_LAST_OF_DRAW:
		{
			do
			{
				if(pCurrent->ProcessType == PROCESSTYPE_W_DRAW)
				{
					pInsertProcess = pCurrent;
				}
			}while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);
			bInsertBefore = FALSE;
			break;
		}

		case PROCESS_PRIORITY_LOWEST:
		{
			do{} while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);
			pInsertProcess = pCurrent;
			bInsertBefore = FALSE;
			break;
		}
		case PROCESS_PRIORITY_DRAW_HIGH:
		{
			do{
				if((PROCESSHANDLE)pCurrent == hInvalidate)
				{
					pInsertProcess = pCurrent;
					break;
				}
			} while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);
			bInsertBefore = FALSE;
			break;
		}
		case PROCESS_PRIORITY_HIGH:
		default:
		{
			pInsertProcess = Command.RegistTop;		/* Topに持ってくる */
			bInsertBefore = FALSE;
			break;
		}
	}

	if(pInsertProcess == NULL) return FALSE;

	/* pTargetProcess をリストから切り離す */
	((PCOMMANDSTRUCT)pTargetProcess->pPrev)->pNext = pTargetProcess->pNext;
	if(pTargetProcess->pNext)
	{
		((PCOMMANDSTRUCT)pTargetProcess->pNext)->pPrev = (PCOMMANDSTRUCT)pTargetProcess->pPrev;
	}

	if(bInsertBefore)
	{
		/* InsertProcessの前にpTargetProcessを挿入する */
		pTargetProcess->pPrev = pInsertProcess->pPrev;
		pInsertProcess->pPrev = (PKMVOID)pTargetProcess;
		pTargetProcess->pNext = (PKMVOID)pInsertProcess;
		if(pTargetProcess->pPrev)
		{
			((PCOMMANDSTRUCT)pTargetProcess->pPrev)->pNext = (PKMVOID)pTargetProcess;
		}
		else
		{
			/* Top Of Queue */
			Command.RegistTop = pTargetProcess;
		}
	}
	else
	{
		/* InsertProcessの後にpTargetProcessを挿入する */
		pTargetProcess->pNext = pInsertProcess->pNext;
		pInsertProcess->pNext = (PKMVOID)pTargetProcess;
		pTargetProcess->pPrev = (PKMVOID)pInsertProcess;
	}

	/* 最後のDrawProcessにFLIPマーカーを付ける */
	pCurrent = Command.RegistTop;
	pTargetProcess = NULL;
	do
	{
		if( pCurrent->ProcessType == PROCESSTYPE_W_DRAW)
		{
			pCurrent->IsLastDraw = FALSE;
			if(pCurrent->Attrib == PROCESSSTATE_ACTIVE)
			{
				pTargetProcess = pCurrent;
			}
		}
	}while((pCurrent = (PCOMMANDSTRUCT)pCurrent->pNext) != NULL);

	if(pTargetProcess) pTargetProcess->IsLastDraw = TRUE;
}

int ExecuteProcess(PKMSYSTEMCONFIGSTRUCT pSysConfig)
{
	PCOMMANDSTRUCT pCommand;

	bProcessExecute = TRUE;

	pCommand = Command.RegistTop;
	do
	{
		if(	pCommand->pProcess && (pCommand->Attrib == PROCESSSTATE_ACTIVE))
		{
			if(pCommand->ProcessType == PROCESSTYPE_W_DRAW)
			{
				kmBeginScene(pSysConfig);
				{
					kmBeginPass(pSysConfig->pBufferDesc);
					{
						FrameDraw(pCommand, pSysConfig->pBufferDesc, pCommand->IsLastDraw);

						/* Clipping Area Set */
						SetClipper(pCommand, pSysConfig->pBufferDesc);
						/* Execute Process */
						(pCommand->pProcess)(pSysConfig->pBufferDesc);
						/* Show Cursor */
						DrawCursor( pSysConfig->pBufferDesc );

					}kmEndPass(pSysConfig->pBufferDesc);

#if 0
					if(pCommand->IsLastDraw)
						kmRender(KM_RENDER_FLIP);
					else
						kmRender(KM_RENDER_NOFLIP);
#else
					if(pCommand->IsLastDraw)
						kmRenderRect(KM_RENDER_FLIP);
					else
						kmRenderRect(KM_RENDER_NOFLIP);
#endif

				}kmEndScene(pSysConfig);
			}
			else
			{
				(pCommand->pProcess)(pCommand->pData);
			}
		}
	}while((pCommand = (PCOMMANDSTRUCT)pCommand->pNext) != NULL);

	bProcessExecute = FALSE;
	return 0;
}