private static MainFieldChara ReadMainChara(byte[] oneb) { MainFieldChara localMfc = new MainFieldChara(); using (MemoryStream ms = new MemoryStream(oneb)) using (BinaryReader br = new BinaryReader(ms)) { List <uint> timOffsets = new List <uint>(); uint timOffset; while ((timOffset = br.ReadUInt32()) != 0xffffffff) { timOffsets.Add(timOffset & 0x00FFFFFF); } uint modelPointer = br.ReadUInt32(); //read textures List <Texture2D> tex2Dreader = new List <Texture2D>(); for (int i = 0; i < timOffsets.Count; i++) { TIM2 tim = new TIM2(br, timOffsets[i]); tex2Dreader.Add(tim.GetTexture()); } localMfc.textures = tex2Dreader.ToArray(); //read models ms.Seek(modelPointer, SeekOrigin.Begin); Debug_MCH mch = new Debug_MCH(ms, br, Debug_MCH.mchMode.FieldMain); localMfc.mch = mch; } return(localMfc); }
public texl(byte[] texlBuffer) { textures = new Texture2D[20][]; using (MemoryStream ms = new MemoryStream(texlBuffer)) using (BinaryReader br = new BinaryReader(ms)) for (int i = 0; i < TEX_COUNT; i++) { int timOffset = i * TEX_SIZE; TIM2 tim = new TIM2(texlBuffer, (uint)timOffset); textures[i] = new Texture2D[tim.GetClutCount]; for (ushort k = 0; k < textures[i].Length; k++) { textures[i][k] = tim.GetTexture(k, true); } } }
public TIM2[] TryReadTIM(BinaryReader br) { try { var tim = new TIM2(br, noExec: true); if (tim.NotTIM) { return(TIM = null); } isTIM = true; return(TIM = new TIM2[] { tim }); } catch (InvalidDataException) { return(TIM = null); } }
public texl(byte[] texlBuffer) { textures = new TextureHandler[20][]; using (MemoryStream ms = new MemoryStream(texlBuffer)) using (BinaryReader br = new BinaryReader(ms)) for (int i = 0; i < TEX_COUNT; i++) { int timOffset = i * TEX_SIZE; TIM2 tim = new TIM2(texlBuffer, (uint)timOffset); textures[i] = new TextureHandler[tim.GetClutCount]; for (ushort k = 0; k < textures[i].Length; k++) { textures[i][k] = TextureHandler.Create($"texl_tim{(i + 1).ToString("D2")}.tim", tim, k, null); } //todo detect if mods aren't using palettes. } }
/// <summary> /// Reads chara.one buffer -> chara one is a file packed with MCH files and TIM textures /// without pointers. File needs to be scanned /// </summary> /// <param name="buffer">Full chara.one file</param> public CharaOne(byte[] buffer) { this.buffer = buffer; List <Debug_MCH> mchs = new List <Debug_MCH>(); List <TextureHandler> texturesList = new List <TextureHandler>(); int i = 0; MemoryStream ms = null; using (BinaryReader br = new BinaryReader(ms = new MemoryStream(this.buffer))) { uint eof = br.ReadUInt32(); TIM2 tim; while (ms.CanRead) { if (ms.Position >= ms.Length) { break; } else if (BitConverter.ToUInt16(this.buffer, (int)ms.Position) == 0) { ms.Seek(2, SeekOrigin.Current); } else if (br.ReadUInt64() == 0x0000000800000010) { ms.Seek(-8, SeekOrigin.Current); tim = new TIM2(this.buffer, (uint)ms.Position); ms.Seek(tim.GetHeight * tim.GetWidth / 2 + 64, SeekOrigin.Current); //i.e. 64*20=1280/2=640 + 64= 704 + eof texturesList.Add(TextureHandler.Create($"chara_tim{(i++).ToString("D2")}", tim, 0, null)); } else //is geometry structure { ms.Seek(-8, SeekOrigin.Current); Debug_MCH mch = new Debug_MCH(ms, br); if (mch.bValid()) { mchs.Add(mch); } } } ms = null; } mchInstances = mchs.ToArray(); textures = texturesList.ToArray(); }
private void Section38() { using (MemoryStream ms = new MemoryStream(buffer)) using (BinaryReader br = new BinaryReader(ms)) { ms.Seek(sectionPointers[38 - 1], SeekOrigin.Begin); var innerSec = GetInnerPointers(br); sec38_textures = new List <Texture2D[]>(); for (int i = 0; i < innerSec.Length; i++) { TIM2 tim = new TIM2(buffer, (uint)(sectionPointers[38 - 1] + innerSec[i])); sec38_textures.Add(new Texture2D[tim.GetClutCount]); for (ushort k = 0; k < sec38_textures[i].Length; k++) { sec38_textures[i][k] = tim.GetTexture(k, true); } } } }
private Textures(byte[] buffer, long byteOffset, string fileName) { //#if DEBUG // //Dump for debug // _br.BaseStream.Seek(start, SeekOrigin.Begin); // using (BinaryWriter fs = new BinaryWriter(File.Create(Path.Combine(Path.GetTempPath(), $"{start}.dump"), (int)(_br.BaseStream.Length - _br.BaseStream.Position), FileOptions.None))) // fs.Write(_br.ReadBytes((int)(_br.BaseStream.Length - _br.BaseStream.Position))); //#endif IReadOnlyList <uint> pTim; using (var br = new BinaryReader(new MemoryStream(buffer))) { br.BaseStream.Seek(byteOffset, SeekOrigin.Begin); //Begin create Textures struct //populate the tim Count; var cTim = br.ReadInt32(); //create arrays per Count and Read pointers into array pTim = Enumerable.Range(0, cTim).Select(_ => (uint)(byteOffset + br.ReadUInt32())).ToList() .AsReadOnly(); //Read EOF Eof = br.ReadUInt32(); } //Read TIM -> TextureHandler into array TextureHandler getTexture(uint offset, int i) { if (buffer[offset] == 0x10) { var tm = new TIM2(buffer, offset); //broken var filename = $"{fileName}_{i}"; var path = Path.Combine(Path.GetTempPath(), "battle.dat"); Directory.CreateDirectory(path); //tm.SavePNG(Path.Combine(path,filename)); return(TextureHandler.Create(filename, tm)); // tm.GetTexture(0); } Memory.Log.WriteLine($"{nameof(Textures)}::{nameof(getTexture)}.{offset} :: Not a tim file!"); return(null); } _textures = pTim.Select(getTexture).ToList().AsReadOnly(); }
/// <summary> /// Section 39: Textures of roads, train tracks and bridge /// </summary> private void Section39() { using (MemoryStream ms = new MemoryStream(buffer)) using (BinaryReader br = new BinaryReader(ms)) { ms.Seek(sectionPointers[39 - 1], SeekOrigin.Begin); var innerSec = GetInnerPointers(br); sec39_texture = new Texture2D(Memory.graphics.GraphicsDevice, VRAM_TEXBLOCKWIDTH, VRAM_TEXBLOCKHEIGHT, false, SurfaceFormat.Color); for (int i = 0; i < innerSec.Length; i++) { TIM2 tim = new TIM2(buffer, (uint)(sectionPointers[39 - 1] + innerSec[i])); Texture2D atlasChunk = tim.GetTexture(0, true); byte[] chunkBuffer = new byte[atlasChunk.Width * atlasChunk.Height * 4]; atlasChunk.GetData(chunkBuffer, 0, chunkBuffer.Length); int newX = tim.GetOrigX - SEC39_VRAM_STARTX; int newY = tim.GetOrigY - SEC39_VRAM_STARTY; newX = (newX / VRAM_BLOCKSTEP) * VRAM_BLOCKSIZE; sec39_texture.SetData(0, new Microsoft.Xna.Framework.Rectangle(newX, newY, atlasChunk.Width, atlasChunk.Height), chunkBuffer, 0, chunkBuffer.Length); } } }
/// <summary> /// Method designed for Stage texture loading. /// </summary> /// <param name="texturePointer">Absolute pointer to TIM texture header in stageBuffer</param> private void ReadTexture(uint texturePointer, BinaryReader br) { TIM2 textureInterface = new TIM2(br, texturePointer); if (Memory.EnableDumpingData || EnableDumpingData) { IEnumerable <Model> temp = (from mg in modelGroups from m in mg select m).Where(x => x.vertices != null && x.triangles != null && x.quads != null); //IOrderedEnumerable<byte> cluts = temp.SelectMany(x => x.quads.Select(y => y.clut)).Union(temp.SelectMany(x => x.triangles.Select(y => y.clut))).Distinct().OrderBy(x => x); //IOrderedEnumerable<byte> unks = temp.SelectMany(x => x.quads.Select(y => y.UNK)).Union(temp.SelectMany(x => x.triangles.Select(y => y.UNK))).Distinct().OrderBy(x => x); //IOrderedEnumerable<byte> hides = temp.SelectMany(x => x.quads.Select(y => y.bHide)).Union(temp.SelectMany(x => x.triangles.Select(y => y.bHide))).Distinct().OrderBy(x => x); //IOrderedEnumerable<byte> gpu = temp.SelectMany(x => x.quads.Select(y => y.GPU)).Union(temp.SelectMany(x => x.triangles.Select(y => y.GPU))).Distinct().OrderBy(x => x); //IOrderedEnumerable<Color> color = temp.SelectMany(x => x.quads.Select(y => y.Color)).Union(temp.SelectMany(x => x.triangles.Select(y => y.Color))).Distinct().OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B); var tuv = (from m in temp where m.triangles != null && m.triangles.Length > 0 from t in m.triangles where t != null select new { t.clut, t.TexturePage, t.MinUV, t.MaxUV, t.Rectangle }).Distinct().OrderBy(x => x.TexturePage).ThenBy(x => x.clut).ToList(); var quv = (from m in temp where m.quads != null && m.quads.Length > 0 from q in m.quads where q != null select new { q.clut, q.TexturePage, q.MinUV, q.MaxUV, q.Rectangle }).Distinct().OrderBy(x => x.TexturePage).ThenBy(x => x.clut) /*.Where(x => x.Rectangle.Height > 0 && x.Rectangle.Width > 0)*/.ToList(); var all = tuv.Union(quv); foreach (var tpGroup in all.GroupBy(x => x.TexturePage)) { byte texturepage = tpGroup.Key; foreach (var clutGroup in tpGroup.GroupBy(x => x.clut)) { byte clut = clutGroup.Key; string filename = Path.GetFileNameWithoutExtension(Memory.Encounters.Filename); string p = Path.Combine(Path.GetTempPath(), "Battle Stages", filename, "Reference"); Directory.CreateDirectory(p); filename = $"{filename}_{clut}_{texturepage}.png"; using (Texture2D tex = textureInterface.GetTexture(clut)) using (RenderTarget2D tmp = new RenderTarget2D(Memory.graphics.GraphicsDevice, 256, 256)) { Memory.graphics.GraphicsDevice.SetRenderTarget(tmp); Memory.SpriteBatchStartAlpha(); Memory.graphics.GraphicsDevice.Clear(Color.TransparentBlack); foreach (Rectangle r in clutGroup.Select(x => x.Rectangle)) { Rectangle src = r; Rectangle dst = r; src.Offset(texturepage * 128, 0); Memory.spriteBatch.Draw(tex, dst, src, Color.White); } Memory.SpriteBatchEnd(); Memory.graphics.GraphicsDevice.SetRenderTarget(null); using (FileStream fs = new FileStream(Path.Combine(p, filename), FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) tmp.SaveAsPng(fs, 256, 256); } } } } Width = textureInterface.GetWidth; Height = textureInterface.GetHeight; string path = Path.Combine(Path.GetTempPath(), "Battle Stages", Path.GetFileNameWithoutExtension(Memory.Encounters.Filename)); Directory.CreateDirectory(path); if (Memory.EnableDumpingData || EnableDumpingData) { string fullpath = Path.Combine(path, $"{Path.GetFileNameWithoutExtension(Memory.Encounters.Filename)}_Clut.png"); if (!File.Exists(fullpath)) { textureInterface.SaveCLUT(fullpath); } } textures = new TextureHandler[textureInterface.GetClutCount]; for (ushort i = 0; i < textureInterface.GetClutCount; i++) { textures[i] = TextureHandler.Create(Memory.Encounters.Filename, textureInterface, i); if (Memory.EnableDumpingData || EnableDumpingData) { textures[i].Save(path, false); } } }
private void ReadBuffer(byte[] oneBuffer) { List <CharaModelHeaders> cmh = new List <CharaModelHeaders>(); int lastMsPosition = 0; using (MemoryStream ms = new MemoryStream(oneBuffer)) using (BinaryReader br = new BinaryReader(ms)) { uint nModels = br.ReadUInt32(); for (int i = 0; i < nModels; i++) { CharaModelHeaders localCmh = new CharaModelHeaders { offset = br.ReadUInt32() + 4, size = br.ReadUInt32(), size2 = br.ReadUInt32(), flagDWORD = br.ReadUInt32() }; bool bIgnorePadding = false; bool bMainChara = false; if (localCmh.flagDWORD >> 24 == 0xD0) //main character file { localCmh.timOffset = new uint[0]; localCmh.modelDataOffset = 0xFFFFFFFF; ms.Seek(4, SeekOrigin.Current); bMainChara = true; } else if (localCmh.flagDWORD >> 24 == 0xa0) //unknown- object without texture/ placeholder? { localCmh.timOffset = new uint[0]; localCmh.modelDataOffset = 0xFFFFFFFF; ms.Seek(8, SeekOrigin.Current); bIgnorePadding = true; } else { List <uint> timOffsets = new List <uint>(); uint flagTimOffset = localCmh.flagDWORD & 0x00FFFFFF; timOffsets.Add(localCmh.flagDWORD << 8); uint localTimOffset; while ((localTimOffset = br.ReadUInt32()) != 0xFFFFFFFF) { timOffsets.Add(localTimOffset & 0x00FFFFFF); } localCmh.timOffset = timOffsets.ToArray(); localCmh.modelDataOffset = br.ReadUInt32(); } localCmh.modelName = br.ReadChars(8); localCmh.padding = br.ReadUInt32(); if (localCmh.padding != 0xEEEEEEEE && !bIgnorePadding) //null models for placeholders are 2 not eeeeeeee { throw new Exception("Chara one- padding was not 0xEEEEEEEE- check code for ReadBuffer in FieldCharaOne"); } if (localCmh.modelDataOffset != 0xFFFFFFFF) { lastMsPosition = (int)ms.Position; ms.Seek(localCmh.offset + localCmh.modelDataOffset, SeekOrigin.Begin); localCmh.mch = new Debug_MCH(ms, br, Debug_MCH.mchMode.FieldNPC, 3f); //ms.Seek(localCmh.offset + 4, SeekOrigin.Begin); List <Texture2D> texList = new List <Texture2D>(); for (int n = 0; n < localCmh.timOffset.Length; n++) { if (localCmh.timOffset[n] > 0x10000000) { localCmh.timOffset[n] = localCmh.timOffset[n] & 0x00FFFFFF; } TIM2 localTim = new TIM2(br, localCmh.offset + localCmh.timOffset[n]); texList.Add(localTim.GetTexture()); } localCmh.textures = texList.ToArray(); ms.Seek(lastMsPosition, SeekOrigin.Begin); } else if (bMainChara) { lastMsPosition = (int)ms.Position; //this is main chara, so please grab data from main_chr.fs int getRefId = int.Parse(new string(localCmh.modelName).Substring(1, 3)); var chara = FieldMainCharaOne.MainFieldCharacters.Where(x => x.id == getRefId).First(); localCmh.modelDataOffset = 1; localCmh.mch = chara.mch; localCmh.textures = chara.textures; ms.Seek(localCmh.offset, SeekOrigin.Begin); localCmh.mch.MergeAnimations(ms, br); ms.Seek(lastMsPosition, SeekOrigin.Begin); } cmh.Add(localCmh); } } fieldModels = cmh.ToArray(); }
private void ReadBuffer(byte[] oneBuffer) { var cmh = new List <CharaModelHeaders>(); using (var ms = new MemoryStream(oneBuffer)) using (var br = new BinaryReader(ms)) { var nModels = br.ReadUInt32(); for (var i = 0; i < nModels; i++) { var localCmh = new CharaModelHeaders { Offset = br.ReadUInt32() + 4, Size = br.ReadUInt32(), Size2 = br.ReadUInt32(), FlagDword = br.ReadUInt32() }; var bIgnorePadding = false; var bMainChara = false; if (localCmh.FlagDword >> 24 == 0xD0) //main character file { localCmh.TIMOffset = new uint[0]; localCmh.ModelDataOffset = 0xFFFFFFFF; ms.Seek(4, SeekOrigin.Current); bMainChara = true; } else if (localCmh.FlagDword >> 24 == 0xa0) //unknown- object without texture/ placeholder? { localCmh.TIMOffset = new uint[0]; localCmh.ModelDataOffset = 0xFFFFFFFF; ms.Seek(8, SeekOrigin.Current); bIgnorePadding = true; } else { var timOffsets = new List <uint>(); // ReSharper disable once UnusedVariable var flagTimOffset = localCmh.FlagDword & 0x00FFFFFF; timOffsets.Add(localCmh.FlagDword << 8); uint localTimOffset; while ((localTimOffset = br.ReadUInt32()) != 0xFFFFFFFF) { timOffsets.Add(localTimOffset & 0x00FFFFFF); } localCmh.TIMOffset = timOffsets.ToArray(); localCmh.ModelDataOffset = br.ReadUInt32(); } localCmh.ModelName = br.ReadChars(8); localCmh.Padding = br.ReadUInt32(); if (localCmh.Padding != 0xEEEEEEEE && !bIgnorePadding) //null models for placeholders are 2 not eeeeeeee { throw new Exception("Chara one- padding was not 0xEEEEEEEE- check code for ReadBuffer in FieldCharaOne"); } int lastMsPosition; if (localCmh.ModelDataOffset != 0xFFFFFFFF) { lastMsPosition = (int)ms.Position; ms.Seek(localCmh.Offset + localCmh.ModelDataOffset, SeekOrigin.Begin); localCmh.MCH = new Debug_MCH(ms, br, Debug_MCH.mchMode.FieldNPC, 3f); //ms.Seek(localCmh.offset + 4, SeekOrigin.Begin); var texList = new List <Texture2D>(); for (var n = 0; n < localCmh.TIMOffset.Length; n++) { if (localCmh.TIMOffset[n] > 0x10000000) { localCmh.TIMOffset[n] = localCmh.TIMOffset[n] & 0x00FFFFFF; } var localTim = new TIM2(br, localCmh.Offset + localCmh.TIMOffset[n]); texList.Add(localTim.GetTexture()); } localCmh.Textures = texList.ToArray(); ms.Seek(lastMsPosition, SeekOrigin.Begin); } else if (bMainChara) { lastMsPosition = (int)ms.Position; //this is main chara, so please grab data from main_chr.fs var getRefId = int.Parse(new string(localCmh.ModelName).Substring(1, 3)); var chara = FieldMainCharaOne.MainFieldCharacters.First(x => x.ID == getRefId); localCmh.ModelDataOffset = 1; localCmh.MCH = chara.MCH; localCmh.Textures = chara.Textures; ms.Seek(localCmh.Offset, SeekOrigin.Begin); localCmh.MCH.MergeAnimations(ms, br); ms.Seek(lastMsPosition, SeekOrigin.Begin); } cmh.Add(localCmh); } } FieldModels = cmh.ToArray(); }