예제 #1
0
        public static void PerformRegionParse(ROM rom, List <Region> regions, int offset)
        {
            rom.PushOffset(offset);
            try
            {
                int cmd = 0;
                do
                {
                    if (rom.Read8() != 0x00)
                    {
                        throw new ArgumentException("invalid instruction");
                    }

                    cmd = rom.Read8(1);
                    if (cmd >= 0x40 && cmd <= 0x44)
                    {
                        parser[cmd - 0x40](rom, regions);
                    }
                    else
                    {
                        RegionParse_common(rom, regions);
                    }
                }while (cmd != 0x42);

                Region region = new DynamicRegion(offset, rom.offset - offset, RegionState.Collision);
                regions.Add(region);
            }
            finally
            {
                rom.PopOffset();
            }
        }
예제 #2
0
        static RegionParseState PerformRegionParseInternal(ROM rom, List <Region> regions, int offset, int layer)
        {
            RegionParseState state = new RegionParseState();

            rom.PushOffset(offset);
            try
            {
                int cmd = 0;
                do
                {
                    cmd = rom.Read8();
                    parser[cmd](rom, regions, state);
                    rom.AddOffset(8);
                }while (cmd != 0xB8);

                Region           region;
                SortedRegionList graphicsData = new SortedRegionList();

                foreach (KeyValuePair <int, int> lightRegion in state.lightData.RegionList)
                {
                    //region = new Region(lightRegion.Key, lightRegion.Value, RegionState.LightData);
                    graphicsData.AddRegion(lightRegion.Key, lightRegion.Value);
                    //regions.Add(region);
                }

                // kostul
                if (state.lightData.RegionList.Count == 0)
                {
                    graphicsData.AddRegion(rom.GetROMAddress(0x0E000000), 0x10);
                }

                foreach (KeyValuePair <int, int> textureRegion in state.textureData.RegionList)
                {
                    //region = new Region(textureRegion.Key, textureRegion.Value, RegionState.TextureInfo);
                    graphicsData.AddRegion(textureRegion.Key, textureRegion.Value);
                    //regions.Add(region);
                }

                foreach (KeyValuePair <int, int> vertexRegion in state.vertexData.RegionList)
                {
                    //region = new Region(vertexRegion.Key, vertexRegion.Value, RegionState.VertexInfo);
                    graphicsData.AddRegion(vertexRegion.Key, vertexRegion.Value);
                    //regions.Add(region);
                }

                int count = 0;
                foreach (KeyValuePair <int, int> notFixedRegion in graphicsData.RegionList)
                {
                    region        = new DynamicRegion(notFixedRegion.Key, notFixedRegion.Value, RegionState.GraphicsData);
                    region.number = count++;
                    regions.Add(region);
                }


                region = new DisplayListRegion(offset, rom.offset - offset, state.isFogEnabled, state.isEnvColorEnabled, state.FCCount, state.B9cmdfirst, layer);
                regions.Add(region);
            }
            finally
            {
                rom.PopOffset();
            }
            return(state);
        }
예제 #3
0
        public static void PerformRegionParse(ROM rom, List <Region> regions, int offset)
        {
            rom.PushOffset(offset);
            try
            {
                List <Region> displayListRegions = new List <Region>();

                int cmd;
                do
                {
                    cmd = rom.Read8();
                    int cmdSize = cmdSizeTable[cmd];
                    if (cmdSize == 0)
                    {
                        throw new ArgumentException("Loop detected");
                    }

                    parser[cmd](rom, displayListRegions);

                    if (cmdSize != 0xFF)
                    {
                        rom.AddOffset(cmdSize);
                    }
                } while (cmd != 0x01);

                // !!! : Group together all display list information in geolayout
                MergedRegionList compoundGraphicsData = new MergedRegionList();
                List <Region>    otherRegions         = new List <Region>();

                int count = 0;
                // Merge together vertex, texture, light descriptions
                // Enumerate display lists
                foreach (Region reg in displayListRegions)
                {
                    switch (reg.state)
                    {
                    case RegionState.GraphicsData:
                        compoundGraphicsData.AddRegion(reg.romStart, reg.length);
                        break;

                    case RegionState.DisplayList:
                        reg.number = count++;
                        otherRegions.Add(reg);
                        break;

                    default:
                        // Passthrough region that we do not need to compound
                        otherRegions.Add(reg);
                        break;
                    }
                }

                Region graphicsRegion = new DynamicRegion(compoundGraphicsData.start, compoundGraphicsData.length, RegionState.GraphicsData);
                regions.Add(graphicsRegion);

                regions.AddRange(otherRegions);

                Region region = new GeoLayoutRegion(offset, rom.offset - offset);
                regions.Add(region);
            }
            finally
            {
                rom.PopOffset();
            }
        }
예제 #4
0
        private void ParseGraphics(string dirname, DataBuilder segment0E, DataBuilder segmentGeoLayouts, ROM rom, out RelocationUnit unit, out RelocationUnit graphicsDataUnit, int area = -1, int model = -1)
        {
            RelocationUnit retValue     = null;
            RelocationUnit graphicsUnit = null;

            segmentGeoLayouts.Backup();
            segment0E.Backup();
            try
            {
                DynamicRegion graphicsDataRegion = new DynamicRegion(dirname, RegionState.GraphicsData, area, model);
                // no relocation needed for dynamic region
                segment0E.AddRegion(graphicsDataRegion);
                segment0E.RoundOffset();

                // Display lists needs to be relocated with static graphics relocation table
                StaticRelocationTable graphicsRelocationTable = new StaticRelocationTable();
                graphicsUnit = new RelocationUnit(graphicsDataRegion, rom, isFromStatic: true);
                graphicsRelocationTable.AddUnit(graphicsUnit);

                // Geolayouts needs to be relocated with queued display lists, will be filled during relocation with graphicsRelocationTable
                QueueRelocationTable dispRelocationTable = new QueueRelocationTable();

                RelocationUnit dispRelocationUnit = null;
                for (int dispNumber = 0; dispNumber < 0xFF; dispNumber++)
                {
                    if (!PathComposer.IsRegionFileExists(dirname, RegionState.DisplayList, area, model, dispNumber))
                    {
                        break;
                    }

                    DisplayListRegion dispRegion = new DisplayListRegion(dirname, area, model, dispNumber);
                    DisplayList.PerformRegionRelocation(dispRegion, graphicsRelocationTable);
                    segment0E.AddRegion(dispRegion);
                    segment0E.RoundOffset();

                    dispRelocationUnit = new RelocationUnit(dispRegion, rom, isFromStatic: true);
                    dispRelocationTable.AddUnit(dispRelocationUnit);
                }

                // Not even one disp relocation unit, sounds like a bug
                if (dispRelocationUnit == null)
                {
                    throw new IOException("No display lists found!");
                }

                // Geolayout might or might not exist for model, check if it exists and if needed, relocate it
                if (PathComposer.IsRegionFileExists(dirname, RegionState.GeoLayout, area, model))
                {
                    // Load geolayout and relocate it with display lists
                    GeoLayoutRegion modelGeoLayoutRegion = new GeoLayoutRegion(dirname, area, model);
                    GeoLayout.PerformRegionRelocation(modelGeoLayoutRegion, dispRelocationTable);
                    segmentGeoLayouts.AddRegion(modelGeoLayoutRegion);
                    segmentGeoLayouts.RoundOffset();

                    // Finalize with returning geolayout for model
                    retValue = new RelocationUnit(modelGeoLayoutRegion, rom, isFromStatic: true);
                }
                else
                {
                    // Return display list only, there should be only one, if more, it is undefinied behaviour :3
                    retValue = dispRelocationUnit;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("Failed to load model {0}, reason : '{1}'", model, ex.Message), "Level Combiner", MessageBoxButtons.OK, MessageBoxIcon.Error);
                segment0E.Restore();
                segmentGeoLayouts.Restore();
            }

            unit             = retValue;
            graphicsDataUnit = graphicsUnit;
        }
예제 #5
0
        private void button1_Click(object sender, EventArgs e)
        {
            GC.Collect();

            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.Filter = "ROM File|*.z64";
            openFileDialog1.Title  = "Select a ROM";

            if (openFileDialog1.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }

            string path = openFileDialog1.FileName;

            path = Path.GetFullPath(path);

            ROM rom    = new ROM(File.ReadAllBytes(path));
            int offset = Convert.ToInt32(addressTextBox.Text, 16);

            if (offset == 0)
            {
                MessageBox.Show("Failed to parse address, input correct address", "Level Split", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            LevelScript.PerformHeaderParse(rom, offset);

            SegmentDescriptor segmentDescriptor0E = rom.GetSegmentDescriptor(0x0E);
            SegmentDescriptor segmentDescriptor19 = rom.GetSegmentDescriptor(0x19);

            DataBuilder segment0E = new DataBuilder(segmentDescriptor0E.start, segmentDescriptor0E.length);
            DataBuilder segment19 = new DataBuilder(segmentDescriptor19.start, segmentDescriptor19.length);

            string dirname = splittedPathTextBox.Text;

            // Fill in area relocation table + geolayouts
            KeyRelocationTable areaGraphicsDescrRelocationTable = new KeyRelocationTable();
            KeyRelocationTable areaGraphicsDataRelocationTable  = new KeyRelocationTable();
            KeyRelocationTable areaCollisionRelocationTable     = new KeyRelocationTable();

            for (int area = 1; area <= 8; area++)
            {
                if (!PathComposer.IsRegionFileExists(dirname, RegionState.GraphicsData, area: area))
                {
                    continue;
                }

                // Area graphics
                ParseGraphics(dirname, segment0E, segment19, rom, out RelocationUnit descrUnit, out RelocationUnit dataUnit, area: area);
                areaGraphicsDescrRelocationTable.AddUnit(area, descrUnit);
                areaGraphicsDataRelocationTable.AddUnit(area, dataUnit);

                // Area collision
                DynamicRegion collision = new DynamicRegion(dirname, RegionState.Collision, area: area);
                // No relocation needed
                segment0E.AddRegion(collision);
                segment0E.RoundOffset();

                RelocationUnit collisionRelocationUnit = new RelocationUnit(collision, rom, isFromStatic: true);
                areaCollisionRelocationTable.AddUnit(area, collisionRelocationUnit);
            }

            // Fill in model relocation table + geolayouts
            KeyRelocationTable modelRelocationTable = new KeyRelocationTable();

            for (int model = 0x00; model < 0xFF; model++)
            {
                if (!PathComposer.IsRegionFileExists(dirname, RegionState.GraphicsData, model: model))
                {
                    continue;
                }

                ParseGraphics(dirname, segment0E, segment19, rom, out RelocationUnit descrUnit, out RelocationUnit graphicsUnit, model: model);
                modelRelocationTable.AddUnit(model, descrUnit);
            }

            // As everything is prepared, we can finally start building level!
            LevelScriptRegion levelHeader = new LevelScriptRegion(dirname, RegionState.LevelHeader);

            LevelScript.FixLoadAddresses(rom, levelHeader);
            segment19.AddRegion(levelHeader);

            int levelScriptSegmentedAddressStart = rom.GetSegmentedAddress(levelHeader.romStart);

            LevelScriptRegion modelsLoader = new LevelScriptRegion(dirname, RegionState.ModelsLoader);

            modelsLoader.Relocate(modelRelocationTable);
            segment19.AddRegion(modelsLoader);

            for (sbyte area = 0; area < 8; area++)
            {
                if (!PathComposer.IsRegionFileExists(dirname, RegionState.GraphicsData, area: area))
                {
                    continue;
                }

                // Area header initializes graphics
                LevelScriptRegion areaHeader = new LevelScriptRegion(dirname, RegionState.AreaHeader, area: area);
                LevelScript.PerformRegionRelocation(areaHeader, areaGraphicsDescrRelocationTable, area);
                segment19.AddRegion(areaHeader);

                LevelScriptRegion areaData = new LevelScriptRegion(dirname, RegionState.AreaData, area: area);
                // No relocation needed
                segment19.AddRegion(areaData);

                if (PathComposer.IsRegionFileExists(dirname, RegionState.AreaScrolls, area: area))
                {
                    LevelScriptRegion scrollsData = new LevelScriptRegion(dirname, RegionState.AreaScrolls, area: area);
                    LevelScript.PerformRegionRelocation(scrollsData, areaGraphicsDataRelocationTable, area);
                    segment19.AddRegion(scrollsData);
                }

                // Area footer initializes collision
                LevelScriptRegion areaFooter = new LevelScriptRegion(dirname, RegionState.AreaFooter, area: area);
                LevelScript.PerformRegionRelocation(areaFooter, areaCollisionRelocationTable, area);
                segment19.AddRegion(areaFooter);
            }

            LevelScriptRegion levelFooter = new LevelScriptRegion(dirname, RegionState.LevelFooter);

            // no relocation needed
            segment19.AddRegion(levelFooter);


            // At this point we know that all data fit in rom
            // So just write all that in rom
            using (Stream stream = new FileStream(path, FileMode.Open))
            {
                stream.Seek(segmentDescriptor0E.start, SeekOrigin.Begin);
                stream.Write(segment0E.Data, 0, segment0E.Offset);

                stream.Seek(segmentDescriptor19.start, SeekOrigin.Begin);
                stream.Write(segment19.Data, 0, segment19.Offset);

                // Also start of level script moved so write that thing too
                int    endianData    = IPAddress.HostToNetworkOrder(levelScriptSegmentedAddressStart);
                byte[] convertedData = BitConverter.GetBytes(endianData);

                stream.Seek(rom.levelScriptEntryOffset, SeekOrigin.Begin);
                stream.Write(convertedData, 0, 4);
            }

            MessageBox.Show(String.Format("ROM was build successfully from {0}", dirname), "Level Split", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }