public async Task LoadAsyncLoadsWhenGivenALoader() { var loader = A.Fake<IROMLoader>(); ROM rom = new ROM(loader); await rom.LoadAsync(); A.CallTo(() => loader.LoadROMAsync()).MustHaveHappened(); }
public async Task<ValidationResults> ValidateChecksum(string filePath) { ValidationResults results = new ValidationResults() { ROMFilePath = filePath }; // Load ROM content ROM rom = new ROM(new BinROMLoader(filePath, new BinROMValidator())); await rom.LoadAsync(); // Get the checksum from the ROM. Also run a checksum calculation and compare the results. If not the same, // update the ROM and save it results.ActualChecksum = rom.Checksum; results.CalculatedChecksum = rom.CalculateChecksum(); results.HasChanged = results.ActualChecksum != results.CalculatedChecksum; if (results.ActualChecksum != results.CalculatedChecksum) { rom.Checksum = results.CalculatedChecksum; await rom.SaveAsync(); } return results; }
public void EditGift() { var arc = ROM.GetFile(GameFile.EncounterGift); var data = arc[0]; var objs = FlatBufferConverter.DeserializeFrom <EncounterGift8Archive>(data); var gifts = objs.Table; var names = Enumerable.Range(0, gifts.Length).Select(z => $"{z:000}").ToArray(); var cache = new DirectCache <EncounterGift8>(gifts); void Randomize() { int[] PossibleHeldItems = Legal.GetRandomItemList(ROM.Game); var pt = Data.PersonalData; int[] ban = pt.Table.Take(ROM.Info.MaxSpeciesID + 1) .Select((z, i) => new { Species = i, Present = ((PersonalInfoSWSH)z).IsPresentInGame }) .Where(z => !z.Present).Select(z => z.Species).ToArray(); var spec = EditUtil.Settings.Species; var srand = new SpeciesRandomizer(ROM.Info, Data.PersonalData); var frand = new FormRandomizer(Data.PersonalData); srand.Initialize(spec, ban); foreach (var t in gifts) { // swap gmax gifts and kubfu for other gmax capable species if (t.CanGigantamax || t.Species == (int)Species.Kubfu) { t.Species = Legal.GigantamaxForms[Randomization.Util.Random.Next(Legal.GigantamaxForms.Length)]; t.Form = (byte)(t.Species is (int)Species.Pikachu or(int) Species.Meowth ? 0 : frand.GetRandomForme(t.Species, false, false, false, false, Data.PersonalData.Table)); // Pikachu & Meowth altforms can't gmax } else { t.Species = srand.GetRandomSpecies(t.Species); t.Form = (byte)frand.GetRandomForme(t.Species, false, false, true, true, Data.PersonalData.Table); } t.Ability = Randomization.Util.Random.Next(1, 4); // 1, 2, or H t.Ball = (Ball)Randomization.Util.Random.Next(1, EncounterGift8.BallToItem.Length); t.HeldItem = PossibleHeldItems[Randomization.Util.Random.Next(PossibleHeldItems.Length)]; t.Nature = (int)Nature.Random25; t.Gender = (byte)FixedGender.Random; t.ShinyLock = (int)Shiny.Random; if (t.IV_HP != -4 && t.IVs.Any(z => z != 31)) { t.IVs = new[] { -1, -1, -1, -1, -1, -1 } } ; } UpdateStarters(); // update placement critter data to match new randomized species } void UpdateStarters() { var container = ROM.GetFile(GameFile.Placement); var placement = new GFPack(container[0]); // a_r0501_i0101.bin for Toxel // a_bt0101.bin for Type: Null // a_wr0201_i0101.bin for Bulbasaur, Squirtle, Porygon, and Kubfu // a_wr0301_i0401.bin for Cosmog // a_d0901.bin for Poipole const string file = "a_0101.bin"; var table = placement.GetDataFileName(file); var obj = FlatBufferConverter.DeserializeFrom <PlacementArea8Archive>(table); var critters = obj.Table[0].Critters; // Grookey critters[3].Species = (uint)gifts[0].Species; critters[3].Form = gifts[0].Form; // Scorbunny critters[1].Species = (uint)gifts[3].Species; critters[1].Form = gifts[3].Form; // Sobble critters[2].Species = (uint)gifts[4].Species; critters[2].Form = gifts[4].Form; var bin = FlatBufferConverter.SerializeFrom(obj); placement.SetDataFileName(file, bin); container[0] = placement.Write(); } using var form = new GenericEditor <EncounterGift8>(cache, names, "Gift Pokémon Editor", Randomize); form.ShowDialog(); if (!form.Modified) { arc.CancelEdits(); } else { arc[0] = FlatBufferConverter.SerializeFrom(objs); } }
public static int parse(ref Level lvl, byte seg, uint off) { ROM rom = ROM.Instance; byte[] data = rom.getSegment(seg); bool end = false; int endCmd = 0; while (!end) { //Stopwatch stopWatch = new Stopwatch(); //stopWatch.Start(); byte cmdLen = data[off + 1]; byte[] cmd = rom.getSubArray(data, off, cmdLen); //rom.printArray(cmd, cmdLen); string desc = "Unknown command"; bool alreadyAdded = false; switch (cmd[0]) { case 0x00: case 0x01: CMD_00(ref lvl, ref desc, cmd, seg, off); alreadyAdded = true; break; case 0x02: endCmd = 2; desc = "End level script"; end = true; break; case 0x03: case 0x04: desc = "Delay frames"; break; case 0x05: endCmd = CMD_05(ref lvl, ref desc, cmd, seg, off); alreadyAdded = true; end = true; break; case 0x06: if (CMD_06(ref lvl, ref desc, cmd, seg, off) == 0x02) { end = true; endCmd = 2; } alreadyAdded = true; break; case 0x07: end = true; desc = "Pop script stack and return back"; endCmd = 0x07; break; case 0x08: desc = "Push script stack and a 16-bit parameter onto stack"; break; case 0x09: desc = "Pops script stack and parameter"; break; case 0x0A: desc = "Push next level command on script stack and param 0x00000000 onto stack"; break; case 0x0B: CMD_0B(ref lvl, ref desc, cmd, seg, off); alreadyAdded = true; break; case 0x0C: CMD_0C(ref lvl, ref desc, cmd, seg, off); alreadyAdded = true; break; case 0x0D: CMD_0D(ref lvl, ref desc, cmd, seg, off); alreadyAdded = true; break; case 0x0E: CMD_0E(ref lvl, ref desc, cmd, seg, off); alreadyAdded = true; break; case 0x0F: desc = "Skip following 0x10 (Do nothing) commands"; break; case 0x10: desc = "Do nothing"; break; case 0x11: desc = "Call ASM function and set level accumulator (script_accum)"; break; case 0x12: desc = "Call ASM function loop and set level accumulator (script_accum)"; break; case 0x13: desc = "Set level accumulator (script_accum) as 0x" + bytesToInt(cmd, 2, 2).ToString("X4"); break; case 0x14: desc = "Call PushPoolState() function"; break; case 0x15: desc = "Call PopPoolState() function"; break; case 0x16: desc = "Copy bytes from ROM (0x" + bytesToInt(cmd, 8, 4).ToString("X8") + " to 0x" + bytesToInt(cmd, 12, 4).ToString("X8") + ") to RAM address 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); break; case 0x17: CMD_17(ref lvl, ref desc, cmd); break; case 0x18: case 0x1A: CMD_18(ref lvl, ref desc, cmd); break; case 0x19: desc = "Create Mario head demo ("; switch (cmd[3]) { case 1: desc += "No face"; break; case 2: desc += "Regular face"; break; case 3: desc += "Game over face"; break; } desc += ")"; break; case 0x1B: desc = "Start loading sequence"; break; case 0x1C: desc = "Level & Memory cleanup"; break; case 0x1D: desc = "End loading sequence"; break; case 0x1E: desc = "Allocate space for level data from pool"; break; case 0x1F: //Globals.DEBUG_PLG = true; CMD_1F(ref lvl, ref desc, cmd); break; case 0x20: desc = "End of area " + lvl.CurrentAreaID; break; case 0x21: CMD_21(ref lvl, ref desc, cmd); break; case 0x22: //Globals.DEBUG_PLG = false; CMD_22(ref lvl, ref desc, cmd); break; case 0x24: CMD_24(ref lvl, ref desc, cmd, seg, off); break; case 0x25: desc = "Setup Mario object"; break; case 0x26: CMD_26(ref lvl, ref desc, cmd, seg, off); break; case 0x27: CMD_27(ref lvl, ref desc, cmd, seg, off); break; case 0x28: CMD_28(ref lvl, ref desc, cmd, seg, off); break; case 0x2B: { desc = "Mario's default pos = (" + (short)bytesToInt(cmd, 6, 2) + "," + (short)bytesToInt(cmd, 8, 2) + "," + (short)bytesToInt(cmd, 10, 2) + "), Y-Rot = " + (short)bytesToInt(cmd, 4, 2) + ", start in area " + cmd[2]; } break; case 0x2E: CMD_2E(ref lvl, ref desc, cmd); break; case 0x2F: CMD_2F(ref lvl, ref desc, cmd); break; case 0x30: desc = "Show dialog message when level starts; dialog ID = 0x" + cmd[3].ToString("X2"); break; case 0x31: switch (cmd[3]) { case 0: desc = "Set default terrain to \"Normal\""; break; case 1: desc = "Set default terrain to \"Normal B\""; break; case 2: desc = "Set default terrain to \"Snow\""; break; case 3: desc = "Set default terrain to \"Sand\""; break; case 4: desc = "Set default terrain to \"Haunted House\""; break; case 5: desc = "Set default terrain to \"Water levels\""; break; case 6: desc = "Set default terrain to \"Slippery Slide\""; break; } break; case 0x32: desc = "Do nothing"; break; case 0x33: if (cmd[2] == 0x01) { desc = "Fade screen with color (R = " + cmd[4] + ", G = " + cmd[5] + ", B = " + cmd[6] + ", duration = " + cmd[3] + " frames)"; } else { desc = "Disable screen fade"; } break; case 0x34: if (cmd[2] == 0x00) { desc = "Cancel blackout"; } else { desc = "Blackout screen"; } break; case 0x36: desc = "Set music (Seq = 0x" + cmd[5].ToString("X2") + ")"; break; case 0x37: desc = "Set music (Seq = 0x" + cmd[3].ToString("X2") + ")"; break; case 0x39: CMD_39(ref lvl, ref desc, cmd); break; case 0x3B: desc = "Add jet stream; Position = (" + (short)bytesToInt(cmd, 4, 2) + "," + (short)bytesToInt(cmd, 6, 2) + "," + (short)bytesToInt(cmd, 8, 2) + "), Intensity = " + (short)bytesToInt(cmd, 10, 2); break; } if (!alreadyAdded) { addLSCommandToDump(ref lvl, cmd, seg, off, desc); } //stopWatch.Stop(); // if(stopWatch.Elapsed.Milliseconds > 1) // Console.WriteLine("RunTime (CMD "+cmd[0].ToString("X2")+"): " + stopWatch.Elapsed.Milliseconds + "ms"); off += cmdLen; } return(endCmd); }
public static void ConvertDL(ROM SM64ROM, uint SegAddr, bool ForceROMAddr) { if (SegAddr >> 24 == 0x02) { SM64ROM.setSegment(2, 0x803156); //Force segment 2 to US addr, sometimes it gets misplaced in level script parsing } uint Offset; if (!ForceROMAddr) { Offset = SM64ROM.readSegmentAddr(SegAddr); //If not forcing a ROM addr, read seg addr } else { Offset = SegAddr; } for (uint i = 0; i < AllAddresses.Length; i++) { if (Offset == AllAddresses[i]) { return; //If already converted certain DL, skip } } Array.Resize(ref AllAddresses, AllAddresses.Length + 1); //If not converted yet, create new index for mem AllAddresses[AllAddresses.Length - 1] = Offset; //Last index is new offset (record dl as converted) for (UInt32 i = Offset; i < SM64ROM.getEndROMAddr(); i += 8) { byte[] CMD = UInt64toByteArray(SM64ROM.ReadEightBytes(i)); switch (CMD[0]) { case 04: //G_VTX byte vertexcount = (byte)((CMD[1] >> 4) + 1); byte index = (byte)(CMD[1] & 0x0F); SM64ROM.changeByte(i + 1, (byte)(index * 2)); //Vertex count * 2 UInt16 Params = (UInt16)((vertexcount << 10) | ((vertexcount * 0x10) - 1)); SM64ROM.WriteTwoBytes(i + 2, Params); break; case 06: //G_DL ConvertDL(SM64ROM, returnSegmentAddr(CMD), false); if (CMD[1] > 0) { return; } break; case 0xB2: //G_RDPHalf_Cont SM64ROM.changeByte(i, 0xB3); //rdphalf_cont not used in newer microcodes; use rdphalf_2 break; case 0xB3: //G_RDPHalf_2 SM64ROM.changeByte(i, 0xB4); //rdphalf_2 change to rdphalf_1 in newer microcodes break; case 0xB4: //G_RDPHalf_1 SM64ROM.WriteFourBytes(i, 0xBC00000E); //replace G_RDPHalf_1 with G_Moveword in newer microcodes break; case 0xBF: //G_TRI1 for (uint j = 5; j < 8; j++) { uint TriAddr = i + j; CMD[j] /= 5; SM64ROM.changeByte(TriAddr, CMD[j]); } break; case 0xB8: //G_ENDDL return; } } }
private static void DecodeF3DCommands(ROM SM64ROM, uint SegOffset, bool ColourBuffer) { uint Offset = SM64ROM.readSegmentAddr(SegOffset); uint CMDCount = 0; for (uint i = Offset; i < SM64ROM.getEndROMAddr(); i += 8) { if (SM64ROM.getByte(i) == 0xB8) { CMDCount = ((i - Offset) / 8) + 1;//Plus one command for B8 break; } } byte[][] DisplayList = new byte[CMDCount][]; //Copy DL into 2D Byte array with double loop for (uint i = 0; i < CMDCount; i++) { DisplayList[i] = new byte[8]; for (uint j = 0; j < 8; j++) { DisplayList[i][j] = SM64ROM.getByte(Offset + (i * 8) + j); } } for (uint i = 0; i < SM64ROM.getEndROMAddr(); i++) { byte[] CMD = DisplayList[i]; if (Textures.FirstTexLoad && ROMManager.debug) //Debug Txt { Array.Resize(ref DebugText, DebugText.Length + 1); DebugText[DebugText.Length - 1] = (Offset + (i * 8)).ToString("x") + ": "; //Addr: for (uint j = 0; j < 8; j++) { DebugText[DebugText.Length - 1] += CMD[j].ToString("x") + " "; //F3D CMD bytes in hex } } if (!ColourBuffer) { switch (DisplayList[i][0]) { case 0x01: //G_MTX break; case 0x03: //movemem if (RenderEdges) { break; } if (CMD[1] == 0x86) { float[] light0_diffuse = new float[4]; uint rgbaAddr = SM64ROM.readSegmentAddr(returnSegmentAddr(CMD)); for (uint j = 0; j < 4; j++) { light0_diffuse[j] = (float)SM64ROM.getByte(rgbaAddr + j) / 255f; } GL.Light(LightName.Light0, LightParameter.Diffuse, light0_diffuse); GL.ColorMaterial(MaterialFace.Front, ColorMaterialParameter.Diffuse); } else if (CMD[1] == 0x88) { float[] light0_ambient = new float[4]; uint rgbaAddr = SM64ROM.readSegmentAddr(returnSegmentAddr(CMD)); for (uint j = 0; j < 4; j++) { light0_ambient[j] = (((float)SM64ROM.getByte(rgbaAddr + j) / 255f) - 0.2f) * 1.25f; } GL.Light(LightName.Light0, LightParameter.Ambient, light0_ambient); GL.ColorMaterial(MaterialFace.Front, ColorMaterialParameter.Ambient); } GL.Enable(EnableCap.ColorMaterial); break; case 0x04: //G_VTX UInt32 VTXStart = SM64ROM.readSegmentAddr(returnSegmentAddr(CMD)); short numVerts = (short)((CMD[1] >> 4) + 1); int bufferIndex = CMD[1] & 0x0F; for (int j = 0; j < numVerts; j++) { VTXBuffer[bufferIndex + j] = Vertex.getVertex(VTXStart + (uint)(j * 0x10), SM64ROM); } Renderer.VertexCount += (uint)numVerts; break; case 0x06: //LoadDL (jump) F3D.DecodeF3DCommands(SM64ROM, returnSegmentAddr(CMD), ColourBuffer); if (CMD[1] == 1) { return; } break; case 0xB1: //0xB1 (TRI2) is not used in F3D v1.0 break; case 0xB2: // Unused in F3D v1.0 break; case 0xB3: //G_RDP_Half2 break; case 0xB4: //G_RDP_Half1 break; case 0xB5: //G_Quad (Unused in F3D v1.0) break; case 0xB6: //ClearGeoMode if (RenderEdges) { break; } UInt32 ClearBits = (UInt32)((CMD[4] << 24) | (CMD[5] << 16) | (CMD[6] << 8) | CMD[7]); GeoMode &= ~ClearBits; SetGeoMode(ColourBuffer); break; case 0xB7: //SetGeoMode if (RenderEdges) { break; } UInt32 SetBits = (UInt32)((CMD[4] << 24) | (CMD[5] << 16) | (CMD[6] << 8) | CMD[7]); GeoMode |= SetBits; SetGeoMode(ColourBuffer); break; case 0xB9: //SetOtherMode break; case 0xBA: //SetOtherMode break; case 0xBB: //G_Texture Vertex.U_Scale = Convert.ToSingle((CMD[4] << 8) | CMD[5]) / Convert.ToSingle(0xFFFF); Vertex.V_Scale = Convert.ToSingle((CMD[6] << 8) | CMD[7]) / Convert.ToSingle(0xFFFF); if (CMD[3] == 0x01 && Renderer.TextureEnabler && !RenderEdges) { GL.Enable(EnableCap.Texture2D); } else { GL.Disable(EnableCap.Texture2D); Textures.T_Scale = 1f; Textures.S_Scale = 1f; } if (DisplayList[i][2] == 0x12) { Textures.MipMapping = true; Textures.T_Scale = 1f; Textures.S_Scale = 1f;//Revert mipmapping for now } break; case 0xBC: //moveword break; case 0xBD: //PopMTX break; case 0xBF: //TRI1 if (LightingEnabled && !Renderer.ViewNonRGBA) { break; } GL.Begin(BeginMode.Triangles); for (int j = 5; j < 8; j++) { int VertIndex = CMD[j] / 0x0A; if (!EnvMapping) { GL.TexCoord2(VTXBuffer[VertIndex].getUVVector()); } if (LightingEnabled) //Normals { Vector3 normals = new Vector3(VTXBuffer[VertIndex].getRGBColor()); if (!EnvMapping) { GL.Normal3(Vector3.Normalize(normals)); } else { Vector4 normals4 = new Vector4(normals, 1f); normals4 = Vector4.Normalize(Renderer.projection * normals4); Vector3 newnorms = new Vector3(normals4.X, normals4.Y, normals4.Z); GL.Normal3(newnorms); } } else { GL.Color4(VTXBuffer[VertIndex].getRGBAColor()); //RGBA } if (RenderEdges) { GL.Color4(0, 0, 0, 0xFF); } GL.Vertex3(VTXBuffer[VertIndex].getCoordVector()); } if (!RenderEdges) { Renderer.TriCount++; } GL.End(); break; case 0xF0: //LoadTLUT if (!Textures.FirstTexLoad) { break; } CICount = (uint)((((CMD[5] << 4) + ((CMD[6] & 0xF0) >> 4)) >> 2) + 1); Textures.currentPalette = Textures.LoadRGBA16TextureData(CICount, SM64ROM); break; case 0xF2: //Settilesize Textures.S_Scale = Convert.ToSingle((((CMD[5] << 4) | ((CMD[6] & 0xF0) >> 4)) >> 2) + 1); Textures.T_Scale = Convert.ToSingle(((((CMD[6] & 0x0F) << 8) | CMD[7]) >> 2) + 1); break; case 0xF3: //LoadBlock if (SM64ROM.getSegmentStart(0x0E) < 0x1200000 && !Renderer.ObjectView) { TextureLoadRoutine(SM64ROM, 0); } break; case 0xF5: //Settile Textures.MODE = (byte)(CMD[1] >> 5); Textures.BitSize = (byte)(4 * Math.Pow(2, ((CMD[1] >> 3) & 3))); Textures.TFlags = (uint)(CMD[5] >> 2) & 3; Textures.SFlags = (uint)CMD[6] & 3; int WidthBits = (((CMD[1] & 3) << 7) + CMD[2] >> 1) * 64; if (CMD[4] != 0) { break; //If RenderTile, continue } int HeightPower = ((CMD[5] & 3) << 2) | (CMD[6] >> 6); int WidthPower = (CMD[7] >> 4); Textures.Width = (uint)Math.Pow(2, WidthPower); Textures.Height = (uint)Math.Pow(2, HeightPower); if (Textures.currentTexAddr == 0) { break; } TextureLoadRoutine(SM64ROM, Offset + (uint)(i * 8)); break; case 0xFB: //Set Env Colour if (RenderEdges) { break; } ColourCombiner = true; GL.Color4((float)CMD[4] / 255f, (float)CMD[5] / 255f, (float)CMD[6] / 255f, (float)CMD[7] / 255f); break; case 0xFC: //Setcombine if (CMD[7] == 0x3C && CMD[6] == 0x79 && CMD[5] == 0xFE) { GL.Disable(EnableCap.Texture2D); } else if (Renderer.TextureEnabler) { GL.Enable(EnableCap.Texture2D); } break; case 0xFD: //SetTIMG Textures.currentSegment = CMD[4]; Textures.currentTexAddr = SM64ROM.readSegmentAddr(returnSegmentAddr(CMD)); if (!Textures.FirstTexLoad) { break; } Textures.BitSize = (byte)(4 * Math.Pow(2, ((CMD[1] >> 3) & 3))); Textures.MODE = (byte)(CMD[1] >> 5); break; case 0xB8: //End DL return; } } else { switch (DisplayList[i][0]) //Vertex Selection Colour buffer here { case 0x03: break; case 0x04: UInt32 VTXStart = SM64ROM.readSegmentAddr(returnSegmentAddr(CMD)); short numVerts = (short)((CMD[1] >> 4) + 1); int bufferIndex = CMD[1] & 0x0F; for (int j = 0; j < numVerts; j++) { VTXBuffer[bufferIndex + j] = Vertex.getVertex(VTXStart + (uint)(j * 0x10), SM64ROM); } Renderer.VertexCount += (uint)numVerts; break; case 0x06: F3D.DecodeF3DCommands(SM64ROM, returnSegmentAddr(CMD), ColourBuffer); if (CMD[1] == 1) { return; } break; case 0xB6: if (RenderEdges) { break; } UInt32 ClearBits = (UInt32)((CMD[4] << 24) | (CMD[5] << 16) | (CMD[6] << 8) | CMD[7]); GeoMode &= ~ClearBits; SetGeoMode(ColourBuffer); break; case 0xB7: if (RenderEdges) { break; } UInt32 SetBits = (UInt32)((CMD[4] << 24) | (CMD[5] << 16) | (CMD[6] << 8) | CMD[7]); GeoMode |= SetBits; SetGeoMode(ColourBuffer); break; case 0xBF: if (LightingEnabled) { break; //Disable painting on non-RGBA meshes } Vertex[] Triangle = new Vertex[3]; Color4[] colour = new Color4[3]; for (int j = 5; j < 8; j++) { int VertIndex = CMD[j] / 0x0A; Triangle[j - 5] = VTXBuffer[VertIndex]; UInt32 Addr = Triangle[j - 5].getAddr(); colour[j - 5] = new Color4((byte)(Addr >> 24), (byte)((Addr >> 16) & 0xFF), (byte)((Addr >> 8) & 0xFF), (byte)(Addr & 0xFF)); //Addr to RGBA } Vector3 CentreCoord = new Vector3 ( (Triangle[0].getCoordVector().X + Triangle[1].getCoordVector().X + Triangle[2].getCoordVector().X) / 3, (Triangle[0].getCoordVector().Y + Triangle[1].getCoordVector().Y + Triangle[2].getCoordVector().Y) / 3, (Triangle[0].getCoordVector().Z + Triangle[1].getCoordVector().Z + Triangle[2].getCoordVector().Z) / 3 ); Vector3 OneTwoAVG = new Vector3 ( (Triangle[0].getCoordVector().X + Triangle[1].getCoordVector().X) / 2, (Triangle[0].getCoordVector().Y + Triangle[1].getCoordVector().Y) / 2, (Triangle[0].getCoordVector().Z + Triangle[1].getCoordVector().Z) / 2 ); Vector3 TwoThreeAVG = new Vector3 ( (Triangle[1].getCoordVector().X + Triangle[2].getCoordVector().X) / 2, (Triangle[1].getCoordVector().Y + Triangle[2].getCoordVector().Y) / 2, (Triangle[1].getCoordVector().Z + Triangle[2].getCoordVector().Z) / 2 ); Vector3 OneThreeAVG = new Vector3 ( (Triangle[0].getCoordVector().X + Triangle[2].getCoordVector().X) / 2, (Triangle[0].getCoordVector().Y + Triangle[2].getCoordVector().Y) / 2, (Triangle[0].getCoordVector().Z + Triangle[2].getCoordVector().Z) / 2 ); GL.Begin(BeginMode.Quads); GL.Color4(colour[0]); //Vert 1 quad GL.Vertex3(Triangle[0].getCoordVector()); GL.Vertex3(OneTwoAVG); GL.Vertex3(CentreCoord); GL.Vertex3(OneThreeAVG); GL.Color4(colour[1]); //Vert 2 quad GL.Vertex3(Triangle[1].getCoordVector()); GL.Vertex3(TwoThreeAVG); GL.Vertex3(CentreCoord); GL.Vertex3(OneTwoAVG); GL.Color4(colour[2]); //Vert 3 quad GL.Vertex3(Triangle[2].getCoordVector()); GL.Vertex3(OneThreeAVG); GL.Vertex3(CentreCoord); GL.Vertex3(TwoThreeAVG); GL.End(); break; case 0xB8: return; } } } }
public static Bitmap TextureToBitMap(uint texaddr, uint width, uint height, uint format, uint bitsize) { ROM SM64ROM = ROMManager.SM64ROM; if (width == 0 || height == 0) { return(new Bitmap(1, 1)); } Bitmap texture = new Bitmap((Int32)width, (Int32)height); Graphics textureGraphics = Graphics.FromImage(texture); uint pxaddr = 0; uint texel = 0; Color[] palette = new Color[0]; if (format == CIMODE) { palette = new Color[(int)Math.Pow(2, bitsize)]; uint paletteaddr = texaddr + (width * height * bitsize / 0x08); //halfway into texture for (uint i = 0; i < palette.Length; i++) { palette[i] = RGBA16TexeltoColor(paletteaddr + (i * 2)); } } for (uint y = 0; y < height; y++) { for (uint x = 0; x < width; x++) { if (bitsize >= 8) { pxaddr = texaddr + texel * (bitsize / 8); } else { pxaddr = texaddr + texel; } SolidBrush brush = new SolidBrush(Color.HotPink); if ((format == RGBAMODE && bitsize == 16) || format == YUVMODE) //Todo: YUV { brush = new SolidBrush(RGBA16TexeltoColor(pxaddr)); } else if (format == RGBAMODE && bitsize == 32) //RGBA32 { byte red = SM64ROM.getByte(pxaddr); byte green = SM64ROM.getByte(pxaddr + 1); byte blue = SM64ROM.getByte(pxaddr + 2); byte alpha = SM64ROM.getByte(pxaddr + 3); brush = new SolidBrush(Color.FromArgb(alpha, red, green, blue)); } else if (format == IAMODE && bitsize == 4) //IA4 { byte pixels = SM64ROM.getByte(pxaddr); byte I1 = (byte)((pixels & 0xE0) | ((pixels & 0xE0) >> 3) | (pixels & 0xE0) >> 6); byte A1 = (byte)(((pixels & 0x10) >> 4) * 0xFF); brush = new SolidBrush(Color.FromArgb(A1, I1, I1, I1)); textureGraphics.FillRectangle(brush, x, y, 1, 1); x++; if (x >= width) { x = 0; y++; } //increment byte I2 = (byte)((((pixels & 0x0E) << 4)) | ((pixels & 0x0E) << 1) | ((pixels & 0x0E) >> 2)); byte A2 = (byte)((pixels & 1) * 0xFF); brush = new SolidBrush(Color.FromArgb(A2, I2, I2, I2)); } else if (format == IAMODE && bitsize == 8) //IA8 { byte pixel = SM64ROM.getByte(pxaddr); byte I1 = (byte)((pixel & 0xF0) | ((pixel & 0xF0) >> 4)); byte A1 = (byte)(((pixel & 0x0F) << 4) | (pixel & 0x0F)); brush = new SolidBrush(Color.FromArgb(A1, I1, I1, I1)); } else if (format == IAMODE && bitsize == 16) //IA16 { byte I = SM64ROM.getByte(pxaddr); byte A = SM64ROM.getByte(pxaddr + 1); brush = new SolidBrush(Color.FromArgb(A, I, I, I)); } else if (format == IMODE && bitsize == 8) //I8 { byte I = SM64ROM.getByte(pxaddr); brush = new SolidBrush(Color.FromArgb((byte)255, I, I, I)); } else if (format == IMODE && bitsize == 4) //I4 { byte I1 = (byte)((SM64ROM.getByte(pxaddr) >> 4) * 17); //*17 for >>4 with 0x0F range brush = new SolidBrush(Color.FromArgb((byte)255, I1, I1, I1)); textureGraphics.FillRectangle(brush, x, y, 1, 1); x++; if (x >= width) { x = 0; y++; } //increment byte I2 = (byte)((SM64ROM.getByte(pxaddr) & 0x0F) * 17); //*17 for >>4 with 0x0F range brush = new SolidBrush(Color.FromArgb((byte)255, I2, I2, I2)); } else if (format == CIMODE && bitsize == 4) //CI4 { int px1 = SM64ROM.getByte(pxaddr) >> 4; brush = new SolidBrush(palette[px1]); textureGraphics.FillRectangle(brush, x, y, 1, 1); x++; if (x >= width) { x = 0; y++; } //increment int px2 = SM64ROM.getByte(pxaddr) & 0x0F; brush = new SolidBrush(palette[px2]); } textureGraphics.FillRectangle(brush, x, y, 1, 1); texel++; } } return(texture); }
public static void ResizeTexture(int F5index, int widthpower, int heightpower, out bool isFailedToResize) { uint[] F5CMDs = Textures.F5CMDArray[F5index]; ROM SM64ROM = ROMManager.SM64ROM; bool isFailedToResizeUVs = false; byte WidthsizeByte = SM64ROM.getByte(F5CMDs[0] + 7); ushort HeightsizeShort = SM64ROM.ReadTwoBytes(F5CMDs[0] + 5); int ogHeightPower = (HeightsizeShort >> 6 & 0x0F); int ogWidthPower = (WidthsizeByte >> 4); int difx = widthpower - ogWidthPower; int dify = heightpower - ogHeightPower; int width = (int)Math.Pow(2, widthpower); int height = (int)Math.Pow(2, heightpower); UInt32 clamp = (UInt32)((((width - 1) << 2) << 12) | ((height - 1) << 2)); for (uint i = 0; i < F5CMDs.Length; i++) { SM64ROM.changeByte(F5CMDs[i] + 7, (byte)(WidthsizeByte + (difx * 16))); //*8 for << 4 with negative carried SM64ROM.WriteTwoBytes(F5CMDs[i] + 5, (ushort)(HeightsizeShort + (dify * 64))); //*8 for << 6 with negative carried SM64ROM.WriteFourBytes(F5CMDs[i] + 12, clamp); //F2 command follows F5 rendertile bool exitUVcorrection = false; for (uint j = F5CMDs[i] + 8; j < SM64ROM.getEndROMAddr(); j += 8) //UV automatic correction { if (exitUVcorrection) { break; } switch (SM64ROM.getByte(j)) { case 0xBF: UInt32 UVStart = 0; double[][] UVs = new double[2][]; for (int k = 0; k < 2; k++) { UVs[k] = new double[3]; } for (uint k = j; k > j - 0x800; k -= 8) { if (SM64ROM.getByte(k) == 0x04) { UVStart = SM64ROM.readSegmentAddr(SM64ROM.ReadFourBytes(k + 4)) + 8; break; } } if (UVStart == 0) { break; } for (uint k = 5; k < 8; k++) { UInt32 addr = Vertex.getAddrFromTriIndex(UVStart, SM64ROM.getByte(j + k)); double U = (short)SM64ROM.ReadTwoBytes(addr); double V = (short)SM64ROM.ReadTwoBytes(addr + 2); U *= Math.Pow(2, difx); V *= Math.Pow(2, dify); UVs[0][k - 5] = U; UVs[1][k - 5] = V; } UVs = Vertex.UVChecker(UVs, out isFailedToResizeUVs); if (isFailedToResizeUVs) { isFailedToResize = true; // recover file return; } for (uint k = 5; k < 8; k++) { UInt32 addr = Vertex.getAddrFromTriIndex(UVStart, SM64ROM.getByte(j + k)); if (UVs[0][k - 5] > 0x7fff || UVs[0][k - 5] < -0x8000) { isFailedToResize = true; return; } SM64ROM.WriteTwoBytes(addr, (ushort)Convert.ToInt16(UVs[0][k - 5])); SM64ROM.WriteTwoBytes(addr + 2, (ushort)Convert.ToInt16(UVs[1][k - 5])); } break; case 0xFD: exitUVcorrection = true; break; case 0x06: exitUVcorrection = true; break; case 0xB8: exitUVcorrection = true; break; } } } isFailedToResize = false; return; }
private void Save(int Lang) { string ext = GetCARCExtension(Lang); var rfs = MainWindow.LoadedROM.ToFileSystem(); int idx = 0; foreach (TextBox elem in CommonTextsList.Items) { Common.DAT1.Strings[idx] = elem.Text; idx++; } var common = Common.Save(); var dmain2d = Main2D.ToFileSystem(); var fcommon = ROMUtils.GetSFSFile("common.bmg", dmain2d); fcommon.Data = common; Main2D.FromFileSystem(dmain2d); var fmain2d = ROMUtils.GetSFSFile("Main2D" + ext + ".carc", rfs); fmain2d.Data = ROM.LZ77_Compress(Main2D.Write()); idx = 0; foreach (TextBox elem in MBChildTextsList.Items) { MBChild.DAT1.Strings[idx] = elem.Text; idx++; } var mbchild = MBChild.Save(); var dstatic2d = Static2D.ToFileSystem(); var fmbchild = ROMUtils.GetSFSFile("MBChild" + ext + ".bmg", dstatic2d); fmbchild.Data = mbchild; Static2D.FromFileSystem(dstatic2d); var fstatic2d = ROMUtils.GetSFSFile("Static2D.carc", rfs); fstatic2d.Data = ROM.LZ77_Compress(Static2D.Write()); idx = 0; foreach (TextBox elem in KartSelectTextsList.Items) { KartSelect.DAT1.Strings[idx] = elem.Text; idx++; } var ksel = KartSelect.Save(); var dchksel = CharacterKartSelect.ToFileSystem(); var fksel = ROMUtils.GetSFSFile("kart_select.bmg", dchksel); fksel.Data = ksel; CharacterKartSelect.FromFileSystem(dchksel); var fchksel = ROMUtils.GetSFSFile("CharacterKartSelect" + ext + ".carc", rfs); fchksel.Data = ROM.LZ77_Compress(CharacterKartSelect.Write()); idx = 0; foreach (TextBox elem in DlPlayTextsList.Items) { Banner.DAT1.Strings[idx] = elem.Text; idx++; } var banner = Banner.Save(); var dwlmenu = WLMenu.ToFileSystem(); var fbanner = ROMUtils.GetSFSFile("banner.bmg", dwlmenu); fbanner.Data = banner; WLMenu.FromFileSystem(dwlmenu); var fwlmenu = ROMUtils.GetSFSFile("WLMenu" + ext + ".carc", rfs); fwlmenu.Data = ROM.LZ77_Compress(WLMenu.Write()); MainWindow.LoadedROM.FromFileSystem(rfs); }
/// <summary> /// Generate the MFORTH hash table. /// </summary> /// <param name="rom">MFORTH ROM.</param> /// <param name="phf1">Upon return, will contain the first /// PearsonHashFunction used by the hash table.</param> /// <param name="phf2">Upon return, will contain the second /// PearsonHashFunction used by the hash table.</param> /// <returns>The MFORTH hash table.</returns> private static CuckooHashTable <Word> GenerateHashTable(ROM rom, out PearsonHashFunction phf1, out PearsonHashFunction phf2) { // Initialize our random number generator. var random = new Random(HashTableRandomSeed); // Initialize our hash functions and the hash table. var hashFunc1 = phf1 = new PearsonHashFunction(random); var hashFunc2 = phf2 = new PearsonHashFunction(random); var hashTable = new CuckooHashTable <Word>( (w) => HashName(w.Name, hashFunc1, hashFunc2, HashMask), (w) => HashName(w.Name, hashFunc2, hashFunc1, HashMask)); // Generate the hash table. #if FINDING_OPTIMAL_HASH_SEED int minValuesAtSecondLocation = int.MaxValue; #endif for (;;) { #if !FINDING_OPTIMAL_HASH_SEED // Display a progress dot. Console.Write("."); #endif // Add all of the words to our hash table; assume that // we will be successful. bool haveCompleteTable = true; foreach (var word in rom.Words) { if (!hashTable.TryAddValue(word)) { haveCompleteTable = false; break; } } #if !FINDING_OPTIMAL_HASH_SEED // We're done if all of the words were added to the // table. if (haveCompleteTable) { break; } // We failed to generate a complete hash table; shuffle // the hash functions, clear the table, and try again. phf1.ShuffleAuxilliaryTable(random); phf2.ShuffleAuxilliaryTable(random); hashTable.Clear(); #else // Print out the results if this seed produced better // results than the previous best seed. if (haveCompleteTable && hashTable.NumValuesStoredAtSecondHash < minValuesAtSecondLocation) { Console.WriteLine( "Seed: {0}; 1st: {1}; 2nd: {2}", HashTableRandomSeed, hashTable.NumValuesStoredAtFirstHash, hashTable.NumValuesStoredAtSecondHash); minValuesAtSecondLocation = hashTable.NumValuesStoredAtSecondHash; } // Generate a new seed and re-create all of the hash // functions and tables. random = new Random(++HashTableRandomSeed); hashFunc1 = phf1 = new PearsonHashFunction(random); hashFunc2 = phf2 = new PearsonHashFunction(random); hashTable = new CuckooHashTable <Word>( (w) => HashName(w.Name, hashFunc1, hashFunc2, HashMask), (w) => HashName(w.Name, hashFunc2, hashFunc1, HashMask)); #endif } // Ensure that all of the words in the ROM were added to the // hash table. if (rom.NumWords != hashTable.Count) { throw new InvalidDataException( string.Format( "Hash table only has {0} words; expected {1} words.", hashTable.Count, rom.NumWords)); } // Return the hash table. return(hashTable); }
public void MakeData(ROM rom) { rom.Write64(lo); rom.Write64(hi, 8); rom.AddOffset(16); }
public int MakeF3D(ROM rom, SortedRegionList vertexBytes, ScrollFactory factory) { int start = rom.offset; foreach (UInt64 cmd in header) { rom.Write64(cmd); rom.AddOffset(8); } // TODO: This is kinda stupid assumption but we believe there are more triangles in the beginning available... List <ScrollingTextureDescription> tds = map.Keys.ToList(); tds.Sort(new ScrollingTextureDescriptionComp()); foreach (ScrollingTextureDescription td in tds) { td.MakeF3D(rom); // Time to do optimization magic List <Triangle> textureTris = map[td]; // Create reverse map for vertices, vertices with more triangles will be used first Dictionary <Vertex, List <Triangle> > vertex2triMap = new Dictionary <Vertex, List <Triangle> >(); foreach (Triangle tri in textureTris) { for (int i = 0; i < 3; i++) { Vertex v = tri.vertices[i]; if (!vertex2triMap.TryGetValue(v, out List <Triangle> weight)) { vertex2triMap[v] = new List <Triangle>(); } vertex2triMap[v].Add(tri); } } // You quite literally can't eat more than that int vertexLength = 0x30 * textureTris.Count(); vertexBytes.CutContigRegion(vertexLength, out int vertexPosition); int allocVertexStart = vertexPosition; int allocVertexEnd = allocVertexStart + vertexLength; int writtenVerticesCount = 0; // Check if there are still vertices that needs to be worked with // Also we must make sure all lists in v2tm are not empty! while (vertex2triMap.Count != 0) { int segmentedVertexStart = rom.GetSegmentedAddress(vertexPosition); // vbd is main structure that holds information about used vertices space VertexBufferDescription vbd = new VertexBufferDescription((UInt32)segmentedVertexStart, 0xF); // Potential triangles also have weight depending on connection to other triangles and to added vertices // Weight +1 for each tri that shares vertice; +vertexPresentBonus for each vbd present vertex // It is recommended to have vertexPresentBonus be more than any weight that shared vertices can give // This way triangle that have the most weight will have the most vertices and potentially help others Dictionary <Triangle, int> potentialTris = new Dictionary <Triangle, int>(); // Add triangles to vbd till it won't be able to fit in the whole triangle while (vbd.freeCount != 0 && vertex2triMap.Count != 0) { // Right now no vertices are in vbd, pick one with the heighest weight and add it to vbd if (potentialTris.Count == 0) { // We need at least 3 vertices to draw not present tri if (vbd.freeCount < 3) { break; } KeyValuePair <Vertex, List <Triangle> > pair; // Let's ask for at least 5 vertices for optimal stuff, otherwise just put the worst triangle and call it if (vbd.freeCount < 5) { pair = vertex2triMap.Aggregate((prev, cur) => prev.Value.Count < cur.Value.Count ? prev : cur); } else { pair = vertex2triMap.Aggregate((prev, cur) => prev.Value.Count > cur.Value.Count ? prev : cur); } Vertex v = pair.Key; List <Triangle> tris = pair.Value; if (tris.Count == 0) { throw new ArithmeticException("Tris count in dict can't be 0"); } // Put current vertex and use found tris as potential next tri to add vbd.AddVertex(v); // Setup all potential triangles to could be added to vbd, the ones that have this vertex in common foreach (Triangle tri in tris) { potentialTris[tri] = 0; } // If vertex is in common between tris, give 1 each var tripairs = tris.Zip(tris.Skip(1), (a, b) => Tuple.Create(a, b)); foreach (Tuple <Triangle, Triangle> tripair in tripairs) { Triangle tri1 = tripair.Item1; Triangle tri2 = tripair.Item2; int common = tri1.CountCommon(tri2); potentialTris[tri1] += common; potentialTris[tri2] += common; } } // Find tri with biggest weight Triangle biggestTri = potentialTris.Aggregate((prev, cur) => prev.Value > cur.Value ? prev : cur).Key; // Add all triangles in vbd int[] indices = new int[3]; for (int i = 0; i < 3; i++) { Vertex v = biggestTri.vertices[i]; int index = vbd.AddVertex(v, out bool isNew); indices[i] = index; // Fix weights of tris if a new vertex was added to vbd (not already in vbd it is) if (isNew) { foreach (Triangle ptri in potentialTris.Keys.ToList()) { if (ptri.Contains(v)) { potentialTris[ptri] += vertexPresentBonus; } } } } // Draw the triangle, all vertices are guaranteed to be in vbd.DrawTriangle(indices); // As triangle was drawn, it needs to be removed from structs that had it // vertex2map & potentialTris // This way triangle won't be able to appear again foreach (Vertex v in biggestTri.vertices) { vertex2triMap[v].Remove(biggestTri); if (vertex2triMap[v].Count == 0) { vertex2triMap.Remove(v); } } potentialTris.Remove(biggestTri); // Setup new triangles to potentialTris HashSet <Triangle> newTris = new HashSet <Triangle>(); foreach (Vertex v in biggestTri.vertices) { if (vertex2triMap.TryGetValue(v, out List <Triangle> tris)) { foreach (Triangle tri in tris) { newTris.Add(tri); } } } // Also do not take into account tris that were added already // If we will take them into account, bad things will happen newTris.RemoveWhere(t => potentialTris.Keys.Contains(t)); // As new triangles appear, proceed to fix weights // First of all, initialize world: create new potential tris that will be merged later with potential tris // Initial value is -vertexPresentBonus as one vertex will be counted anyways Dictionary <Triangle, int> newPotentialTris = new Dictionary <Triangle, int>(); foreach (Triangle ntri in newTris) { newPotentialTris[ntri] = -vertexPresentBonus; } // Calculate weights for vertices that were present foreach (Triangle ntri in newTris) { foreach (Vertex v in vbd.vbuf) { if (ntri.Contains(v)) { newPotentialTris[ntri] += vertexPresentBonus; } } } // Check between triangles new/new var newNewTripairs = newTris.Zip(newTris.Skip(1), (a, b) => Tuple.Create(a, b)); foreach (Tuple <Triangle, Triangle> tripair in newNewTripairs) { Triangle tri1 = tripair.Item1; Triangle tri2 = tripair.Item2; int common = tri1.CountCommon(tri2); newPotentialTris[tri1] += common; newPotentialTris[tri2] += common; } // Check between triangles new/old List <Triangle> oldTris = potentialTris.Keys.ToList(); var newOldTripairs = newTris.Zip(oldTris, (a, b) => Tuple.Create(a, b)); foreach (Tuple <Triangle, Triangle> tripair in newOldTripairs) { Triangle newTri = tripair.Item1; Triangle oldTri = tripair.Item2; int common = newTri.CountCommon(oldTri); newPotentialTris[newTri] += common; potentialTris[oldTri] += common; } // Merge together old and new foreach (KeyValuePair <Triangle, int> pair in newPotentialTris) { potentialTris.Add(pair.Key, pair.Value); } // Check if there are triangles that have all vertexes inside the vbd // All such vertices could be initially drawn so just draw them // Triangles with weight over 2*vertexPresetBonus have 2+1 vertices in buffer so just draw them var drawnPairs = potentialTris.Where((t, w) => w >= 2 * vertexPresentBonus); foreach (KeyValuePair <Triangle, int> pair in drawnPairs) { Triangle ftri = pair.Key; for (int i = 0; i < 3; i++) { Vertex v = ftri.vertices[i]; int index = vbd.AddVertex(v, out bool isNew); indices[i] = index; // Fix weights of tris if a new vertex was added to vbd (not already in vbd it is) if (isNew) { throw new ArithmeticException("Triangles with high weight has new vertices!"); } } // Draw the triangle, all vertices are guaranteed to be in vbd.DrawTriangle(indices); potentialTris.Remove(biggestTri); } // Check if there are less then 2 vertices, which are required to be able to draw any tri // If there is a vertex that has vertexPresentBonus weight, we good, otherwise retreat if (vbd.freeCount == 1) { if (potentialTris.Values.ToList().FindIndex(w => w >= vertexPresentBonus) == -1) { break; } } } rom.PushOffset(vertexPosition); vbd.MakeData(rom); writtenVerticesCount += (rom.offset - vertexPosition) / 0x10; vertexPosition = rom.offset; rom.PopOffset(); vbd.MakeF3D(rom); } if (td.scroll != null) { // Vertices must be rounded by 3 because skelux scrolls work like that /* * if (writtenVerticesCount % 3 != 0) * { * int leftToRoundVertices = 3 - (writtenVerticesCount % 3); * writtenVerticesCount += leftToRoundVertices; * vertexPosition += leftToRoundVertices * 0x10; * } */ int segmentedAddress = rom.GetSegmentedAddress(allocVertexStart); List <ScrollObject> scrolls = factory.GetScrolls(writtenVerticesCount, segmentedAddress, td); foreach (ScrollObject scroll in scrolls) { scroll.WriteScroll(rom); } } vertexBytes.AddRegion(vertexPosition, allocVertexEnd - vertexPosition); } foreach (UInt64 cmd in footer) { rom.Write64(cmd); rom.AddOffset(8); } return(rom.offset - start); }
/// <summary> /// Returns an enumeration definition for the specified name. /// </summary> public abstract EnumValueDefinition?FindByName(ROM name);
private static void CMD_39(ref Level lvl, ref string desc, byte[] cmd) { if (cmd.Length < 8) { return; } ROM rom = ROM.Instance; uint pos = bytesToInt(cmd, 4, 4); desc = "Place macro objects loaded from address 0x" + pos.ToString("X8"); byte[] data = rom.getDataFromSegmentAddress_safe(pos, 10); lvl.getCurrentArea().MacroObjects.Clear(); bool endList = false; while (!endList) { //rom.printArray(data, 10); uint id = bytesToInt(data, 0, 2) & 0x1FF; if (id == 0 || id == 0x1E) { break; } Object3D newObj = new Object3D(); if (rom.isSegmentMIO0(cmd[4])) { newObj.MakeReadOnly(); newObj.Address = "N/A"; } else { newObj.Address = "0x" + rom.decodeSegmentAddress(pos).ToString("X"); } uint table_off = (id - 0x1F) * 8; byte[] entryData = rom.getSubArray(rom.Bytes, Globals.macro_preset_table + table_off, 8); newObj.level = lvl; newObj.createdFromLevelScriptCommand = Object3D.FROM_LS_CMD.CMD_39; newObj.setBehaviorFromAddress(bytesToInt(entryData, 0, 4)); newObj.HideProperty(Object3D.FLAGS.ROTATION_X); newObj.HideProperty(Object3D.FLAGS.ROTATION_Z); newObj.HideProperty(Object3D.FLAGS.BPARAM_3); newObj.HideProperty(Object3D.FLAGS.BPARAM_4); newObj.ModelID = entryData[5]; ushort firstAndSecond = (ushort)bytesToInt(data, 0, 2); newObj.setPresetID((ushort)(firstAndSecond & 0x1FF)); newObj.yRot = (short)((firstAndSecond >> 9) * 2.8125); newObj.xPos = (short)bytesToInt(data, 2, 2); newObj.yPos = (short)bytesToInt(data, 4, 2); newObj.zPos = (short)bytesToInt(data, 6, 2); newObj.DontShowActs(); newObj.MakeBehaviorReadOnly(true); newObj.MakeModelIDReadOnly(true); ushort bp = (ushort)bytesToInt(data, 8, 2); if (data[8] != 0) { newObj.BehaviorParameter1 = data[8]; } else { newObj.BehaviorParameter1 = entryData[6]; } if (data[9] != 0) { newObj.BehaviorParameter2 = data[9]; } else { newObj.BehaviorParameter2 = entryData[7]; } lvl.getCurrentArea().MacroObjects.Add(newObj); pos += 10; data = rom.getDataFromSegmentAddress_safe(pos, 10); } //uint end = bytesToInt(cmd, 8, 4); //rom.setSegment(seg, start, end, false); }
/* Process collision map, Special Objects, and waterboxes. */ private static void CMD_2E(ref Level lvl, ref string desc, byte[] cmd) { ROM rom = ROM.Instance; if (cmd.Length < 8) { return; } desc = "Load collision, and place special objects from address 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); ushort sub_cmd = 0x40; byte segment = cmd[4]; uint off = bytesToInt(cmd, 5, 3); byte[] data = rom.getSegment(segment); sub_cmd = (ushort)bytesToInt(data, (int)off, 2); CollisionMap cmap = lvl.getCurrentArea().collision; uint num_verts = (ushort)bytesToInt(data, (int)off + 2, 2); off += 4; for (int i = 0; i < num_verts; i++) { short x = (short)bytesToInt(data, (int)off + 0, 2); short y = (short)bytesToInt(data, (int)off + 2, 2); short z = (short)bytesToInt(data, (int)off + 4, 2); cmap.AddVertex(new OpenTK.Vector3(x, y, z)); off += 6; } while (sub_cmd != 0x0041) { sub_cmd = (ushort)bytesToInt(data, (int)off, 2); //Console.WriteLine(sub_cmd.ToString("X8")); if (sub_cmd == 0x0041) { break; } //rom.printArraySection(data, (int)off, 4 + (int)collisionLength(sub_cmd)); cmap.NewTriangleList((int)bytesToInt(data, (int)off, 2)); uint num_tri = (ushort)bytesToInt(data, (int)off + 2, 2); uint col_len = collisionLength(sub_cmd); off += 4; for (int i = 0; i < num_tri; i++) { uint a = bytesToInt(data, (int)off + 0, 2); uint b = bytesToInt(data, (int)off + 2, 2); uint c = bytesToInt(data, (int)off + 4, 2); cmap.AddTriangle(a, b, c); off += col_len; } } cmap.buildCollisionMap(); off += 2; bool end = false; while (!end) { sub_cmd = (ushort)bytesToInt(data, (int)off, 2); switch (sub_cmd) { case 0x0042: end = true; break; case 0x0043: uint num_obj = (ushort)bytesToInt(data, (int)off + 2, 2); off += 4; for (int i = 0; i < num_obj; i++) { ushort obj_id = (ushort)bytesToInt(data, (int)off, 2); byte[] entry = getSpecialObjectEntry((byte)obj_id); uint obj_len = getSpecialObjectLength(obj_id); Object3D newObj = new Object3D(); if (rom.isSegmentMIO0(segment)) { newObj.MakeReadOnly(); newObj.Address = "N/A"; } else { newObj.Address = "0x" + rom.decodeSegmentAddress(segment, off).ToString("X"); } newObj.setPresetID(obj_id); newObj.level = lvl; newObj.HideProperty(Object3D.FLAGS.ROTATION_X); newObj.HideProperty(Object3D.FLAGS.ROTATION_Z); newObj.HideProperty(Object3D.FLAGS.BPARAM_3); newObj.HideProperty(Object3D.FLAGS.BPARAM_4); newObj.xPos = (short)bytesToInt(data, (int)off + 2, 2); newObj.yPos = (short)bytesToInt(data, (int)off + 4, 2); newObj.zPos = (short)bytesToInt(data, (int)off + 6, 2); newObj.BehaviorParameter1 = entry[1]; newObj.BehaviorParameter2 = entry[2]; newObj.MakeBehaviorReadOnly(true); newObj.MakeModelIDReadOnly(true); if (obj_len > 8) { newObj.yRot = (short)(bytesToInt(data, (int)off + 8, 2) * 1.40625); if (obj_len > 10) { newObj.BehaviorParameter1 = data[off + 10]; newObj.BehaviorParameter2 = data[off + 11]; newObj.createdFromLevelScriptCommand = Object3D.FROM_LS_CMD.CMD_2E_12; lvl.AddSpecialObjectPreset_12(obj_id, entry[3], bytesToInt(entry, 4, 4), data[off + 10], data[off + 11]); } else { lvl.AddSpecialObjectPreset_10(obj_id, entry[3], bytesToInt(entry, 4, 4)); newObj.HideProperty(Object3D.FLAGS.BPARAM_1); newObj.HideProperty(Object3D.FLAGS.BPARAM_2); newObj.createdFromLevelScriptCommand = Object3D.FROM_LS_CMD.CMD_2E_10; } } else { lvl.AddSpecialObjectPreset_8(obj_id, entry[3], bytesToInt(entry, 4, 4)); newObj.HideProperty(Object3D.FLAGS.BPARAM_1); newObj.HideProperty(Object3D.FLAGS.BPARAM_2); newObj.HideProperty(Object3D.FLAGS.ROTATION_Y); newObj.createdFromLevelScriptCommand = Object3D.FROM_LS_CMD.CMD_2E_8; } newObj.ModelID = entry[3]; uint behavior = bytesToInt(entry, 4, 4); newObj.setBehaviorFromAddress(behavior); newObj.DontShowActs(); if (behavior != 0) { lvl.getCurrentArea().SpecialObjects.Add(newObj); } off += obj_len; } break; case 0x0044: // Also skipping water boxes. Will come back to it later. uint num_boxes = (ushort)bytesToInt(data, (int)off + 2, 2); off += 4 + (num_boxes * 0xC); break; } } }
public ByteRegister this[ROM r] { get { return(this[(uint)r]); } set { this[(uint)r] = value; } }
public void Load() { if (ComboIndex < 0) { LanguageCombo.SelectedIndex = 0; } var rfs = MainWindow.LoadedROM.ToFileSystem(); string ext = GetCARCExtension(LanguageCombo.SelectedIndex); var cbmain2d = ROMUtils.GetFile("Main2D" + ext + ".carc", rfs); var bmain2d = ROM.LZ77_Decompress(cbmain2d); Main2D = new NARC(bmain2d); var dmain2d = Main2D.ToFileSystem(); var common = ROMUtils.GetFile("common.bmg", dmain2d); Common = new BMG(common); var cbstatic2d = ROMUtils.GetFile("Static2D.carc", rfs); var bstatic2d = ROM.LZ77_Decompress(cbstatic2d); Static2D = new NARC(bstatic2d); var dstatic2d = Static2D.ToFileSystem(); var mbchild = ROMUtils.GetFile("MBChild" + ext + ".bmg", dstatic2d); MBChild = new BMG(mbchild); var cbchksel = ROMUtils.GetFile("CharacterKartSelect" + ext + ".carc", rfs); var bchksel = ROM.LZ77_Decompress(cbchksel); CharacterKartSelect = new NARC(bchksel); var dchksel = CharacterKartSelect.ToFileSystem(); var ksel = ROMUtils.GetFile("kart_select.bmg", dchksel); KartSelect = new BMG(ksel); var cbwlmenu = ROMUtils.GetFile("WLMenu" + ext + ".carc", rfs); var bwlmenu = ROM.LZ77_Decompress(cbwlmenu); WLMenu = new NARC(bwlmenu); var dwlmenu = WLMenu.ToFileSystem(); var banner = ROMUtils.GetFile("banner.bmg", dwlmenu); Banner = new BMG(banner); CommonTextsList.Items.Clear(); MBChildTextsList.Items.Clear(); KartSelectTextsList.Items.Clear(); DlPlayTextsList.Items.Clear(); foreach (var str in Common.DAT1.Strings) { CommonTextsList.Items.Add(new TextBox() { TextWrapping = TextWrapping.Wrap, AcceptsReturn = true, Text = str, }); } foreach (var str in MBChild.DAT1.Strings) { MBChildTextsList.Items.Add(new TextBox() { TextWrapping = TextWrapping.Wrap, AcceptsReturn = true, Text = str, }); } foreach (var str in KartSelect.DAT1.Strings) { KartSelectTextsList.Items.Add(new TextBox() { TextWrapping = TextWrapping.Wrap, AcceptsReturn = true, Text = str, }); } foreach (var str in Banner.DAT1.Strings) { DlPlayTextsList.Items.Add(new TextBox() { TextWrapping = TextWrapping.Wrap, AcceptsReturn = true, Text = str, }); } }
private void ImportTexture_Click(object sender, EventArgs e) { int index = TextureNumBox.SelectedIndex; // Displays an OpenFileDialog so the user can select a Cursor. OpenFileDialog OpenTexture = OFD(); OpenTexture.Filter = "Image Files|*.png;*.bmp;*.jpg"; OpenTexture.Title = "Select a texture image file"; if (OpenTexture.ShowDialog() == System.Windows.Forms.DialogResult.OK) { Bitmap TextureBMP = (Bitmap)Image.FromFile(OpenTexture.FileName); double widthpower = Math.Log(TextureBMP.Width, 2); double heightpower = Math.Log(TextureBMP.Height, 2); if ((widthpower % 1) != 0 || (heightpower % 1) != 0) { MessageBox.Show("Only texture sizes in powers of 2 \n(ie 16x16, 32x32, 64x64, 128x64) are supported!", "Invalid texture resolution"); return; } Vector2 originalpowers = Textures.getWidthHeightPowers(index); if ((Math.Pow(2, originalpowers.X) * Math.Pow(2, originalpowers.Y)) < (Math.Pow(2, widthpower) * Math.Pow(2, heightpower))) { MessageBox.Show("Texture is beyond the max data for this tile! \nTry lowering resolution or bitsize.", "Texture data too large!"); return; } else if (TexFormatBox.SelectedIndex == 2 && ((Math.Pow(2, originalpowers.X) * Math.Pow(2, originalpowers.Y)) < (Math.Pow(2, widthpower + 1) * Math.Pow(2, heightpower)))) //CI4 needs twice data atm for palette { MessageBox.Show("Texture is beyond the max data for this tile! \nTry lowering resolution or bitsize.\n(CI needs extra data for palette and commands)", "Texture data too large!"); return; } else if (TexFormatBox.SelectedIndex == 2 && BitsizeBox.SelectedIndex == 0 && Textures.getImageColors(TextureBMP).Length > 16) { MessageBox.Show("Texture has too many colours for CI4.\nPlease reduce colour count to 16."); return; } Textures.ResizeTexture(index, Convert.ToInt32(widthpower), Convert.ToInt32(heightpower)); Textures.ImportBMPtoTexture(TextureBMP, index); UInt32[] F5CMDs = Textures.F5CMDArray[TextureNumBox.SelectedIndex]; ROM SM64ROM = ROMManager.SM64ROM; ROMManager.InitialiseModelLoad(ClientRectangle, RenderPanel, Width, Height); UpdateTextureNum(); int width = TextureBMP.Width; int selectedbitsize = (int)(4 * Math.Pow(2, BitsizeBox.SelectedIndex)); ushort linesperword = Convert.ToUInt16((64d * 2048d) / ((double)TextureBMP.Width * selectedbitsize)); ushort texelcount = (ushort)((double)(TextureBMP.Width * TextureBMP.Height) * ((double)selectedbitsize / 16d) - 1); for (uint i = 0; i < F5CMDs.Length; i++) //Update F5 scanline width { uint F5 = F5CMDs[i]; if (SM64ROM.getByte(F5 - 0x10) == 0xF3) { SM64ROM.WriteEightBytes(F5 - 0x10, 0xF300000007000000 | (uint)(texelcount << 12) | linesperword); } SM64ROM.WriteTwoBytes(F5 + 1, (ushort)((SM64ROM.ReadTwoBytes(F5CMDs[i] + 1) & 0xFC00) | ((width * selectedbitsize / 64) << 1))); } TextureBMP.Dispose(); } }
private List <RadioButtonWithInfo> parseOtherListJSON(JArray array, out string blockName) { ROM rom = ROM.Instance; blockName = "Unknown"; List <RadioButtonWithInfo> list = new List <RadioButtonWithInfo>(); uint segmentAddressForLoadingData = 0; byte[][] tempSegments = new byte[0x20][]; uint[] tempSegmentStarts = new uint[0x20]; bool[] tempSegmentsAreMIO0 = new bool[0x20]; foreach (JObject obj in array.Children()) { if (obj["Block Name"] != null) { blockName = obj["Block Name"].ToString(); segmentAddressForLoadingData = 0; // Reset for every new block } else if (obj["UseSegmentAddressesFromLevelScriptStartingFrom"] != null) { segmentAddressForLoadingData = uint.Parse(obj["UseSegmentAddressesFromLevelScriptStartingFrom"].ToString(), NumberStyles.HexNumber); for (int i = 0; i < 0x20; i++) { tempSegments[i] = new byte[0]; // reset segments tempSegmentsAreMIO0[i] = false; tempSegmentStarts[i] = 0; } tempSegments[0x00] = rom.Bytes; tempSegments[0x15] = rom.cloneSegment(0x15, (byte)level.CurrentAreaID); tempSegmentStarts[0x15] = Globals.seg15_location[0]; tempSegments[0x02] = rom.cloneSegment(0x02, (byte)level.CurrentAreaID); tempSegmentStarts[0x02] = Globals.seg02_location[0]; tempSegmentsAreMIO0[0x02] = !rom.Seg02_isFakeMIO0; //Console.WriteLine("SegOff:0x{0}", segmentAddressForLoadingData.ToString("X8")); parseLevelScriptTemporarlyForSegments(tempSegments, tempSegmentStarts, tempSegmentsAreMIO0, (byte)(segmentAddressForLoadingData >> 24), segmentAddressForLoadingData & 0xFFFFFF); } else { if (checkForValidEntry(obj)) { int width = int.Parse(obj["Width"].ToString()); int height = int.Parse(obj["Height"].ToString()); byte format = TextureFormats.ConvertStringToFormat(obj["Format"].ToString()); uint dataSize = (uint)((TextureFormats.getNumberOfBitsForFormat(format) * width * height) / 8); byte[] data; if (obj["FromSegmentAddress"] != null) { uint segOffset = uint.Parse(obj["FromSegmentAddress"].ToString(), NumberStyles.HexNumber); if (segmentAddressForLoadingData == 0) { data = rom.getDataFromSegmentAddress_safe(segOffset, dataSize, (byte)level.CurrentAreaID); } else { byte segment = (byte)(segOffset >> 24); uint segment_off = segOffset & 0x00FFFFFF; data = rom.getSubArray_safe(tempSegments[segment], segment_off, dataSize); } } else { if (rom.Type == ROM_Type.VANILLA && obj["ForExtendedROM"] != null) { string forExtendedROM = obj["ForExtendedROM"].ToString().ToLower(); if (forExtendedROM.Equals("true")) { continue; } } uint romOff = uint.Parse(obj["FromROMAddress"].ToString(), NumberStyles.HexNumber); data = rom.getSubArray_safe(rom.Bytes, romOff, dataSize); } Bitmap image = TextureFormats.decodeTexture(format, data, width, height, null, true); string[] tags = (string[])image.Tag; Array.Resize(ref tags, tags.Length + 3); uint segOff = 0; if (obj["FromSegmentAddress"] != null) { segOff = uint.Parse(obj["FromSegmentAddress"].ToString(), NumberStyles.HexNumber); if (segmentAddressForLoadingData == 0) { if (!rom.isSegmentMIO0((byte)(segOff >> 24), (byte)level.CurrentAreaID)) { tags[tags.Length - 3] = "ROM Address: " + rom.decodeSegmentAddress(segOff, (byte)level.CurrentAreaID).ToString("X"); } else { tags[tags.Length - 3] = "ROM Address: N/A"; } } else { byte seg_temp = (byte)(segOff >> 24); uint seg_temp_offset = segOff & 0x00FFFFFF; if (tempSegmentsAreMIO0[seg_temp]) { tags[tags.Length - 3] = "ROM Address: N/A"; } else { tags[tags.Length - 3] = "ROM Address: " + (tempSegmentStarts[seg_temp] + seg_temp_offset).ToString("X"); } } tags[tags.Length - 2] = "Seg Addr: " + obj["FromSegmentAddress"]; } else { tags[tags.Length - 3] = "ROM Address: " + obj["FromROMAddress"]; tags[tags.Length - 2] = "Seg Addr: N/A"; } tags[tags.Length - 1] = "Name: " + obj["Name"]; image.Tag = tags; AddNewImage(ref list, image, segOff, ot_RadioButtonWithInfo_Click); //Console.WriteLine("Added Other Image: " + obj["Name"]); } //Bitmap image = TextureFormats.decodeTexture(); //AddNewImage(ref list, level.ModelIDs[modelID].builder.TextureImages[i], address, ot_RadioButtonWithInfo_Click); } //Console.WriteLine(obj.ToString()); } return(list); }
public static void parse(ref Model3D mdl, ref Level lvl, byte seg, uint off, byte?areaID) { if (seg == 0) { return; } ROM rom = ROM.Instance; byte[] data = rom.getSegment(seg, areaID); bool end = false; while (!end) { byte cmdLen = getCmdLength(data[off]); byte[] cmd = rom.getSubArray_safe(data, off, cmdLen); string desc = "Unknown command"; bool alreadyAdded = false; /* * if (cmd[0] != 0x05 && nodeCurrent.isSwitch && nodeCurrent.switchPos != 1) * { * if (nodeCurrent.switchFunc == 0x8029DB48) * { * //rom.printArray(cmd, cmdLen); * //Console.WriteLine(nodeCurrent.switchPos); * } * nodeCurrent.switchPos++; * off += cmdLen; * continue; * }*/ switch (cmd[0]) { case 0x00: desc = "Branch geometry layout to address 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); addGLSCommandToDump(ref mdl, cmd, seg, off, desc, areaID); alreadyAdded = true; CMD_00(ref mdl, ref lvl, cmd, areaID); break; case 0x01: desc = "End geometry layout"; end = true; break; case 0x02: desc = "Branch geometry layout to address 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); addGLSCommandToDump(ref mdl, cmd, seg, off, desc, areaID); alreadyAdded = true; CMD_02(ref mdl, ref lvl, cmd, areaID); if (cmd[1] == 0x01) { if (nodeCurrent.parent == null || (nodeCurrent.parent != null && nodeCurrent.parent.callSwitch == false)) { // If the next command is not another 0x02 command, or a 0x05 command... if (data[off + cmdLen] != 0x02 && data[off + cmdLen] != 0x05) { end = true; } } } break; case 0x03: desc = "Return from branch"; end = true; break; case 0x04: desc = "Open New Node"; CMD_04(); break; case 0x05: desc = "Close Node"; if (nodeCurrent != rootNode) { nodeCurrent = nodeCurrent.parent; } break; case 0x08: desc = "Set screen rendering area (" + "center X = " + (short)bytesToInt(cmd, 4, 2) + ", center Y = " + (short)bytesToInt(cmd, 6, 2) + ", Width = " + (short)(bytesToInt(cmd, 8, 2) * 2) + ", Height = " + (short)(bytesToInt(cmd, 10, 2) * 2) + ")"; break; case 0x0A: desc = "Set camera frustum (" + "FOV = " + (short)bytesToInt(cmd, 2, 2) + ", Near = " + (short)bytesToInt(cmd, 4, 2) + ", Far = " + (short)bytesToInt(cmd, 6, 2) + ")"; break; case 0x0B: desc = "Start geometry layout"; break; case 0x0C: if (cmd[1] == 0x00) { desc = "Disable Z-Buffer"; } else { desc = "Enable Z-Buffer"; } break; case 0x0D: desc = "Set render range from camera (min = " + (short)bytesToInt(cmd, 4, 2) + ", max = " + (short)bytesToInt(cmd, 6, 2) + ")"; break; case 0x0E: desc = "Switch case with following display lists using ASM function 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); //rom.printArray(cmd, cmdLen); CMD_0E(ref mdl, ref lvl, cmd); break; case 0x10: desc = "Translate and rotate"; //CMD_10(ref mdl, ref lvl, cmd); break; case 0x11: //rom.printArray(cmd, cmdLen); desc = "Translate Node"; CMD_11(ref mdl, ref lvl, cmd); break; case 0x13: desc = "Load display list 0x" + bytesToInt(cmd, 8, 4).ToString("X8") + " into layer " + cmd[1] + " and offset position by (" + (short)bytesToInt(cmd, 2, 2) + "," + (short)bytesToInt(cmd, 2, 2) + "," + (short)bytesToInt(cmd, 2, 2) + ")"; //rom.printArray(cmd, cmdLen); CMD_13(ref mdl, ref lvl, cmd, areaID); break; case 0x14: desc = "Billboard Model"; //CMD_10(ref mdl, ref lvl, cmd); break; case 0x15: desc = "Load display list 0x" + bytesToInt(cmd, 4, 4).ToString("X8") + " into layer " + cmd[1]; CMD_15(ref mdl, ref lvl, cmd, areaID); // rom.printArray(cmd, cmdLen); break; case 0x16: desc = "Start geometry layout with a shadow. (type = " + cmd[3] + ", solidity = " + cmd[5] + ", scale = " + bytesToInt(cmd, 6, 2) + ")"; //CMD_10(ref mdl, ref lvl, cmd); break; case 0x17: desc = "Setup display lists for level objects"; break; case 0x18: desc = "Create display list(s) from the ASM function 0x" + bytesToInt(cmd, 4, 4).ToString("X8") + " (a0 = " + bytesToInt(cmd, 2, 2) + ")"; CMD_18(ref mdl, ref lvl, cmd); // rom.printArray(cmd, cmdLen); break; case 0x19: if (bytesToInt(cmd, 4, 4) == 0x00000000) { desc = "Draw solid color background. Color = ("; ushort color = (ushort)bytesToInt(cmd, 2, 2); desc += (((color >> 11) & 0x1F) * 8) + "," + (((color >> 6) & 0x1F) * 8) + "," + (((color >> 1) & 0x1F) * 8) + ")"; } else { desc = "Draw background image. bgID = " + bytesToInt(cmd, 2, 2) + ", calls ASM function 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); } CMD_19(ref mdl, ref lvl, cmd, rom.decodeSegmentAddress(seg, off, areaID)); // rom.printArray(cmd, cmdLen); break; case 0x1D: desc = "Scale following node by " + ((bytesToInt(cmd, 4, 4) / 65536.0f) * 100.0f) + "%"; CMD_1D(ref mdl, cmd); break; case 0x1A: case 0x1E: case 0x1F: desc = "Do nothing"; break; case 0x20: desc = "Start geometry layout with render area of " + bytesToInt(cmd, 2, 2); break; } if (!alreadyAdded) { addGLSCommandToDump(ref mdl, cmd, seg, off, desc, areaID); } off += cmdLen; /* * if (nodeCurrent.isSwitch) * nodeCurrent.switchPos++; */ } }
private int parseLevelScriptTemporarlyForSegments(byte[][] segments, uint[] segmentStarts, bool[] segmentsAreMIO0, byte seg, uint off) { ROM rom = ROM.Instance; byte[] data = segments[seg]; if (data == null || data.Length < 1) { return(2); } bool end = false; int endCmd = 0; byte l_seg; uint l_start, l_end, l_off; while (!end) { byte cmdLen = data[off + 1]; byte[] cmd = rom.getSubArray_safe(data, off, cmdLen); //rom.printArray(cmd, cmdLen); switch (cmd[0]) { case 0x00: case 0x01: { l_seg = cmd[3]; l_start = bytesToInt(cmd, 4, 4); l_end = bytesToInt(cmd, 8, 4); l_off = bytesToInt(cmd, 13, 3); segmentStarts[l_seg] = l_start; segments[l_seg] = rom.getROMSection(l_start, l_end); int end_r = parseLevelScriptTemporarlyForSegments(segments, segmentStarts, segmentsAreMIO0, l_seg, l_off); if (end_r == 0x02) { end = true; endCmd = 2; } } break; case 0x02: endCmd = 2; end = true; break; case 0x05: l_seg = cmd[4]; l_off = bytesToInt(cmd, 5, 3); if (l_seg == seg) { if ((long)l_off - (long)off == -4) { //Console.WriteLine("Infinite loop detected!"); return(0x02); } } endCmd = parseLevelScriptTemporarlyForSegments(segments, segmentStarts, segmentsAreMIO0, l_seg, l_off); end = true; break; case 0x06: l_seg = cmd[4]; l_off = bytesToInt(cmd, 5, 3); int end_ret = parseLevelScriptTemporarlyForSegments(segments, segmentStarts, segmentsAreMIO0, l_seg, l_off); if (end_ret == 0x02) { end = true; endCmd = 2; } break; case 0x07: end = true; endCmd = 0x07; break; case 0x17: l_seg = cmd[3]; l_start = bytesToInt(cmd, 4, 4); l_end = bytesToInt(cmd, 8, 4); if (l_start < l_end) { segmentStarts[l_seg] = l_start; segments[l_seg] = rom.getROMSection(l_start, l_end); } //rom.setSegment(seg, start, end, false); break; case 0x18: case 0x1A: l_seg = cmd[3]; l_start = bytesToInt(cmd, 4, 4); l_end = bytesToInt(cmd, 8, 4); if (l_start < l_end) { byte[] MIO0_header = rom.getSubArray_safe(rom.Bytes, l_start, 0x10); if (bytesToInt(MIO0_header, 0, 4) == 0x4D494F30) // Check MIO0 signature { int compressedOffset = (int)bytesToInt(MIO0_header, 0x8, 4); int uncompressedOffset = (int)bytesToInt(MIO0_header, 0xC, 4); bool isFakeMIO0 = rom.testIfMIO0IsFake(l_start, compressedOffset, uncompressedOffset); segmentsAreMIO0[l_seg] = !isFakeMIO0; if (isFakeMIO0) { segmentStarts[l_seg] = l_start + (uint)uncompressedOffset; } segments[l_seg] = MIO0.mio0_decode(rom.getROMSection(l_start, l_end)); } } break; case 0x1D: end = true; endCmd = 0x02; break; } off += cmdLen; } return(endCmd); }
public static void ImportBMPtoTexture(Bitmap bmp, int index) { ROM SM64ROM = ROMManager.SM64ROM; bool RGBAMode = TextureAddrArray[index][1] == RGBAMODE; bool IAMode = TextureAddrArray[index][1] == IAMODE; bool IMode = TextureAddrArray[index][1] == IMODE; bool CIMode = TextureAddrArray[index][1] == CIMODE; bool YUVMode = TextureAddrArray[index][1] == YUVMODE; uint bitsize = TextureAddrArray[index][2]; UInt32 addr = TextureAddrArray[index][0]; UInt32[] inttexels = new UInt32[bmp.Width * bmp.Height]; ushort[] shorttexels = new ushort[bmp.Width * bmp.Height]; byte[] bytetexels; int x = 0; int y = 0; switch (bitsize) { case 16: if (RGBAMode) //RGBA16 { for (uint i = 0; i < shorttexels.Length; i++) { System.Drawing.Color texel = bmp.GetPixel(x, y); byte alpha = texel.A; if (alpha > 0) { alpha = 1; } else { alpha = 0; } ushort colour = (ushort) ( ((byte)(texel.R >> 3) << 11) | ((byte)(texel.G >> 3) << 6) | ((byte)(texel.B >> 3) << 1) | ((byte)(alpha)) ); shorttexels[i] = colour; x++; if (x >= bmp.Width) { x = 0; y++; } } for (uint i = 0; i < shorttexels.Length; i++) { SM64ROM.WriteTwoBytes(addr + i * 2, shorttexels[i]); } } else if (IAMode) //IA16 { for (uint i = 0; i < shorttexels.Length; i++) { System.Drawing.Color texel = bmp.GetPixel(x, y); ushort intensity = (ushort)((((texel.R + texel.G + texel.B) / 3) << 8) | texel.A); shorttexels[i] = intensity; x++; if (x >= bmp.Width) { x = 0; y++; } } for (uint i = 0; i < shorttexels.Length; i++) { SM64ROM.WriteTwoBytes(addr + i * 2, shorttexels[i]); } } return; case 32: //RGBA32 for (uint i = 0; i < inttexels.Length; i++) { System.Drawing.Color texel = bmp.GetPixel(x, y); UInt32 colour = (UInt32)((texel.R << 24) | (texel.G << 16) | (texel.B << 8) | texel.A); inttexels[i] = colour; x++; if (x >= bmp.Width) { x = 0; y++; } } for (uint i = 0; i < inttexels.Length; i++) { SM64ROM.WriteFourBytes(addr + i * 4, inttexels[i]); } return; case 8: bytetexels = new byte[bmp.Width * bmp.Height]; if (IMode) //I8 { for (uint i = 0; i < bytetexels.Length; i++) { System.Drawing.Color texel = bmp.GetPixel(x, y); byte intensity = (byte)((texel.R + texel.G + texel.B) / 3); bytetexels[i] = intensity; x++; if (x >= bmp.Width) { x = 0; y++; } } for (uint i = 0; i < bytetexels.Length; i++) { SM64ROM.changeByte(addr + i, bytetexels[i]); } } else if (IAMode) //IA8 { for (uint i = 0; i < bytetexels.Length; i++) { System.Drawing.Color texel = bmp.GetPixel(x, y); byte intensity = (byte)((byte)((texel.R + texel.G + texel.B) / 3) & 0xF0); byte alpha = (byte)((texel.A & 0xF0) >> 4); byte IA = (byte)(intensity | alpha); bytetexels[i] = IA; x++; if (x >= bmp.Width) { x = 0; y++; } } for (uint i = 0; i < bytetexels.Length; i++) { SM64ROM.changeByte(addr + i, bytetexels[i]); } } return; case 4: bytetexels = new byte[(bmp.Width * bmp.Height) / 2]; if (IMode) //I4 { for (uint i = 0; i < bytetexels.Length; i++) { System.Drawing.Color texel = bmp.GetPixel(x, y); byte intensity1 = (byte)((byte)((texel.R + texel.G + texel.B) / 3) & 0xF0); x++; if (x >= bmp.Width) { x = 0; y++; } System.Drawing.Color texel2 = bmp.GetPixel(x, y); byte intensity2 = (byte)(((byte)((texel2.R + texel2.G + texel2.B) / 3) & 0xF0) >> 4); byte ii = (byte)(intensity1 | intensity2); bytetexels[i] = ii; x++; if (x >= bmp.Width) { x = 0; y++; } } for (uint i = 0; i < bytetexels.Length; i++) { SM64ROM.changeByte(addr + i, bytetexels[i]); } } else if (IAMode) //IA4 { for (uint i = 0; i < bytetexels.Length; i++) { System.Drawing.Color texel = bmp.GetPixel(x, y); byte intensity1 = (byte)((byte)(((texel.R + texel.G + texel.B) / 3) >> 5) << 5); byte alpha1 = (byte)(((texel.A) >> 7) << 4); byte ia1 = (byte)(intensity1 | alpha1); x++; if (x >= bmp.Width) { x = 0; y++; } System.Drawing.Color texel2 = bmp.GetPixel(x, y); byte intensity2 = (byte)((byte)(((texel2.R + texel2.G + texel2.B) / 3) >> 5) << 1); byte alpha2 = (byte)((texel2.A) >> 7); byte ia2 = (byte)(intensity2 | alpha2); byte iaia = (byte)(ia1 | ia2); bytetexels[i] = iaia; x++; if (x >= bmp.Width) { x = 0; y++; } } for (uint i = 0; i < bytetexels.Length; i++) { SM64ROM.changeByte(addr + i, bytetexels[i]); } } else if (CIMode) //CI4 { if (bmp.Width * bmp.Height > 0x1000) { MessageBox.Show("CI4 cannot be above 64x64 due to\nTMEM limitations with palettes.", "Texture too large"); return; } Color[] colours = getImageColors(bmp); UInt32 paletteaddr = (UInt32)(addr + (bmp.Width * bmp.Height / 2)); //Put palette right after CI data for (int i = 0; i < colours.Length; i++) { byte alpha = colours[i].A; if (alpha > 0) { alpha = 1; } else { alpha = 0; } ushort colour = (ushort) ( ((byte)(colours[i].R >> 3) << 11) | ((byte)(colours[i].G >> 3) << 6) | ((byte)(colours[i].B >> 3) << 1) | ((byte)(alpha)) ); SM64ROM.WriteTwoBytes((UInt32)(paletteaddr + (i * 2)), colour); } byte[] CIData = getCIData(bmp, colours); for (uint i = 0; i < CIData.Length; i++) { SM64ROM.changeByte(i + addr, CIData[i]); } //Write CI data over texture taking up **half** memory compared to RGBA16 UInt32 branchDLAddr = (UInt32)(paletteaddr + 0x20); //palette size is 0x20 for ci4 UInt32 branchDLSegAddr = 0x0E000000 | (branchDLAddr - SM64ROM.getSegmentStart(0x0E)); UInt32[] F5CMDs = Textures.F5CMDArray[index]; ushort linesperword = Convert.ToUInt16((64d * 2048d) / ((double)bmp.Width * bitsize)); for (uint i = 0; i < F5CMDs.Length; i++) { SM64ROM.changeByte(F5CMDs[i] + 1, 0x40); //CI4 format bool firsttexture = (i == 0 && SM64ROM.getByte(F5CMDs[0] + 0x10) == 0xFD); for (uint j = F5CMDs[i]; j > F5CMDs[i] - 0x30; j -= 8) // Update 0xFD { if (SM64ROM.getByte(j) == 0xF3) { SM64ROM.WriteEightBytes(j, 0xF3000000073FF000 | linesperword); } else if (SM64ROM.getByte(j) == 0xFD || firsttexture) //includes first texture check { if (firsttexture) { j += 0x10; } SM64ROM.changeByte(j + 1, 0x50); //Format and bitsize byte, 0x50 for CI4 SM64ROM.copyBytes(j, branchDLAddr + 0x28, 8); SM64ROM.WriteTwoBytes(j, 0x0600); //Branch to load routine SM64ROM.WriteFourBytes(j + 4, branchDLSegAddr); if (SM64ROM.getByte(j + 0x10) == 0x06) { SM64ROM.WriteEightBytes(j + 0x10, 0xE600000000000000); //Revert the TMEM shift undo (This tex still needs TMEM shift) } break; } } } for (uint i = 0; i < F5CMDs.Length; i++) { bool firsttexture = (i == 0 && SM64ROM.getByte(F5CMDs[0] + 0x10) == 0xFD); for (uint j = F5CMDs[i]; j < SM64ROM.getEndROMAddr(); j += 8) { if (firsttexture && SM64ROM.getByte(j + 0x20) == 0xF3) { j += 0x20; SM64ROM.WriteEightBytes(j + 0x20, 0xF3000000073FF000 | linesperword); } //Update first texture command if (SM64ROM.getByte(j) == 0x06) { break; //If next texture is CI then don't revert the tmem shift } else if (SM64ROM.getByte(j) == 0xE6) { if (SM64ROM.getByte(j - 0x10) == 0x06) { break; //If there is already a CI jump, escape from reverting it } SM64ROM.changeByte(j, 0x06); SM64ROM.WriteFourBytes(j + 4, branchDLSegAddr + 56); break; } else if (SM64ROM.getByte(j) == 0xB8) { for (uint k = j; k > j - 0x30; k -= 8) { if (SM64ROM.getByte(k) == 0xBB) { SM64ROM.changeByte(k, 0x06); SM64ROM.WriteFourBytes(k + 4, branchDLSegAddr + 80); /*throw new Exception(branchDLSegAddr.ToString("x")+"\n"+branchDLAddr.ToString("x")+"\n");*/ break; } } break; //allow last texture to jump and revert TMEM shift } } } SM64ROM.WriteEightBytes(branchDLAddr, 0xE700000000000000); // Loadsync SM64ROM.WriteEightBytes(branchDLAddr + 8, 0xFD10000000000000 | (branchDLSegAddr - 0x20)); //load palette SM64ROM.WriteEightBytes(branchDLAddr + 16, 0xF500010001000000); //Settile (palette) SM64ROM.WriteEightBytes(branchDLAddr + 24, 0xF00000000103C000); //Load palette into TMEM SM64ROM.WriteEightBytes(branchDLAddr + 32, 0xBA000E0200008000); //shift TMEM to palette SM64ROM.WriteEightBytes(branchDLAddr + 48, 0xB800000000000000); //Break out of jump SM64ROM.WriteEightBytes(branchDLAddr + 56, 0xE600000000000000); //Loadsync for next texture SM64ROM.WriteEightBytes(branchDLAddr + 64, 0xBA000E0200000000); //shift TMEM back SM64ROM.WriteEightBytes(branchDLAddr + 72, 0xB800000000000000); //Break from jump SM64ROM.WriteEightBytes(branchDLAddr + 80, 0xBB000000FFFFFFFF); //Disable tex at end of DL SM64ROM.WriteEightBytes(branchDLAddr + 88, 0xBA000E0200000000); //shift TMEM back SM64ROM.WriteEightBytes(branchDLAddr + 96, 0xB800000000000000); //Break out of jump } return; } }
public void Load(ROM rom) { }
public static void CentreUVs(bool ChangeU, int F5index, int width, int height) { uint[] F5CMDs = Textures.F5CMDArray[F5index]; ROM SM64ROM = ROMManager.SM64ROM; for (uint i = 0; i < F5CMDs.Length; i++) { bool exitUVcorrection = false; for (uint j = F5CMDs[i] + 8; j < SM64ROM.getEndROMAddr(); j += 8) { if (exitUVcorrection) { break; } switch (SM64ROM.getByte(j)) { case 0xBF: UInt32 UVStart = 0; short[][] UVs = new short[2][]; for (int k = 0; k < 2; k++) { UVs[k] = new short[3]; } for (uint k = j; k > j - 0x800; k -= 8) { if (SM64ROM.getByte(k) == 0x04) { UVStart = SM64ROM.readSegmentAddr(SM64ROM.ReadFourBytes(k + 4)) + 8; break; } } if (UVStart == 0) { break; } for (uint k = 5; k < 8; k++) { UInt32 addr = Vertex.getAddrFromTriIndex(UVStart, SM64ROM.getByte(j + k)); UVs[0][k - 5] = (short)SM64ROM.ReadTwoBytes(addr); UVs[1][k - 5] = (short)SM64ROM.ReadTwoBytes(addr + 2); } UVs = Vertex.CentreTRIUVs(UVs, width, height, ChangeU); for (uint k = 5; k < 8; k++) { UInt32 addr = Vertex.getAddrFromTriIndex(UVStart, SM64ROM.getByte(j + k)); if (ChangeU) { SM64ROM.WriteTwoBytes(addr, (ushort)UVs[0][k - 5]); } else { SM64ROM.WriteTwoBytes(addr + 2, (ushort)UVs[1][k - 5]); } } break; case 0xFD: exitUVcorrection = true; break; case 0x06: exitUVcorrection = true; break; case 0xB8: exitUVcorrection = true; break; } } } }
/*************************************************************************** * 函数名称:treeView1_NodeMouseDoubleClick() * 功能:组件库列表表项鼠标双击事件,在graphControl绘图控制区创建相应组件 * 参数:sender;e * 返回值:无 * *************************************************************************/ private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); if (treeView1.SelectedNode.Level > 1) { string name; //int tabIndex = 0; //第一个选项卡 name = e.Node.Name.ToString(); switch (name) { //================================================================// //======================创建基本组件==============================// //================================================================// //B01 人体血压 case "BloodPressure": bloodPressure = new BloodPressure(this.graphControl, null, null, null); graphControl.AddShape(bloodPressure, bloodPressure.Location); break; //B02 人体体温 case "Temperature": temperature = new Temperature(this.graphControl, null, null, null); graphControl.AddShape(temperature, new PointF(temperature.Location.X, temperature.Location.Y + 80)); break; //B03 人体心率 case "HeartRate": heartRate = new HeartRate(this.graphControl, null, null, null); graphControl.AddShape(heartRate, new PointF(heartRate.Location.X, heartRate.Location.Y + 160)); break; //B04 血压传感器 case "BloodPressureSensor": bloodPressureSensor = new BloodPressureSensor(this.graphControl, null, null, null); graphControl.AddShape(bloodPressureSensor, new PointF(bloodPressureSensor.Location.X + 110, bloodPressureSensor.Location.Y)); break; //B05 体温传感器 case "TemperatureSensor": temperatureSensor = new TemperatureSensor(this.graphControl, null, null, null); graphControl.AddShape(temperatureSensor, new PointF(temperatureSensor.Location.X + 110, temperatureSensor.Location.Y + 80)); break; //B06 心率传感器 case "HeartRateSensor": heartRateSensor = new HeartRateSensor(this.graphControl, null, null, null); graphControl.AddShape(heartRateSensor, new PointF(heartRateSensor.Location.X + 110, heartRateSensor.Location.Y + 160)); break; //B07 显示控制器 case "DisplayController": displayController = new DisplayController(this.graphControl, null, null, null); graphControl.AddShape(displayController, new PointF(displayController.Location.X + 220, displayController.Location.Y)); break; //B08 音频控制器 case "AudioController": audioController = new AudioController(this.graphControl, null, null, null); graphControl.AddShape(audioController, new PointF(audioController.Location.X + 220, audioController.Location.Y + 80)); break; //B09 电机控制器 case "ElectricMachineryController": electricMachineryController = new ElectricMachineryController(this.graphControl, null, null, null); graphControl.AddShape(electricMachineryController, new PointF(electricMachineryController.Location.X + 220, electricMachineryController.Location.Y + 160)); break; //B10 运算器 微处理器 case "MicroProcessor": microProcessor = new MicroProcessor(this.graphControl, null, null, null); graphControl.AddShape(microProcessor, new PointF(microProcessor.Location.X + 330, microProcessor.Location.Y)); break; //B11 协议转换器 case "ProtocolConverter": protocolConverter = new ProtocolConverter(this.graphControl, null, null, null); graphControl.AddShape(protocolConverter, new PointF(protocolConverter.Location.X + 330, protocolConverter.Location.Y + 70)); break; //B12 数据处理器 case "DataProcessor": dataProcessor = new DataProcessor(this.graphControl, null, null, null); graphControl.AddShape(dataProcessor, new PointF(dataProcessor.Location.X + 330, dataProcessor.Location.Y + 160)); break; //B13 数据分析器 case "DataAnalyzer": dataAnalyzer = new DataAnalyzer(this.graphControl, null, null, null); graphControl.AddShape(dataAnalyzer, new PointF(dataAnalyzer.Location.X + 330, dataAnalyzer.Location.Y + 240)); break; //B14 有线通信模块 case "WiredModule": wiredModule = new WiredModule(this.graphControl, null, null, null); graphControl.AddShape(wiredModule, new PointF(wiredModule.Location.X + 440, wiredModule.Location.Y)); break; //B15 无线通信模块 case "WirelessModule": wirelessModule = new WirelessModule(this.graphControl, null, null, null); graphControl.AddShape(wirelessModule, new PointF(wirelessModule.Location.X + 440, wirelessModule.Location.Y + 80)); break; //B16 有线媒介 case "WiredMedia": wiredMedia = new WiredMedia(this.graphControl, null, null, null); graphControl.AddShape(wiredMedia, new PointF(wiredMedia.Location.X + 440, wiredMedia.Location.Y + 160)); break; //B17 无线媒介 case "WirelessMedia": wirelessMedia = new WirelessMedia(this.graphControl, null, null, null); graphControl.AddShape(wirelessMedia, new PointF(wirelessMedia.Location.X + 440, wirelessMedia.Location.Y + 240)); break; //18 寄存器 case "Register": register = new Register(this.graphControl, null, null, null); graphControl.AddShape(register, new PointF(register.Location.X + 550, register.Location.Y)); break; //B19 存储器RAM case "RAM": ram = new RAM(this.graphControl, null, null, null); graphControl.AddShape(ram, new PointF(ram.Location.X + 550, ram.Location.Y + 80)); break; //B20 存储器ROM case "ROM": rom = new ROM(this.graphControl, null, null, null); graphControl.AddShape(rom, new PointF(rom.Location.X + 550, rom.Location.Y + 160)); break; //B21 数据存储器 case "DataMemory": dataMemory = new DataMemory(this.graphControl, null, null, null); graphControl.AddShape(dataMemory, new PointF(dataMemory.Location.X + 550, dataMemory.Location.Y + 240)); break; //B22 缓冲区 case "Buffer": buffer = new MyBuffer(this.graphControl, null, null, null); graphControl.AddShape(buffer, new PointF(buffer.Location.X + 550, buffer.Location.Y + 320)); break; //B23 路由模块 case "RouteModule": routeModule = new RouteModule(this.graphControl, null, null, null); graphControl.AddShape(routeModule, new PointF(routeModule.Location.X + 330, routeModule.Location.Y + 320)); break; //B24 监控器 case "Monitor": monitor = new MyMonitor(this.graphControl, null, null, null); graphControl.AddShape(monitor, new PointF(monitor.Location.X + 220, monitor.Location.Y + 240)); break; //B25 血压监控器 case "BloodPressureMonitor": bpMonitor = new BloodPressureMonitor(this.graphControl, null, null, null); graphControl.AddShape(bpMonitor, new PointF(bpMonitor.Location.X + 220, bpMonitor.Location.Y + 280)); break; //B26 体温监控器 case "TemperatureMonitor": tempMonitor = new TemperatureMonitor(this.graphControl, null, null, null); graphControl.AddShape(tempMonitor, new PointF(tempMonitor.Location.X + 220, tempMonitor.Location.Y + 320)); break; //B27 心率监控器 case "HeartRateMonitor": hrMonitor = new HeartRateMonitor(this.graphControl, null, null, null); graphControl.AddShape(hrMonitor, new PointF(hrMonitor.Location.X + 220, hrMonitor.Location.Y + 360)); break; //====================================================================// //======================CMIoT组件库中组件=============================// //====================================================================// //C01 患者组件 case "Patient": patient = new Patient(this.graphControl); graphControl.AddShape(patient, patient.Location); break; //C02 血压传感节点 case "BloodPressureSensorNode": BPSN = new BloodPressureSensorNode(this.graphControl); //BPSN_InsideForm = new InsideForm(BPSN); //构建内部结构 graphControl.AddShape(BPSN, BPSN.Location); break; //C03 体温传感节点 case "TemperatureSensorNode": TSN = new TemperatureSensorNode(this.graphControl); graphControl.AddShape(TSN, TSN.Location); break; //C04 心率传感节点 case "HeartRateSensorNode": HRSN = new HeartRateSensorNode(this.graphControl); graphControl.AddShape(HRSN, HRSN.Location); break; //C05 物联网网关 case "IoTGateway": IoTG = new IoTGateway(this.graphControl); graphControl.AddShape(IoTG, IoTG.Location); break; //C06 802.11信道组件 case "802.11Channel": channel_802_11 = new Channel802_11(this.graphControl, null, null, null); graphControl.AddShape(channel_802_11, channel_802_11.Location); break; //C07 802.15.1信道组件 case "802.15.1Channel": channel802_15_1 = new Channel802_15_1(this.graphControl, null, null, null); graphControl.AddShape(channel802_15_1, channel802_15_1.Location); break; //C08 802.15.4信道组件 case "802.15.4Channel": channel802_15_4 = new Channel802_15_4(this.graphControl, null, null, null); graphControl.AddShape(channel802_15_4, channel802_15_4.Location); break; //C09 Ethernet信道组件 case "EthernetChannel": channel_ethernet = new ChannelEthernet(this.graphControl, null, null, null); graphControl.AddShape(channel_ethernet, channel_ethernet.Location); break; //C10 IPv6路由器组件 case "IPv6Router": ipv6Router = new IPv6Router(this.graphControl); graphControl.AddShape(ipv6Router, ipv6Router.Location); break; //C11 医疗服务器组件 case "MedicalServer": MS = new MedicalServer(this.graphControl); graphControl.AddShape(MS, MS.Location); break; } } // if (treeView1.SelectedNode.Level > 1) } //treeView1_NodeMouseDoubleClick
public static void parse(ref List <ScriptDumpCommandInfo> dump, byte seg, uint off) { if (seg == 0) { return; } ROM rom = ROM.Instance; byte[] data = rom.getSegment(seg, null); bool end = false; while (!end) { byte cmdLen = getCmdLength(data[off]); byte[] cmd = rom.getSubArray_safe(data, off, cmdLen); //rom.printArray(cmd, cmdLen); string desc = "Unknown command"; bool alreadyAdded = false; switch (cmd[0]) { case 0x00: desc = "Start Behavior (Object type = " + cmd[1] + ")"; break; case 0x02: desc = "Jump & link to address 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); alreadyAdded = true; addBehCommandToDump(ref dump, cmd, seg, off, desc); parse(ref dump, cmd[4], bytesToInt(cmd, 5, 3)); break; case 0x03: desc = "Return back from jump & link"; end = true; break; case 0x04: desc = "Jump to address 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); alreadyAdded = true; addBehCommandToDump(ref dump, cmd, seg, off, desc); parse(ref dump, cmd[4], bytesToInt(cmd, 5, 3)); end = true; break; case 0x05: desc = "Loop " + bytesToInt(cmd, 2, 2) + " times"; break; case 0x07: desc = "Infinite loop (jump back 4 bytes)"; break; case 0x08: desc = "Start of loop"; break; case 0x06: case 0x09: desc = "End of loop"; end = true; break; case 0x0A: desc = "End behavior script"; end = true; break; case 0x0B: desc = "End behavior script"; end = true; break; case 0x0C: desc = "Call ASM function 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); break; case 0x0D: desc = "Add (float)" + bytesToInt(cmd, 2, 2) + " to the value at obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2"); break; case 0x0E: desc = "(Set value) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = (float)" + bytesToInt(cmd, 2, 2); break; case 0x0F: desc = "Add " + (short)(bytesToInt(cmd, 2, 2) & 0xFFFF) + " to the value at obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2"); break; case 0x10: desc = "(Set value) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = " + (short)(bytesToInt(cmd, 2, 2) & 0xFFFF); break; case 0x11: desc = "(Set bits) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " |= 0x" + bytesToInt(cmd, 2, 2).ToString("X4"); break; case 0x12: desc = "(Clear bits) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " &= (0x" + bytesToInt(cmd, 2, 2).ToString("X4") + " ^ 0xFFFF)"; break; case 0x13: desc = "(Set RNG) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = " + bytesToInt(cmd, 2, 2) + " + (randU16() >> " + bytesToInt(cmd, 4, 2) + ")"; break; case 0x14: desc = "(Set float from multi) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = (float)" + bytesToInt(cmd, 2, 2) + " * (float)" + bytesToInt(cmd, 4, 2) + ")"; break; case 0x15: desc = "(Set float RNG from multi) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = (float)" + bytesToInt(cmd, 2, 2) + " + (randFloat() * (float)" + bytesToInt(cmd, 4, 2) + ")"; break; case 0x16: desc = "(Set float RNG from add) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = (float)" + bytesToInt(cmd, 2, 2) + " + randFloat() + (float)" + bytesToInt(cmd, 4, 2); break; case 0x17: desc = "(Set RNG) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = (obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " + " + bytesToInt(cmd, 2, 2) + ") + (randU16() >> " + bytesToInt(cmd, 4, 2) + ")"; break; case 0x18: case 0x19: case 0x1A: desc = "Do nothing"; break; case 0x1B: desc = "Set Model ID to 0x" + bytesToInt(cmd, 2, 2).ToString("X4"); break; case 0x1C: desc = "Spawn child object (Model ID = 0x" + bytesToInt(cmd, 4, 4).ToString("X4") + ", Behavior = 0x" + bytesToInt(cmd, 8, 4).ToString("X8"); break; case 0x1D: desc = "Deactivate object"; break; case 0x1E: desc = "Drop object to ground, and object->_0xEC |= 0x2"; break; case 0x1F: desc = "(Add floats) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = (float)obj->_0x" + (cmd[2] * 4 + 0x88).ToString("X2") + " + (float)obj->_0x" + (cmd[3] * 4 + 0x88).ToString("X2"); break; case 0x20: desc = "(Add values) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = obj->_0x" + (cmd[2] * 4 + 0x88).ToString("X2") + " + obj->_0x" + (cmd[3] * 4 + 0x88).ToString("X2"); break; case 0x21: desc = "Set billboarding flag in graph flags (obj->_0x02 |= 0x04)"; break; case 0x22: desc = "Set 0x10 flag in graph flags (obj->_0x02 |= 0x10)"; break; case 0x23: desc = "Set Collision sphere size (XZ radius = " + bytesToInt(cmd, 4, 2) + ", Y radius = " + bytesToInt(cmd, 6, 2) + ")"; break; case 0x24: desc = "Do nothing. (Unused function)"; break; case 0x25: desc = "obj->_0x1F4 = ((obj->_0x1F4 < (obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " - 1)) ? obj->_0x1F4 + 1 : 0)"; break; case 0x26: desc = "Loop " + cmd[1] + " times"; break; case 0x27: desc = "(Set word) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); break; case 0x28: desc = "Set obj->_0x3C from (obj->_0x120 + 0x" + (cmd[1] * 4).ToString("X") + ")"; break; case 0x29: desc = "Spawn child object (Model ID = 0x" + bytesToInt(cmd, 4, 4).ToString("X4") + ", Behavior = 0x" + bytesToInt(cmd, 8, 4).ToString("X8") + ", B.Param = 0x" + bytesToInt(cmd, 2, 2).ToString("X4"); break; case 0x2A: desc = "Set collision address (obj->_0x218) from address 0x" + bytesToInt(cmd, 4, 4).ToString("X8");; break; case 0x2B: desc = "Set Collision sphere size (XZ radius = " + bytesToInt(cmd, 4, 2) + ", Y radius = " + bytesToInt(cmd, 6, 2) + ", obj->_0x208 = " + bytesToInt(cmd, 8, 2) + ")"; break; case 0x2C: desc = "(Spawn child object) obj->_0x6C = (Model ID = 0x" + bytesToInt(cmd, 4, 4).ToString("X4") + ", Behavior = 0x" + bytesToInt(cmd, 8, 4).ToString("X8"); break; case 0x2D: desc = "Set inital position. (Used in Dorrie, Fly guys, etc. to determine in which range they can move)"; break; case 0x2E: desc = "obj->_0x200 = (float)" + bytesToInt(cmd, 4, 2).ToString("X4") + ", obj->_0x204 = (float)" + bytesToInt(cmd, 6, 2).ToString("X4"); break; case 0x2F: desc = "(Set interaction value) obj->_0x130 = 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); break; case 0x30: desc = "(Set gravity) obj->_0x128 = " + bytesToInt(cmd, 4, 2) + "f, obj->_0xE8 = " + (bytesToInt(cmd, 6, 2) / 100.0f) + "f, obj->_0x158 = " + (bytesToInt(cmd, 8, 2) / 100.0f) + "f, obj->_0x12C = " + (bytesToInt(cmd, 10, 2) / 100.0f) + "f, obj->_0x170 = " + (bytesToInt(cmd, 12, 2) / 100.0f) + "f, obj->_0x174 = " + (bytesToInt(cmd, 14, 2) / 100.0f) + "f"; break; case 0x31: desc = "obj->_0x190 = 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); break; case 0x32: desc = "Set uniform scaling to " + (bytesToInt(cmd, 2, 2) / 100f) + "%"; break; case 0x33: desc = "(Clear flags in child) obj->_0x68->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " &= ~0x" + bytesToInt(cmd, 4, 4).ToString("X8"); break; case 0x34: desc = "(Increment texture animate rate) if((*0x8032D5D4) / " + bytesToInt(cmd, 2, 2) + " == 0) obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + "++"; break; case 0x35: desc = "(Clear lsb of graph flags) obj->_0x2 &= 0xFFFE"; break; case 0x36: desc = "obj->_0x" + (cmd[1] * 4 + 0x88).ToString("X2") + " = " + ((short)bytesToInt(cmd, 4, 4)).ToString("X4"); break; } if (!alreadyAdded) { addBehCommandToDump(ref dump, cmd, seg, off, desc); } off += cmdLen; } }
public void ThrowsWhenGivenANullLoader() { ROM rom = new ROM(null); }
private void EditShop(bool shop2) { var arc = ROM.GetFile(GameFile.Shops); var data = arc[0]; int[] PossibleHeldItems = Legal.GetRandomItemList(ROM.Game); var shop = FlatBufferConverter.DeserializeFrom <ShopInventory>(data); if (!shop2) { var table = shop.Shop1; var names = table.Select((z, _) => $"{(z.SWSH.TryGetValue(z.Hash, out var shopName) ? shopName : z.Hash.ToString("X"))}").ToArray(); var cache = new DirectCache <Shop1>(table); using var form = new GenericEditor <Shop1>(cache, names, $"{nameof(Shop1)} Editor", Randomize); form.ShowDialog(); if (!form.Modified) { arc.CancelEdits(); return; } void Randomize() { foreach (var shopDefinition in table) { var items = shopDefinition.Inventory.Items; for (int i = 0; i < items.Length; i++) { if (Legal.Pouch_TMHM_SM.Contains((ushort)items[i]) || items[i] == 1230) // skip TMs { continue; } items[i] = PossibleHeldItems[Randomization.Util.Random.Next(PossibleHeldItems.Length)]; } } } } else { var table = shop.Shop2; var names = table.Select((z, _) => $"{(z.SWSH.TryGetValue(z.Hash, out var shopName) ? shopName : z.Hash.ToString("X"))}").ToArray(); var cache = new DirectCache <Shop2>(table); using var form = new GenericEditor <Shop2>(cache, names, $"{nameof(Shop2)} Editor", Randomize); form.ShowDialog(); if (!form.Modified) { arc.CancelEdits(); return; } void Randomize() { foreach (var shopDefinition in table) { foreach (var inv in shopDefinition.Inventories) { var items = inv.Items; for (int i = 0; i < items.Length; i++) { items[i] = PossibleHeldItems[Randomization.Util.Random.Next(PossibleHeldItems.Length)]; } } } } } arc[0] = FlatBufferConverter.SerializeFrom(shop); }
public ByteRegister this[ROM r] { get { return this[(uint)r]; } set { this[(uint)r] = value; } }
public static void parse(ref Model3D mdl, ref Level lvl, byte seg, uint off) { if (seg == 0) { return; } ROM rom = ROM.Instance; byte[] data = rom.getSegment(seg); bool end = false; while (!end) { byte cmdLen = getCmdLength(data[off]); byte[] cmd = rom.getSubArray(data, off, cmdLen); //rom.printArray(cmd, cmdLen); if (cmd[0] != 0x05 && nodeCurrent.isSwitch && nodeCurrent.switchPos != 1) { if (nodeCurrent.switchFunc == 0x8029DB48) { //rom.printArray(cmd, cmdLen); //Console.WriteLine(nodeCurrent.switchPos); } nodeCurrent.switchPos++; off += cmdLen; continue; } switch (cmd[0]) { case 0x00: case 0x01: end = true; break; case 0x02: CMD_02(ref mdl, ref lvl, cmd); break; case 0x03: end = true; break; case 0x04: CMD_04(); break; case 0x05: if (nodeCurrent != rootNode) { nodeCurrent = nodeCurrent.parent; } break; case 0x0E: //rom.printArray(cmd, cmdLen); CMD_0E(ref mdl, ref lvl, cmd); break; case 0x10: //CMD_10(ref mdl, ref lvl, cmd); break; case 0x11: //rom.printArray(cmd, cmdLen); CMD_11(ref mdl, ref lvl, cmd); break; case 0x13: //rom.printArray(cmd, cmdLen); CMD_13(ref mdl, ref lvl, cmd); break; case 0x15: CMD_15(ref mdl, ref lvl, cmd); // rom.printArray(cmd, cmdLen); break; case 0x1D: CMD_1D(ref mdl, cmd); break; } off += cmdLen; if (nodeCurrent.isSwitch) { nodeCurrent.switchPos++; } } }
public void writeAllSprites(SortedList <ushort, List <i_sprite> > allSprites) { int[] pointers = new int[roomPointers.Length]; const int blah = 2; //inspired by HM source code int lowestPointer = int.MaxValue; foreach (int i in roomPointers) { lowestPointer = Math.Min(lowestPointer, i); } List <byte> data = new List <byte>(); for (ushort i = 0; i < roomPointers.Length; i++) { if (!allSprites.ContainsKey(i)) { allSprites.Add(i, new List <i_sprite>()); } } foreach (ushort i in allSprites.Keys) { if (allSprites[i].Count == 0) { pointers[i] = lowestPointer + sizeOfData - blah; } else { List <byte> data2 = new List <byte>(); byte byteSortByte = 0x0; bool first = true; foreach (i_sprite s in allSprites[i]) { byte[] b = null; if (first) { b = s.getBytes(out byteSortByte); first = false; data2.Add(byteSortByte); } else { b = s.getBytes(out byte temp); if (temp != byteSortByte) { throw new Exception(); } } data2 = data2.Concat(b).ToList(); } data2.Add(sprite_delim); pointers[i] = lowestPointer + data.Count; data = data.Concat(data2).ToList(); } } if (data.Count > sizeOfData - blah) { throw new Exception(); } while (data.Count < sizeOfData - blah) { data.Add(sprite_delim); } data.Add(0xAA); data.Add(sprite_delim); List <byte> pointerData = new List <byte>(); foreach (int address in pointers) { byte[] d = new byte[] { (byte)AddressLoROM.PcToSnes_Lo(address), (byte)AddressLoROM.PcToSnes_Hi(address) }; pointerData = pointerData.Concat(d).ToList(); } ROM.Write(secondaryPointer, size, pointerData.ToArray()); ROM.Write(lowestPointer, sizeOfData, data.ToArray()); updatePointers(); }
public static void parse(ref Model3D mdl, ref Level lvl, byte seg, uint off, byte?areaID, int current_depth) { if (seg == 0 || current_depth >= 300) { return; // depth was added to prevent infinite loops with 0x06 command. } ROM rom = ROM.Instance; byte[] data = rom.getSegment(seg, areaID); if (data == null) { return; } bool end = false; bool useUVOffsetFix = true; while (!end) { if (off + 8 > data.Length) { return; } byte[] cmd = rom.getSubArray_safe(data, off, 8); if (!Enum.IsDefined(typeof(CMD), (int)cmd[0])) { return; //throw new Exception("UNDEFINED FAST3D COMMAND: 0x"+cmd[0].ToString("X2")); } string desc = ((CMD)cmd[0]).ToString(); bool alreadyAdded = false; switch ((CMD)cmd[0]) { case CMD.F3D_NOOP: desc = "Do nothing"; if (bytesToInt(cmd, 0, 4) != 0) { return; } break; case CMD.F3D_MTX: desc = "G_MTX"; // Detect if empty data has been found. if (bytesToLong(cmd, 0) == 0x0101010101010101) { return; } break; case CMD.F3D_MOVEMEM: switchTextureStatus(ref mdl, ref tempMaterial, true, areaID); F3D_MOVEMEM(ref tempMaterial, ref lvl, cmd, ref desc, areaID); break; case CMD.F3D_VTX: switchTextureStatus(ref mdl, ref tempMaterial, false, areaID); //if (tempMaterial.id != 0) return; if (!F3D_VTX(vertices, ref lvl, cmd, ref desc, areaID, useUVOffsetFix)) { return; } break; case CMD.F3D_DL: alreadyAdded = true; if (cmd[1] == 0x00) { desc = "Jump and link to display list at 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); } else { desc = "Jump to display list at 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); } addF3DCommandToDump(ref mdl, cmd, seg, off, desc, areaID); F3D_DL(ref mdl, ref lvl, cmd, areaID, current_depth); if (cmd[1] == 1) { end = true; } break; case CMD.F3D_CLEARGEOMETRYMODE: tempMaterial.geometryMode &= ~bytesToInt(cmd, 4, 4); break; case CMD.F3D_SETGEOMETRYMODE: tempMaterial.geometryMode |= bytesToInt(cmd, 4, 4); break; case CMD.F3D_ENDDL: desc = "End of display list"; end = true; break; case CMD.F3D_TEXTURE: F3D_TEXTURE(ref tempMaterial, cmd); break; case CMD.F3D_TRI1: switchTextureStatus(ref mdl, ref tempMaterial, false, areaID); //if (tempMaterial.id != 0) return; F3D_TRI1(vertices, ref mdl, ref lvl, ref tempMaterial, cmd, ref desc); break; case CMD.G_RDPLOADSYNC: desc = "RDP Load sync"; break; case CMD.G_RDPPIPESYNC: desc = "RDP Pipe sync"; break; case CMD.G_RDPTILESYNC: desc = "RDP Tile sync"; break; case CMD.G_RDPFULLSYNC: desc = "RDP Full sync"; break; case CMD.G_LOADTLUT: G_LOADTLUT(cmd, ref tempMaterial, ref desc, areaID); break; case CMD.G_SETTILESIZE: switchTextureStatus(ref mdl, ref tempMaterial, true, areaID); G_SETTILESIZE(cmd, ref tempMaterial, ref desc); break; case CMD.G_LOADBLOCK: desc = "Load " + (((bytesToInt(cmd, 4, 4) >> 12) & 0xFFF) + 1) + " texels into texture memory cache"; break; case CMD.G_SETTILE: G_SETTILE(ref tempMaterial, cmd); break; case CMD.G_SETFOGCOLOR: mdl.builder.UsesFog = true; mdl.builder.FogColor = Color.FromArgb(cmd[4], cmd[5], cmd[6]); mdl.builder.FogColor_romLocation.Add(rom.getSegmentStart(seg, areaID) + off); //Console.WriteLine("Fog color = 0x{0}", bytesToInt(cmd, 4, 4).ToString("X8")); break; case CMD.G_SETCOMBINE: if (G_SETCOMBINE(ref tempMaterial, cmd)) { switchTextureStatus(ref mdl, ref tempMaterial, true, areaID); } break; case CMD.G_SETTIMG: switchTextureStatus(ref mdl, ref tempMaterial, true, areaID); G_SETTIMG(ref tempMaterial, cmd, ref desc); break; case CMD.F3D_SETOTHERMODE_H: processSetOtherMode_H(cmd, ref useUVOffsetFix); break; } if (!alreadyAdded) { addF3DCommandToDump(ref mdl, cmd, seg, off, desc, areaID); } off += 8; } }
public void EditGift() { var arc = ROM.GetFile(GameFile.EncounterGift); var data = arc[0]; var objs = FlatBufferConverter.DeserializeFrom <EncounterGift8Archive>(data); var gifts = objs.Table; var names = Enumerable.Range(0, gifts.Length).Select(z => $"{z:000}").ToArray(); var cache = new DirectCache <EncounterGift8>(gifts); void Randomize() { int[] PossibleHeldItems = Legal.GetRandomItemList(ROM.Game); var pt = ROM.Data.PersonalData; int[] ban = pt.Table.Take(ROM.Info.MaxSpeciesID + 1) .Select((z, i) => new { Species = i, Present = ((PersonalInfoSWSH)z).IsPresentInGame }) .Where(z => !z.Present).Select(z => z.Species).ToArray(); var spec = EditUtil.Settings.Species; var srand = new SpeciesRandomizer(ROM.Info, ROM.Data.PersonalData); var frand = new FormRandomizer(ROM.Data.PersonalData); srand.Initialize(spec, ban); foreach (var t in gifts) { // swap gmax gifts and kubfu for other gmax capable species if (t.CanGigantamax || t.Species == Species.Kubfu) { t.Species = (Species)Legal.GigantamaxForms[Randomization.Util.Random.Next(Legal.GigantamaxForms.Length)]; t.AltForm = t.Species == Species.Pikachu || t.Species == Species.Meowth ? 0 : frand.GetRandomForme((int)t.Species, false, false, false, false, ROM.Data.PersonalData.Table); // Pikachu & Meowth altforms can't gmax } else { t.Species = (Species)srand.GetRandomSpecies((int)t.Species); t.AltForm = frand.GetRandomForme((int)t.Species, false, false, true, true, ROM.Data.PersonalData.Table); } t.Ability = Randomization.Util.Random.Next(1, 4); // 1, 2, or H t.Ball = (Ball)Randomization.Util.Random.Next(1, EncounterGift8.BallToItem.Length); t.HeldItem = PossibleHeldItems[Randomization.Util.Random.Next(PossibleHeldItems.Length)]; t.Nature = Nature.Random25; t.Gender = FixedGender.Random; t.ShinyLock = Shiny.Random; if (t.IV_Hp != -4 && t.IVs.Any(z => z != 31)) { t.IVs = new[] { -1, -1, -1, -1, -1, -1 } } ; } } using var form = new GenericEditor <EncounterGift8>(cache, names, "Gift Pokémon Editor", Randomize); form.ShowDialog(); if (!form.Modified) { arc.CancelEdits(); } else { arc[0] = FlatBufferConverter.SerializeFrom(objs); } }
// private ROMType _type; public GameboyROM(byte[] buffer) { _rom = new ROM(buffer); // _type = ReadByte(0xA7) == 0x34 ? ROMType.Fusion : ROMType.ZeroMission; }
protected static void Cmd07 <T>(ROM rom, T state) { rom.PopOffset(); rom.AddOffset(8); // diff between 0x07 length and 0x06 length }