Ejemplo n.º 1
0
        public static void ParseRDPSetOtherMode(F3DEX2Command cmd,
                                                out PipelineMode pm, out CycleType cyc, out TexturePersp tp, out TextureDetail td, out TextureLOD tl,
                                                out TextureLUT tt, out TextureFilter tf, out TextureConvert tc, out CombineKey ck, out ColorDither cd,
                                                out AlphaDither ad, out AlphaCompare ac, out DepthSource zs, out RenderMode rm)
        {
            rm = new RenderMode(cmd.Words & (0xFFFFFFFF & ~((ulong)AlphaCompare.Mask | (ulong)DepthSource.Mask)));

            if (!rm.Known) // Handle TCL modes by checking again with alpha compare and dither included
            {
                rm = new RenderMode(cmd.Words & (0xFFFFFFFF & ~(ulong)DepthSource.Mask));
            }

            ulong wordH = cmd.Words >> 32;

            ad  = (AlphaDither)(wordH & (ulong)AlphaDither.Mask);
            cd  = (ColorDither)(wordH & (ulong)ColorDither.Mask);
            ck  = (CombineKey)(wordH & (ulong)CombineKey.Mask);
            pm  = (PipelineMode)(wordH & (ulong)PipelineMode.Mask);
            cyc = (CycleType)(wordH & (ulong)CycleType.Mask);
            tp  = (TexturePersp)(wordH & (ulong)TexturePersp.Mask);
            td  = (TextureDetail)(wordH & (ulong)TextureDetail.Mask);
            tl  = (TextureLOD)(wordH & (ulong)TextureLOD.Mask);
            tt  = (TextureLUT)(wordH & (ulong)TextureLUT.Mask);
            tf  = (TextureFilter)(wordH & (ulong)TextureFilter.Mask);
            tc  = (TextureConvert)(wordH & (ulong)TextureConvert.Mask);

            ac = (AlphaCompare)(cmd.Words & (ulong)AlphaCompare.Mask);
            zs = (DepthSource)(cmd.Words & (ulong)DepthSource.Mask);
        }
Ejemplo n.º 2
0
        public string ParseString(List <F3DEX2Command> nextCmds, out int cmdsSkipped, ref int totalTris, ref int totalVertices, string indentation)
        {
            cmdsSkipped = 0;
            switch (CommandId)
            {
            case F3DEX2CommandId.G_NOOP:
            {
                if ((Words & 0xFFFFFF) == 0)
                {
                    return("gsDPNoOp()");
                }
                else
                {
                    return(string.Format("gsDPNoOpTag({0})", Words & 0xFFFFFF));
                }
            }

            case F3DEX2CommandId.G_RDPHALF_2: break;

            case F3DEX2CommandId.G_SETOTHERMODE_H:
            {
                F3DEX2Decoder.ParseOtherMode(this,
                                             out int sft, out int len, out ulong data);

                OthermodeHShift sftType = (OthermodeHShift)sft;

                switch (sftType)
                {
                case OthermodeHShift.G_MDSFT_ALPHADITHER:
                    if (len == 2)
                    {
                        return(string.Format("gsDPSetAlphaDither({0})", (AlphaDither)data));
                    }
                    break;

                case OthermodeHShift.G_MDSFT_RGBDITHER:
                    if (len == 2)
                    {
                        return(string.Format("gsDPSetColorDither({0})", (ColorDither)data));
                    }
                    break;

                case OthermodeHShift.G_MDSFT_COMBKEY:
                    if (len == 1)
                    {
                        return(string.Format("gsDPSetCombineKey({0})", (CombineKey)data));
                    }
                    break;

                case OthermodeHShift.G_MDSFT_TEXTCONV:
                    if (len == 3)
                    {
                        return(string.Format("gsDPSetTextureConvert({0})", (TextureConvert)data));
                    }
                    break;

                case OthermodeHShift.G_MDSFT_TEXTFILT:
                    if (len == 2)
                    {
                        return(string.Format("gsDPSetTextureFilter({0})", (TextureFilter)data));
                    }
                    break;

                case OthermodeHShift.G_MDSFT_TEXTLUT:
                    if (len == 2)
                    {
                        return(string.Format("gsDPSetTextureLUT({0})", (TextureLUT)data));
                    }
                    break;

                case OthermodeHShift.G_MDSFT_TEXTLOD:
                    if (len == 1)
                    {
                        return(string.Format("gsDPSetTextureLOD({0})", (TextureLOD)data));
                    }
                    break;

                case OthermodeHShift.G_MDSFT_TEXTDETAIL:
                    if (len == 2)
                    {
                        return(string.Format("gsDPSetTextureDetail({0})", (TextureDetail)data));
                    }
                    break;

                case OthermodeHShift.G_MDSFT_TEXTPERSP:
                    if (len == 1)
                    {
                        return(string.Format("gsDPSetTexturePersp({0})", (TexturePersp)data));
                    }
                    break;

                case OthermodeHShift.G_MDSFT_CYCLETYPE:
                    if (len == 2)
                    {
                        return(string.Format("gsDPSetCycleType({0})", (CycleType)data));
                    }
                    break;

                case OthermodeHShift.G_MDSFT_PIPELINE:
                    if (len == 1)
                    {
                        return(string.Format("gsDPPipelineMode({0})", (PipelineMode)data));
                    }
                    break;
                }
                break;
            }

            case F3DEX2CommandId.G_SETOTHERMODE_L:
            {
                F3DEX2Decoder.ParseOtherMode(this,
                                             out int sft, out int len, out ulong data);

                OthermodeLShift sftType = (OthermodeLShift)sft;

                switch (sftType)
                {
                case OthermodeLShift.G_MDSFT_ALPHACOMPARE:
                    if (len == 2)
                    {
                        return(string.Format("gsDPSetAlphaCompare({0})", (AlphaCompare)data));
                    }
                    break;

                case OthermodeLShift.G_MDSFT_ZSRCSEL:
                    if (len == 1)
                    {
                        return(string.Format("gsDPSetDepthSource({0})", (DepthSource)data));
                    }
                    break;

                case OthermodeLShift.G_MDSFT_RENDERMODE:
                    if (len == 29)
                    {
                        RenderMode rm = new RenderMode(Words);
                        return(string.Format("gsDPSetRenderMode({0})", rm));
                    }
                    break;

                case OthermodeLShift.G_MDSFT_BLENDER:
                    break;
                }

                break;
            }

            case F3DEX2CommandId.G_RDPHALF_1:
            {
                ulong rdpHalfData = Words & 0xFFFFFFFF;

                if (nextCmds.Count >= 1)
                {
                    // gsSPBranchLessZrg/raw
                    if (nextCmds[0].CommandId == F3DEX2CommandId.G_BRANCH_Z)
                    {
                        F3DEX2Decoder.ParseBranchLessZ(nextCmds[0],
                                                       out int vtx, out int zval);

                        cmdsSkipped = 1;

                        return(string.Format("gsSPBranchLessZraw(0x{0:X8}, {1}, {2})", rdpHalfData, vtx, zval));
                    }
                    // gsSPLoadUCodeEx
                    else if (nextCmds[0].CommandId == F3DEX2CommandId.G_LOAD_UCODE)
                    {
                        F3DEX2Decoder.ParseLoadUcode(nextCmds[0],
                                                     out ulong uc_start, out int uc_dsize);

                        cmdsSkipped = 1;

                        return(string.Format("gsSPLoadUcodeEx(0x{0:X8}, 0x{1:X8}, 0x{2:X8})", uc_start, rdpHalfData, uc_dsize));
                    }
                }

                return(string.Format("gImmp1(pkt, G_RDPHALF_1, {0})", rdpHalfData));
            }

            case F3DEX2CommandId.G_SPNOOP:
                return("gsSPNoOp()");

            case F3DEX2CommandId.G_ENDDL:
                return("gsSPEndDisplayList()");

            case F3DEX2CommandId.G_DL:
                if ((Words >> (32 + 16) & 0xFF) == 0x01)
                {
                    return(string.Format("gsSPBranchList(0x{0:X8})", Words & 0xFFFFFFFF));
                }
                else
                {
                    return(string.Format("gsSPDisplayList(0x{0:X8})", Words & 0xFFFFFFFF));
                }

            case F3DEX2CommandId.G_LOAD_UCODE: break;

            case F3DEX2CommandId.G_MOVEMEM:
            {
                MoveMem mm = new MoveMem(Words);
                return(mm.ToString());
            }

            case F3DEX2CommandId.G_MOVEWORD:
            {
                MoveWord mw = new MoveWord(Words);
                return(mw.ToString(nextCmds, out cmdsSkipped));
            }

            case F3DEX2CommandId.G_MTX:
            {
                F3DEX2Decoder.ParseMatrix(this,
                                          out MatrixType mType, out MatrixLoadType loadType, out MatrixPushType pushType, out ulong mAddr,
                                          out int size, out int offset);

                if (size == 64 && offset == 0)         // TODO remove magic number
                {
                    return(string.Format("gsSPMatrix(0x{0:X8}, {1} | {2} | {3})", mAddr, mType, loadType, pushType));
                }
                else
                {
                    return(string.Format("gsDma2p(G_MTX, {0:X8}, {1}, {2} | {3} | {4}, {5}", mAddr, size, mType, loadType, pushType, offset));
                }
            }

            case F3DEX2CommandId.G_GEOMETRYMODE:
            {
                GeometryMode gm = new GeometryMode(Words);
                return(gm.ToString());
            }

            case F3DEX2CommandId.G_POPMTX:
            {
                F3DEX2Decoder.ParsePopMtx(this,
                                          out int bytes, out int idx);

                if (idx == 2)
                {
                    if (bytes == 64)
                    {
                        return("gsSPPopMatrix(G_MTX_MODELVIEW)");
                    }
                    else if (bytes % 64 == 0)
                    {
                        return(string.Format("gsSPPopMatrixN(G_MTX_MODELVIEW, {0})", bytes / 64));
                    }
                }

                break;
            }

            case F3DEX2CommandId.G_TEXTURE:
            {
                F3DEX2Decoder.ParseTexture(this,
                                           out int s, out int t, out int level, out int tile, out int on);

                string tileString;

                if (tile == 7)
                {
                    tileString = "G_TX_LOADTILE";
                }
                else if (tile == 0)
                {
                    tileString = "G_TX_RENDERTILE";
                }
                else
                {
                    tileString = tile.ToString();
                }

                string onString;

                if (on == 1)
                {
                    onString = "G_ON";
                }
                else if (on == 0)
                {
                    onString = "G_OFF";
                }
                else
                {
                    onString = on.ToString();
                }

                return(string.Format("gsSPTexture(0x{0:X4}, 0x{1:X4}, {2}, {3}, {4})", s, t, level, tileString, onString));
            }

            case F3DEX2CommandId.G_DMA_IO: break;

            case F3DEX2CommandId.G_SPECIAL_1:
            case F3DEX2CommandId.G_SPECIAL_2:
            case F3DEX2CommandId.G_SPECIAL_3:
            {
                // TODO This will not work in the general case, and is tailored to F3DEX2 2.04H, which is the only ucode I've seen
                // that uses any G_SPECIAL commands (G_SPECIAL_1 in that case).
                return(string.Format("gsImmp1({0}, {1})", CommandId, Words & 0xFFFFFFFF));
            }

            case F3DEX2CommandId.G_VTX:
            {
                F3DEX2Decoder.ParseVtx(this,
                                       out int vtxCount, out int vtxOffset, out ulong vtxAddr);

                totalVertices += vtxCount;

                return(string.Format("gsSPVertex(0x{0:X8}, {1}, {2})", vtxAddr, vtxCount, vtxOffset));
            }

            case F3DEX2CommandId.G_MODIFYVTX: break;

            case F3DEX2CommandId.G_CULLDL:
            {
                F3DEX2Decoder.ParseCullDL(this,
                                          out int vstart, out int vend);
                return(string.Format("gsSPCullDisplayList({0}, {1})", vstart, vend));
            }

            case F3DEX2CommandId.G_BRANCH_Z: break;

            case F3DEX2CommandId.G_TRI1:
            {
                F3DEX2Decoder.ParseTri(this, true,
                                       out int a, out int b, out int c);

                totalTris++;

                return(string.Format("gsSP1Triangle({0}, {1}, {2}, 0)", a, b, c));
            }

            case F3DEX2CommandId.G_TRI2:
            {
                F3DEX2Decoder.ParseTri(this, true,
                                       out int a1, out int b1, out int c1);
                F3DEX2Decoder.ParseTri(this, false,
                                       out int a2, out int b2, out int c2);

                totalTris += 2;

                return(string.Format("gsSP2Triangles({0}, {1}, {2}, 0, {3}, {4}, {5}, 0)", a1, b1, c1, a2, b2, c2));
            }

            case F3DEX2CommandId.G_QUAD:     // TODO test this
            {
                F3DEX2Decoder.ParseTri(this, true,
                                       out int a1, out int b1, out int c1);
                F3DEX2Decoder.ParseTri(this, false,
                                       out int _, out int _, out int c2);

                return(string.Format("gsSP1Quadrangle({0}, {1}, {2}, {3}, 0)", a1, b1, c1, c2));
            }

            case F3DEX2CommandId.G_LINE3D: break;

            case F3DEX2CommandId.G_SETCIMG:
            {
                F3DEX2Decoder.ParseSetImage(this,
                                            out int fmt, out int siz, out int width, out ulong i);

                return(string.Format("gsDPSetColorImage({0}, {1}, {2}, 0x{3:X8})",
                                     (RDPImgFormat)fmt, (RDPImgSize)siz,
                                     width, i));
            }

            case F3DEX2CommandId.G_SETZIMG:
            {
                F3DEX2Decoder.ParseSetImage(this,
                                            out int fmt, out int siz, out int width, out ulong i);

                if (fmt == 0 && siz == 0 && width == 1)
                {
                    return(string.Format("gsDPSetDepthImage(0x{0:X8})", i));
                }
                else
                {
                    return(string.Format("gsSetImage(G_SETZIMG, {0}, {1}, {2}, 0x{3:X8})", fmt, siz, width, i));
                }
            }

            case F3DEX2CommandId.G_SETTIMG:
            {
                F3DEX2Decoder.ParseSetImage(this,
                                            out int fmt, out int siz, out int width, out ulong i);

                return(string.Format("gsDPSetTextureImage({0}, {1}, {2}, 0x{3:X8})",
                                     (RDPImgFormat)fmt, (RDPImgSize)siz,
                                     width, i));
            }

            case F3DEX2CommandId.G_SETCOMBINE:
            {
                F3DEX2Decoder.ParseSetCombine(this,
                                              out ulong ulongMode);

                CombineMode mode = new CombineMode(ulongMode);

                string modeStr = mode.ToString();

                if (modeStr.StartsWith("G_CC"))
                {
                    return(string.Format("gsDPSetCombine({0})", modeStr));
                }
                else
                {
                    return(string.Format("gsDPSetCombineLerp({0})", modeStr));
                }
            }

            case F3DEX2CommandId.G_SETENVCOLOR:
            {
                F3DEX2Decoder.ParseSetColor(this,
                                            out ulong col);
                F3DEX2Decoder.GetComponents(col,
                                            out int r, out int g, out int b, out int a);

                return(string.Format("gsDPSetEnvColor(0x{0:X2}, 0x{1:X2}, 0x{2:X2}, 0x{3:X2})", r, g, b, a));
            }

            case F3DEX2CommandId.G_SETPRIMCOLOR:
            {
                F3DEX2Decoder.ParseSetColor(this,
                                            out ulong col);
                F3DEX2Decoder.GetComponents(col,
                                            out int r, out int g, out int b, out int a);

                int m = (int)(Words >> (32 + 8)) & 0xFF;
                int l = (int)(Words >> (32 + 0)) & 0xFF;

                return(string.Format("gsDPSetPrimColor(0x{0:X2}, 0x{1:X2}, 0x{2:X2}, 0x{3:X2}, 0x{4:X2}, 0x{5:X2})", m, l, r, g, b, a));
            }

            case F3DEX2CommandId.G_SETBLENDCOLOR:
            {
                F3DEX2Decoder.ParseSetColor(this,
                                            out ulong col);
                F3DEX2Decoder.GetComponents(col,
                                            out int r, out int g, out int b, out int a);

                return(string.Format("gsDPSetBlendColor(0x{0:X2}, 0x{1:X2}, 0x{2:X2}, 0x{3:X2})", r, g, b, a));
            }

            case F3DEX2CommandId.G_SETFOGCOLOR:
            {
                F3DEX2Decoder.ParseSetColor(this,
                                            out ulong col);
                F3DEX2Decoder.GetComponents(col,
                                            out int r, out int g, out int b, out int a);

                return(string.Format("gsDPSetFogColor(0x{0:X2}, 0x{1:X2}, 0x{2:X2}, 0x{3:X2})", r, g, b, a));
            }

            case F3DEX2CommandId.G_SETFILLCOLOR:
            {
                F3DEX2Decoder.ParseSetColor(this,
                                            out ulong col);

                return(string.Format("gsDPSetFillColor({0})", F3DEX2Decoder.PackedColorWordToStr(col)));
            }

            case F3DEX2CommandId.G_FILLRECT:
            {
                F3DEX2Decoder.ParseRect(this,
                                        out int xl, out int yl, out int xh, out int yh, out int _);

                return(string.Format("gsDPFillRectangle({0}, {1}, {2}, {3})",
                                     xl >> 2, yl >> 2, (xh >> 2), (yh >> 2)));
            }

            case F3DEX2CommandId.G_SETTILE:
            {
                F3DEX2Decoder.ParseSetTile(this,
                                           out int fmt, out int siz, out int line, out int tmem, out int tile, out int palette, out int cmt,
                                           out int maskt, out int shiftt, out int cms, out int masks, out int shifts);
                RDPMirror    mirrorT = (RDPMirror)(cmt & 0x1);
                RDPWrapClamp clampT  = (RDPWrapClamp)(cmt & 0x2);
                RDPMirror    mirrorS = (RDPMirror)(cms & 0x1);
                RDPWrapClamp clampS  = (RDPWrapClamp)(cms & 0x2);

                return(string.Format("gsDPSetTile({0}, {1}, {2}, {3}, {4}, {5}, {6}|{7}, {8}, {9}, {10}|{11}, {12}, {13})",
                                     (RDPImgFormat)fmt, (RDPImgSize)siz,
                                     line, tmem, tile, palette,
                                     mirrorT, clampT,
                                     maskt, shiftt,
                                     mirrorS, clampS,
                                     masks, shifts));
            }

            case F3DEX2CommandId.G_LOADTILE:
            {
                F3DEX2Decoder.ParseLoadTileGeneric(this,
                                                   out int tile, out int uls, out int ult, out int lrs, out int lrt);

                string ulsStr = F3DEX2Decoder.TexCoord102ToStr(uls);
                string ultStr = F3DEX2Decoder.TexCoord102ToStr(ult);
                string lrsStr = F3DEX2Decoder.TexCoord102ToStr(lrs, true);
                string lrtStr = F3DEX2Decoder.TexCoord102ToStr(lrt, true);

                return(string.Format("gsDPLoadTile({0}, {1}, {2}, {3}, {4})",
                                     tile, ulsStr, ultStr, lrsStr, lrtStr)); // TODO CI4 textures are loaded as 8b, so this may not produce a clean output
            }

            case F3DEX2CommandId.G_LOADBLOCK:
            {
                F3DEX2Decoder.ParseLoadTileGeneric(this,
                                                   out int tile, out int uls, out int ult, out int lrs, out int dxt);

                return(string.Format("gsDPLoadBlock({0}, 0x{1:X3}, 0x{2:X3}, 0x{3:X3}, 0x{4:X3})",
                                     tile, uls, ult, lrs, dxt));
            }

            case F3DEX2CommandId.G_SETTILESIZE:
            {
                F3DEX2Decoder.ParseLoadTileGeneric(this,
                                                   out int tile, out int uls, out int ult, out int lrs, out int lrt);

                string ulsStr = F3DEX2Decoder.TexCoord102ToStr(uls);
                string ultStr = F3DEX2Decoder.TexCoord102ToStr(ult);
                string lrsStr = F3DEX2Decoder.TexCoord102ToStr(lrs, true);
                string lrtStr = F3DEX2Decoder.TexCoord102ToStr(lrt, true);

                return(string.Format("gsDPSetTileSize({0}, {1}, {2}, {3}, {4})",
                                     tile, ulsStr, ultStr, lrsStr, lrtStr));
            }

            case F3DEX2CommandId.G_LOADTLUT:
            {
                F3DEX2Decoder.ParseLoadTLUT(this,
                                            out int tile, out int count);
                return(string.Format("gsDPLoadTLUTCmd({0}, {1})", tile, count));
            }

            case F3DEX2CommandId.G_RDPSETOTHERMODE:
            {
                F3DEX2Decoder.ParseRDPSetOtherMode(this,
                                                   out PipelineMode pm, out CycleType cyc, out TexturePersp tp, out TextureDetail td, out TextureLOD tl,
                                                   out TextureLUT tt, out TextureFilter tf, out TextureConvert tc, out CombineKey ck, out ColorDither cd,
                                                   out AlphaDither ad, out AlphaCompare ac, out DepthSource zs, out RenderMode rm);

                return(string.Format("gsDPSetOtherMode(\n" +
                                     indentation + "{0} | {1} | {2} | {3} | {4} | {5}\n" +
                                     indentation + "{6} | {7} | {8} | {9} | {10},\n" +
                                     indentation + "{11} | {12} | {13})",
                                     pm, cyc, tp, td, tl, tt, tf, tc, ck, cd, ad,
                                     ac, zs, rm.ToString().Replace(",", " |")));
            }

            case F3DEX2CommandId.G_SETPRIMDEPTH: break;

            case F3DEX2CommandId.G_SETSCISSOR:
            {
                F3DEX2Decoder.ParseScissor(this,
                                           out int mode, out int ulx, out int uly, out int lrx, out int lry);

                return(string.Format("gsDPSetScissor({0}, {1:F2}f, {2:F2}f, {3:F2}f, {4:F2}f)",
                                     (ScissorMode)mode, ulx / 4.0f, uly / 4.0f, lrx / 4.0f, lry / 4.0f));
            }

            case F3DEX2CommandId.G_SETCONVERT:
            {
                F3DEX2Decoder.ParseConvert(this,
                                           out int[] coeffs);

                string k0Str = (coeffs[0] == (short)ConvertCoeff.G_CV_K0) ? "G_CV_K0" : coeffs[0].ToString();
                string k1Str = (coeffs[1] == (short)ConvertCoeff.G_CV_K1) ? "G_CV_K1" : coeffs[1].ToString();
                string k2Str = (coeffs[2] == (short)ConvertCoeff.G_CV_K2) ? "G_CV_K2" : coeffs[2].ToString();
                string k3Str = (coeffs[3] == (short)ConvertCoeff.G_CV_K3) ? "G_CV_K3" : coeffs[3].ToString();
                string k4Str = (coeffs[4] == (short)ConvertCoeff.G_CV_K4) ? "G_CV_K4" : coeffs[4].ToString();
                string k5Str = (coeffs[5] == (short)ConvertCoeff.G_CV_K5) ? "G_CV_K5" : coeffs[5].ToString();

                return(string.Format("gsDPSetConvert({0}, {1}, {2}, {3}, {4}, {5})",
                                     k0Str, k1Str, k2Str, k3Str, k4Str, k5Str));
            }

            case F3DEX2CommandId.G_SETKEYR: break;

            case F3DEX2CommandId.G_SETKEYGB: break;

            case F3DEX2CommandId.G_RDPFULLSYNC:
                return("gsDPFullSync()");

            case F3DEX2CommandId.G_RDPTILESYNC:
                return("gsDPTileSync()");

            case F3DEX2CommandId.G_RDPPIPESYNC:
                return("gsDPPipeSync()");

            case F3DEX2CommandId.G_RDPLOADSYNC:
                return("gsDPLoadSync()");

            case F3DEX2CommandId.G_TEXRECTFLIP:     // Fall through
            case F3DEX2CommandId.G_TEXRECT:
            {
                F3DEX2Decoder.ParseRect(this,
                                        out int xl, out int yl, out int xh, out int yh, out int tile);

                string xlStr = F3DEX2Decoder.TexCoord102ToStr(xl);
                string ylStr = F3DEX2Decoder.TexCoord102ToStr(yl);

                string xhStr = F3DEX2Decoder.TexCoord102OffsetToStr(xl, xh);
                string yhStr = F3DEX2Decoder.TexCoord102OffsetToStr(yl, yh);

                F3DEX2Command nextCmd0 = nextCmds[0];
                F3DEX2Command nextCmd1 = nextCmds[1];

                if (nextCmd0.CommandId == F3DEX2CommandId.G_RDPHALF_1 && nextCmd1.CommandId == F3DEX2CommandId.G_RDPHALF_2)
                {
                    F3DEX2Decoder.ParseRDPHalf_HH(nextCmd0, out int s, out int t);
                    F3DEX2Decoder.ParseRDPHalf_HH(nextCmd1, out int dsdx, out int dtdy);

                    cmdsSkipped = 2;

                    if (CommandId == F3DEX2CommandId.G_TEXRECT)
                    {
                        return(string.Format("gsSPTextureRectangle({0}, {1}, {2}, {3}, {4}, 0x{5:X4}, 0x{6:X4}, 0x{7:X4}, 0x{8:X4})",
                                             xlStr, ylStr, xhStr, yhStr, tile, s, t, dsdx, dtdy));
                    }
                    else
                    {
                        return(string.Format("gsSPTextureRectangleFlip({0}, {1}, {2}, {3}, {4}, 0x{5:X4}, 0x{6:X4}, 0x{7:X4}, 0x{8:X4})",
                                             xlStr, ylStr, xhStr, yhStr, tile, s, t, dsdx, dtdy));
                    }
                }
                break;
            }
            }
            return(string.Format("{0:X8},{1:X8}", Words >> 32, Words & 0xFFFFFFFF));
        }