Cores/Nds/GPU3D.Commands.cs
namespace Emulotl.Nds;
public sealed partial class GPU3D
{
private void ExecuteCommand()
{
CmdFIFOEntry entry = CmdFIFORead();
uint paramsRequiredCount = CmdNumParams[entry.Command];
if ( paramsRequiredCount <= 1 )
{
switch ( entry.Command )
{
case 0x10:
VertexPipelineCmdDelayed4();
MatrixMode = entry.Param & 0x3;
break;
case 0x11:
VertexPipelineCmdDelayed4();
NumPushPopCommands--;
if ( MatrixMode == 0 )
{
if ( ProjMatrixStackPointer > 0 ) GXStat |= 1u << 15;
MatrixCopy( ProjMatrixStack, ProjMatrix );
ProjMatrixStackPointer++;
ProjMatrixStackPointer &= 0x1;
}
else if ( MatrixMode == 3 )
{
if ( TexMatrixStackPointer > 0 ) GXStat |= 1u << 15;
MatrixCopy( TexMatrixStack, TexMatrix );
TexMatrixStackPointer++;
TexMatrixStackPointer &= 0x1;
}
else
{
if ( PosMatrixStackPointer > 30 ) GXStat |= 1u << 15;
MatrixCopyToStack( PosMatrixStack, (int)(PosMatrixStackPointer & 0x1F), PosMatrix );
MatrixCopyToStack( VecMatrixStack, (int)(PosMatrixStackPointer & 0x1F), VecMatrix );
PosMatrixStackPointer++;
PosMatrixStackPointer &= 0x3F;
}
AddCycles( 16 );
break;
case 0x12:
VertexPipelineCmdDelayed4();
NumPushPopCommands--;
if ( MatrixMode == 0 )
{
if ( ProjMatrixStackPointer == 0 ) GXStat |= 1u << 15;
ProjMatrixStackPointer--;
ProjMatrixStackPointer &= 0x1;
MatrixCopy( ProjMatrix, ProjMatrixStack );
ClipMatrixDirty = true;
AddCycles( 35 );
}
else if ( MatrixMode == 3 )
{
if ( TexMatrixStackPointer == 0 ) GXStat |= 1u << 15;
TexMatrixStackPointer--;
TexMatrixStackPointer &= 0x1;
MatrixCopy( TexMatrix, TexMatrixStack );
AddCycles( 17 );
}
else
{
int offset = ((int)(entry.Param << 26)) >> 26;
PosMatrixStackPointer = (uint)(((int)PosMatrixStackPointer - offset) & 0x3F);
if ( PosMatrixStackPointer > 30 ) GXStat |= 1u << 15;
MatrixCopyFromStack( PosMatrix, PosMatrixStack, (int)(PosMatrixStackPointer & 0x1F) );
MatrixCopyFromStack( VecMatrix, VecMatrixStack, (int)(PosMatrixStackPointer & 0x1F) );
ClipMatrixDirty = true;
AddCycles( 35 );
}
break;
case 0x13:
VertexPipelineCmdDelayed4();
if ( MatrixMode == 0 )
MatrixCopy( ProjMatrixStack, ProjMatrix );
else if ( MatrixMode == 3 )
MatrixCopy( TexMatrixStack, TexMatrix );
else
{
uint addr = entry.Param & 0x1F;
if ( addr > 30 ) GXStat |= 1u << 15;
MatrixCopyToStack( PosMatrixStack, (int)addr, PosMatrix );
MatrixCopyToStack( VecMatrixStack, (int)addr, VecMatrix );
}
AddCycles( 16 );
break;
case 0x14:
VertexPipelineCmdDelayed4();
if ( MatrixMode == 0 )
{
MatrixCopy( ProjMatrix, ProjMatrixStack );
ClipMatrixDirty = true;
AddCycles( 35 );
}
else if ( MatrixMode == 3 )
{
MatrixCopy( TexMatrix, TexMatrixStack );
AddCycles( 17 );
}
else
{
uint addr = entry.Param & 0x1F;
if ( addr > 30 ) GXStat |= 1u << 15;
MatrixCopyFromStack( PosMatrix, PosMatrixStack, (int)addr );
MatrixCopyFromStack( VecMatrix, VecMatrixStack, (int)addr );
ClipMatrixDirty = true;
AddCycles( 35 );
}
break;
case 0x15:
VertexPipelineCmdDelayed4();
if ( MatrixMode == 0 )
{
MatrixLoadIdentity( ProjMatrix );
ClipMatrixDirty = true;
AddCycles( 18 );
}
else if ( MatrixMode == 3 )
MatrixLoadIdentity( TexMatrix );
else
{
MatrixLoadIdentity( PosMatrix );
if ( MatrixMode == 2 )
MatrixLoadIdentity( VecMatrix );
ClipMatrixDirty = true;
AddCycles( 18 );
}
break;
case 0x20:
VertexPipelineCmdDelayed6();
{
uint cc = entry.Param;
VertexColor[0] = (byte)(cc & 0x1F);
VertexColor[1] = (byte)((cc >> 5) & 0x1F);
VertexColor[2] = (byte)((cc >> 10) & 0x1F);
}
break;
case 0x21:
VertexPipelineCmdDelayed4();
Normal[0] = (short)((short)((entry.Param & 0x000003FF) << 6) >> 6);
Normal[1] = (short)((short)((entry.Param & 0x000FFC00) >> 4) >> 6);
Normal[2] = (short)((short)((entry.Param & 0x3FF00000) >> 14) >> 6);
CalculateLighting();
break;
case 0x22:
VertexPipelineCmdDelayed4();
RawTexCoords[0] = (short)(entry.Param & 0xFFFF);
RawTexCoords[1] = (short)(entry.Param >> 16);
if ( (TexParam >> 30) == 1 )
{
TexCoords[0] = (short)((RawTexCoords[0] * TexMatrix[0] + RawTexCoords[1] * TexMatrix[4] + TexMatrix[8] + TexMatrix[12]) >> 12);
TexCoords[1] = (short)((RawTexCoords[0] * TexMatrix[1] + RawTexCoords[1] * TexMatrix[5] + TexMatrix[9] + TexMatrix[13]) >> 12);
}
else
{
TexCoords[0] = RawTexCoords[0];
TexCoords[1] = RawTexCoords[1];
}
break;
case 0x24:
VertexPipelineSubmitCmd();
CurVertex[0] = (short)((entry.Param & 0x000003FF) << 6);
CurVertex[1] = (short)((entry.Param & 0x000FFC00) >> 4);
CurVertex[2] = (short)((entry.Param & 0x3FF00000) >> 14);
SubmitVertex();
break;
case 0x25:
VertexPipelineSubmitCmd();
CurVertex[0] = (short)(entry.Param & 0xFFFF);
CurVertex[1] = (short)(entry.Param >> 16);
SubmitVertex();
break;
case 0x26:
VertexPipelineSubmitCmd();
CurVertex[0] = (short)(entry.Param & 0xFFFF);
CurVertex[2] = (short)(entry.Param >> 16);
SubmitVertex();
break;
case 0x27:
VertexPipelineSubmitCmd();
CurVertex[1] = (short)(entry.Param & 0xFFFF);
CurVertex[2] = (short)(entry.Param >> 16);
SubmitVertex();
break;
case 0x28:
VertexPipelineSubmitCmd();
CurVertex[0] += (short)((short)((entry.Param & 0x000003FF) << 6) >> 6);
CurVertex[1] += (short)((short)((entry.Param & 0x000FFC00) >> 4) >> 6);
CurVertex[2] += (short)((short)((entry.Param & 0x3FF00000) >> 14) >> 6);
SubmitVertex();
break;
case 0x29:
VertexPipelineCmdDelayed8();
PolygonAttr = entry.Param;
break;
case 0x2A:
VertexPipelineCmdDelayed8();
TexParam = entry.Param;
break;
case 0x2B:
VertexPipelineCmdDelayed8();
TexPalette = entry.Param & 0x1FFF;
break;
case 0x30:
VertexPipelineCmdDelayed6();
MatDiffuse[0] = (byte)(entry.Param & 0x1F);
MatDiffuse[1] = (byte)((entry.Param >> 5) & 0x1F);
MatDiffuse[2] = (byte)((entry.Param >> 10) & 0x1F);
MatAmbient[0] = (byte)((entry.Param >> 16) & 0x1F);
MatAmbient[1] = (byte)((entry.Param >> 21) & 0x1F);
MatAmbient[2] = (byte)((entry.Param >> 26) & 0x1F);
if ( (entry.Param & 0x8000) != 0 )
{
VertexColor[0] = MatDiffuse[0];
VertexColor[1] = MatDiffuse[1];
VertexColor[2] = MatDiffuse[2];
}
AddCycles( 3 );
break;
case 0x31:
VertexPipelineCmdDelayed6();
MatSpecular[0] = (byte)(entry.Param & 0x1F);
MatSpecular[1] = (byte)((entry.Param >> 5) & 0x1F);
MatSpecular[2] = (byte)((entry.Param >> 10) & 0x1F);
MatEmission[0] = (byte)((entry.Param >> 16) & 0x1F);
MatEmission[1] = (byte)((entry.Param >> 21) & 0x1F);
MatEmission[2] = (byte)((entry.Param >> 26) & 0x1F);
UseShininessTable = (entry.Param & 0x8000) != 0;
AddCycles( 3 );
break;
case 0x32:
StallPolygonPipeline( 8 + 1, 2 );
{
uint l = entry.Param >> 30;
short d0 = (short)((short)((entry.Param & 0x000003FF) << 6) >> 6);
short d1 = (short)((short)((entry.Param & 0x000FFC00) >> 4) >> 6);
short d2 = (short)((short)((entry.Param & 0x3FF00000) >> 14) >> 6);
LightDirection[l, 0] = (short)((-((d0 * VecMatrix[0] + d1 * VecMatrix[4] + d2 * VecMatrix[8]) >> 12) << 21) >> 21);
LightDirection[l, 1] = (short)((-((d0 * VecMatrix[1] + d1 * VecMatrix[5] + d2 * VecMatrix[9]) >> 12) << 21) >> 21);
LightDirection[l, 2] = (short)((-((d0 * VecMatrix[2] + d1 * VecMatrix[6] + d2 * VecMatrix[10]) >> 12) << 21) >> 21);
int den = -(((d0 * VecMatrix[2] + d1 * VecMatrix[6] + d2 * VecMatrix[10]) << 9) >> 21) + (1 << 9);
if ( den == 0 ) SpecRecip[l] = 0;
else SpecRecip[l] = (1 << 18) / den;
}
AddCycles( 5 );
break;
case 0x33:
VertexPipelineCmdDelayed8();
{
uint l = entry.Param >> 30;
LightColor[l, 0] = (byte)(entry.Param & 0x1F);
LightColor[l, 1] = (byte)((entry.Param >> 5) & 0x1F);
LightColor[l, 2] = (byte)((entry.Param >> 10) & 0x1F);
}
AddCycles( 1 );
break;
case 0x40:
StallPolygonPipeline( 1, 0 );
PolygonMode = entry.Param & 0x3;
VertexNum = 0;
VertexNumInPoly = 0;
NumConsecutivePolygons = 0;
LastStripPolygon = -1;
CurPolygonAttr = PolygonAttr;
break;
case 0x41:
VertexPipelineCmdDelayed8();
break;
case 0x50:
VertexPipelineCmdDelayed4();
FlushRequest = 1;
FlushAttributes = entry.Param & 0x3;
CycleCount = 325;
VertexPipeline = 0;
NormalPipeline = 0;
PolygonPipeline = 0;
VertexSlotCounter = 0;
VertexSlotsFree = 1;
break;
case 0x60:
VertexPipelineCmdDelayed8();
Viewport[0] = entry.Param & 0xFF;
Viewport[1] = (191 - ((entry.Param >> 8) & 0xFF)) & 0xFF;
Viewport[2] = (entry.Param >> 16) & 0xFF;
Viewport[3] = (191 - (entry.Param >> 24)) & 0xFF;
Viewport[4] = (Viewport[2] - Viewport[0] + 1) & 0x1FF;
Viewport[5] = (Viewport[1] - Viewport[3] + 1) & 0xFF;
break;
case 0x72:
VertexPipelineCmdDelayed6();
NumTestCommands--;
VecTest( entry.Param );
break;
default:
VertexPipelineCmdDelayed4();
break;
}
}
else
{
ExecParams[ExecParamCount] = (int)entry.Param;
ExecParamCount++;
if ( ExecParamCount == 1 )
{
switch ( entry.Command )
{
case 0x23: VertexPipelineSubmitCmd(); break;
case 0x34:
case 0x71:
VertexPipelineCmdDelayed8();
break;
case 0x70: StallPolygonPipeline( 10 + 1, 0 ); break;
default: VertexPipelineCmdDelayed4(); break;
}
}
else
{
AddCycles( 1 );
if ( ExecParamCount >= paramsRequiredCount )
{
ExecParamCount = 0;
switch ( entry.Command )
{
case 0x16:
if ( MatrixMode == 0 )
{
MatrixLoad4x4( ProjMatrix, ExecParams );
ClipMatrixDirty = true;
AddCycles( 18 );
}
else if ( MatrixMode == 3 )
{
MatrixLoad4x4( TexMatrix, ExecParams );
AddCycles( 10 );
}
else
{
MatrixLoad4x4( PosMatrix, ExecParams );
if ( MatrixMode == 2 )
MatrixLoad4x4( VecMatrix, ExecParams );
ClipMatrixDirty = true;
AddCycles( 18 );
}
break;
case 0x17:
if ( MatrixMode == 0 )
{
MatrixLoad4x3( ProjMatrix, ExecParams );
ClipMatrixDirty = true;
AddCycles( 18 );
}
else if ( MatrixMode == 3 )
{
MatrixLoad4x3( TexMatrix, ExecParams );
AddCycles( 7 );
}
else
{
MatrixLoad4x3( PosMatrix, ExecParams );
if ( MatrixMode == 2 )
MatrixLoad4x3( VecMatrix, ExecParams );
ClipMatrixDirty = true;
AddCycles( 18 );
}
break;
case 0x18:
if ( MatrixMode == 0 )
{
MatrixMult4x4( ProjMatrix, ExecParams );
ClipMatrixDirty = true;
AddCycles( 35 - 16 );
}
else if ( MatrixMode == 3 )
{
MatrixMult4x4( TexMatrix, ExecParams );
AddCycles( 33 - 16 );
}
else
{
MatrixMult4x4( PosMatrix, ExecParams );
if ( MatrixMode == 2 )
{
MatrixMult4x4( VecMatrix, ExecParams );
AddCycles( 35 + 30 - 16 );
}
else AddCycles( 35 - 16 );
ClipMatrixDirty = true;
}
break;
case 0x19:
if ( MatrixMode == 0 )
{
MatrixMult4x3( ProjMatrix, ExecParams );
ClipMatrixDirty = true;
AddCycles( 35 - 12 );
}
else if ( MatrixMode == 3 )
{
MatrixMult4x3( TexMatrix, ExecParams );
AddCycles( 33 - 12 );
}
else
{
MatrixMult4x3( PosMatrix, ExecParams );
if ( MatrixMode == 2 )
{
MatrixMult4x3( VecMatrix, ExecParams );
AddCycles( 35 + 30 - 12 );
}
else AddCycles( 35 - 12 );
ClipMatrixDirty = true;
}
break;
case 0x1A:
if ( MatrixMode == 0 )
{
MatrixMult3x3( ProjMatrix, ExecParams );
ClipMatrixDirty = true;
AddCycles( 35 - 9 );
}
else if ( MatrixMode == 3 )
{
MatrixMult3x3( TexMatrix, ExecParams );
AddCycles( 33 - 9 );
}
else
{
MatrixMult3x3( PosMatrix, ExecParams );
if ( MatrixMode == 2 )
{
MatrixMult3x3( VecMatrix, ExecParams );
AddCycles( 35 + 30 - 9 );
}
else AddCycles( 35 - 9 );
ClipMatrixDirty = true;
}
break;
case 0x1B:
if ( MatrixMode == 0 )
{
MatrixScale( ProjMatrix, ExecParams );
ClipMatrixDirty = true;
AddCycles( 35 - 3 );
}
else if ( MatrixMode == 3 )
{
MatrixScale( TexMatrix, ExecParams );
AddCycles( 33 - 3 );
}
else
{
MatrixScale( PosMatrix, ExecParams );
ClipMatrixDirty = true;
AddCycles( 35 - 3 );
}
break;
case 0x1C:
if ( MatrixMode == 0 )
{
MatrixTranslate( ProjMatrix, ExecParams );
ClipMatrixDirty = true;
AddCycles( 35 - 3 );
}
else if ( MatrixMode == 3 )
{
MatrixTranslate( TexMatrix, ExecParams );
AddCycles( 33 - 3 );
}
else
{
MatrixTranslate( PosMatrix, ExecParams );
if ( MatrixMode == 2 )
{
MatrixTranslate( VecMatrix, ExecParams );
AddCycles( 35 + 30 - 3 );
}
else AddCycles( 35 - 3 );
ClipMatrixDirty = true;
}
break;
case 0x23:
CurVertex[0] = (short)(ExecParams[0] & 0xFFFF);
CurVertex[1] = (short)((uint)ExecParams[0] >> 16);
CurVertex[2] = (short)(ExecParams[1] & 0xFFFF);
SubmitVertex();
break;
case 0x34:
for ( int i = 0; i < 128; i += 4 )
{
uint val = (uint)ExecParams[i >> 2];
ShininessTable[i + 0] = (byte)(val & 0xFF);
ShininessTable[i + 1] = (byte)((val >> 8) & 0xFF);
ShininessTable[i + 2] = (byte)((val >> 16) & 0xFF);
ShininessTable[i + 3] = (byte)(val >> 24);
}
break;
case 0x71:
NumTestCommands -= 2;
CurVertex[0] = (short)(ExecParams[0] & 0xFFFF);
CurVertex[1] = (short)((uint)ExecParams[0] >> 16);
CurVertex[2] = (short)(ExecParams[1] & 0xFFFF);
PosTest();
break;
case 0x70:
NumTestCommands -= 3;
BoxTest( ExecParams );
break;
}
}
}
}
}
private static void MatrixCopy( int[] dst, int[] src )
{
for ( int i = 0; i < 16; i++ ) dst[i] = src[i];
}
private static void MatrixCopyToStack( int[,] stack, int idx, int[] src )
{
for ( int i = 0; i < 16; i++ ) stack[idx, i] = src[i];
}
private static void MatrixCopyFromStack( int[] dst, int[,] stack, int idx )
{
for ( int i = 0; i < 16; i++ ) dst[i] = stack[idx, i];
}
}