private void GenerateTexGenBPCommands(Material mat, List <BinaryTextureImage> textures) { for (int i = 0; i < 8; i++) { if (mat.TexCoord1Gens[i] == null) { continue; } BPCommand suSizeMask = new BPCommand() { Register = BPRegister.BP_MASK }; suSizeMask.SetBits(0x03FFFF, 0, 24); BPCommand sSize = new BPCommand() { Register = BPRegister.SU_SSIZE0 + (i * 2) }; sSize.SetFlag(false, 16); BPCommand tSize = new BPCommand() { Register = BPRegister.SU_TSIZE0 + (i * 2) }; tSize.SetFlag(false, 16); BinaryTextureImage curTex = textures[mat.TextureIndices[i]]; sSize.SetBits(curTex.Width - 1, 0, 16); tSize.SetBits(curTex.Height - 1, 0, 16); BPCommands.Add(suSizeMask); BPCommands.Add(sSize); BPCommands.Add(tSize); } }
public Texture(string name, BinaryTextureImage compressedData) { Name = name; CompressedData = compressedData; m_glTextureIndex = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, m_glTextureIndex); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)GXToOpenGL.GetWrapMode(compressedData.WrapS)); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)GXToOpenGL.GetWrapMode(compressedData.WrapT)); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)GXToOpenGL.GetMinFilter(compressedData.MinFilter)); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)GXToOpenGL.GetMagFilter(compressedData.MagFilter)); // Border Color WLinearColor borderColor = compressedData.BorderColor; GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, new[] { borderColor.R, borderColor.G, borderColor.B, borderColor.A }); // ToDo: Min/Mag LOD & Biases // Upload Image Data GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, compressedData.Width, compressedData.Height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, compressedData.GetData()); // Generate Mip Maps if (compressedData.MipMapCount > 0) { GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); } }
public TEX1(EndianBinaryReader reader, int offset) { Textures = new List <BinaryTextureImage>(); reader.BaseStream.Seek(offset, System.IO.SeekOrigin.Begin); reader.SkipInt32(); int tex1Size = reader.ReadInt32(); short texCount = reader.ReadInt16(); reader.SkipInt16(); int textureHeaderOffset = reader.ReadInt32(); int textureNameTableOffset = reader.ReadInt32(); List <string> names = NameTableIO.Load(reader, offset + textureNameTableOffset); reader.BaseStream.Seek(textureHeaderOffset + offset, System.IO.SeekOrigin.Begin); for (int i = 0; i < texCount; i++) { reader.BaseStream.Seek((offset + 0x20 + (0x20 * i)), System.IO.SeekOrigin.Begin); BinaryTextureImage img = new BinaryTextureImage(names[i]); img.Load(reader, (offset + 0x20 + (0x20 * i))); Textures.Add(img); } }
private void LoadTexturesFromJson(string headers_path, string directory_path) { JsonSerializer serial = new JsonSerializer(); serial.Formatting = Formatting.Indented; serial.Converters.Add(new StringEnumConverter()); using (StreamReader strm_reader = new StreamReader(headers_path)) { strm_reader.BaseStream.Seek(0, SeekOrigin.Begin); JsonTextReader reader = new JsonTextReader(strm_reader); Textures = serial.Deserialize <List <BinaryTextureImage> >(reader); } foreach (BinaryTextureImage tex in Textures) { // We'll search for duplicate texture names. BinaryTextureImage duplicate_search = Textures.Find(x => x.Name == tex.Name); // Otherwise we have to load the image from disk string name_without_ext = Path.Combine(directory_path, tex.Name); string full_img_path = FindImagePath(name_without_ext); if (full_img_path == "") { Console.WriteLine($"Could not find texture \"{ name_without_ext }\". It will not be imported."); continue; } tex.LoadImageFromDisk(full_img_path); } }
private static List <Texture2D> LoadTEX1FromFile(EndianBinaryReader reader, long chunkStart) { ushort textureCount = reader.ReadUInt16(); ushort padding = reader.ReadUInt16(); // Usually 0xFFFF? uint textureHeaderOffset = reader.ReadUInt32(); // textureCount # bti image headers are stored here, relative to chunkStart. uint stringTableOffset = reader.ReadUInt32(); // One filename per texture. relative to chunkStart. List <Texture2D> textureList = new List <Texture2D>(); // Get all Texture Names reader.BaseStream.Position = chunkStart + stringTableOffset; StringTable stringTable = StringTable.FromStream(reader); for (int t = 0; t < textureCount; t++) { // 0x20 is the length of the BinaryTextureImage header which all come in a row, but then the stream gets jumped around while loading the BTI file. reader.BaseStream.Position = chunkStart + textureHeaderOffset + (t * 0x20); BinaryTextureImage texture = new BinaryTextureImage(); texture.Load(reader, chunkStart + 0x20, t); Texture2D texture2D = new Texture2D(texture.Width, texture.Height); texture2D.Name = stringTable[t]; texture2D.PixelData = texture.GetData(); textureList.Add(texture2D); string executionPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); texture.SaveImageToDisk(executionPath + "/TextureDump/" + string.Format("{0}_({1}-{2}).png", stringTable[t], texture.Format, t)); } return(textureList); }
public TexBlock(EndianBinaryReader reader) { Images = new List <BinaryTextureImage>(); Textures = new List <Texture>(); // Get the offset of the TexBlock, save the reader's current offset, then go to the TexBlock int offset = reader.ReadInt32(); long curOffset = reader.BaseStream.Position; reader.BaseStream.Seek(offset, System.IO.SeekOrigin.Begin); // Get the offset of the first texture's image data int firstTexOffset = offset + reader.ReadInt32At(offset + 8); // We'll read texture data as long as the next image's width isn't 0 and // the stream's position isn't at the place where the first texture's image data starts. while (reader.PeekReadInt16() != 0 && reader.BaseStream.Position != firstTexOffset) { BinaryTextureImage tex = new BinaryTextureImage(); tex.LoadBinTex(reader, offset); Images.Add(tex); } //DumpTextures(@"D:\SZS Tools\TextureTest"); reader.BaseStream.Seek(curOffset, System.IO.SeekOrigin.Begin); }
/// <summary> /// Reads in the clamp settings and mipmap count for each texture. /// Textures are often duplicated to have one image with multiple pairs of clamp settings. /// </summary> /// <param name="reader"></param> public void GetTextureSettings(EndianBinaryReader reader) { // Get the offset of the TexBlock, get the offset of the next section, save the reader's current offset, // then go to the TextureSettings section int offset = reader.ReadInt32(); int nextSectionOffset = reader.PeekReadInt32(); long curOffset = reader.BaseStream.Position; reader.BaseStream.Seek(offset, System.IO.SeekOrigin.Begin); // New list to store the images with proper clamp settings List <BinaryTextureImage> newImageList = new List <BinaryTextureImage>(); while ((reader.PeekReadInt32() & 0xFFFF) == 0xFFFF && reader.BaseStream.Position != nextSectionOffset) { // Create a new texture from the texture at the index provided BinaryTextureImage modifiedTex = new BinaryTextureImage(Images[reader.ReadInt16()]); reader.SkipInt16(); // Padding, 0xFFFF modifiedTex.SetTexSettingsFromBin(reader); newImageList.Add(modifiedTex); Textures.Add(new Texture(modifiedTex)); } // Replace original list of textures Images = newImageList; DumpTextures(@"D:\SZS Tools\TextureTest"); reader.BaseStream.Seek(curOffset, System.IO.SeekOrigin.Begin); }
private static List<Texture2D> LoadTEX1FromFile(EndianBinaryReader reader, long chunkStart) { ushort textureCount = reader.ReadUInt16(); ushort padding = reader.ReadUInt16(); // Usually 0xFFFF? uint textureHeaderOffset = reader.ReadUInt32(); // textureCount # bti image headers are stored here, relative to chunkStart. uint stringTableOffset = reader.ReadUInt32(); // One filename per texture. relative to chunkStart. List<Texture2D> textureList = new List<Texture2D>(); // Get all Texture Names reader.BaseStream.Position = chunkStart + stringTableOffset; StringTable stringTable = StringTable.FromStream(reader); for (int t = 0; t < textureCount; t++) { // 0x20 is the length of the BinaryTextureImage header which all come in a row, but then the stream gets jumped around while loading the BTI file. reader.BaseStream.Position = chunkStart + textureHeaderOffset + (t * 0x20); BinaryTextureImage texture = new BinaryTextureImage(); texture.Load(reader, chunkStart + 0x20, t); Texture2D texture2D = new Texture2D(texture.Width, texture.Height); texture2D.Name = stringTable[t]; texture2D.PixelData = texture.GetData(); textureList.Add(texture2D); string executionPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); texture.SaveImageToDisk(executionPath + "/TextureDump/" + string.Format("{0}_({1}-{2}).png", stringTable[t], texture.Format, t)); } return textureList; }
public void SetTexture(Grendgine_Collada_Texture sourceTex, string texName, Bitmap bmp) { BinaryTextureImage tex = null; // Check to see if we need an alpha channel in our texture bool hasAlpha = HasAlpha(bmp); // If so, we'll use RGB565 if (hasAlpha) { tex = new BinaryTextureImage(texName, bmp, BinaryTextureImage.TextureFormats.RGBA32); // This sets the alpha compare settings so that alpha is set correctly. // It won't allow translucency, just a sharp transparent/opaque dichotemy. AlphCompare.Comp0 = GXCompareType.GEqual; AlphCompare.Comp1 = GXCompareType.LEqual; AlphCompare.Operation = GXAlphaOp.And; AlphCompare.Reference0 = 0x80; AlphCompare.Reference1 = 0xFF; // We'll default to showing the texture on both sides for now. Maybe it'll be changable in the future CullMode = GXCullMode.None; // Make sure z compare happens *after* texture look up so we can take the alpha compare results into account ZCompLoc = false; } // Otherwise, we'll use CMPR to save space else { tex = new BinaryTextureImage(texName, bmp, BinaryTextureImage.TextureFormats.CMPR); } tex.SetTextureSettings(sourceTex); CullMode = GXCullMode.None; // Search for an open texture slot and if there is one, put the texture there, // Include tex cooord gens, // Include a tex matrix, // And configure tev orders for (int i = 0; i < 8; i++) { if (Textures[i] == null) { Textures[i] = tex; TexCoord1Gens[i] = new TexCoordGen(GXTexGenType.Matrix2x4, GXTexGenSrc.Tex0 + i, GXTexMatrix.TexMtx0); TexMatrix1[i] = new TexMatrix(); TevOrders[i].TexCoordId = GXTexCoordSlot.TexCoord0 + i; TevOrders[i].TexMap = (byte)i; TevOrders[i].ChannelId = GXColorChannelId.Color0A0; break; } } TevStages[0].ColorIn[0] = GXCombineColorInput.TexColor; TevStages[0].ColorIn[1] = GXCombineColorInput.TexColor; TevStages[0].AlphaIn[0] = GXCombineAlphaInput.TexAlpha; }
private int GetGLTexIdFromCache(int j3dTextureId) { if (_textureCache.ContainsKey(j3dTextureId)) { return(_textureCache[j3dTextureId]); } //Console.WriteLine("Generating GL texture for id: " + j3dTextureId); //Look up the material first. //_file.Materials.GetMaterialRemapTable((ushort)j3dTextureId); J3DFormat.MaterialInitData matData = _file.Materials.GetMaterialInitData(_file.Materials.GetMaterialRemapTable((ushort)j3dTextureId)); //If the texture cache doesn't contain the ID, we're going to load it here. ushort textureIndex = matData.GetTextureIndex(0); if (textureIndex == 0xFF || textureIndex == 0xFFFF) { _textureCache[j3dTextureId] = 0; return(0); } BinaryTextureImage image = _file.Textures.GetTexture(_file.Materials.GetMaterialIndex(textureIndex)); //image.WriteImageToFile("image_" + matChunk.GetMaterialIndex(matData.GetTextureIndex(0)) + image.Format + ".png"); byte[] imageData = image.GetData(); ushort imageWidth = image.Width; ushort imageHeight = image.Height; //Generate a black and white textureboard if the texture format is not supported. if (imageData.Length == 0) { imageData = new byte[] { 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 255 }; imageWidth = 2; imageHeight = 2; } int glTextureId; GL.GenTextures(1, out glTextureId); GL.BindTexture(TextureTarget.Texture2D, glTextureId); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Repeat); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Repeat); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, imageWidth, imageHeight, 0, PixelFormat.Bgra, PixelType.UnsignedInt8888Reversed, imageData); _textureCache[j3dTextureId] = glTextureId; return(glTextureId); }
private void LoadTexturesFromScene(Assimp.Scene scene, string model_directory, Arguments cmdargs) { foreach (Assimp.Mesh mesh in scene.Meshes) { Console.Write(mesh.Name); Assimp.Material mat = scene.Materials[mesh.MaterialIndex]; if (mat.HasTextureDiffuse) { string texname = System.IO.Path.GetFileNameWithoutExtension(mat.TextureDiffuse.FilePath); bool isEmbedded = false; int embeddedIndex = -1; if (mat.TextureDiffuse.FilePath.StartsWith("*")) { string index = mat.TextureDiffuse.FilePath.Substring(1, mat.TextureDiffuse.FilePath.Length);; isEmbedded = int.TryParse(index, out embeddedIndex); texname = String.Format("embedded_tex{0}", embeddedIndex); } bool already_exists = false; foreach (BinaryTextureImage image in Textures) { if (image.Name == texname) { already_exists = true; break; } } if (already_exists) { continue; } BinaryTextureImage img = new BinaryTextureImage(); if (isEmbedded) { Assimp.EmbeddedTexture embeddedTexture = scene.Textures[embeddedIndex]; img.Load(mat.TextureDiffuse, embeddedTexture); } else { img.Load(mat.TextureDiffuse, model_directory, cmdargs.readMipmaps); } Textures.Add(img); } else { Console.WriteLine(" -> Has No Textures"); } } }
public Material(EndianBinaryReader stream, uint texOffset) { //Console.WriteLine("Reading Material at 0x{0:X}", stream.BaseStream.Position); textureIndex = stream.ReadInt16(); stream.SkipInt16(); wrapU = stream.ReadByte(); wrapV = stream.ReadByte(); stream.SkipInt16(); stream.Skip(12); texture = new BinaryTextureImage(stream, texOffset + (0xC * textureIndex), texOffset); }
/// <summary> /// This is used to emulate a feature used in The Legend of Zelda: The Wind Waker. In WW all characters appear to share /// their Toon texture lookup image. The J3D files include a texture in their files which is a black/white checkerboard /// that is a placeholder for the one the game overrides. Unfortunately, if we use the black/white checkerboard then lighting /// gets broken, so this function is provided to optionally override a texture name with a specific texture, such as the /// texture name "ZBtoonEX" used by WW. /// </summary> /// <param name="textureName">Name of the texture to override. All textures with this name will be overriden.</param> /// <param name="filePath">Path to the texture to use.</param> public void SetTextureOverride(string textureName, string filePath) { BinaryTextureImage btiData = new BinaryTextureImage(); btiData.LoadImageFromDisk(filePath); if (m_textureOverrides.ContainsKey(textureName)) { m_textureOverrides[textureName].Dispose(); } m_textureOverrides[textureName] = new Texture(textureName, btiData); }
public void AddTextureFromPath(string path, bool readMipmaps) { string modelDirectory = System.IO.Path.GetDirectoryName(path); BinaryTextureImage img = new BinaryTextureImage(); // Only the path and the wrap mode are relevant, the rest doesn't matter for img.Load TextureSlot tex = new TextureSlot(path, 0, 0, 0, 0, (float)0.0, 0, TextureWrapMode.Clamp, TextureWrapMode.Clamp, 0); img.Load(tex, modelDirectory, readMipmaps); Textures.Add(img); }
private void LoadTexturesFromScene(Assimp.Scene scene, string model_directory) { foreach (Assimp.Mesh mesh in scene.Meshes) { Assimp.Material mat = scene.Materials[mesh.MaterialIndex]; if (mat.HasTextureDiffuse) { BinaryTextureImage img = new BinaryTextureImage(); img.Load(mat.TextureDiffuse, model_directory); Textures.Add(img); } } }
public TEX1(Assimp.Scene scene, string modelDirectory) { Textures = new List <BinaryTextureImage>(); foreach (Assimp.Material mat in scene.Materials) { if (mat.HasTextureDiffuse) { BinaryTextureImage img = new BinaryTextureImage(); img.Load(mat.TextureDiffuse, modelDirectory); Textures.Add(img); } } }
protected virtual void Dispose(bool manualDispose) { if (!m_hasBeenDisposed) { if (manualDispose) { // TODO: dispose managed state (managed objects). } GL.DeleteTexture(m_glTextureIndex); // Set large fields to null. CompressedData = null; m_hasBeenDisposed = true; } }
private ObservableCollection <BinaryTextureImage> LoadImages(string[] paths) { if (ImageList == null) { ImageList = new ObservableCollection <BinaryTextureImage>(); } ObservableCollection <BinaryTextureImage> tempList = ImageList; foreach (string path in paths) { BinaryTextureImage openedImage = null; // Open a BTI if (path.EndsWith(".bti")) { using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { EndianBinaryReader reader = new EndianBinaryReader(stream, Endian.Big); openedImage = new BinaryTextureImage(); openedImage.Load(reader, path, 0); } } // Open a PNG else if (path.EndsWith(".png") || path.EndsWith(".PNG")) { Bitmap input = new Bitmap(path); openedImage = new BinaryTextureImage(path, input, BinaryTextureImage.TextureFormats.PNG); } // Open a TGA else if (path.EndsWith(".tga")) { Bitmap input = TgaReader.Load(path); openedImage = new BinaryTextureImage(path, input, BinaryTextureImage.TextureFormats.TGA); } tempList.Add(openedImage); } return(tempList); }
public void LoadTEX1FromStream(EndianBinaryReader reader, long tagStart, bool dumpTextures) { ushort numTextures = reader.ReadUInt16(); Trace.Assert(reader.ReadUInt16() == 0xFFFF); // Padding int textureHeaderDataOffset = reader.ReadInt32(); int stringTableOffset = reader.ReadInt32(); // Texture Names reader.BaseStream.Position = tagStart + stringTableOffset; StringTable nameTable = StringTable.FromStream(reader); Textures = new BindingList <Texture>(); for (int t = 0; t < numTextures; t++) { // Reset the stream position to the start of this header as loading the actual data of the texture // moves the stream head around. reader.BaseStream.Position = tagStart + textureHeaderDataOffset + (t * 0x20); BinaryTextureImage compressedTex = new BinaryTextureImage(); string tempFileName = string.Format("TextureDump/{1}_{0}.png", nameTable[t], t); if (!m_allowTextureCache || !File.Exists(tempFileName)) { compressedTex.Load(reader, tagStart + 0x20 /* Size of TEX1 header?*/, t); } else { compressedTex.LoadImageFromDisk(tempFileName); } Texture texture = new Texture(nameTable[t], compressedTex); Textures.Add(texture); if (dumpTextures) { compressedTex.SaveImageToDisk(string.Format("TextureDump/{2}__{0}_{1}_{3}.png", texture.Name, compressedTex.Format, t, compressedTex.PaletteFormat)); } } }
/// <summary> /// Pass this a Room<x> folder or a Stage folder directory! This will look for specific subfolders /// (bdl, btk, dzb, dzr, dzs, dat, etc.) and load each file within them as appropriate. /// </summary> /// <param name="directory">Absolute file path to a folder containing a bdl/btk/etc. files(s)</param> public void LoadFromDirectory(string directory) { if (!Directory.Exists(directory)) { new Exception("Invalid directory specified for WorldspaceProject."); } //Get all of the sub folders (bdl, btk, etc.) string[] subFolders = Directory.GetDirectories(directory); foreach (string folder in subFolders) { //Then grab all of the files that are inside this folder and we'll load each one. string[] subFiles = Directory.GetFiles(folder); foreach (string filePath in subFiles) { BinaryReader br = new BinaryReader(File.OpenRead(filePath)); BaseArchiveFile file; byte[] fileData = br.ReadBytes((int)br.BaseStream.Length); switch ((new DirectoryInfo(folder).Name).ToLower()) { /* Map Collision Format */ case "dzb": file = new StaticCollisionModel(); break; /* Room and Stage Entity Data */ case "dzr": case "dzs": //Apparently Nintendo likes to mis-categorize files sometimes and put the wrong //file format inside the wrong folder! We'll name-check dzr and dzs before loading //them as they have fixed names (Room.*) if (filePath.EndsWith(".dzr") || filePath.EndsWith(".dzs")) { file = new WindWakerEntityData(); } else { file = new GenericArchiveData(); } break; /* 3D Model Formats */ case "bmd": case "bdl": file = new JStudioModel(); break; case "tex": file = new BinaryTextureImage(); break; case "bck": case "brk": case "btk": default: Console.WriteLine("Unknown file extension {0} found ({1}). Creating GenericData holder for it!", Path.GetExtension(filePath), Path.GetFileName(filePath)); file = new GenericArchiveData(); break; } file.FileName = Path.GetFileName(filePath); file.FolderName = new DirectoryInfo(folder).Name; file.ParentArchive = this; file.Load(fileData); //Now that we've created the appropriate file (and hopefully mapped them all out!) we'll just stick //it in our list of loaded files. They can later be gotten with the templated getter! _archiveFiles.Add(file); br.Close(); } } }
public MdlModel(string path) { m_Counts = new ushort[20]; m_Offsets = new long[18]; shapes = new List <GXBatch>(); globalMatrixTable = new List <Matrix4>(); textures = new List <BinaryTextureImage>(); using (FileStream fs = new FileStream(path, FileMode.Open)) { EndianBinaryReader stream = new EndianBinaryReader(fs, Endian.Big); stream.ReadInt32(); //ignore the magic for (int i = 0; i < 20; i++) { m_Counts[i] = stream.ReadUInt16(); } stream.BaseStream.Seek(0x30, 0); for (int i = 0; i < 18; i++) { m_Offsets[i] = stream.ReadUInt32(); } verticies = fromVec3(LoadSection <vec3>(stream, 6, 6)); normals = fromVec3(LoadSection <vec3>(stream, 7, 7)); uvs = fromVec2(LoadSection <vec2>(stream, 9, 9)); drawelements = LoadSection <DrawElement>(stream, 17, 17); shapepackets = LoadSection <ShapePacket>(stream, 1, 3); materials = LoadSection <Material>(stream, 14, 18); texobjs = LoadSection <TexObj>(stream, 15, 16); stream.BaseStream.Seek(m_Offsets[2], 0); for (int i = 0; i < m_Counts[5]; i++) { Matrix4 mat = new Matrix4( new Vector4(stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle()), new Vector4(stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle()), new Vector4(stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle()), new Vector4(0, 0, 0, 1) ); globalMatrixTable.Add(mat.Inverted()); } for (int i = 0; i < m_Counts[4]; i++) { globalMatrixTable.Add(Matrix4.Identity); } stream.BaseStream.Seek(m_Offsets[16], 0); for (int i = 0; i < m_Counts[19]; i++) { GXBatch bat = new GXBatch(); bat.LoadMdlBatch(stream, shapepackets, globalMatrixTable, verticies); shapes.Add(bat); } /* * foreach (var packet in shapepackets) * { * //create local matrix table for shape packet * Matrix4[] localMats = new Matrix4[packet.numMatIndicies]; * for (int i = 0; i < packet.numMatIndicies; i++) * { * if (packet.matIndicies[i] != 0xFFFF) * { * localMats[i] = globalMatrixTable[packet.matIndicies[i]]; * } else {break;} * } * //apply to shapes * foreach (GXBatch shape in shapes) * { * if (shape.ActiveAttributes.Contains(GXAttribute.PositionMatrixIndex)) * { * foreach (var vert in shape.RawVertices) * { * var matIndex = vert.Indices[shape.ActiveAttributes.IndexOf(GXAttribute.PositionMatrixIndex)]; * Console.WriteLine($"Mat Index: {matIndex}\nLocal Matrix List Size: {localMats.Length}"); * if(shape.ActiveAttributes.Contains(GXAttribute.PositionMatrixIndex)){ * Matrix4 mat = localMats[matIndex]; * Vector4 pos = new Vector4(verticies[vert.Indices[shape.ActiveAttributes.IndexOf(GXAttribute.Position)]]); * Vector4.Transform(pos, mat); * verticies[vert.Indices[shape.ActiveAttributes.IndexOf(GXAttribute.Position)]] = new Vector3(pos); * } * } * } * } * }*/ stream.BaseStream.Seek(m_Offsets[12], SeekOrigin.Begin); for (int i = 0; i < m_Counts[14]; i++) { int textureOffset = stream.ReadInt32(); long nextOffsetPos = stream.BaseStream.Position; stream.BaseStream.Seek(textureOffset, SeekOrigin.Begin); BinaryTextureImage img = new BinaryTextureImage(); img.Load(stream, textureOffset, 1); textures.Add(img); stream.BaseStream.Seek(nextOffsetPos, SeekOrigin.Begin); } WriteObj("mdlTest.obj"); } }
public void WriteObj(string f) { //string dirPath = Path.GetDirectoryName(f); string fileName = $"{ AppContext.BaseDirectory }\\{ Path.GetFileNameWithoutExtension(f) }"; StringWriter objWriter = new StringWriter(); StringWriter mtlWriter = new StringWriter(); objWriter.WriteLine("# dumped with booldozer"); objWriter.WriteLine($"mtllib { fileName }.mtl"); foreach (var vert in verticies) { objWriter.WriteLine($"v {vert.X} {vert.Y} {vert.Z}"); } if (normals.Count != 0) { foreach (var vert in normals) { objWriter.WriteLine($"vn { vert.X } { vert.Y } { vert.Z }"); } } if (uvs.Count != 0) { foreach (var vert in uvs) { objWriter.WriteLine($"vt { vert.X } { 1 - vert.Y }"); } } objWriter.WriteLine(); int index = 0; foreach (DrawElement drw in drawelements) { Material mat = materials[drw.matIndex]; GXBatch shp = shapes[drw.shapeIndex]; mtlWriter.WriteLine($"newmtl { index }"); mtlWriter.WriteLine($"Kd { ((mat.color & 0xFF000000) >> 24) / 255 } { ((mat.color & 0x00FF0000) >> 16) / 255 } { ((mat.color & 0x0000FF00) >> 8) / 255 }"); mtlWriter.WriteLine($"d { (mat.color & 0x000000FF) / 255 }"); if (mat.num_tev_stages > 0) { TexObj texObj = texobjs[mat.stages[0].texobj_index]; mtlWriter.WriteLine($"map_Kd { index }.png"); BinaryTextureImage tex = textures[texObj.textureIndex]; tex.SaveImageToDisk($"{ AppContext.BaseDirectory }\\{ index }.png", tex.GetData(), tex.Width, tex.Height); } objWriter.WriteLine($"o { index }"); objWriter.WriteLine($"usemtl { index }"); for (int i = 0; i < shp.RawVertices.Count; i += 3) { string[] verts = new string[3] { "", "", "" }; for (int j = 0; j < 3; j++) { string pos = ""; string uv = ""; string norm = ""; if (shp.ActiveAttributes.Contains(GXAttribute.Position)) { pos = $"{ Convert.ToString(shp.RawVertices[i + j].Indices[shp.ActiveAttributes.IndexOf(GXAttribute.Position)] + 1) }/"; } if (shp.ActiveAttributes.Contains(GXAttribute.Tex0)) { uv = $"{ Convert.ToString(shp.RawVertices[i + j].Indices[shp.ActiveAttributes.IndexOf(GXAttribute.Tex0)] + 1) }"; } if (shp.ActiveAttributes.Contains(GXAttribute.Normal)) { norm = $"/{ Convert.ToString(shp.RawVertices[i + j].Indices[shp.ActiveAttributes.IndexOf(GXAttribute.Normal)] + 1) }/"; } verts[j] = $"{ pos }{ uv }{ norm }"; } objWriter.WriteLine($"f { verts[0] } { verts[1] } { verts[2] }"); } index++; } using (FileStream s = new FileStream($"{ fileName }.obj", FileMode.Create, FileAccess.Write)) { EndianBinaryWriter w = new EndianBinaryWriter(s, Endian.Big); w.Write(objWriter.ToString().ToCharArray()); } using (FileStream s = new FileStream($"{ fileName }.mtl", FileMode.Create, FileAccess.Write)) { EndianBinaryWriter w = new EndianBinaryWriter(s, Endian.Big); w.Write(mtlWriter.ToString().ToCharArray()); } }
private void GenerateTextureCommands(Material mat, List <BinaryTextureImage> textures) { BPRegister[] texInfoRegs = new BPRegister[] { BPRegister.TX_SETIMAGE0_I0, BPRegister.TX_SETIMAGE0_I1, BPRegister.TX_SETIMAGE0_I2, BPRegister.TX_SETIMAGE0_I3, BPRegister.TX_SETIMAGE0_I4, BPRegister.TX_SETIMAGE0_I5, BPRegister.TX_SETIMAGE0_I6, BPRegister.TX_SETIMAGE0_I7 }; BPRegister[] texIndexRegs = new BPRegister[] { BPRegister.TX_SETIMAGE3_I0, BPRegister.TX_SETIMAGE3_I1, BPRegister.TX_SETIMAGE3_I2, BPRegister.TX_SETIMAGE3_I3, BPRegister.TX_SETIMAGE3_I4, BPRegister.TX_SETIMAGE3_I5, BPRegister.TX_SETIMAGE3_I6, BPRegister.TX_SETIMAGE3_I7 }; BPRegister[] texMode0Regs = new BPRegister[] { BPRegister.TX_SET_MODE0_I0, BPRegister.TX_SET_MODE0_I1, BPRegister.TX_SET_MODE0_I2, BPRegister.TX_SET_MODE0_I3, BPRegister.TX_SET_MODE0_I4, BPRegister.TX_SET_MODE0_I5, BPRegister.TX_SET_MODE0_I6, BPRegister.TX_SET_MODE0_I7 }; BPRegister[] texMode1Regs = new BPRegister[] { BPRegister.TX_SET_MODE1_I0, BPRegister.TX_SET_MODE1_I1, BPRegister.TX_SET_MODE1_I2, BPRegister.TX_SET_MODE1_I3, BPRegister.TX_SET_MODE1_I4, BPRegister.TX_SET_MODE1_I5, BPRegister.TX_SET_MODE1_I6, BPRegister.TX_SET_MODE1_I7 }; for (int i = 0; i < 8; i++) { if (mat.TextureIndices[i] == -1) { continue; } BinaryTextureImage curTex = textures[mat.TextureIndices[i]]; // Records width, height, and format BPCommand texInfo = new BPCommand() { Register = texInfoRegs[i] }; texInfo.SetBits(curTex.Width - 1, 0, 10); texInfo.SetBits(curTex.Height - 1, 10, 10); texInfo.SetBits((int)curTex.Format, 20, 4); // Records the index of the texture BPCommand texIndex = new BPCommand() { Register = texIndexRegs[i] }; texIndex.SetBits(mat.TextureIndices[i], 0, 24); BPCommand mode0 = new BPCommand() { Register = texMode0Regs[i] }; mode0.SetBits((int)curTex.WrapS, 0, 2); mode0.SetBits((int)curTex.WrapT, 2, 2); mode0.SetBits((int)curTex.MagFilter, 4, 1); switch (curTex.MinFilter) { case BinaryTextureImage.FilterMode.Nearest: mode0.SetBits(0, 5, 3); break; case BinaryTextureImage.FilterMode.Linear: mode0.SetBits(4, 5, 3); break; case BinaryTextureImage.FilterMode.NearestMipmapNearest: mode0.SetBits(1, 5, 3); break; case BinaryTextureImage.FilterMode.NearestMipmapLinear: mode0.SetBits(2, 5, 3); break; case BinaryTextureImage.FilterMode.LinearMipmapNearest: mode0.SetBits(5, 5, 3); break; case BinaryTextureImage.FilterMode.LinearMipmapLinear: mode0.SetBits(6, 5, 3); break; } // Unimplemented: mode0.SetFlag(true, 8); // Edge LOD (diag_lod) mode0.SetBits(0, 9, 8); // LoDBias (lod_bias) mode0.SetBits(0, 19, 2); // Max aniso (max_aniso) mode0.SetFlag(false, 21); // Bias Clamp (lod_clamp) // MinLOD // MaxLOD BPCommand mode1 = new BPCommand() { Register = texMode1Regs[i] }; BPCommands.Add(texIndex); BPCommands.Add(texInfo); BPCommands.Add(mode0); BPCommands.Add(mode1); } }