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(); } }
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); }
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(); } }
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; }
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); }