public static uint ReadDLCommands(int FileNumber, UInt32 Address, ref DisplayListStruct ThisDL)
        {
            DLCommandStruct ThisCommand = new DLCommandStruct();

            int Segment = (int)(Address >> 24);
            UInt32 Offset = (Address & 0x00FFFFFF);

            if (GameHandler.IsAddressValid(Address) == false) return Offset + 8;

            // Loop through the Display List in memory until we reach an EndDL command
            while (ThisCommand.ID != EndDLCmd)
            {
                // Take note of the command's data, type, name, memory location and file number
                ThisCommand.w0 = GameHandler.Read32(GameHandler.RAM[Segment].Data, Offset);
                ThisCommand.w1 = GameHandler.Read32(GameHandler.RAM[Segment].Data, Offset + 4);
                ThisCommand.ID = (byte)(ThisCommand.w0 >> 24);
                IdentifyCommand(ThisCommand.ID, ref ThisCommand.Name);
                ThisCommand.Address = (((UInt32)Segment << 24) | Offset);
                ThisCommand.InFileNumber = FileNumber;

                // Add the command to our Display List's command structure
                ThisDL.Commands.Add(ThisCommand);

                // If the command is a DL call or a RDP_HALF1 storage, go and process that Display List next
                if (ThisCommand.ID == DLCmd || ThisCommand.ID == RDPHalf1Cmd)
                {
                    ReadDLCommands(FileNumber, ThisCommand.w1, ref ThisDL);
                }

                Offset += 8;
            }

            return Offset;
        }
        public static void ReadDL(int FileNumber, UInt32 Address, ref List<DisplayListStruct> DLists)
        {
            // Some sanity checking and data extraction from the RAM address
            if (GameHandler.IsAddressValid(Address) == false) return;

            // Prepare some temporary structures
            DisplayListStruct ThisDL = new DisplayListStruct();
            ThisDL.Commands = new List<DLCommandStruct>();

            // Add identification information to the Display List
            ThisDL.InFileNumber = FileNumber;
            ThisDL.StartAddress = Address;
            ThisDL.EndAddress = ((Address & 0xFF000000) | ReadDLCommands(FileNumber, Address, ref ThisDL));
            ThisDL.GLID = GL.GenLists(1);

            // Generate random color for picking
            ThisDL.PickColor = RandomColor();

            // Add the Display List to our DL list
            DLists.Add(ThisDL);
        }
        public static void ParseAllDLs(ref List<DisplayListStruct> DLists)
        {
            // Clear primitive and environment colors
            NGraphics.PrimColor = new NPrimColor(new Color4(0.5f, 0.5f, 0.5f, 0.5f), 0.0f, 0);
            NGraphics.EnvColor = new Color4(0.5f, 0.5f, 0.5f, 0.5f);
            GL.Arb.ProgramEnvParameter4(AssemblyProgramTargetArb.FragmentProgram, 0, NGraphics.PrimColor.Color.R, NGraphics.PrimColor.Color.G, NGraphics.PrimColor.Color.B, NGraphics.PrimColor.Color.A);
            GL.Arb.ProgramEnvParameter4(AssemblyProgramTargetArb.FragmentProgram, 1, NGraphics.EnvColor.R, NGraphics.EnvColor.G, NGraphics.EnvColor.B, NGraphics.EnvColor.A);

            // For temporary access by other functions
            CurrentDLists = DLists;

            // Loop through each Display List for parsing
            foreach (DisplayListStruct ThisDL in CurrentDLists)
            {
                // Again, for temporary access
                CurrentDL = ThisDL;

                // Begin new OpenGL Display List
                GL.NewList(ThisDL.GLID, ListMode.CompileAndExecute);

                // Parse all commands of the Display List
                ParseDL(CurrentDL);

                // If the current Display List is supposed to be highlighted, parse its essential commands once more
                if (CurrentDL.Highlight == true && ParseMode != 2)
                {
                    ParseMode = 1;
                    ParseDL(CurrentDL);
                    ParseMode = 0;
                }

                // End the GL Display List
                GL.EndList();
                GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            }
        }
        public static void ParseDL(DisplayListStruct ThisDL)
        {
            // See if we're told to parse everything, or just selectively
            if (ParseMode > 0)
            {
                if (ParseMode == 1)
                {
                    // Prepare highlight rendering
                    GL.Enable((EnableCap)All.FragmentProgram);
                    GL.Arb.BindProgram(AssemblyProgramTargetArb.FragmentProgram, FPHighlight);
                    GL.Enable(EnableCap.Blend);
                    GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
                }
                else if (ParseMode == 2)
                {
                    GL.Disable(EnableCap.Texture2D);
                    GL.Color4(ThisDL.PickColor);
                }

                GL.Disable(EnableCap.AlphaTest);
                GL.Disable(EnableCap.Lighting);

                // Go through every command in the current DList
                for (int i = 0; i < ThisDL.Commands.Count; i++)
                {
                    // If it's either DL/EndDL, GeometryMode or otherwise geometry-related, execute it
                    if (ThisDL.Commands[i].ID == (byte)UcodeF3DEX2.VTX ||
                        ThisDL.Commands[i].ID == (byte)UcodeF3DEX2.TRI1 ||
                        ThisDL.Commands[i].ID == (byte)UcodeF3DEX2.TRI2 ||
                        ThisDL.Commands[i].ID == (byte)UcodeF3DEX2.DL ||
                        ThisDL.Commands[i].ID == (byte)UcodeF3DEX2.ENDDL ||
                        ThisDL.Commands[i].ID == (byte)UcodeF3DEX2.GEOMETRYMODE ||
                        ThisDL.Commands[i].ID == (byte)UcodeF3DEX2.MODIFYVTX ||
                        ThisDL.Commands[i].ID == (byte)UcodeF3DEX2.MTX ||
                        ThisDL.Commands[i].ID == (byte)UcodeF3DEX2.POPMTX)
                    {
                        UcodeCommands[ThisDL.Commands[i].ID](ThisDL.Commands[i].w0, ThisDL.Commands[i].w1);
                    }
                }

                // Reset some changed states
                GL.Enable(EnableCap.Texture2D);
                GL.Enable(EnableCap.Lighting);
                GL.Enable(EnableCap.AlphaTest);
                GL.Disable((EnableCap)All.FragmentProgram);
            }
            else
            {
                // Go through every command in the current DList
                for (int i = 0; i < ThisDL.Commands.Count; i++)
                {
                    if (i < ThisDL.Commands.Count - Macros.Max(a => a.Commands.Length))
                    {
                        foreach (MacroStruct ThisMacro in Macros)
                        {
                            // Get the next commands from the current position in the DList
                            byte[] NextCmds = new byte[ThisMacro.Commands.Length];
                            UInt32[] NextW0 = new UInt32[ThisMacro.Commands.Length + 1];
                            UInt32[] NextW1 = new UInt32[ThisMacro.Commands.Length + 1];

                            for (int j = 0; j <= ThisMacro.Commands.Length; j++)
                            {
                                if (j != ThisMacro.Commands.Length) NextCmds[j] = ThisDL.Commands[i + j].ID;
                                NextW0[j] = ThisDL.Commands[i + j].w0;
                                NextW1[j] = ThisDL.Commands[i + j].w1;
                            }

                            // Compare the bytes to the macro and execute it if we have a match
                            if (CompareBytes(NextCmds, ThisMacro.Commands))
                            {
                                IsMacro = true;
                                ThisMacro.Function(NextW0, NextW1);
                                i += ThisMacro.Commands.Length - 1;
                                break;
                            }
                        }
                        IsMacro = false;
                    }

                    // Execute the next command
                    UcodeCommands[ThisDL.Commands[i].ID](ThisDL.Commands[i].w0, ThisDL.Commands[i].w1);
                }
            }

            return;
        }
        private static void Ucode_F3DEX2_BRANCH_Z(UInt32 w0, UInt32 w1)
        {
            if (GameHandler.IsAddressValid(NGraphics.RDPHalf1) == false) return;

            uint Vtx = ShiftR(w0, 1, 11);
            short ZVal = (short)w1;

            if (CurrentVertices[Vtx].Position.Z < ZVal)
            {
                DisplayListStruct BranchDL = new DisplayListStruct();
                BranchDL.Commands = new List<DLCommandStruct>();
                ReadDLCommands(CurrentDL.InFileNumber, NGraphics.RDPHalf1, ref BranchDL);
                ParseDL(BranchDL);
            }
        }