private static void WriteToConvertedFormat(Texture target, uint width, uint height, uint depth, ushort format, uint mipmapCount, byte[] textureData, Func <string, string, string> getExportPath) { var assetPath = AssetDatabase.GetAssetPath(target); var assetExtension = System.IO.Path.GetExtension(assetPath); var inverseAssetExtension = assetExtension == ".ftex" ? ".dds" : ".ftex"; var exportPath = getExportPath(assetPath, inverseAssetExtension); if (string.IsNullOrEmpty(exportPath)) { return; } switch (assetExtension) { case ".dds": GrTextureExporter.ExportGrTexture(assetPath, (ushort)width, (ushort)height, (ushort)depth, format, (byte)mipmapCount, textureData, exportPath); break; default: DirectXTexHelper.SaveAsDDS(width, height, depth, GrTextureUtils.GetDXGIFormat(format), mipmapCount, textureData, exportPath); break; } }
/// <summary> /// Exports a GrTexture to an .ftex file and a group of .ftexs files. /// </summary> /// <param name="foxKitFormVariation">The Form Variation to export.</param> /// <param name="exportPath">File path to export to.</param> public static void ExportGrTexture(string assetPath, ushort width, ushort height, ushort depth, ushort format, byte mipmapCount, byte[] data, string exportPath) { Assert.IsNotNull(exportPath, "exportPath must not be null."); var userData = AssetImporter.GetAtPath(assetPath).userData; string[] separators = { "NrtFlag: ", ", TextureType: ", ", UnknownFlags: " }; var flags = userData.Split(separators, StringSplitOptions.RemoveEmptyEntries); byte nrtFlag; if (!byte.TryParse(flags[0], out nrtFlag)) { Debug.Log($"Error: Incorrect nrt flag value: {flags[0]}"); return; } else { if (!(nrtFlag == 0x0 || nrtFlag == 0x2)) { Debug.Log($"Error: Incorrect nrt flag value: {nrtFlag}"); return; } } FoxLib.GrTexture.TextureType textureType; if (!FoxLib.GrTexture.TextureType.TryParse(flags[1], out textureType)) { Debug.Log($"Error: Incorrect texture type value: {flags[1]}"); return; } FoxLib.GrTexture.UnknownFlags unknownFlags; if (!FoxLib.GrTexture.UnknownFlags.TryParse(flags[2], out unknownFlags)) { Debug.Log($"Error: Incorrect unknown flags: {flags[2]}"); return; } var flippedData = FoxKit.Modules.Gr.GrTexture.Utils.DirectXTexHelper.Flip2DImage(width, height, mipmapCount, GrTextureUtils.GetDXGIFormat(format), data); Debug.Log("The flipped data is " + ((flippedData == data) ? "the same" : "not the same") + "."); data = flippedData; FoxLib.GrTexture.GrTexture grTexture = new FoxLib.GrTexture.GrTexture(height, width, depth, format, nrtFlag, textureType, unknownFlags, mipmapCount, data); var precomputedSlicePitches = FoxKit.Modules.Gr.GrTexture.Utils.DirectXTexHelper.ComputeSlicePitches((uint)grTexture.Width, (uint)grTexture.Height, GrTextureUtils.GetDXGIFormat(grTexture.PixelFormat), (uint)grTexture.MipMapCount); var ftexsFileCount = GetFtexsFileCount(grTexture.DDSData.Length, grTexture.MipMapCount); BinaryWriter[] writers = new BinaryWriter[ftexsFileCount + 1]; try { var filepathSansExtension = Path.GetDirectoryName(exportPath) + "\\" + Path.GetFileNameWithoutExtension(exportPath); writers[0] = new BinaryWriter(new FileStream(exportPath, FileMode.Create)); for (int i = 1; i < writers.Length; i++) { writers[i] = new BinaryWriter(new FileStream(filepathSansExtension + "." + i + ".ftexs", FileMode.Create)); } var writeFunctions = new FoxLib.GrTexture.WriteFunctions[writers.Length]; for (int i = 0; i < writers.Length; ++i) { var forClosureCopy = i; writeFunctions[forClosureCopy] = new FoxLib.GrTexture.WriteFunctions(writers[forClosureCopy].Write, writers[forClosureCopy].Write, writers[forClosureCopy].Write, writers[forClosureCopy].Write, writers[forClosureCopy].Write, writers[forClosureCopy].Write, numberOfBytes => WriteEmptyBytes(writers[forClosureCopy], numberOfBytes), () => writers[forClosureCopy].BaseStream.Position); } FoxLib.GrTexture.Write(grTexture, writeFunctions, precomputedSlicePitches); } finally { foreach (var writer in writers) { writer.Close(); } } }
private static void WriteTexture(Texture2D target, Func <string, string, string> getExportPath) { var data = FoxKit.Modules.Gr.GrTexture.Utils.DirectXTexHelper.Flip2DImage((uint)target.width, (uint)target.height, (uint)target.mipmapCount, GrTextureUtils.GetDXGIFormat(target.format), target.GetRawTextureData()); WriteToConvertedFormat(target, (uint)target.width, (uint)target.height, 1, GrTextureUtils.GetTextureFormat(target.format), (uint)target.mipmapCount, data, getExportPath); }
private static void WriteTexture(Cubemap target, Func <string, string, string> getExportPath) { List <byte> rawData = new List <byte>(); for (int i = 0; i < 6; i++) { for (int j = 0; j < target.mipmapCount; j++) { var colors = target.GetPixels((CubemapFace)i, j); for (int h = 0; h < colors.Length; h++) { byte[][] rawBytes = { BitConverter.GetBytes(colors[h].r), BitConverter.GetBytes(colors[h].g), BitConverter.GetBytes(colors[h].b), BitConverter.GetBytes(colors[h].a) }; rawData.AddRange(rawBytes[0]); rawData.AddRange(rawBytes[1]); rawData.AddRange(rawBytes[2]); rawData.AddRange(rawBytes[3]); } } } var bytes = rawData.ToArray(); var data = FoxKit.Modules.Gr.GrTexture.Utils.DirectXTexHelper.Flip2DImage((uint)target.width, (uint)target.height, (uint)target.mipmapCount, GrTextureUtils.GetDXGIFormat(target.format), bytes); WriteToConvertedFormat(target, (uint)target.width, (uint)target.height, 1, GrTextureUtils.GetTextureFormat(target.format), (uint)target.mipmapCount, data, getExportPath); }
/// <summary> /// Import a .ftex file. /// </summary> /// <param name="ctx"></param> public override void OnImportAsset(AssetImportContext ctx) { #region Readers var filepathSansExtension = Path.GetDirectoryName(assetPath) + "\\" + Path.GetFileNameWithoutExtension(assetPath); List <BinaryReader> binaryReaders = new List <BinaryReader>(); binaryReaders.Add(new BinaryReader(new FileStream(assetPath, FileMode.Open))); for (int i = 1; i < 7; i++) { var file = filepathSansExtension + "." + i + ".ftexs"; if (!File.Exists(file)) { break; } var fileStream = new FileStream(file, FileMode.Open); binaryReaders.Add(new BinaryReader(fileStream)); } #endregion try { var readFunctions = (from reader in binaryReaders select new FoxLib.GrTexture.ReadFunctions(reader.ReadUInt16, reader.ReadUInt32, reader.ReadUInt64, reader.ReadByte, reader.ReadBytes, (numberOfBytes => SkipBytes(reader, numberOfBytes)), (bytePos => MoveStream(reader, bytePos)))).ToArray(); FoxLib.GrTexture.GrTexture grTexture = FoxLib.GrTexture.Read(readFunctions); var textureFormat = GrTextureUtils.GetTextureFormat(grTexture.PixelFormat, grTexture.Depth); var isLinear = GrTextureUtils.GetLinear(grTexture.TextureType); if (grTexture.TextureType == FoxLib.GrTexture.TextureType.Cube) { #region Cube var texture = new Cubemap(grTexture.Width, UnityEngine.Experimental.Rendering.GraphicsFormat.R8G8B8A8_SRGB, UnityEngine.Experimental.Rendering.TextureCreationFlags.MipChain); var textureData = DirectXTexHelper.Decompress(grTexture.Width, grTexture.Height, GrTextureUtils.GetDXGIFormat(grTexture.PixelFormat), grTexture.MipMapCount, grTexture.DDSData); for (int i = 0; i < textureData.Length; i++) { var faceData = textureData[i]; { var colours = new Color[faceData.Length / 4]; for (int j = 0; j < faceData.Length / 4; j++) { var data = faceData.Skip(j * 4).Take(4).ToArray(); float R = data[0]; float G = data[1]; float B = data[2]; float A = data[3]; float nrmR = R / 255.0f; float nrmG = G / 255.0f; float nrmB = B / 255.0f; float nrmA = A / 255.0f; colours[j] = new Color(nrmR, nrmG, nrmB, nrmA); } texture.SetPixels(colours, (CubemapFace)i); } } texture.Apply(true); ctx.AddObjectToAsset("ftex", texture); ctx.SetMainObject(texture); #endregion } else { if (grTexture.Depth == 1) { #region 2D var hasMipmaps = grTexture.MipMapCount > 1; var texture = new Texture2D(grTexture.Width, grTexture.Height, textureFormat, hasMipmaps, isLinear); if (hasMipmaps) { if (texture.mipmapCount > grTexture.MipMapCount) { var length = grTexture.DDSData.Length; IntPtr pixelBuffer = DirectXTexHelper.GenerateNecessaryMipMapsAndFlipImage(grTexture.Width, grTexture.Height, GrTextureUtils.GetDXGIFormat(grTexture.PixelFormat), grTexture.MipMapCount, grTexture.DDSData, ref length); texture.LoadRawTextureData(pixelBuffer, length); } else { texture.LoadRawTextureData(grTexture.DDSData); } } else { byte[] newPixelData = DirectXTexHelper.Flip2DImage(grTexture.Width, grTexture.Height, GrTextureUtils.GetDXGIFormat(grTexture.PixelFormat), grTexture.MipMapCount, grTexture.DDSData); texture.LoadRawTextureData(newPixelData); texture.Apply(); } ctx.AddObjectToAsset("ftex", texture, texture); ctx.SetMainObject(texture); #endregion } else { #region 3D var texture = GrTextureUtils.CreateTexture3D(grTexture.Width, grTexture.Height, grTexture.Depth, GrTextureUtils.GetTextureFormat(grTexture.PixelFormat, grTexture.Depth), grTexture.DDSData); ctx.AddObjectToAsset("ftex", texture); ctx.SetMainObject(texture); #endregion } } this.userData = "NrtFlag: " + grTexture.NrtFlag + ", TextureType: " + grTexture.TextureType + ", UnknownFlags: " + grTexture.UnknownFlags; } finally { foreach (var reader in binaryReaders) { reader.Close(); } } }