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