public static byte[] ConvertDDS(GUIDEntry value, DXGI_FORMAT targetFormat, DDSConverter.ImageFormat imageFormat, int frame) { try { if (GetDataType(value) != DataType.Image) { return(null); } teTexture texture = new teTexture(IOHelper.OpenFile(value)); if (texture.PayloadRequired) { ulong payload = texture.GetPayloadGUID(value.GUID, 1); if (IOHelper.HasFile(payload)) { texture.LoadPayload(IOHelper.OpenFile(payload), 1); } else { return(null); } } Stream ms = texture.SaveToDDS(1); return(DDSConverter.ConvertDDS(ms, targetFormat, imageFormat, frame)); } catch { // ignored } return(null); }
internal static teTexture LoadTexture(GUIDEntry value, Stream fileStream = null) { teTexture texture = new teTexture(fileStream ?? IOHelper.OpenFile(value)); if (texture.PayloadRequired) { ulong payload = texture.GetPayloadGUID(value.GUID, 0); if (IOHelper.HasFile(payload)) { texture.LoadPayload(IOHelper.OpenFile(payload), 0); } else { return(null); } } return(texture); }
public void TestGetPayloadGUID() { using (var ms = new MemoryStream(TestPayloadNoSurfaceBytes) { Position = 0 }) { var tex = new teTexture(ms); const ulong baseGuid = 0x0C00000000001234UL; Assert.AreEqual(0x0320000300001234UL, tex.GetPayloadGUID(baseGuid, 0), "GetPayloadGuid(1, 0) != 000300001234.04D"); Assert.AreEqual(0x0320000200001234UL, tex.GetPayloadGUID(baseGuid, 1), "GetPayloadGuid(1, 1) != 000200001234.04D"); Assert.AreEqual(0x0320000100001234UL, tex.GetPayloadGUID(baseGuid, 2), "GetPayloadGuid(1, 2) != 000100001234.04D"); Assert.AreEqual(0x0320000000001234UL, tex.GetPayloadGUID(baseGuid, 3), "GetPayloadGuid(1, 3) != 000000001234.04D"); const ulong baseGuid0F1 = 0x00F0000000000002; Assert.AreEqual(0x0320010300000002ul, tex.GetPayloadGUID(baseGuid0F1, 0), "GetPayloadGuid(1, 0) != 010300000002.04D"); Assert.AreEqual(0x0320010200000002ul, tex.GetPayloadGUID(baseGuid0F1, 1), "GetPayloadGuid(1, 1) != 010200000002.04D"); Assert.AreEqual(0x0320010100000002ul, tex.GetPayloadGUID(baseGuid0F1, 2), "GetPayloadGuid(1, 2) != 010100000002.04D"); Assert.AreEqual(0x0320010000000002ul, tex.GetPayloadGUID(baseGuid0F1, 3), "GetPayloadGuid(1, 3) != 010000000002.04D"); } }
public static void SaveTexture(ICLIFlags flags, string path, FindLogic.Combo.ComboInfo info, ulong textureGUID) { bool convertTextures = true; string convertType = "dds"; bool lossless = false; if (flags is ExtractFlags extractFlags) { convertTextures = extractFlags.ConvertTextures && !extractFlags.Raw; convertType = extractFlags.ConvertTexturesType.ToLowerInvariant(); lossless = extractFlags.ConvertTexturesLossless; if (extractFlags.SkipTextures) { return; } } path += Path.DirectorySeparatorChar; FindLogic.Combo.TextureInfoNew textureInfo = info.Textures[textureGUID]; string filePath = Path.Combine(path, $"{textureInfo.GetNameIndex()}"); if (Program.Flags.Deduplicate) { if (ScratchDBInstance.HasRecord(textureGUID)) { return; } ScratchDBInstance[textureGUID] = new ScratchDB.ScratchPath($"{filePath}.{convertType}"); } CreateDirectoryFromFile(path); if (!convertTextures) { using (Stream textureStream = OpenFile(textureInfo.GUID)) { teTexture texture = new teTexture(textureStream, true); textureStream.Position = 0; WriteFile(textureStream, $"{filePath}.004"); if (!texture.PayloadRequired) { return; } using (Stream texturePayloadStream = OpenFile(texture.GetPayloadGUID(textureGUID))) WriteFile(texturePayloadStream, $"{filePath}.04D"); } } else { using (Stream textureStream = OpenFile(textureGUID)) { if (textureStream == null) { return; } teTexture texture = new teTexture(textureStream); if (texture.PayloadRequired) { texture.LoadPayload(OpenFile(texture.GetPayloadGUID(textureGUID))); } using (Stream convertedStream = texture.SaveToDDS()) { convertedStream.Position = 0; if (convertType == "dds" || convertedStream.Length == 0) { WriteFile(convertedStream, $"{filePath}.dds"); return; } uint fourCC = texture.Header.GetFormat().ToPixelFormat().FourCC; bool isBcffValid = TextureConfig.DXGI_BC4.Contains((int)texture.Header.Format) || TextureConfig.DXGI_BC5.Contains((int)texture.Header.Format) || fourCC == TextureConfig.FOURCC_ATI1 || fourCC == TextureConfig.FOURCC_ATI2; ImageFormat imageFormat = null; if (convertType == "tif") { imageFormat = ImageFormat.Tiff; } // if (convertType == "tga") imageFormat = Im.... oh // so there is no TGA image format. // guess the TGA users are stuck with the DirectXTex stuff for now. if (isBcffValid && imageFormat != null) { BlockDecompressor decompressor = new BlockDecompressor(convertedStream); decompressor.CreateImage(); decompressor.Image.Save($"{filePath}.{convertType}", imageFormat); return; } string losslessFlag = lossless ? "-wiclossless" : string.Empty; Process pProcess = new Process { StartInfo = { FileName = "Third Party\\texconv.exe", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardInput = true, RedirectStandardError = true, CreateNoWindow = true, Arguments = $"-- \"{Path.GetFileName(filePath)}.dds\" -y -wicmulti {losslessFlag} -nologo -m 1 -ft {convertType} -f R8G8B8A8_UNORM -o \"{path}" }, EnableRaisingEvents = true }; // erm, so if you add an end quote to this then it breaks. // but start one on it's own is fine (we need something for "Winged Victory") pProcess.Start(); convertedStream.Position = 0; convertedStream.CopyTo(pProcess.StandardInput.BaseStream); pProcess.StandardInput.BaseStream.Close(); // pProcess.WaitForExit(); // not using this is kinda dangerous but I don't care // when texconv writes with to the console -nologo is has done/failed conversion string line = pProcess.StandardOutput.ReadLine(); if (line?.Contains("FAILED") == true) { convertedStream.Position = 0; WriteFile(convertedStream, $"{filePath}.dds"); } } } } }
private static async Task SaveTextureTask(ICLIFlags flags, string path, SaveContext info, ulong textureGUID, string name = null) { bool convertTextures = true; string convertType = "tif"; string multiSurfaceConvertType = "tif"; bool createMultiSurfaceSheet = false; bool lossless = false; int maxMips = 1; if (flags is ExtractFlags extractFlags) { if (extractFlags.SkipTextures) { return; } createMultiSurfaceSheet = extractFlags.SheetMultiSurface; convertTextures = !extractFlags.RawTextures && !extractFlags.Raw; convertType = extractFlags.ConvertTexturesType.ToLowerInvariant(); lossless = extractFlags.ConvertTexturesLossless; multiSurfaceConvertType = convertType; if (extractFlags.ForceDDSMultiSurface) { multiSurfaceConvertType = "dds"; } if (convertType == "dds" && extractFlags.SaveMips) { maxMips = 0xF; } } if (!path.EndsWith(Path.DirectorySeparatorChar.ToString())) { path += Path.DirectorySeparatorChar; } FindLogic.Combo.TextureAsset textureInfo = info.m_info.m_textures[textureGUID]; string filePath = Path.Combine(path, name ?? $"{textureInfo.GetNameIndex()}"); if (teResourceGUID.Type(textureGUID) != 0x4) { filePath += $".{teResourceGUID.Type(textureGUID):X3}"; } if (Program.Flags != null && Program.Flags.Deduplicate) { if (ScratchDBInstance.HasRecord(textureGUID)) { return; } ScratchDBInstance[textureGUID] = new ScratchDB.ScratchPath($"{filePath}.{convertType}", true); } CreateDirectoryFromFile(path); await s_texurePrepareSemaphore.WaitAsync(); try { if (!convertTextures) { teTexture texture; using (Stream textureStream = OpenFile(textureGUID)) { texture = new teTexture(textureStream, true); textureStream.Position = 0; WriteFile(textureStream, $"{filePath}.004"); } if (!texture.PayloadRequired) { return; } for (int i = 0; i < texture.Payloads.Length; ++i) { using (Stream texturePayloadStream = OpenFile(texture.GetPayloadGUID(textureGUID, i))) WriteFile(texturePayloadStream, $"{filePath}_{i}.04D"); } } else { teTexture texture; using (Stream textureStream = OpenFile(textureGUID)) { if (textureStream == null) { return; } texture = new teTexture(textureStream); } //if (texture.Header.Flags.HasFlag(teTexture.Flags.CUBEMAP)) return; // for diffing when they add/regen loads of cubemaps if (texture.PayloadRequired) { for (int i = 0; i < texture.Payloads.Length; ++i) { using (var payloadStream = OpenFile(texture.GetPayloadGUID(textureGUID, i))) texture.LoadPayload(payloadStream, i); if (maxMips == 1) { break; } } } uint?width = null; uint?height = null; uint?surfaces = null; if (texture.Header.IsCubemap || texture.Header.IsArray || texture.HasMultipleSurfaces) { if (createMultiSurfaceSheet) { Logger.Debug("Combo", $"Saving {Path.GetFileName(filePath)} as a sheet because it has more than one surface"); height = (uint)(texture.Header.Height * texture.Header.Surfaces); surfaces = 1; texture.Header.Flags = 0; } else if (convertType != "tif" && convertType != "dds") { Logger.Debug("Combo", $"Saving {Path.GetFileName(filePath)} as {multiSurfaceConvertType} because it has more than one surface"); convertType = multiSurfaceConvertType; } } WICCodecs?imageFormat = null; switch (convertType) { case "tif": imageFormat = WICCodecs.TIFF; break; case "png": imageFormat = WICCodecs.PNG; break; case "jpg": imageFormat = WICCodecs.JPEG; break; } // if (convertType == "tga") imageFormat = Im.... oh // so there is no TGA image format. // sucks to be them if (convertType == "dds") { using (Stream convertedStream = texture.SaveToDDS(maxMips == 1 ? 1 : texture.Header.MipCount, width, height, surfaces)) { WriteFile(convertedStream, $"{filePath}.dds"); } return; } Process pProcess; using (Stream convertedStream = texture.SaveToDDS(maxMips == 1 ? 1 : texture.Header.MipCount, width, height, surfaces)) { var data = DDSConverter.ConvertDDS(convertedStream, DXGI_FORMAT.R8G8B8A8_UNORM, imageFormat.Value, 0); if (data != null) { WriteFile(data, $"{filePath}.{convertType}"); } else { convertedStream.Position = 0; WriteFile(convertedStream, $"{filePath}.dds"); Logger.Error("Combo", $"Unable to save {Path.GetFileName(filePath)} as {convertType} because DirectXTex failed."); } } } } finally { s_texurePrepareSemaphore.Release(); } }
public static void SaveTexture(ICLIFlags flags, string path, FindLogic.Combo.ComboInfo info, ulong textureGUID) { bool convertTextures = true; string convertType = "tif"; string multiSurfaceConvertType = "tif"; bool createMultiSurfaceSheet = false; bool lossless = false; int maxMips = 1; if (flags is ExtractFlags extractFlags) { if (extractFlags.SkipTextures) { return; } createMultiSurfaceSheet = extractFlags.SheetMultiSurface; convertTextures = !extractFlags.RawTextures && !extractFlags.Raw; convertType = extractFlags.ConvertTexturesType.ToLowerInvariant(); lossless = extractFlags.ConvertTexturesLossless; multiSurfaceConvertType = convertType; if (extractFlags.ForceDDSMultiSurface) { multiSurfaceConvertType = "dds"; } if (convertType == "dds" && extractFlags.SaveMips) { maxMips = 0xF; } } path += Path.DirectorySeparatorChar; FindLogic.Combo.TextureInfoNew textureInfo = info.Textures[textureGUID]; string filePath = Path.Combine(path, $"{textureInfo.GetNameIndex()}"); if (teResourceGUID.Type(textureGUID) != 0x4) { filePath += $".{teResourceGUID.Type(textureGUID):X3}"; } if (Program.Flags.Deduplicate) { if (ScratchDBInstance.HasRecord(textureGUID)) { return; } ScratchDBInstance[textureGUID] = new ScratchDB.ScratchPath($"{filePath}.{convertType}"); } CreateDirectoryFromFile(path); if (!convertTextures) { using (Stream textureStream = OpenFile(textureGUID)) { teTexture texture = new teTexture(textureStream, true); textureStream.Position = 0; WriteFile(textureStream, $"{filePath}.004"); if (!texture.PayloadRequired) { return; } for (int i = 0; i < texture.Payloads.Length; ++i) { using (Stream texturePayloadStream = OpenFile(texture.GetPayloadGUID(textureGUID, i))) WriteFile(texturePayloadStream, $"{filePath}_{i}.04D"); } } } else { using (Stream textureStream = OpenFile(textureGUID)) { if (textureStream == null) { return; } teTexture texture = new teTexture(textureStream); //if (texture.Header.Flags.HasFlag(teTexture.Flags.CUBEMAP)) return; // for diffing when they add/regen loads of cubemaps if (texture.PayloadRequired) { for (int i = 0; i < texture.Payloads.Length; ++i) { texture.LoadPayload(OpenFile(texture.GetPayloadGUID(textureGUID, i)), i); if (maxMips == 1) { break; } } } uint?width = null; uint?height = null; uint?surfaces = null; if (texture.Header.IsCubemap || texture.Header.IsArray || texture.HasMultipleSurfaces) { if (createMultiSurfaceSheet) { TankLib.Helpers.Logger.Debug("Combo", $"Saving {Path.GetFileName(filePath)} as a sheet because it has more than one surface"); height = (uint)(texture.Header.Height * texture.Header.Surfaces); surfaces = 1; texture.Header.Flags = 0; } else { TankLib.Helpers.Logger.Debug("Combo", $"Saving {Path.GetFileName(filePath)} as {multiSurfaceConvertType} because it has more than one surface"); convertType = multiSurfaceConvertType; } } using (Stream convertedStream = texture.SaveToDDS(maxMips == 1 ? 1 : texture.Header.MipCount, width, height, surfaces)) { convertedStream.Position = 0; if (convertType == "dds" || convertedStream.Length == 0) { WriteFile(convertedStream, $"{filePath}.dds"); return; } bool isBcffValid = teTexture.DXGI_BC4.Contains(texture.Header.Format) || teTexture.DXGI_BC5.Contains(texture.Header.Format) || teTexture.ATI2.Contains(texture.Header.GetTextureType()); ImageFormat imageFormat = null; if (convertType == "tif") { imageFormat = ImageFormat.Tiff; } if (convertType == "png") { imageFormat = ImageFormat.Png; } if (convertType == "jpg") { imageFormat = ImageFormat.Jpeg; } // if (convertType == "tga") imageFormat = Im.... oh // so there is no TGA image format. // guess the TGA users are stuck with the DirectXTex stuff for now. if (isBcffValid && imageFormat != null && !(texture.Header.IsCubemap || texture.Header.IsArray || texture.HasMultipleSurfaces)) { BlockDecompressor decompressor = new BlockDecompressor(convertedStream); decompressor.CreateImage(); decompressor.Image.Save($"{filePath}.{convertType}", imageFormat); return; } string losslessFlag = lossless ? "-wiclossless" : string.Empty; Process pProcess = new Process { StartInfo = { FileName = "Third Party\\texconv.exe", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardInput = true, RedirectStandardError = true, CreateNoWindow = true, Arguments = $"-- \"{Path.GetFileName(filePath)}.dds\" -y -wicmulti {losslessFlag} -nologo -m 1 -ft {convertType} -f R8G8B8A8_UNORM -o \"{(path.EndsWith(@"/") || path.EndsWith("\\") ? path.Substring(0, path.Length - 1) : path)}" }, EnableRaisingEvents = true }; pProcess.Start(); convertedStream.Position = 0; convertedStream.CopyTo(pProcess.StandardInput.BaseStream); pProcess.StandardInput.BaseStream.Flush(); pProcess.StandardInput.BaseStream.Close(); pProcess.WaitForExit(); // when texconv writes with to the console -nologo is has done/failed conversion string line = pProcess.StandardOutput.ReadToEnd(); if (line.Contains("FAILED")) { convertedStream.Position = 0; TankLib.Helpers.Logger.Debug("Combo", $"Saving {Path.GetFileName(filePath)} as dds because texconv failed."); WriteFile(convertedStream, $"{filePath}.dds"); } } } } }
public static Task <Control> Get(ProgressWorker a1, SynchronizationContext context, Window window, bool npc) { var source = new TaskCompletionSource <Control>(); context.Send(obj => { var control = new ImageGridView(); var t = new Thread(() => { if (!(obj is Tuple <ProgressWorker, TaskCompletionSource <Control> > tuple)) { return; } var worker = tuple.Item1; var tcs = tuple.Item2; try { var i = 0; worker.ReportProgress(0, "Loading heroes..."); if (TrackedFiles == null || !TrackedFiles.ContainsKey(0x75)) { throw new DataToolWpfException("Open storage first"); } var max = TrackedFiles[0x75].Count; foreach (var key in TrackedFiles[0x75]) { try { var hero = GetInstance <STUHero>(key); if (hero == null) { continue; } string heroNameActual = GetString(hero.m_0EDCE350) ?? teResourceGUID.Index(key).ToString("X"); heroNameActual = heroNameActual.TrimEnd(' '); ProgressionUnlocks progressionUnlocks = new ProgressionUnlocks(hero); if (progressionUnlocks.LevelUnlocks == null && !npc) { continue; } if (progressionUnlocks.LootBoxesUnlocks != null && npc) { continue; } var tex = hero.m_8203BFE1.FirstOrDefault(x => teResourceGUID.Index(x.m_id) == 0x40C9 || teResourceGUID.Index(x.m_id) == 0x40CA)?.m_texture; if (tex == 0) { tex = hero.m_8203BFE1.FirstOrDefault()?.m_texture; } var image = new byte[] { }; var width = 128; var height = 128; if (tex != 0) { teTexture texture = new teTexture(OpenFile(tex)); if (texture.PayloadRequired) { ulong payload = texture.GetPayloadGUID(tex); Stream payloadStream = OpenFile(payload); if (payloadStream != null) { texture.LoadPayload(payloadStream); } else { continue; } } width = texture.Header.Width; height = texture.Header.Height; Stream ms = texture.SaveToDDS(); image = DDSConverter.ConvertDDS(ms, DXGI_FORMAT.R8G8B8A8_UNORM, DDSConverter.ImageFormat.PNG, 0); } var entry = control.Add(heroNameActual, image, 128, (int)ImagingHelper.CalculateSizeAS(height, width, 128)); entry.Payload = progressionUnlocks; entry.OnClick += (sender, args) => { window.Close(); }; } catch { // ignored } finally { i += 1; worker.ReportProgress((int)(i / (float)max * 100)); } } tcs.SetResult(control); } catch (Exception e) { tcs.SetException(e); } finally { worker.ReportProgress(100); } }); t.SetApartmentState(ApartmentState.STA); t.Start(); }, new Tuple <ProgressWorker, TaskCompletionSource <Control> >(a1, source)); return(source.Task); }
public static byte[] ConvertDDS(GUIDEntry value, DXGI_FORMAT targetFormat, ImageFormat imageFormat, int frame) { try { if (GetDataType(value) != DataType.Image) { return(null); } teTexture texture = new teTexture(IOHelper.OpenFile(value)); if (texture.PayloadRequired) { ulong payload = texture.GetPayloadGUID(value.GUID); if (value.APM.FirstOccurence.ContainsKey(payload)) { texture.LoadPayload(IOHelper.OpenFile(value.APM.FirstOccurence[payload])); } else { return(null); } } Stream ms = texture.SaveToDDS(); CoInitializeEx(IntPtr.Zero, CoInit.MultiThreaded | CoInit.SpeedOverMemory); byte[] data = new byte[ms.Length]; ms.Read(data, 0, data.Length); ScratchImage scratch = null; try { unsafe { fixed(byte *dataPin = data) { scratch = TexHelper.Instance.LoadFromDDSMemory((IntPtr)dataPin, data.Length, DDS_FLAGS.NONE); TexMetadata info = scratch.GetMetadata(); if (TexHelper.Instance.IsCompressed(info.Format)) { ScratchImage temp = scratch.Decompress(frame, DXGI_FORMAT.UNKNOWN); scratch.Dispose(); scratch = temp; } info = scratch.GetMetadata(); if (info.Format != targetFormat) { ScratchImage temp = scratch.Convert(targetFormat, TEX_FILTER_FLAGS.DEFAULT, 0.5f); scratch.Dispose(); scratch = temp; } UnmanagedMemoryStream stream = null; if (imageFormat == ImageFormat.TGA) { stream = scratch.SaveToTGAMemory(frame < 0 ? 0 : frame); } else { WICCodecs codec = WICCodecs.PNG; bool isMultiframe = false; switch (imageFormat) { case ImageFormat.BMP: codec = WICCodecs.BMP; break; case ImageFormat.GIF: codec = WICCodecs.GIF; isMultiframe = true; break; case ImageFormat.JPEG: codec = WICCodecs.JPEG; break; case ImageFormat.PNG: codec = WICCodecs.PNG; break; case ImageFormat.TIF: codec = WICCodecs.TIFF; isMultiframe = true; break; } if (frame < 0) { if (!isMultiframe) { frame = 0; } else { stream = scratch.SaveToWICMemory(0, info.ArraySize, WIC_FLAGS.ALL_FRAMES, TexHelper.Instance.GetWICCodec(codec)); } } if (frame >= 0) { stream = scratch.SaveToWICMemory(frame, WIC_FLAGS.NONE, TexHelper.Instance.GetWICCodec(codec)); } byte[] tex = new byte[stream.Length]; stream.Read(tex, 0, tex.Length); scratch.Dispose(); return(tex); } } } } catch { if (scratch != null && scratch.IsDisposed == false) { scratch?.Dispose(); } } } catch { } return(null); }