public static void PerformRegionOptimize(ROM realRom, Region region, FixConfig config) { // This is fake rom but it works anyways, just more convenient // Want to be safe with overwriting the whole display list ROM fakeRom = new ROM(region.data); RegionOptimizeState state = new RegionOptimizeState(config); DisplayListRegion dlRegion = (DisplayListRegion)region; byte curCmdIndex; do { curCmdIndex = fakeRom.Read8(); OptimizeParserCmd func = optimizeParser[curCmdIndex]; func(fakeRom, dlRegion, state); fakeRom.AddOffset(8); }while (fakeRom.offset < region.length); // Now write data to real rom + trimming // bzero fakeRom.offset = 0; realRom.PushOffset(region.romStart); { do { realRom.Write64(0x0101010101010101); realRom.AddOffset(8); fakeRom.AddOffset(8); } while (fakeRom.offset < region.length); } realRom.PopOffset(); fakeRom.offset = 0; realRom.PushOffset(region.romStart); { int start = region.romStart; do { Int64 cmd = fakeRom.Read64(); fakeRom.AddOffset(8); if (config.trimNOPs && cmd == 0 && dlRegion.isUnusedTrimmingAllowed) { continue; } realRom.Write64((ulong)cmd); realRom.AddOffset(8); } while (fakeRom.offset < region.length); region.length = realRom.offset - start; region.data = new byte[region.length]; realRom.ReadData(region.romStart, region.length, region.data); } realRom.PopOffset(); }
public static void PerformVisualMapRebuild(ROM realRom, Region region, int maxDLLength) { // This is fake rom but it works anyways, just more convenient // Want to be safe with overwriting the whole display list ROM fakeRom = new ROM(region.data); VisualMapParseState state = new VisualMapParseState(); DisplayListRegion dlRegion = (DisplayListRegion)region; VisualMap map = new VisualMap(); byte curCmdIndex; do { curCmdIndex = fakeRom.Read8(); VisualMapParserCmd func = visualMapParser[curCmdIndex]; func(fakeRom, map, state); fakeRom.AddOffset(8); }while (fakeRom.offset < region.length); ROM visualMapROM = new ROM(new byte[maxDLLength]); int visualMapLength = map.MakeF3D(visualMapROM); // Now write data to real rom + trimming // bzero fakeRom.offset = 0; realRom.PushOffset(region.romStart); { do { realRom.Write64(0x0101010101010101); realRom.AddOffset(8); fakeRom.AddOffset(8); } while (fakeRom.offset < region.length); } realRom.PopOffset(); visualMapROM.offset = 0; realRom.PushOffset(region.romStart); { int start = region.romStart; do { Int64 cmd = visualMapROM.Read64(); visualMapROM.AddOffset(8); realRom.Write64((ulong)cmd); realRom.AddOffset(8); } while (visualMapROM.offset < visualMapLength); region.length = realRom.offset - start; region.data = new byte[region.length]; realRom.ReadData(region.romStart, region.length, region.data); } realRom.PopOffset(); }
public void MakeF3D(ROM rom) { foreach (UInt64 cmd04 in data.Keys) { rom.Write64(cmd04); rom.AddOffset(8); SortedSet <UInt64> set = data[cmd04]; foreach (UInt64 cmdBF in set) { rom.Write64(cmdBF); rom.AddOffset(8); } } }
public static void RebuildTriangleMap(ROM realRom, Region region, int maxDLLength, TriangleMap map, SortedRegionList vertexData, ScrollFactory factory) { ROM fakeRom = (ROM)realRom.Clone(); // bzero fakeRom.PushOffset(region.romStart); { do { fakeRom.Write64(0x0101010101010101); fakeRom.AddOffset(8); } while (fakeRom.offset < region.romStart + region.length); } fakeRom.PopOffset(); fakeRom.offset = region.romStart; int triangleMapLength = map.MakeF3D(fakeRom, vertexData, factory); if (triangleMapLength > maxDLLength) { throw new OutOfMemoryException("No memory for DL available :("); } realRom.TransferFrom(fakeRom); realRom.offset = fakeRom.offset; region.length = realRom.offset - region.romStart; region.data = new byte[region.length]; realRom.ReadData(region.romStart, region.length, region.data); }
public static void PerformRegionRelocation(Region region, RelocationTable table) { // This is fake rom but it works anyways, just more convenient ROM rom = new ROM(region.data); byte cmd; do { cmd = rom.Read8(); int cmdSize = cmdSizeTable[cmd]; if (cmdSize == 0) { throw new ArgumentException("Loop detected"); } RelocationParseCmd func = relocationParser[cmd]; func(rom, table); if (cmdSize != 0xFF) { rom.AddOffset(cmdSize); } }while (rom.offset < region.length); }
private static void TriangleMapParse_cmd04(ROM rom, TriangleMap map, TriangleMapParseState state) { state.vertexLoadCmd = (UInt64)rom.Read64(); byte vertexDesc = rom.Read8(1); byte vertexCount = (byte)(((vertexDesc & 0xF0) >> 4) + 1); byte vertexOffset = (byte)((vertexDesc & 0x0F)); Int32 vertexSegmentedAddress = rom.Read32(4); state.segmentedVertexBufferAddress = vertexSegmentedAddress; Int32 romPtr = rom.GetROMAddress(vertexSegmentedAddress); if (romPtr == -1) { throw new ArgumentException("Invalid segmented address!"); } rom.PushOffset(romPtr); for (int vertex = vertexOffset; vertex < vertexCount; vertex++) { Int64 lo = rom.Read64(); Int64 hi = rom.Read64(8); state.vbuf[vertex] = new Vertex((UInt64)lo, (UInt64)hi); state.vbufRomStart[vertex] = rom.offset; state.scrollBuf[vertex] = FindMatchingScroll(state.scrolls, vertexSegmentedAddress, state.td); rom.AddOffset(0x10); vertexSegmentedAddress += 0x10; } rom.PopOffset(); }
private static void RegionParse_common(ROM rom, List <Region> regions) { // Triangles of any collision int size = rom.Read16(2); if (size == 0) { throw new ArgumentException("common collision loop detected"); } int collType = rom.Read8(1); int triangleSize = 6; switch (collType) { case 0x0E: case 0x24: case 0x25: case 0x27: case 0x2C: case 0x2D: triangleSize = 8; break; } rom.AddOffset(4 + size * triangleSize); }
private static void RegionParse_cmd40(ROM rom, List <Region> regions) { // Vertexes int size = rom.Read16(2); rom.AddOffset(4 + size * 6); }
public static void PerformRegionRelocation(Region region, RelocationTable table, sbyte area = -1) { // This is fake rom but it works anyways, just more convenient ROM rom = new ROM(region.data); RegionParseState state = new RegionParseState(); state.area = area; byte curCmdIndex; while (rom.offset < region.length) { curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdSize == 0) { throw new ArgumentException("cmd size is 0, loop detected"); } RelocationParseCmd func = relocationParser[curCmdIndex]; func(rom, table, state); if (curCmdIndex != 0x7) { rom.AddOffset(curCmdSize); } } }
public void MakeF3D(ROM rom) { foreach (UInt64 cmd in cmds) { rom.Write64(cmd); if ((cmd & 0xF200000000000000) == 0xF200000000000000) { f2SegmentedAddress = rom.GetSegmentedAddress(rom.offset); } rom.AddOffset(8); } }
public static void PerformRegionRelocation(Region region, RelocationTable table) { // This is fake rom but it works anyways, just more convenient ROM rom = new ROM(region.data); byte curCmdIndex; do { curCmdIndex = rom.Read8(); RelocationParseCmd func = relocationParser[curCmdIndex]; func(rom, table, (DisplayListRegion)region); rom.AddOffset(8); }while (rom.offset < region.length); }
public static void PerformTriangleMapRebuild(ROM realRom, Region region, int maxDLLength, List <ScrollObject> scrolls) { TriangleMapParseState state = new TriangleMapParseState(scrolls); DisplayListRegion dlRegion = (DisplayListRegion)region; TriangleMap map = new TriangleMap(); realRom.PushOffset(region.romStart); byte curCmdIndex; do { curCmdIndex = realRom.Read8(); TriangleMapParserCmd func = triangleMapParser[curCmdIndex]; func(realRom, map, state); realRom.AddOffset(8); }while (realRom.offset < region.romStart + region.length); realRom.PopOffset(); ROM fakeRom = (ROM)realRom.Clone(); // bzero fakeRom.PushOffset(region.romStart); { do { fakeRom.Write64(0x0101010101010101); fakeRom.AddOffset(8); } while (fakeRom.offset < region.romStart + region.length); } fakeRom.PopOffset(); fakeRom.offset = region.romStart; int triangleMapLength = map.MakeF3D(fakeRom, state.vertexBytes, new ScrollFactory(scrolls)); if (triangleMapLength > maxDLLength) { throw new OutOfMemoryException("No memory for DL available :("); } realRom.TransferFrom(fakeRom); realRom.offset = fakeRom.offset; region.length = realRom.offset - region.romStart; region.data = new byte[region.length]; realRom.ReadData(region.romStart, region.length, region.data); }
public static void PerformRegionFix(ROM rom, Region region, FixConfig config) { RegionFixState state = new RegionFixState(config); DisplayListRegion dlRegion = (DisplayListRegion)region; rom.PushOffset(region.romStart); byte curCmdIndex; do { curCmdIndex = rom.Read8(); FixParseCmd func = fixParser[curCmdIndex]; func(rom, dlRegion, state); rom.AddOffset(8); }while (rom.offset < region.romStart + region.length); rom.PopOffset(); rom.ReadData(region.romStart, region.length, region.data); }
public static void Trim(Region region, bool addObjects) { ROM rom = new ROM(region.data); MemoryStream trimmedObject = new MemoryStream(); while (rom.offset < region.length) { byte curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdIndex == 0x24) { byte acts = rom.Read8(2); if (acts == 0) { goto fini; } } byte[] data = new byte[curCmdSize]; rom.ReadData(rom.offset, curCmdSize, data); trimmedObject.Write(data, 0, curCmdSize); fini: rom.AddOffset(curCmdSize); } if (addObjects) { trimmedObject.Write(emptyObject, 0, emptyObject.Count()); trimmedObject.Write(emptyObject, 0, emptyObject.Count()); trimmedObject.Write(emptyObject, 0, emptyObject.Count()); trimmedObject.Write(emptyObject, 0, emptyObject.Count()); trimmedObject.Write(emptyObject, 0, emptyObject.Count()); } region.data = trimmedObject.ToArray(); region.length = (int)trimmedObject.Length; trimmedObject.Dispose(); }
public static void PerformHeaderParse(ROM rom, int offset) { rom.PushOffset(offset); RegionParseState state = new RegionParseState(); state.start = rom.offset; byte curCmdIndex; int stepCounter = 0; do { curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdSize == 0) { throw new ArgumentException("cmd size is 0, loop detected"); } if (curCmdIndex == 0x00) { HeaderParse_cmd00(rom); } if (curCmdIndex == 0x17) { HeaderParse_cmd17(rom); } rom.AddOffset(curCmdSize); stepCounter++; if (stepCounter > 100) { throw new ArgumentException("Bank 0x19 && 0x0E loader was not detected"); } }while (rom.GetSegmentDescriptor(0x0E) == null || rom.GetSegmentDescriptor(0x19) == null); rom.PopOffset(); }
public static void FixLoadAddresses(ROM initROM, Region region) { // This is fake rom but it works anyways, just more convenient ROM rom = new ROM(region.data); RegionParseState state = new RegionParseState(); state.start = rom.offset; byte curCmdIndex; int stepCounter = 0; do { curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdSize == 0) { throw new ArgumentException("cmd size is 0, loop detected"); } if (curCmdIndex == 0x17) { bool isFixed; HeaderFix_cmd17(rom, initROM, out isFixed); if (isFixed) { break; } } rom.AddOffset(curCmdSize); stepCounter++; if (stepCounter > 100) { throw new ArgumentException("Bank 0x19 && 0x0E loader was not detected"); } }while (rom.GetSegmentDescriptor(0x0E) == null || rom.GetSegmentDescriptor(0x19) == null); }
public static void PerformRegionParse(ROM rom, List <Region> regions, int offset, bool isOldScrollBehaviour) { rom.PushOffset(offset); RegionParseState state = new RegionParseState { start = rom.offset, isOldBehaviourChecked = isOldScrollBehaviour }; byte curCmdIndex; do { curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdSize == 0) { throw new ArgumentException("cmd size is 0, loop detected"); } RegionParseCmd func = regionParser[curCmdIndex]; if (func != RegionParse_common) { RegionParse_common(rom, regions, state); } func(rom, regions, state); if (curCmdIndex != 0x7) { rom.AddOffset(curCmdSize); } }while (curCmdIndex != terminateCmd); rom.PopOffset(); }
public static void PerformRegionParse(ROM rom, List <Region> regions, int offset, out Dictionary <int, List <ScrollObject> > scrolls) { rom.PushOffset(offset); RegionParseState state = new RegionParseState(); state.start = rom.offset; byte curCmdIndex; do { curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdSize == 0) { throw new ArgumentException("cmd size is 0, loop detected"); } RegionParseCmd func = regionParser[curCmdIndex]; if (func != RegionParse_common) { RegionParse_common(rom, regions, state); } func(rom, regions, state); if (curCmdIndex != 0x7) { rom.AddOffset(curCmdSize); } }while (curCmdIndex != terminateCmd); rom.PopOffset(); scrolls = state.scrolls; }
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); }
private static void RegionParse_cmd42(ROM rom, List <Region> regions) { rom.AddOffset(2); }
private static void RegionParse_cmd0A(ROM rom, List <Region> regions) { int useAsm = rom.Read8(1); rom.AddOffset(useAsm == 0 ? 0x8 : 0xC); }
private static void RelocationParse_cmd0A(ROM rom, RelocationTable table) { int useAsm = rom.Read8(1); rom.AddOffset(useAsm == 0 ? 0x8 : 0xC); }
public static void GetTriangleMap(ROM realRom, Region region, int maxDLLength, List <ScrollObject> scrolls, out TriangleMap map, out SortedRegionList vertexData) { TriangleMapParseState state = new TriangleMapParseState(scrolls); DisplayListRegion dlRegion = (DisplayListRegion)region; map = new TriangleMap(); realRom.PushOffset(region.romStart); byte curCmdIndex; do { curCmdIndex = realRom.Read8(); TriangleMapParserCmd func = triangleMapParser[curCmdIndex]; func(realRom, map, state); realRom.AddOffset(8); }while (realRom.offset < region.romStart + region.length); realRom.PopOffset(); // Check map validity // There are 2 possible ways to mess up scroll // 'Too much' - scroll is performing too much scrolling, 1st warn detect, 2nd falsing, 3rd can fix such scroll if scrolls are done properly // 'Not enough' - scroll is not scrolling the whole texture, 2nd warn may be able to detect that, no fix yet but 'stretch' the scroll should work // I assume there is no scrolls that do not correspond to no texture, such case will leave weird things :) // Currently ScrollingTextures cannot be longed so it is impossible to fix 'Not enough' :( List <ScrollingTextureDescription> brokenTextures = new List <ScrollingTextureDescription>(); { // Not enough HashSet <TextureDescription> scrollingTds = new HashSet <TextureDescription>(map.map.Keys.Where(k => k.scroll != null)); foreach (TextureDescription td in scrollingTds) { var stds = map.map.Keys.Where(k => k.Equals(td)).ToList(); if (stds.Count() > 1) { int a = 0; } } // Check if scroll 'fits' foreach (ScrollingTextureDescription std in map.map.Keys) { if (std.scroll == null) { continue; } if (!std.vertexRegions.Equals(std.scrollRegions)) { brokenTextures.Add(std); } } } foreach (ScrollingTextureDescription brokenTd in brokenTextures) { if (brokenTd.omitScrollCheck) { continue; } // Figure out the way to "heal", either drop scroll or extend it // If scroll does not start at the same place, just drop it, such solution may backfire if 2 scrolls intersect bool shouldDrop = brokenTd.scrollRegions.RegionList.First().Key != brokenTd.vertexRegions.RegionList.First().Key; if (shouldDrop) { // Find if texture without scroll exists, if it does, merge tris in it, otherwise drop the scroll List <ScrollingTextureDescription> similarTextures = map.map.Keys.Where(k => k.scroll == null).Where(k => TextureDescription.Equals(brokenTd, k)).ToList(); if (similarTextures.Count() != 0) { ScrollingTextureDescription stdNoScroll = similarTextures[0]; List <Triangle> tris = map.map[brokenTd]; map.map.Remove(brokenTd); map.map[stdNoScroll].AddRange(tris); } else { state.td.scroll = null; } } else { // Find if texture without scroll exists, if it does, merge tris from it (make it scroll) List <ScrollingTextureDescription> similarTextures = map.map.Keys.Where(k => k.scroll == null).Where(k => TextureDescription.Equals(brokenTd, k)).ToList(); foreach (ScrollingTextureDescription similarStd in similarTextures) { List <Triangle> tris = map.map[similarStd]; map.map.Remove(similarStd); map.map[brokenTd].AddRange(tris); } } } vertexData = state.vertexBytes; }
private static void RegionParse_cmd1D(ROM rom, List <Region> regions) { // TODO: msbit thing rom.AddOffset(0x8); }
private static void RelocationParse_cmd1D(ROM rom, RelocationTable table) { // TODO: msbit thing rom.AddOffset(0x8); }
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(); } }