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