public static Texture2D ProcessTexture( EmbeddedTextureData embeddedTextureData, string name, ref bool hasAlphaChannel, bool isNormalMap = false, TextureWrapMode textureWrapMode = TextureWrapMode.Repeat, FilterMode textureFilterMode = FilterMode.Bilinear, TextureCompression textureCompression = TextureCompression.None, bool checkAlphaChannel = false, bool generateMipMaps = true ) { Texture2D finalTexture2D = null; if (embeddedTextureData.DataPointer == IntPtr.Zero || embeddedTextureData.DataLength <= 0) { #if TRILIB_OUTPUT_MESSAGES Debug.LogWarningFormat("Texture '{0}' not found", path); #endif } else { Texture2D tempTexture2D; if (ApplyTextureData(embeddedTextureData, out tempTexture2D)) { finalTexture2D = ProcessTextureData(tempTexture2D, name, ref hasAlphaChannel, textureWrapMode, textureFilterMode, textureCompression, isNormalMap, checkAlphaChannel, generateMipMaps); } #if TRILIB_OUTPUT_MESSAGES Debug.LogErrorFormat("Unable to load texture '{0}'", path); #endif } embeddedTextureData.Dispose(); return(finalTexture2D); }
public static Texture2D ProcessTexture(int width, int height, string name, ref bool hasAlphaChannel, byte[] data, bool isRawData = false, bool isNormalMap = false, TextureWrapMode textureWrapMode = TextureWrapMode.Repeat, TextureCompression textureCompression = TextureCompression.None, bool checkAlphaChannel = false, bool generateMipMaps = true ) { if (data == null || data.Length == 0) { return(null); } Texture2D tempTexture2D; if (ApplyTextureData(data, isRawData, out tempTexture2D, width, height, generateMipMaps)) { return(ProccessTextureData(tempTexture2D, name, ref hasAlphaChannel, textureWrapMode, textureCompression, isNormalMap, checkAlphaChannel)); } return(null); }
public static Texture2D ProcessTexture(int width, int height, string name, ref bool hasAlphaChannel, byte[] data, bool isRawData = false, bool isNormalMap = false, TextureWrapMode textureWrapMode = TextureWrapMode.Repeat, TextureCompression textureCompression = TextureCompression.None, bool checkAlphaChannel = false, bool generateMipMaps = true ) { if (data == null || data.Length == 0) { #if TRILIB_OUTPUT_MESSAGES || ASSIMP_OUTPUT_MESSAGES Debug.LogWarningFormat("Texture '{0}' not found", path); #endif return(null); } Texture2D tempTexture2D; if (ApplyTextureData(data, isRawData, out tempTexture2D, width, height, generateMipMaps)) { return(ProccessTextureData(tempTexture2D, name, ref hasAlphaChannel, textureWrapMode, textureCompression, isNormalMap, checkAlphaChannel)); } #if TRILIB_OUTPUT_MESSAGES || ASSIMP_OUTPUT_MESSAGES Debug.LogErrorFormat("Unable to load texture '{0}'", path); #endif return(null); }
public TextureOutput(bool a, string n, TextureScale s, bool sr, TextureChannels c, TextureCompression nc, ImageFormat i) { Active = a; Name = n; Scale = s; SRGB = sr; Channels = c; Compression = nc; ImageFormat = i; }
public static Texture2D LoadTextureFromFile( string path, int width, int height, string name, ref bool checkAlphaChannel, byte[] data, bool isRawData = false, bool isNormalMap = false, string basePath = null, TextureWrapMode textureWrapMode = TextureWrapMode.Repeat, TextureCompression textureCompression = TextureCompression.None ) { var finalPath = path; if (data == null) { string filename = null; data = FileUtils.LoadFileData(finalPath); if (data.Length == 0 && basePath != null) { finalPath = Path.Combine(basePath, path); data = FileUtils.LoadFileData(finalPath); } if (data.Length == 0) { filename = FileUtils.GetFilename(path); finalPath = filename; data = FileUtils.LoadFileData(finalPath); } if (data.Length == 0 && basePath != null && filename != null) { finalPath = Path.Combine(basePath, filename); data = FileUtils.LoadFileData(finalPath); } if (data.Length == 0) { #if TRILIB_OUTPUT_MESSAGES || ASSIMP_OUTPUT_MESSAGES Debug.LogWarningFormat("Texture '{0}' not found", path); #endif return(null); } } Texture2D tempTexture2D; if (ApplyTextureData(data, isRawData, out tempTexture2D, width, height)) { return(ProccessTextureData(tempTexture2D, name, ref checkAlphaChannel, textureWrapMode, finalPath, textureCompression, isNormalMap)); } #if TRILIB_OUTPUT_MESSAGES || ASSIMP_OUTPUT_MESSAGES Debug.LogErrorFormat("Unable to load texture '{0}'", path); #endif return(null); }
/// <summary> /// /// </summary> /// <param name="buildContext"></param> /// <param name="src"></param> /// <param name="dst"></param> /// <param name="noMips"></param> /// <param name="fast"></param> /// <param name="toNormal"></param> /// <param name="color"></param> /// <param name="alpha"></param> /// <param name="normal"></param> /// <param name="compression"></param> internal static void RunNVCompress( BuildContext buildContext, string src, string dst, bool noMips, bool fast, bool toNormal, bool color, bool alpha, bool normal, TextureCompression compression ) { string commandLine = ""; if ( noMips ) commandLine += " -nomips" ; if ( fast ) commandLine += " -fast" ; if ( toNormal ) commandLine += " -tonormal"; if ( color ) commandLine += " -color" ; if ( alpha ) commandLine += " -alpha" ; if ( normal ) commandLine += " -normal" ; commandLine += ( " -" + compression.ToString().ToLower() ); commandLine += ( " \"" + src + "\"" ); commandLine += ( " \"" + dst + "\"" ); buildContext.RunTool( @"nvcompress.exe", commandLine );//*/ }
/// <summary> /// Loads a <see cref="UnityEngine.Texture2D"/> from an external source. /// </summary> /// <param name="scene">Scene where the texture belongs.</param> /// <param name="path">Path to load the texture data.</param> /// <param name="name">Name of the <see cref="UnityEngine.Texture2D"/> to be created.</param> /// <param name="material"><see cref="UnityEngine.Material"/> to assign the <see cref="UnityEngine.Texture2D"/>.</param> /// <param name="propertyName"><see cref="UnityEngine.Material"/> property name to assign to the <see cref="UnityEngine.Texture2D"/>.</param> /// <param name="checkAlphaChannel">If True, checks every image pixel to determine if alpha channel is being used and sets this value.</param> /// <param name="textureWrapMode">Wrap mode of the <see cref="UnityEngine.Texture2D"/> to be created.</param> /// <param name="basePath">Base path to lookup for the <see cref="UnityEngine.Texture2D"/>.</param> /// <param name="onTextureLoaded">Event to trigger when the <see cref="UnityEngine.Texture2D"/> finishes loading.</param> /// <param name="textureCompression">Texture loading compression level.</param> /// <param name="textureFileNameWithoutExtension">Texture filename without the extension.</param> /// <param name="isNormalMap">Is the Texture a Normal Map?</param> /// <returns>The loaded <see cref="UnityEngine.Texture2D"/>.</returns> public static Texture2D LoadTextureFromFile(IntPtr scene, string path, string name, Material material, string propertyName, ref bool checkAlphaChannel, TextureWrapMode textureWrapMode = TextureWrapMode.Repeat, string basePath = null, TextureLoadHandle onTextureLoaded = null, TextureCompression textureCompression = TextureCompression.None, string textureFileNameWithoutExtension = null, bool isNormalMap = false) { if (string.IsNullOrEmpty(path)) { return(null); } bool assimpUncompressed; string finalPath; byte[] data; var texture = AssimpInterop.aiScene_GetEmbeddedTexture(scene, path); if (texture != IntPtr.Zero) { assimpUncompressed = !AssimpInterop.aiMaterial_IsEmbeddedTextureCompressed(scene, texture); var dataLength = AssimpInterop.aiMaterial_GetEmbeddedTextureDataSize(scene, texture, !assimpUncompressed); data = AssimpInterop.aiMaterial_GetEmbeddedTextureData(scene, texture, dataLength); finalPath = Path.GetFileNameWithoutExtension(path); } else { string filename = null; finalPath = path; data = FileUtils.LoadFileData(finalPath); if (data.Length == 0 && basePath != null) { finalPath = Path.Combine(basePath, path); } data = FileUtils.LoadFileData(finalPath); if (data.Length == 0) { filename = Path.GetFileName(path); finalPath = filename; } data = FileUtils.LoadFileData(finalPath); if (data.Length == 0 && basePath != null && filename != null) { finalPath = Path.Combine(basePath, filename); } data = FileUtils.LoadFileData(finalPath); if (data.Length == 0) { #if ASSIMP_OUTPUT_MESSAGES Debug.LogWarningFormat("Texture '{0}' not found", path); #endif return(null); } assimpUncompressed = false; } bool loaded; Texture2D tempTexture2D; if (assimpUncompressed) { //TODO: additional DLL methods to load actual resolution var textureResolution = Mathf.FloorToInt(Mathf.Sqrt(data.Length / 4)); tempTexture2D = new Texture2D(textureResolution, textureResolution, TextureFormat.ARGB32, true); tempTexture2D.LoadRawTextureData(data); tempTexture2D.Apply(); loaded = true; } else { #if USE_DEVIL && (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN) loaded = IlLoader.LoadTexture2DFromByteArray(data, data.Length, out tempTexture2D); #else tempTexture2D = new Texture2D(2, 2, TextureFormat.RGBA32, true); loaded = tempTexture2D.LoadImage(data); #endif } tempTexture2D.name = name; tempTexture2D.wrapMode = textureWrapMode; if (loaded) { var colors = tempTexture2D.GetPixels32(); var finalTexture2D = new Texture2D(tempTexture2D.width, tempTexture2D.height, TextureFormat.ARGB32, true); if (isNormalMap) { for (var i = 0; i < colors.Length; i++) { var color = colors[i]; color.a = color.r; color.r = 0; color.b = 0; colors[i] = color; } finalTexture2D.SetPixels32(colors); finalTexture2D.Apply(); } else { finalTexture2D.SetPixels32(colors); finalTexture2D.Apply(); if (textureCompression != TextureCompression.None) { tempTexture2D.Compress(textureCompression == TextureCompression.HighQuality); } } if (checkAlphaChannel) { checkAlphaChannel = false; foreach (var color in colors) { if (color.a != 255) { checkAlphaChannel = true; break; } } } if (material != null) { material.SetTexture(propertyName, finalTexture2D); } if (onTextureLoaded != null) { onTextureLoaded(finalPath, material, propertyName, finalTexture2D); } return(finalTexture2D); } else { #if ASSIMP_OUTPUT_MESSAGES Debug.LogErrorFormat("Unable to load texture '{0}'", path); #endif } return(null); }
public static string Replace(this Texture2D t2d, Image image, PropertyCollection props, string fileSourcePath = null, string forcedTFCName = null) { string errors = ""; var textureCache = forcedTFCName ?? t2d.GetTopMip().TextureCacheName; string fmt = t2d.TextureFormat; PixelFormat pixelFormat = Image.getPixelFormatType(fmt); t2d.RemoveEmptyMipsFromMipList(); // Not sure what this does? // Remove all but one mip? //if (Export.Game == MEGame.ME1 && texture.mipMapsList.Count < 6) //{ // for (int i = texture.mipMapsList.Count - 1; i != 0; i--) // texture.mipMapsList.RemoveAt(i); //} PixelFormat newPixelFormat = pixelFormat; //Changing Texture Type. Not sure what this is, exactly. //if (mod.markConvert) // newPixelFormat = changeTextureType(pixelFormat, image.pixelFormat, ref package, ref texture); if (!image.checkDDSHaveAllMipmaps() || t2d.Mips.Count > 1 && image.mipMaps.Count() <= 1 || image.pixelFormat != newPixelFormat) //(!mod.markConvert && image.pixelFormat != pixelFormat)) { bool dxt1HasAlpha = false; byte dxt1Threshold = 128; if (pixelFormat == PixelFormat.DXT1 && props.GetProp <EnumProperty>("CompressionSettings") is EnumProperty compressionSettings && compressionSettings.Value.Name == "TC_OneBitAlpha") { dxt1HasAlpha = true; if (image.pixelFormat == PixelFormat.ARGB || image.pixelFormat == PixelFormat.DXT3 || image.pixelFormat == PixelFormat.DXT5) { errors += "Warning: Texture was converted from full alpha to binary alpha." + Environment.NewLine; } } //Generate lower mips image.correctMips(newPixelFormat, dxt1HasAlpha, dxt1Threshold); } if (t2d.Mips.Count == 1) { var topMip = image.mipMaps[0]; image.mipMaps.Clear(); image.mipMaps.Add(topMip); } else { // remove lower mipmaps from source image which not exist in game data //Not sure what this does since we just generated most of these mips for (int t = 0; t < image.mipMaps.Count(); t++) { if (image.mipMaps[t].origWidth <= t2d.Mips[0].width && image.mipMaps[t].origHeight <= t2d.Mips[0].height && t2d.Mips.Count > 1) { if (!t2d.Mips.Exists(m => m.width == image.mipMaps[t].origWidth && m.height == image.mipMaps[t].origHeight)) { image.mipMaps.RemoveAt(t--); } } } // put empty mips if missing for (int t = 0; t < t2d.Mips.Count; t++) { if (t2d.Mips[t].width <= image.mipMaps[0].origWidth && t2d.Mips[t].height <= image.mipMaps[0].origHeight) { if (!image.mipMaps.Exists(m => m.origWidth == t2d.Mips[t].width && m.origHeight == t2d.Mips[t].height)) { MipMap mipmap = new MipMap(t2d.Mips[t].width, t2d.Mips[t].height, pixelFormat); image.mipMaps.Add(mipmap); } } } } //if (!texture.properties.exists("LODGroup")) // texture.properties.setByteValue("LODGroup", "TEXTUREGROUP_Character", "TextureGroup", 1025); List <byte[]> compressedMips = new List <byte[]>(); for (int m = 0; m < image.mipMaps.Count(); m++) { if (t2d.Export.Game == MEGame.ME2) { compressedMips.Add(TextureCompression.CompressTexture(image.mipMaps[m].data, StorageTypes.extLZO)); //LZO } else { compressedMips.Add(TextureCompression.CompressTexture(image.mipMaps[m].data, StorageTypes.extZlib)); //ZLib } } List <Texture2DMipInfo> mipmaps = new List <Texture2DMipInfo>(); for (int m = 0; m < image.mipMaps.Count(); m++) { Texture2DMipInfo mipmap = new Texture2DMipInfo(); mipmap.Export = t2d.Export; mipmap.width = image.mipMaps[m].origWidth; mipmap.height = image.mipMaps[m].origHeight; mipmap.TextureCacheName = textureCache; if (t2d.Mips.Exists(x => x.width == mipmap.width && x.height == mipmap.height)) { var oldMip = t2d.Mips.First(x => x.width == mipmap.width && x.height == mipmap.height); mipmap.storageType = oldMip.storageType; } else { mipmap.storageType = t2d.Mips[0].storageType; if (t2d.Mips.Count() > 1) { //Will implement later. ME3Explorer won't support global relinking, that's MEM's job. //if (Export.Game == MEGame.ME1 && matched.linkToMaster == -1) //{ // if (mipmap.storageType == StorageTypes.pccUnc) // { // mipmap.storageType = StorageTypes.pccLZO; // } //} //else if (Export.Game == MEGame.ME1 && matched.linkToMaster != -1) //{ // if (mipmap.storageType == StorageTypes.pccUnc || // mipmap.storageType == StorageTypes.pccLZO || // mipmap.storageType == StorageTypes.pccZlib) // { // mipmap.storageType = StorageTypes.extLZO; // } //} //else } } //ME2,ME3: Force compression type (not implemented yet) if (t2d.Export.Game == MEGame.ME3) { if (mipmap.storageType == StorageTypes.extLZO) //ME3 LZO -> ZLIB { mipmap.storageType = StorageTypes.extZlib; } if (mipmap.storageType == StorageTypes.pccLZO) //ME3 PCC LZO -> PCCZLIB { mipmap.storageType = StorageTypes.pccZlib; } if (mipmap.storageType == StorageTypes.extUnc) //ME3 Uncomp -> ZLib { mipmap.storageType = StorageTypes.extZlib; } //Leave here for future. WE might need this after dealing with double compression //if (mipmap.storageType == StorageTypes.pccUnc && mipmap.width > 32) //ME3 Uncomp -> ZLib // mipmap.storageType = StorageTypes.pccZlib; if (mipmap.storageType == StorageTypes.pccUnc && m < image.mipMaps.Count() - 6 && textureCache != null) //Moving texture to store externally. { mipmap.storageType = StorageTypes.extZlib; } } else if (t2d.Export.Game == MEGame.ME2) { if (mipmap.storageType == StorageTypes.extZlib) //ME2 ZLib -> LZO { mipmap.storageType = StorageTypes.extLZO; } if (mipmap.storageType == StorageTypes.pccZlib) //M2 ZLib -> LZO { mipmap.storageType = StorageTypes.pccLZO; } if (mipmap.storageType == StorageTypes.extUnc) //ME2 Uncomp -> LZO { mipmap.storageType = StorageTypes.extLZO; } //Leave here for future. We might neable this after dealing with double compression //if (mipmap.storageType == StorageTypes.pccUnc && mipmap.width > 32) //ME2 Uncomp -> LZO // mipmap.storageType = StorageTypes.pccLZO; if (mipmap.storageType == StorageTypes.pccUnc && m < image.mipMaps.Count() - 6 && textureCache != null) //Moving texture to store externally. make sure bottom 6 are pcc stored { mipmap.storageType = StorageTypes.extLZO; } } //Investigate. this has something to do with archive storage types //if (mod.arcTexture != null) //{ // if (mod.arcTexture[m].storageType != mipmap.storageType) // { // mod.arcTexture = null; // } //} mipmap.width = image.mipMaps[m].width; mipmap.height = image.mipMaps[m].height; mipmaps.Add(mipmap); if (t2d.Mips.Count() == 1) { break; } } #region MEM code comments. Should probably leave for reference //if (texture.properties.exists("TextureFileCacheName")) //{ // string archive = texture.properties.getProperty("TextureFileCacheName").valueName; // if (mod.arcTfcDLC && mod.arcTfcName != archive) // mod.arcTexture = null; // if (mod.arcTexture == null) // { // archiveFile = Path.Combine(GameData.MainData, archive + ".tfc"); // if (matched.path.ToLowerInvariant().Contains("\\dlc")) // { // mod.arcTfcDLC = true; // string DLCArchiveFile = Path.Combine(Path.GetDirectoryName(GameData.GamePath + matched.path), archive + ".tfc"); // if (File.Exists(DLCArchiveFile)) // archiveFile = DLCArchiveFile; // else if (!File.Exists(archiveFile)) // { // List<string> files = Directory.GetFiles(GameData.bioGamePath, archive + ".tfc", // SearchOption.AllDirectories).Where(item => item.EndsWith(".tfc", StringComparison.OrdinalIgnoreCase)).ToList(); // if (files.Count == 1) // archiveFile = files[0]; // else if (files.Count == 0) // { // using (FileStream fs = new FileStream(DLCArchiveFile, FileMode.CreateNew, FileAccess.Write)) // { // fs.WriteFromBuffer(texture.properties.getProperty("TFCFileGuid").valueStruct); // } // archiveFile = DLCArchiveFile; // newTfcFile = true; // } // else // throw new Exception("More instnces of TFC file: " + archive + ".tfc"); // } // } // else // { // mod.arcTfcDLC = false; // } // // check if texture fit in old space // for (int mip = 0; mip < image.mipMaps.Count(); mip++) // { // Texture.MipMap testMipmap = new Texture.MipMap(); // testMipmap.width = image.mipMaps[mip].origWidth; // testMipmap.height = image.mipMaps[mip].origHeight; // if (ExistMipmap(testMipmap.width, testMipmap.height)) // testMipmap.storageType = texture.getMipmap(testMipmap.width, testMipmap.height).storageType; // else // { // oldSpace = false; // break; // } // if (testMipmap.storageType == StorageTypes.extZlib || // testMipmap.storageType == StorageTypes.extLZO) // { // Texture.MipMap oldTestMipmap = texture.getMipmap(testMipmap.width, testMipmap.height); // if (mod.cacheCprMipmaps[mip].Length > oldTestMipmap.compressedSize) // { // oldSpace = false; // break; // } // } // if (texture.mipMapsList.Count() == 1) // break; // } // long fileLength = new FileInfo(archiveFile).Length; // if (!oldSpace && fileLength + 0x5000000 > 0x80000000) // { // archiveFile = ""; // foreach (TFCTexture newGuid in guids) // { // archiveFile = Path.Combine(GameData.MainData, newGuid.name + ".tfc"); // if (!File.Exists(archiveFile)) // { // texture.properties.setNameValue("TextureFileCacheName", newGuid.name); // texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid); // using (FileStream fs = new FileStream(archiveFile, FileMode.CreateNew, FileAccess.Write)) // { // fs.WriteFromBuffer(newGuid.guid); // } // newTfcFile = true; // break; // } // else // { // fileLength = new FileInfo(archiveFile).Length; // if (fileLength + 0x5000000 < 0x80000000) // { // texture.properties.setNameValue("TextureFileCacheName", newGuid.name); // texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid); // break; // } // } // archiveFile = ""; // } // if (archiveFile == "") // throw new Exception("No free TFC texture file!"); // } // } // else // { // texture.properties.setNameValue("TextureFileCacheName", mod.arcTfcName); // texture.properties.setStructValue("TFCFileGuid", "Guid", mod.arcTfcGuid); // } //} #endregion int allextmipssize = 0; for (int m = 0; m < image.mipMaps.Count(); m++) { Texture2DMipInfo x = mipmaps[m]; var compsize = image.mipMaps[m].data.Length; if (x.storageType == StorageTypes.extZlib || x.storageType == StorageTypes.extLZO || x.storageType == StorageTypes.extUnc) { allextmipssize += compsize; //compsize on Unc textures is same as LZO/ZLib } } //todo: check to make sure TFC will not be larger than 2GiB Guid tfcGuid = Guid.NewGuid(); //make new guid as storage bool locallyStored = mipmaps[0].storageType == StorageTypes.pccUnc || mipmaps[0].storageType == StorageTypes.pccZlib || mipmaps[0].storageType == StorageTypes.pccLZO; for (int m = 0; m < image.mipMaps.Count(); m++) { Texture2DMipInfo mipmap = mipmaps[m]; //if (mipmap.width > 32) //{ // if (mipmap.storageType == StorageTypes.pccUnc) // { // mipmap.storageType = Export.Game == MEGame.ME2 ? StorageTypes.pccLZO : StorageTypes.pccZlib; // } // if (mipmap.storageType == StorageTypes.extUnc) // { // mipmap.storageType = Export.Game == MEGame.ME2 ? StorageTypes.extLZO : StorageTypes.extZlib; // } //} mipmap.uncompressedSize = image.mipMaps[m].data.Length; if (t2d.Export.Game == MEGame.ME1) { if (mipmap.storageType == StorageTypes.pccLZO || mipmap.storageType == StorageTypes.pccZlib) { mipmap.Mip = compressedMips[m]; mipmap.compressedSize = mipmap.Mip.Length; } else if (mipmap.storageType == StorageTypes.pccUnc) { mipmap.compressedSize = mipmap.uncompressedSize; mipmap.Mip = image.mipMaps[m].data; } else { throw new Exception("Unknown mip storage type!"); } } else { if (mipmap.storageType == StorageTypes.extZlib || mipmap.storageType == StorageTypes.extLZO) { if (compressedMips.Count != image.mipMaps.Count()) { throw new Exception("Amount of compressed mips does not match number of mips of incoming image!"); } mipmap.Mip = compressedMips[m]; mipmap.compressedSize = mipmap.Mip.Length; } if (mipmap.storageType == StorageTypes.pccUnc || mipmap.storageType == StorageTypes.extUnc) { mipmap.compressedSize = mipmap.uncompressedSize; mipmap.Mip = image.mipMaps[m].data; } if (mipmap.storageType == StorageTypes.pccLZO || mipmap.storageType == StorageTypes.pccZlib) { mipmap.Mip = compressedMips[m]; mipmap.compressedSize = mipmap.Mip.Length; } if (mipmap.storageType == StorageTypes.extZlib || mipmap.storageType == StorageTypes.extLZO || mipmap.storageType == StorageTypes.extUnc) { if (!string.IsNullOrEmpty(mipmap.TextureCacheName) && mipmap.Export.Game != MEGame.ME1) { //Check local dir string tfcarchive = mipmap.TextureCacheName + ".tfc"; var localDirectoryTFCPath = Path.Combine(Path.GetDirectoryName(mipmap.Export.FileRef.FilePath), tfcarchive); if (File.Exists(localDirectoryTFCPath)) { try { using (FileStream fs = new FileStream(localDirectoryTFCPath, FileMode.Open, FileAccess.ReadWrite)) { tfcGuid = fs.ReadGuid(); fs.Seek(0, SeekOrigin.End); mipmap.externalOffset = (int)fs.Position; fs.Write(mipmap.Mip, 0, mipmap.compressedSize); } } catch (Exception e) { throw new Exception("Problem appending to TFC file " + tfcarchive + ": " + e.Message); } continue; } //Check game var gameFiles = MELoadedFiles.GetFilesLoadedInGame(mipmap.Export.Game, includeTFCs: true); if (gameFiles.TryGetValue(tfcarchive, out string archiveFile)) { try { using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.ReadWrite)) { tfcGuid = fs.ReadGuid(); fs.Seek(0, SeekOrigin.End); mipmap.externalOffset = (int)fs.Position; fs.Write(mipmap.Mip, 0, mipmap.compressedSize); } } catch (Exception e) { throw new Exception("Problem appending to TFC file " + archiveFile + ": " + e.Message); } continue; } //Cache not found. Make new TFC try { using (FileStream fs = new FileStream(localDirectoryTFCPath, FileMode.OpenOrCreate, FileAccess.Write)) { fs.WriteGuid(tfcGuid); mipmap.externalOffset = (int)fs.Position; fs.Write(mipmap.Mip, 0, mipmap.compressedSize); } } catch (Exception e) { throw new Exception("Problem creating new TFC file " + tfcarchive + ": " + e.Message); } continue; } } } mipmaps[m] = mipmap; if (t2d.Mips.Count() == 1) { break; } } t2d.ReplaceMips(mipmaps); //Set properties // The bottom 6 mips are apparently always pcc stored. If there is less than 6 mips, set neverstream to true, which tells game // and toolset to never look into archives for mips. //if (Export.Game == MEGame.ME2 || Export.Game == MEGame.ME3) //{ // if (texture.properties.exists("TextureFileCacheName")) // { // if (texture.mipMapsList.Count < 6) // { // mipmap.storageType = StorageTypes.pccUnc; // texture.properties.setBoolValue("NeverStream", true); // } // else // { // if (Export.Game == MEGame.ME2) // mipmap.storageType = StorageTypes.extLZO; // else // mipmap.storageType = StorageTypes.extZlib; // } // } //} var hasNeverStream = props.GetProp <BoolProperty>("NeverStream") != null; if (locallyStored) { // Rules for default neverstream // 1. Must be Package Stored // 2. Must have at least 6 not empty mips if (mipmaps.Count >= 6) { props.AddOrReplaceProp(new BoolProperty(true, "NeverStream")); } // Side case: NeverStream property was already set, we should respect the value // But won't that always be set here? // Is there a time where we should remove NeverStream? I can't see any logical way // neverstream would be here } if (mipmaps.Count < 6) { props.RemoveNamedProperty("NeverStream"); } if (!locallyStored) { props.AddOrReplaceProp(tfcGuid.ToGuidStructProp("TFCFileGuid")); if (mipmaps[0].storageType == StorageTypes.extLZO || mipmaps[0].storageType == StorageTypes.extUnc || mipmaps[0].storageType == StorageTypes.extZlib) { //Requires texture cache name props.AddOrReplaceProp(new NameProperty(textureCache, "TextureFileCacheName")); } else { //Should not have texture cache name var cacheProp = props.GetProp <NameProperty>("TextureFileCacheName"); if (cacheProp != null) { props.Remove(cacheProp); } } } else { props.RemoveNamedProperty("TFCFileGuid"); } props.AddOrReplaceProp(new IntProperty(t2d.Mips.First().width, "SizeX")); props.AddOrReplaceProp(new IntProperty(t2d.Mips.First().height, "SizeY")); if (t2d.Export.Game < MEGame.ME3 && fileSourcePath != null) { props.AddOrReplaceProp(new StrProperty(fileSourcePath, "SourceFilePath")); props.AddOrReplaceProp(new StrProperty(File.GetLastWriteTimeUtc(fileSourcePath).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), "SourceFileTimestamp")); } var mipTailIdx = props.GetProp <IntProperty>("MipTailBaseIdx"); if (mipTailIdx != null) { mipTailIdx.Value = t2d.Mips.Count - 1; } EndianReader mem = new EndianReader(new MemoryStream()) { Endian = t2d.Export.FileRef.Endian }; props.WriteTo(mem.Writer, t2d.Export.FileRef); mem.Position = 0; var test = PropertyCollection.ReadProps(t2d.Export, mem.BaseStream, "Texture2D", true, true); //do not set properties as this may interfere with some other code. may change later. int propStart = t2d.Export.GetPropertyStart(); var pos = mem.Position; mem.Position = 0; byte[] propData = mem.ToArray(); if (t2d.Export.Game == MEGame.ME3) { t2d.Export.Data = t2d.Export.Data.Take(propStart).Concat(propData).Concat(t2d.SerializeNewData()).ToArray(); } else { var array = t2d.Export.Data.Take(propStart).Concat(propData).ToArray(); var testdata = new MemoryStream(array); var test2 = PropertyCollection.ReadProps(t2d.Export, testdata, "Texture2D", true, true, t2d.Export); //do not set properties as this may interfere with some other code. may change later. //ME2 post-data is this right? t2d.Export.Data = t2d.Export.Data.Take(propStart).Concat(propData).Concat(t2d.SerializeNewData()).ToArray(); } //using (MemoryStream newData = new MemoryStream()) //{ // newData.WriteFromBuffer(texture.properties.toArray()); // newData.WriteFromBuffer(texture.toArray(0, false)); // filled later // package.setExportData(matched.exportID, newData.ToArray()); //} //using (MemoryStream newData = new MemoryStream()) //{ // newData.WriteFromBuffer(texture.properties.toArray()); // newData.WriteFromBuffer(texture.toArray(package.exportsTable[matched.exportID].dataOffset + (uint)newData.Position)); // package.setExportData(matched.exportID, newData.ToArray()); //} //Since this is single replacement, we don't want to relink to master //We want to ensure names are different though, will have to implement into UI //if (Export.Game == MEGame.ME1) //{ // if (matched.linkToMaster == -1) // mod.masterTextures.Add(texture.mipMapsList, entryMap.listIndex); //} //else //{ // if (triggerCacheArc) // { // mod.arcTexture = texture.mipMapsList; // mod.arcTfcGuid = texture.properties.getProperty("TFCFileGuid").valueStruct; // mod.arcTfcName = texture.properties.getProperty("TextureFileCacheName").valueName; // } //} return(errors); }
/// <summary> /// Loads a <see cref="UnityEngine.Texture2D"/> from a local source. /// </summary> /// <param name="scene">Scene where the texture belongs.</param> /// <param name="path">Path to load the texture data.</param> /// <param name="name">Name of the <see cref="UnityEngine.Texture2D"/> to be created.</param> /// <param name="material"><see cref="UnityEngine.Material"/> to assign the <see cref="UnityEngine.Texture2D"/>.</param> /// <param name="propertyName"><see cref="UnityEngine.Material"/> property name to assign to the <see cref="UnityEngine.Texture2D"/>.</param> /// <param name="checkAlphaChannel">If True, checks every image pixel to determine if alpha channel is being used and sets this value.</param> /// <param name="textureWrapMode">Wrap mode of the <see cref="UnityEngine.Texture2D"/> to be created.</param> /// <param name="basePath">Base path to lookup for the <see cref="UnityEngine.Texture2D"/>.</param> /// <param name="onTextureLoaded">Event to trigger when the <see cref="UnityEngine.Texture2D"/> finishes loading.</param> /// <param name="textureCompression">Texture loading compression level.</param> /// <param name="textureFileNameWithoutExtension">Texture filename without the extension.</param> /// <param name="isNormalMap">Is the Texture a Normal Map?</param> /// <returns>The loaded <see cref="UnityEngine.Texture2D"/>.</returns> public static Texture2D LoadTextureFromFile(IntPtr scene, string path, string name, Material material, string propertyName, ref bool checkAlphaChannel, TextureWrapMode textureWrapMode = TextureWrapMode.Repeat, string basePath = null, TextureLoadHandle onTextureLoaded = null, TextureCompression textureCompression = TextureCompression.None, string textureFileNameWithoutExtension = null, bool isNormalMap = false) { if (scene == IntPtr.Zero || string.IsNullOrEmpty(path)) { return(null); } string finalPath; byte[] data; bool isRawData; var width = 0; var height = 0; if (!LoadEmbeddedTextureData(scene, path, out finalPath, out data, out isRawData, out width, out height)) { string filename = null; finalPath = path; data = FileUtils.LoadFileData(finalPath); if (data.Length == 0 && basePath != null) { finalPath = Path.Combine(basePath, path); data = FileUtils.LoadFileData(finalPath); } if (data.Length == 0) { filename = FileUtils.GetFilename(path); finalPath = filename; data = FileUtils.LoadFileData(finalPath); } if (data.Length == 0 && basePath != null && filename != null) { finalPath = Path.Combine(basePath, filename); data = FileUtils.LoadFileData(finalPath); } if (data.Length == 0) { #if TRILIB_OUTPUT_MESSAGES || ASSIMP_OUTPUT_MESSAGES Debug.LogWarningFormat("Texture '{0}' not found", path); #endif return(null); } } Texture2D tempTexture2D; if (ApplyTextureData(data, isRawData, out tempTexture2D, width, height)) { return(ProccessTextureData(tempTexture2D, name, material, propertyName, ref checkAlphaChannel, textureWrapMode, finalPath, onTextureLoaded, textureCompression, isNormalMap)); } #if TRILIB_OUTPUT_MESSAGES || ASSIMP_OUTPUT_MESSAGES Debug.LogErrorFormat("Unable to load texture '{0}'", path); #endif return(null); }
/// <summary> /// Proccesses the texture. /// </summary> /// <returns>The texture.</returns> /// <param name="tempTexture2D">Temp <see cref="UnityEngine.Texture2D"/>.</param> /// <param name="name">Name.</param> /// <param name="material">Material.</param> /// <param name="propertyName">Property name.</param> /// <param name="checkAlphaChannel">Check alpha channel.</param> /// <param name="textureWrapMode">Texture wrap mode.</param> /// <param name="finalPath">Final path.</param> /// <param name="onTextureLoaded">On texture loaded.</param> /// <param name="textureCompression">Texture compression.</param> /// <param name="isNormalMap">If set to <c>true</c> is normal map.</param> public static Texture2D ProccessTextureData(Texture2D tempTexture2D, string name, Material material, string propertyName, ref bool checkAlphaChannel, TextureWrapMode textureWrapMode = TextureWrapMode.Repeat, string finalPath = null, TextureLoadHandle onTextureLoaded = null, TextureCompression textureCompression = TextureCompression.None, bool isNormalMap = false) { if (tempTexture2D == null) { return(null); } tempTexture2D.name = name; tempTexture2D.wrapMode = textureWrapMode; var colors = tempTexture2D.GetPixels32(); Texture2D finalTexture2D; if (isNormalMap) { #if UNITY_5 finalTexture2D = new Texture2D(tempTexture2D.width, tempTexture2D.height, TextureFormat.ARGB32, true); for (var i = 0; i < colors.Length; i++) { var color = colors[i]; color.a = color.r; color.r = 0; color.b = 0; colors[i] = color; } #else finalTexture2D = Texture2D.Instantiate(AssetLoader.NormalBaseTexture); finalTexture2D.filterMode = tempTexture2D.filterMode; finalTexture2D.wrapMode = tempTexture2D.wrapMode; finalTexture2D.Resize(tempTexture2D.width, tempTexture2D.height); #endif finalTexture2D.SetPixels32(colors); finalTexture2D.Apply(); } else { finalTexture2D = new Texture2D(tempTexture2D.width, tempTexture2D.height, TextureFormat.ARGB32, true); finalTexture2D.SetPixels32(colors); finalTexture2D.Apply(); if (textureCompression != TextureCompression.None) { tempTexture2D.Compress(textureCompression == TextureCompression.HighQuality); } } if (checkAlphaChannel) { checkAlphaChannel = false; foreach (var color in colors) { if (color.a != 255) { checkAlphaChannel = true; break; } } } if (material != null) { material.SetTexture(propertyName, finalTexture2D); } if (onTextureLoaded != null) { onTextureLoaded(finalPath, material, propertyName, finalTexture2D); } return(finalTexture2D); }
public void ConvertTo(MEGame newGame) { MEGame oldGame = Game; var prePropBinary = new List <byte[]>(ExportCount); var propCollections = new List <PropertyCollection>(ExportCount); var postPropBinary = new List <ObjectBinary>(ExportCount); if (oldGame == MEGame.ME1 && newGame != MEGame.ME1) { int idx = names.IndexOf("BIOC_Base"); if (idx >= 0) { names[idx] = "SFXGame"; } } else if (newGame == MEGame.ME1) { int idx = names.IndexOf("SFXGame"); if (idx >= 0) { names[idx] = "BIOC_Base"; } } //fix up Default_ imports if (newGame == MEGame.ME3) { using (IMEPackage core = MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.cookedPath, "Core.pcc"))) using (IMEPackage engine = MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.cookedPath, "Engine.pcc"))) using (IMEPackage sfxGame = MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.cookedPath, "SFXGame.pcc"))) { foreach (ImportEntry defImp in imports.Where(imp => imp.ObjectName.Name.StartsWith("Default_")).ToList()) { string packageName = defImp.FullPath.Split('.')[0]; IMEPackage pck = packageName == "Core" ? core : packageName == "Engine" ? engine : packageName == "SFXGame" ? sfxGame : null; if (pck != null && pck.Exports.FirstOrDefault(exp => exp.ObjectName == defImp.ObjectName) is ExportEntry defExp) { var impChildren = defImp.GetChildren(); var expChildren = defExp.GetChildren(); foreach (IEntry expChild in expChildren) { if (impChildren.FirstOrDefault(imp => imp.ObjectName == expChild.ObjectName) is ImportEntry matchingImp) { impChildren.Remove(matchingImp); } else { AddImport(new ImportEntry(this) { idxLink = defImp.UIndex, ClassName = expChild.ClassName, ObjectName = expChild.ObjectName, PackageFile = defImp.PackageFile }); } } foreach (IEntry impChild in impChildren) { EntryPruner.TrashEntries(this, impChild.GetAllDescendants().Prepend(impChild)); } } } } } //purge MaterialExpressions if (newGame == MEGame.ME3) { var entriesToTrash = new List <IEntry>(); foreach (ExportEntry mat in exports.Where(exp => exp.ClassName == "Material").ToList()) { entriesToTrash.AddRange(mat.GetAllDescendants()); } EntryPruner.TrashEntries(this, entriesToTrash.ToHashSet()); } EntryPruner.TrashIncompatibleEntries(this, oldGame, newGame); foreach (ExportEntry export in exports) { //convert stack, or just get the pre-prop binary if no stack prePropBinary.Add(ExportBinaryConverter.ConvertPrePropBinary(export, newGame)); if (export.ClassName == "Class") { propCollections.Add(null); } else { //read in all properties in the old format, and remove ones that are incompatible with newGame propCollections.Add(EntryPruner.RemoveIncompatibleProperties(this, export.GetProperties(), export.ClassName, newGame)); } //convert binary data postPropBinary.Add(ExportBinaryConverter.ConvertPostPropBinary(export, newGame)); //writes header in whatever format is correct for newGame export.RegenerateHeader(newGame, true); } Game = newGame; for (int i = 0; i < exports.Count; i++) { var newData = new MemoryStream(); newData.WriteFromBuffer(prePropBinary[i]); //write back properties in new format propCollections[i]?.WriteTo(newData, this); postPropBinary[i].WriteTo(newData, this, exports[i].DataOffset + exports[i].propsEnd()); //should do this again during Save to get offsets correct //might not matter though exports[i].Data = newData.ToArray(); } if (newGame == MEGame.ME3) { //change all materials to default material, but try to preserve diff and norm textures using var resourcePCC = MEPackageHandler.OpenME3Package(App.CustomResourceFilePath(MEGame.ME3)); var normDiffMat = resourcePCC.Exports.First(exp => exp.ObjectName == "NormDiffMaterial"); foreach (ExportEntry mat in exports.Where(exp => exp.ClassName == "Material" || exp.ClassName == "MaterialInstanceConstant")) { UIndex[] textures = Array.Empty <UIndex>(); if (mat.ClassName == "Material") { textures = ObjectBinary.From <Material>(mat).SM3MaterialResource.UniformExpressionTextures; } else if (mat.GetProperty <BoolProperty>("bHasStaticPermutationResource")?.Value == true) { textures = ObjectBinary.From <MaterialInstance>(mat).SM3StaticPermutationResource.UniformExpressionTextures; } else if (mat.GetProperty <ArrayProperty <StructProperty> >("TextureParameterValues") is ArrayProperty <StructProperty> texParams) { textures = texParams.Select(structProp => new UIndex(structProp.GetProp <ObjectProperty>("ParameterValue")?.Value ?? 0)).ToArray(); } else if (mat.GetProperty <ObjectProperty>("Parent") is ObjectProperty parentProp && GetEntry(parentProp.Value) is ExportEntry parent && parent.ClassName == "Material") { textures = ObjectBinary.From <Material>(parent).SM3MaterialResource.UniformExpressionTextures; } EntryImporter.ReplaceExportDataWithAnother(normDiffMat, mat); int norm = 0; int diff = 0; foreach (UIndex texture in textures) { if (GetEntry(texture) is IEntry tex) { if (diff == 0 && tex.ObjectName.Name.Contains("diff", StringComparison.OrdinalIgnoreCase)) { diff = texture; } else if (norm == 0 && tex.ObjectName.Name.Contains("norm", StringComparison.OrdinalIgnoreCase)) { norm = texture; } } } if (diff == 0) { diff = EntryImporter.GetOrAddCrossImportOrPackage("EngineMaterials.DefaultDiffuse", resourcePCC, this).UIndex; } var matBin = ObjectBinary.From <Material>(mat); matBin.SM3MaterialResource.UniformExpressionTextures = new UIndex[] { norm, diff }; mat.setBinaryData(matBin.ToBytes(this)); mat.Class = imports.First(imp => imp.ObjectName == "Material"); } } if (newGame != MEGame.ME3) { foreach (ExportEntry texport in exports.Where(exp => exp.IsTexture())) { texport.WriteProperty(new BoolProperty(true, "NeverStream")); } } else if (exports.Any(exp => exp.IsTexture() && Texture2D.GetTexture2DMipInfos(exp, null) .Any(mip => mip.storageType == StorageTypes.pccLZO || mip.storageType == StorageTypes.pccZlib))) { //ME3 can't deal with compressed textures in a pcc, so we'll need to stuff them into a tfc string tfcName = Path.GetFileNameWithoutExtension(FilePath); using var tfc = File.OpenWrite(Path.ChangeExtension(FilePath, "tfc")); Guid tfcGuid = Guid.NewGuid(); tfc.WriteGuid(tfcGuid); foreach (ExportEntry texport in exports.Where(exp => exp.IsTexture())) { List <Texture2DMipInfo> mips = Texture2D.GetTexture2DMipInfos(texport, null); var offsets = new List <int>(); foreach (Texture2DMipInfo mipInfo in mips) { if (mipInfo.storageType == StorageTypes.pccLZO || mipInfo.storageType == StorageTypes.pccZlib) { offsets.Add((int)tfc.Position); byte[] mip; if (mipInfo.storageType == StorageTypes.pccLZO) { mip = TextureCompression.CompressTexture(Texture2D.GetTextureData(mipInfo), StorageTypes.extZlib); } else { mip = Texture2D.GetTextureData(mipInfo, false); } tfc.WriteFromBuffer(mip); } } offsets.Add((int)tfc.Position); texport.setBinaryData(ExportBinaryConverter.ConvertTexture2D(texport, Game, offsets, StorageTypes.extZlib)); texport.WriteProperty(new NameProperty(tfcName, "TextureFileCacheName")); texport.WriteProperty(tfcGuid.ToGuidStructProp("TFCFileGuid")); } } }
private static Texture2D ProcessTextureData(Texture2D texture2D, string name, ref bool hasAlphaChannel, TextureWrapMode textureWrapMode, FilterMode textureFilterMode, TextureCompression textureCompression, bool isNormalMap, bool checkAlphaChannel = false, bool generateMipMaps = false) { if (texture2D == null) { return(null); } if (string.IsNullOrEmpty(name)) { texture2D.name = StringUtils.GenerateUniqueName(texture2D); } texture2D.name = name; texture2D.wrapMode = textureWrapMode; texture2D.filterMode = textureFilterMode; var colors = texture2D.GetPixels32(); if (isNormalMap) { var tempTexture2D = new Texture2D(texture2D.width, texture2D.height, TextureFormat.RGBA32, generateMipMaps); tempTexture2D.name = texture2D.name; tempTexture2D.wrapMode = texture2D.wrapMode; tempTexture2D.filterMode = texture2D.filterMode; for (var i = 0; i < colors.Length; i++) { var color = colors[i]; var r = color.r; color.r = color.a; color.a = r; colors[i] = color; } tempTexture2D.SetPixels32(colors); tempTexture2D.Apply(generateMipMaps); UnityEngine.Object.Destroy(texture2D); texture2D = tempTexture2D; } if (!isNormalMap && generateMipMaps) { var tempTexture2D = new Texture2D(texture2D.width, texture2D.height, TextureFormat.RGBA32, true); tempTexture2D.name = texture2D.name; tempTexture2D.wrapMode = texture2D.wrapMode; tempTexture2D.filterMode = texture2D.filterMode; tempTexture2D.SetPixels32(colors); tempTexture2D.Apply(true); if (Application.isPlaying) { UnityEngine.Object.Destroy(texture2D); } else { UnityEngine.Object.DestroyImmediate(texture2D); } texture2D = tempTexture2D; } if (textureCompression != TextureCompression.None) { texture2D.Compress(textureCompression == TextureCompression.HighQuality); } if (checkAlphaChannel) { hasAlphaChannel = false; foreach (var color in colors) { if (color.a == 255) { continue; } hasAlphaChannel = true; break; } } return(texture2D); }
private static Texture2D ProccessTextureData(Texture2D tempTexture2D, string name, ref bool checkAlphaChannel, TextureWrapMode textureWrapMode, string finalPath, TextureCompression textureCompression, bool isNormalMap) { if (tempTexture2D == null) { return(null); } tempTexture2D.name = name; tempTexture2D.wrapMode = textureWrapMode; var colors = tempTexture2D.GetPixels32(); Texture2D finalTexture2D; if (isNormalMap) { #if UNITY_5 finalTexture2D = new Texture2D(tempTexture2D.width, tempTexture2D.height, TextureFormat.ARGB32, true); for (var i = 0; i < colors.Length; i++) { var color = colors[i]; color.a = color.r; color.r = 0; color.b = 0; colors[i] = color; } finalTexture2D.SetPixels32(colors); finalTexture2D.Apply(); #else finalTexture2D = Object.Instantiate(AssetLoaderBase.NormalBaseTexture); finalTexture2D.filterMode = tempTexture2D.filterMode; finalTexture2D.wrapMode = tempTexture2D.wrapMode; finalTexture2D.Resize(tempTexture2D.width, tempTexture2D.height); finalTexture2D.SetPixels32(colors); finalTexture2D.Apply(); #endif } else { finalTexture2D = new Texture2D(tempTexture2D.width, tempTexture2D.height, TextureFormat.ARGB32, true); finalTexture2D.SetPixels32(colors); finalTexture2D.Apply(); if (textureCompression != TextureCompression.None) { tempTexture2D.Compress(textureCompression == TextureCompression.HighQuality); } } if (checkAlphaChannel) { checkAlphaChannel = false; foreach (var color in colors) { if (color.a == 255) { continue; } checkAlphaChannel = true; break; } } return(finalTexture2D); }
internal static void RunNVCompress(BuildContext buildContext, string src, string dst, bool noMips, bool fast, bool toNormal, bool color, bool alpha, bool normal, TextureCompression compression) { string commandLine = ""; if (noMips) { commandLine += " -nomips"; } if (fast) { commandLine += " -fast"; } if (toNormal) { commandLine += " -tonormal"; } if (color) { commandLine += " -color"; } if (alpha) { commandLine += " -alpha"; } if (normal) { commandLine += " -normal"; } commandLine += (" -" + compression.ToString().ToLower()); commandLine += (" \"" + src + "\""); commandLine += (" \"" + dst + "\""); buildContext.RunTool(@"nvcompress.exe", commandLine); //*/ }
private static Texture2D ProccessTextureData(Texture2D inputTexture2D, string name, ref bool hasAlphaChannel, TextureWrapMode textureWrapMode, TextureCompression textureCompression, bool isNormalMap, bool checkAlphaChannel = false) { if (inputTexture2D == null) { return(null); } inputTexture2D.name = name; inputTexture2D.wrapMode = textureWrapMode; if (isNormalMap) { var colors = inputTexture2D.GetPixels32(); #if UNITY_5 Texture2D outputTexture2D = new Texture2D(inputTexture2D.width, inputTexture2D.height, TextureFormat.ARGB32, true); for (var i = 0; i < colors.Length; i++) { var color = colors[i]; color.a = color.r; color.r = 0; color.b = 0; colors[i] = color; } outputTexture2D.SetPixels32(colors); outputTexture2D.Apply(); #else Texture2D outputTexture2D = UnityEngine.Object.Instantiate(AssetLoaderBase.NormalBaseTexture); outputTexture2D.filterMode = inputTexture2D.filterMode; outputTexture2D.wrapMode = inputTexture2D.wrapMode; outputTexture2D.Resize(inputTexture2D.width, inputTexture2D.height); outputTexture2D.SetPixels32(colors); outputTexture2D.Apply(); #endif return(outputTexture2D); } if (textureCompression != TextureCompression.None) { inputTexture2D.Compress(textureCompression == TextureCompression.HighQuality); } if (checkAlphaChannel) { hasAlphaChannel = false; var colors = inputTexture2D.GetPixels32(); foreach (var color in colors) { if (color.a == 255) { continue; } hasAlphaChannel = true; break; } } return(inputTexture2D); }
private static Texture2D ProcessTextureData(Texture2D texture2D, string name, ref bool hasAlphaChannel, TextureWrapMode textureWrapMode, FilterMode textureFilterMode, TextureCompression textureCompression, bool isNormalMap, bool checkAlphaChannel = false, bool generateMipMaps = false) { //FIXME //THIS WAS THE TRUE CULPRIT OF CAMERA FREEZING ON IMPORT I BET IT IS THE SETPIXELLS FUNCTION -- MAYBE THE SETTING IS NOT ACTIVATED ON TEXTURE if (texture2D == null) { return(null); } if (string.IsNullOrEmpty(name)) { name = StringUtils.GenerateUniqueName(texture2D); } texture2D.name = name; texture2D.wrapMode = textureWrapMode; texture2D.filterMode = textureFilterMode; // var colors = texture2D.GetPixels32(); //if (isNormalMap) //{ // var tempTexture2D = new Texture2D(texture2D.width, texture2D.height, TextureFormat.RGBA32, generateMipMaps); // tempTexture2D.name = texture2D.name; // tempTexture2D.wrapMode = texture2D.wrapMode; // tempTexture2D.filterMode = texture2D.filterMode; // for (var i = 0; i < colors.Length; i++) // { // var color = colors[i]; // var r = color.r; // color.r = color.a; // color.a = r; // colors[i] = color; // } // tempTexture2D.SetPixels32(colors); // tempTexture2D.Apply(generateMipMaps); // if (Application.isPlaying) // { // UnityEngine.Object.Destroy(texture2D); // } // else // { // UnityEngine.Object.DestroyImmediate(texture2D); // } // texture2D = tempTexture2D; //} //if (!isNormalMap && generateMipMaps) //{ // var tempTexture2D = new Texture2D(texture2D.width, texture2D.height, TextureFormat.RGBA32, true); // tempTexture2D.name = texture2D.name; // tempTexture2D.wrapMode = texture2D.wrapMode; // tempTexture2D.filterMode = texture2D.filterMode; // tempTexture2D.SetPixels32(colors); // tempTexture2D.Apply(true); // if (Application.isPlaying) // { // UnityEngine.Object.Destroy(texture2D); // } // else // { // UnityEngine.Object.DestroyImmediate(texture2D); // } // texture2D = tempTexture2D; //} //THIS DOESNT CAUSE CRASH if (textureCompression != TextureCompression.None) { var isPowerOfTwo = IsPowerOf2(texture2D.width) && IsPowerOf2(texture2D.height); if (isPowerOfTwo) { texture2D.Compress(textureCompression == TextureCompression.HighQuality); } } //if (checkAlphaChannel) //{ // hasAlphaChannel = false; // foreach (var color in colors) // { // if (color.a == 255) continue; // hasAlphaChannel = true; // break; // } //} return(texture2D); }
/// <summary> /// Loads a <see cref="UnityEngine.Texture2D"/> from an external source. /// </summary> /// <param name="scene">Scene where the texture belongs.</param> /// <param name="path">Path to load the texture data.</param> /// <param name="name">Name of the <see cref="UnityEngine.Texture2D"/> to be created.</param> /// <param name="material"><see cref="UnityEngine.Material"/> to assign the <see cref="UnityEngine.Texture2D"/>.</param> /// <param name="propertyName"><see cref="UnityEngine.Material"/> property name to assign to the <see cref="UnityEngine.Texture2D"/>.</param> /// <param name="textureWrapMode">Wrap mode of the <see cref="UnityEngine.Texture2D"/> to be created.</param> /// <param name="basePath">Base path to lookup for the <see cref="UnityEngine.Texture2D"/>.</param> /// <param name="onTextureLoaded">Event to trigger when the <see cref="UnityEngine.Texture2D"/> finishes loading.</param> /// <param name="textureCompression">Texture loading compression level.</param> /// <param name="textureFileNameWithoutExtension">Texture filename without the extension.</param> public static void LoadTextureFromFile(IntPtr scene, string path, string name, Material material, string propertyName, TextureWrapMode textureWrapMode = TextureWrapMode.Repeat, string basePath = null, TextureLoadHandle onTextureLoaded = null, TextureCompression textureCompression = TextureCompression.None, string textureFileNameWithoutExtension = null) { if (string.IsNullOrEmpty(path)) { return; } bool assimpUncompressed; string finalPath; byte[] data; if (path[0] == '*') { UInt32 slotIndex; if (UInt32.TryParse(path.Substring(1), out slotIndex)) { assimpUncompressed = !AssimpInterop.aiMaterial_IsEmbeddedTextureCompressed(scene, slotIndex); var dataLength = AssimpInterop.aiMaterial_GetEmbeddedTextureDataSize(scene, slotIndex, !assimpUncompressed); data = AssimpInterop.aiMaterial_GetEmbeddedTextureData(scene, slotIndex, dataLength); } else { #if ASSIMP_OUTPUT_MESSAGES Debug.LogWarningFormat("Unable to process embedded texture '{0}'", path); #endif return; } finalPath = StringUtils.GenerateUniqueName(path); } else { finalPath = path; if (!File.Exists(finalPath)) { if (basePath != null) { finalPath = Path.Combine(basePath, path); } } if (!File.Exists(finalPath)) { var filename = Path.GetFileName(path); if (basePath != null) { finalPath = Path.Combine(basePath, filename); } } if (!File.Exists(finalPath)) { #if ASSIMP_OUTPUT_MESSAGES Debug.LogWarningFormat("Texture '{0}' not found", path); #endif return; } data = File.ReadAllBytes(finalPath); assimpUncompressed = false; } bool loaded; Texture2D texture2D; if (assimpUncompressed) { //TODO: additional DLL methods to load actual resolution var textureResolution = Mathf.FloorToInt(Mathf.Sqrt(data.Length / 4)); texture2D = new Texture2D(textureResolution, textureResolution, TextureFormat.ARGB32, false); texture2D.LoadRawTextureData(data); texture2D.Apply(); loaded = true; } else { #if USE_DEVIL && (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN) loaded = IlLoader.LoadTexture2DFromByteArray(data, data.Length, out texture2D); #else texture2D = new Texture2D(2, 2, TextureFormat.RGBA32, false); loaded = texture2D.LoadImage(data); #endif } texture2D.name = name; texture2D.wrapMode = textureWrapMode; if (loaded) { if (textureCompression != TextureCompression.None) { texture2D.Compress(textureCompression == TextureCompression.HighQuality); } material.SetTexture(propertyName, texture2D); if (onTextureLoaded != null) { onTextureLoaded(finalPath, material, propertyName, texture2D); } } else { #if ASSIMP_OUTPUT_MESSAGES Debug.LogErrorFormat("Unable to load texture '{0}'", path); #endif } }
/// <summary> /// Draws the chart to a texture. /// </summary> /// <param name="texture">The output texture.</param> /// <param name="filtering">The filtering applied to the texture when rendered.</param> /// <param name="compression">How much the output texture will be compressed.</param> public static ChartOption DrawToTexture(Texture2D texture, FilterMode filtering, TextureCompression compression) { TextureSettings settings = new TextureSettings(); settings.filtering = filtering; settings.compression = compression; return(new DrawToTextureOption(texture, settings)); }
public static Texture2D LoadTextureFromMemory(byte[] data, string path, ref bool checkAlphaChannel, TextureWrapMode textureWrapMode = TextureWrapMode.Repeat, TextureCompression textureCompression = TextureCompression.None, bool isNormalMap = false, bool isRawData = false, int width = 0, int height = 0) { if (data.Length == 0 || string.IsNullOrEmpty(path)) { return(null); } Texture2D tempTexture2D; if (ApplyTextureData(data, isRawData, out tempTexture2D, width, height)) { return(ProccessTextureData(tempTexture2D, StringUtils.GenerateUniqueName(path.GetHashCode()), ref checkAlphaChannel, textureWrapMode, null, textureCompression, isNormalMap)); } #if TRILIB_OUTPUT_MESSAGES || ASSIMP_OUTPUT_MESSAGES Debug.LogErrorFormat("Unable to load texture '{0}'", path); #endif return(null); }
public static byte[] GetTextureData(Texture2DMipInfo mipToLoad, GameTarget target, bool decompress = true, List <string> additionalTFCs = null) { var imagebytes = new byte[decompress ? mipToLoad.uncompressedSize : mipToLoad.compressedSize]; //Debug.WriteLine("getting texture data for " + mipToLoad.Export.FullPath); if (mipToLoad.storageType == StorageTypes.pccUnc) { Buffer.BlockCopy(mipToLoad.Export.Data, mipToLoad.localExportOffset, imagebytes, 0, mipToLoad.uncompressedSize); } else if (mipToLoad.storageType == StorageTypes.pccLZO || mipToLoad.storageType == StorageTypes.pccZlib) { if (decompress) { try { TextureCompression.DecompressTexture(imagebytes, new MemoryStream(mipToLoad.Export.Data, mipToLoad.localExportOffset, mipToLoad.compressedSize), mipToLoad.storageType, mipToLoad.uncompressedSize, mipToLoad.compressedSize); } catch (Exception e) { throw new Exception($"{e.Message}\nStorageType: {mipToLoad.storageType}\n"); } } else { Buffer.BlockCopy(mipToLoad.Export.Data, mipToLoad.localExportOffset, imagebytes, 0, mipToLoad.compressedSize); } } else if (mipToLoad.storageType == StorageTypes.extUnc || mipToLoad.storageType == StorageTypes.extLZO || mipToLoad.storageType == StorageTypes.extZlib) { string filename = null; List <string> loadedFiles = MEDirectories.EnumerateGameFiles(target.Game, target.TargetPath); if (mipToLoad.Export.Game == Mod.MEGame.ME1) { var fullPath = loadedFiles.FirstOrDefault(x => Path.GetFileName(x).Equals(mipToLoad.TextureCacheName, StringComparison.InvariantCultureIgnoreCase)); if (fullPath != null) { filename = fullPath; } else { throw new FileNotFoundException($"Externally referenced texture file not found in game: {mipToLoad.TextureCacheName}."); } } else { string archive = mipToLoad.TextureCacheName + ".tfc"; var localDirectoryTFCPath = Path.Combine(Path.GetDirectoryName(mipToLoad.Export.FileRef.FilePath), archive); if (File.Exists(localDirectoryTFCPath)) { filename = localDirectoryTFCPath; } else if (additionalTFCs != null && additionalTFCs.Any(x => Path.GetFileName(x).Equals(archive, StringComparison.InvariantCultureIgnoreCase))) { filename = additionalTFCs.First(x => Path.GetFileName(x).Equals(archive, StringComparison.InvariantCultureIgnoreCase)); } else { var tfcs = loadedFiles.Where(x => x.EndsWith(@".tfc")).ToList(); var fullPath = loadedFiles.FirstOrDefault(x => Path.GetFileName(x).Equals(archive, StringComparison.InvariantCultureIgnoreCase)); if (fullPath != null) { filename = fullPath; } else { throw new FileNotFoundException($@"Externally referenced texture cache not found: {archive}."); } } } //exceptions above will prevent filename from being null here try { using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) { try { fs.Seek(mipToLoad.externalOffset, SeekOrigin.Begin); if (mipToLoad.storageType == StorageTypes.extLZO || mipToLoad.storageType == StorageTypes.extZlib) { if (decompress) { using (MemoryStream tmpStream = new MemoryStream(fs.ReadToBuffer(mipToLoad.compressedSize))) { try { TextureCompression.DecompressTexture(imagebytes, tmpStream, mipToLoad.storageType, mipToLoad.uncompressedSize, mipToLoad.compressedSize); } catch (Exception e) { throw new Exception(e.Message + "\n" + "File: " + filename + "\n" + "StorageType: " + mipToLoad.storageType + "\n" + "External file offset: " + mipToLoad.externalOffset); } } } else { fs.Read(imagebytes, 0, mipToLoad.compressedSize); } } else { fs.Read(imagebytes, 0, mipToLoad.uncompressedSize); } } catch (Exception e) { throw new Exception(e.Message + "\n" + "File: " + filename + "\n" + "StorageType: " + mipToLoad.storageType + "\n" + "External file offset: " + mipToLoad.externalOffset); } } } catch (Exception e) { throw new Exception(e.Message + "\n" + "File: " + filename + "\n" + "StorageType: " + mipToLoad.storageType + "\n" + "External file offset: " + mipToLoad.externalOffset); } } return(imagebytes); }
public static void ConvertTo(this MEPackage package, MEGame newGame, string tfcPath = null, bool preserveMaterialInstances = false) { MEGame oldGame = package.Game; var prePropBinary = new List <byte[]>(package.ExportCount); var propCollections = new List <PropertyCollection>(package.ExportCount); var postPropBinary = new List <ObjectBinary>(package.ExportCount); if (oldGame == MEGame.ME1 && newGame != MEGame.ME1) { int idx = package.Names.IndexOf("BIOC_Base"); if (idx >= 0) { package.replaceName(idx, "SFXGame"); } } else if (newGame == MEGame.ME1) { int idx = package.Names.IndexOf("SFXGame"); if (idx >= 0) { package.replaceName(idx, "BIOC_Base"); } } //fix up Default_ package.Imports if (newGame == MEGame.ME3) { using IMEPackage core = MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.CookedPCPath, "Core.pcc")); using IMEPackage engine = MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.CookedPCPath, "Engine.pcc")); using IMEPackage sfxGame = MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.CookedPCPath, "SFXGame.pcc")); foreach (ImportEntry defImp in package.Imports.Where(imp => imp.ObjectName.Name.StartsWith("Default_")).ToList()) { string packageName = defImp.FullPath.Split('.')[0]; IMEPackage pck = packageName switch { "Core" => core, "Engine" => engine, "SFXGame" => sfxGame, _ => null }; if (pck != null && pck.Exports.FirstOrDefault(exp => exp.ObjectName == defImp.ObjectName) is ExportEntry defExp) { List <IEntry> impChildren = defImp.GetChildren(); List <IEntry> expChildren = defExp.GetChildren(); foreach (IEntry expChild in expChildren) { if (impChildren.FirstOrDefault(imp => imp.ObjectName == expChild.ObjectName) is ImportEntry matchingImp) { impChildren.Remove(matchingImp); } else { package.AddImport(new ImportEntry(package) { idxLink = defImp.UIndex, ClassName = expChild.ClassName, ObjectName = expChild.ObjectName, PackageFile = defImp.PackageFile }); } } foreach (IEntry impChild in impChildren) { EntryPruner.TrashEntries(package, impChild.GetAllDescendants().Prepend(impChild)); } } } } //purge MaterialExpressions if (newGame == MEGame.ME3) { var entriesToTrash = new List <IEntry>(); foreach (ExportEntry mat in package.Exports.Where(exp => exp.ClassName == "Material").ToList()) { entriesToTrash.AddRange(mat.GetAllDescendants()); } EntryPruner.TrashEntries(package, entriesToTrash.ToHashSet()); } EntryPruner.TrashIncompatibleEntries(package, oldGame, newGame); foreach (ExportEntry export in package.Exports) { //convert stack, or just get the pre-prop binary if no stack prePropBinary.Add(ExportBinaryConverter.ConvertPrePropBinary(export, newGame)); PropertyCollection props = export.ClassName == "Class" ? null : EntryPruner.RemoveIncompatibleProperties(package, export.GetProperties(), export.ClassName, newGame); propCollections.Add(props); //convert binary data postPropBinary.Add(ExportBinaryConverter.ConvertPostPropBinary(export, newGame, props)); //writes header in whatever format is correct for newGame export.RegenerateHeader(newGame, true); } package.setGame(newGame); for (int i = 0; i < package.Exports.Count; i++) { package.Exports[i].WritePrePropsAndPropertiesAndBinary(prePropBinary[i], propCollections[i], postPropBinary[i]); } if (newGame != MEGame.ME3) //Fix Up Textures before Materials { foreach (ExportEntry texport in package.Exports.Where(exp => exp.IsTexture())) { texport.WriteProperty(new BoolProperty(true, "NeverStream")); } } else if (package.Exports.Any(exp => exp.IsTexture() && Texture2D.GetTexture2DMipInfos(exp, null) .Any(mip => mip.storageType == StorageTypes.pccLZO || mip.storageType == StorageTypes.pccZlib))) { //ME3 can't deal with compressed textures in a pcc, so we'll need to stuff them into a tfc tfcPath ??= Path.ChangeExtension(package.FilePath, "tfc"); string tfcName = Path.GetFileNameWithoutExtension(tfcPath); using var tfc = new FileStream(tfcPath, FileMode.OpenOrCreate, FileAccess.ReadWrite); Guid tfcGuid; if (tfc.Length >= 16) { tfcGuid = tfc.ReadGuid(); tfc.SeekEnd(); } else { tfcGuid = Guid.NewGuid(); tfc.WriteGuid(tfcGuid); } foreach (ExportEntry texport in package.Exports.Where(exp => exp.IsTexture())) { List <Texture2DMipInfo> mips = Texture2D.GetTexture2DMipInfos(texport, null); var offsets = new List <int>(); foreach (Texture2DMipInfo mipInfo in mips) { if (mipInfo.storageType == StorageTypes.pccLZO || mipInfo.storageType == StorageTypes.pccZlib) { offsets.Add((int)tfc.Position); byte[] mip = mipInfo.storageType == StorageTypes.pccLZO ? TextureCompression.CompressTexture(Texture2D.GetTextureData(mipInfo, texport.Game), StorageTypes.extZlib) : Texture2D.GetTextureData(mipInfo, texport.Game, decompress: false); tfc.WriteFromBuffer(mip); } } offsets.Add((int)tfc.Position); texport.WriteBinary(ExportBinaryConverter.ConvertTexture2D(texport, package.Game, offsets, StorageTypes.extZlib)); texport.WriteProperty(new NameProperty(tfcName, "TextureFileCacheName")); texport.WriteProperty(tfcGuid.ToGuidStructProp("TFCFileGuid")); } } if (oldGame == MEGame.ME3 && newGame != MEGame.ME3) { int idx = package.Names.IndexOf("location"); if (idx >= 0) { package.replaceName(idx, "Location"); } } else if (newGame == MEGame.ME3) { int idx = package.Names.IndexOf("Location"); if (idx >= 0) { package.replaceName(idx, "location"); } } if (newGame == MEGame.ME3) //Special handling where materials have been ported between games. { //change all materials to default material, but try to preserve diff and norm textures using var resourcePCC = MEPackageHandler.OpenMEPackageFromStream(ME3ExplorerCoreUtilities.GetCustomAppResourceStream(MEGame.ME3)); var defaultmaster = resourcePCC.Exports.First(exp => exp.ObjectName == "NormDiffMaterial"); var materiallist = package.Exports.Where(exp => exp.ClassName == "Material" || exp.ClassName == "MaterialInstanceConstant").ToList(); foreach (var mat in materiallist) { Debug.WriteLine($"Fixing up {mat.FullPath}"); var masterMat = defaultmaster; var hasDefaultMaster = true; UIndex[] textures = Array.Empty <UIndex>(); if (mat.ClassName == "Material") { textures = ObjectBinary.From <Material>(mat).SM3MaterialResource.UniformExpressionTextures; switch (mat.FullPath) { case "BioT_Volumetric.LAG_MM_Volumetric": case "BioT_Volumetric.LAG_MM_FalloffSphere": case "BioT_LevelMaster.Materials.Opaque_MM": case "BioT_LevelMaster.Materials.GUI_Lit_MM": case "BioT_LevelMaster.Materials.Signage.MM_GUIMaster_Emissive": case "BioT_LevelMaster.Materials.Signage.MM_GUIMaster_Emissive_Fallback": case "BioT_LevelMaster.Materials.Opaque_Standard_MM": case "BioT_LevelMaster.Tech_Inset_MM": case "BioT_LevelMaster.Tech_Border_MM": case "BioT_LevelMaster.Brushed_Metal": masterMat = resourcePCC.Exports.First(exp => exp.FullPath == mat.FullPath); hasDefaultMaster = false; break; default: break; } } else if (mat.GetProperty <BoolProperty>("bHasStaticPermutationResource")?.Value == true) { if (mat.GetProperty <ObjectProperty>("Parent") is ObjectProperty parentProp && package.GetEntry(parentProp.Value) is IEntry parent && parent.ClassName == "Material") { switch (parent.FullPath) { case "BioT_LevelMaster.Materials.Opaque_MM": masterMat = resourcePCC.Exports.First(exp => exp.FullPath == "Materials.Opaque_MM_INST"); hasDefaultMaster = false; break; case "BIOG_APL_MASTER_MATERIAL.Placeable_MM": masterMat = resourcePCC.Exports.First(exp => exp.FullPath == "Materials.Placeable_MM_INST"); hasDefaultMaster = false; break; case "BioT_LevelMaster.Materials.Opaque_Standard_MM": masterMat = resourcePCC.Exports.First(exp => exp.FullPath == "Materials.Opaque_Standard_MM_INST"); hasDefaultMaster = false; break; default: textures = ObjectBinary.From <MaterialInstance>(mat).SM3StaticPermutationResource.UniformExpressionTextures; break; } if (!hasDefaultMaster && mat.GetProperty <ArrayProperty <StructProperty> >("TextureParameterValues") is ArrayProperty <StructProperty> texParams) { textures = texParams.Select(structProp => new UIndex(structProp.GetProp <ObjectProperty>("ParameterValue")?.Value ?? 0)).ToArray(); } } } else if (preserveMaterialInstances) { continue; } else if (mat.GetProperty <ArrayProperty <StructProperty> >("TextureParameterValues") is ArrayProperty <StructProperty> texParams) { textures = texParams.Select(structProp => new UIndex(structProp.GetProp <ObjectProperty>("ParameterValue")?.Value ?? 0)).ToArray(); } else if (mat.GetProperty <ObjectProperty>("Parent") is ObjectProperty parentProp && package.GetEntry(parentProp.Value) is ExportEntry parent && parent.ClassName == "Material") { textures = ObjectBinary.From <Material>(parent).SM3MaterialResource.UniformExpressionTextures; } if (hasDefaultMaster) { EntryImporter.ReplaceExportDataWithAnother(masterMat, mat); int norm = 0; int diff = 0; foreach (UIndex texture in textures) { if (package.GetEntry(texture) is IEntry tex) { if (diff == 0 && tex.ObjectName.Name.Contains("diff", StringComparison.OrdinalIgnoreCase)) { diff = texture; } else if (norm == 0 && tex.ObjectName.Name.Contains("norm", StringComparison.OrdinalIgnoreCase)) { norm = texture; } } } if (diff == 0) { diff = EntryImporter.GetOrAddCrossImportOrPackage("EngineMaterials.DefaultDiffuse", resourcePCC, package).UIndex; } var matBin = ObjectBinary.From <Material>(mat); matBin.SM3MaterialResource.UniformExpressionTextures = new UIndex[] { norm, diff }; mat.WriteBinary(matBin); mat.Class = package.Imports.First(imp => imp.ObjectName == "Material"); } else if (mat.ClassName == "Material") { var mmparent = EntryImporter.GetOrAddCrossImportOrPackage(masterMat.ParentFullPath, resourcePCC, package); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, masterMat, package, mmparent, true, out IEntry targetexp); mat.ReplaceAllReferencesToThisOne(targetexp); EntryPruner.TrashEntryAndDescendants(mat); } else if (mat.ClassName == "MaterialInstanceConstant") { try { var matprops = mat.GetProperties(); var parentlightguid = masterMat.GetProperty <StructProperty>("ParentLightingGuid"); matprops.AddOrReplaceProp(parentlightguid); var mguid = masterMat.GetProperty <StructProperty>("m_Guid"); matprops.AddOrReplaceProp(mguid); var lguid = masterMat.GetProperty <StructProperty>("LightingGuid"); matprops.AddOrReplaceProp(lguid); var masterBin = ObjectBinary.From <MaterialInstance>(masterMat); var matBin = ObjectBinary.From <MaterialInstance>(mat); var staticResTextures3 = masterBin.SM3StaticPermutationResource.UniformExpressionTextures.ToList(); var newtextures3 = new List <UIndex>(); var staticResTextures2 = masterBin.SM2StaticPermutationResource.UniformExpressionTextures.ToList(); var newtextures2 = new List <UIndex>(); IEntry norm = null; IEntry diff = null; IEntry spec = null; foreach (var texref in textures) { IEntry texEnt = package.GetEntry(texref); string texName = texEnt?.ObjectName ?? "None"; if (texName.ToLowerInvariant().Contains("norm")) { norm = texEnt; } else if (texName.ToLowerInvariant().Contains("diff")) { diff = texEnt; } else if (texName.ToLowerInvariant().Contains("spec")) { spec = texEnt; } else if (texName.ToLowerInvariant().Contains("msk")) { spec = texEnt; } } foreach (var texidx in staticResTextures2) { var masterTxt = resourcePCC.GetEntry(texidx); IEntry newTxtEnt = masterTxt; switch (masterTxt?.ObjectName.Name) { case "DefaultDiffuse": if (diff != null) { newTxtEnt = diff; } break; case "DefaultNormal": if (norm != null) { newTxtEnt = norm; } break; case "Gray": //Spec if (spec != null) { newTxtEnt = spec; } break; default: break; } var newtexidx = package.Exports.FirstOrDefault(x => x.FullPath == newTxtEnt.FullPath)?.UIndex ?? 0; if (newtexidx == 0) { newtexidx = package.Imports.FirstOrDefault(x => x.FullPath == newTxtEnt.FullPath)?.UIndex ?? 0; } if (newTxtEnt == masterTxt && newtexidx == 0) { var texparent = EntryImporter.GetOrAddCrossImportOrPackage(newTxtEnt.ParentFullPath, resourcePCC, package); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, newTxtEnt, package, texparent, true, out IEntry newtext); newtextures2.Add(newtext?.UIndex ?? 0); } else { newtextures2.Add(newtexidx); } } foreach (var texidx in staticResTextures3) { var masterTxt = resourcePCC.GetEntry(texidx); IEntry newTxtEnt = masterTxt; switch (masterTxt?.ObjectName) { case "DefaultDiffuse": if (diff != null) { newTxtEnt = diff; } break; case "DefaultNormal": if (norm != null) { newTxtEnt = norm; } break; case "Gray": //Spec if (spec != null) { newTxtEnt = spec; } break; default: break; } var newtexidx = package.Exports.FirstOrDefault(x => x.FullPath == newTxtEnt.FullPath)?.UIndex ?? 0; if (newtexidx == 0) { newtexidx = package.Imports.FirstOrDefault(x => x.FullPath == newTxtEnt.FullPath)?.UIndex ?? 0; } if (newTxtEnt == masterTxt && newtexidx == 0) { var texparent = EntryImporter.GetOrAddCrossImportOrPackage(newTxtEnt.ParentFullPath, resourcePCC, package); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, newTxtEnt, package, texparent, true, out IEntry newtext); newtextures3.Add(newtext?.UIndex ?? 0); } else { newtextures3.Add(newtexidx); } } masterBin.SM2StaticPermutationResource.UniformExpressionTextures = newtextures2.ToArray(); masterBin.SM3StaticPermutationResource.UniformExpressionTextures = newtextures3.ToArray(); mat.WritePropertiesAndBinary(matprops, masterBin); } catch { Debug.WriteLine("MaterialInstanceConversion error"); } } } } } }
public static byte[] GetTextureData(Texture2DMipInfo mipToLoad, MEGame game, string gamePathToUse = null, bool decompress = true, List <string> additionalTFCs = null) { var imagebytes = new byte[decompress ? mipToLoad.uncompressedSize : mipToLoad.compressedSize]; //Debug.WriteLine("getting texture data for " + mipToLoad.Export.FullPath); if (mipToLoad.storageType == StorageTypes.pccUnc) { Buffer.BlockCopy(mipToLoad.Mip, 0, imagebytes, 0, mipToLoad.uncompressedSize); } else if (mipToLoad.storageType == StorageTypes.pccLZO || mipToLoad.storageType == StorageTypes.pccZlib) { if (decompress) { try { TextureCompression.DecompressTexture(imagebytes, new MemoryStream(mipToLoad.Mip), mipToLoad.storageType, mipToLoad.uncompressedSize, mipToLoad.compressedSize); } catch (Exception e) { throw new Exception(GetLocalizedTextureExceptionInternalMessage(e.Message, mipToLoad.storageType.ToString())); } } else { Buffer.BlockCopy(mipToLoad.Mip, 0, imagebytes, 0, mipToLoad.compressedSize); } } else if (mipToLoad.storageType == StorageTypes.extUnc || mipToLoad.storageType == StorageTypes.extLZO || mipToLoad.storageType == StorageTypes.extZlib || mipToLoad.storageType == StorageTypes.extLZMA) { string filename = null; List <string> loadedFiles = MELoadedFiles.GetAllGameFiles(gamePathToUse, game, false, true); if (mipToLoad.Export.Game == MEGame.ME1) { var fullPath = loadedFiles.FirstOrDefault(x => Path.GetFileName(x).Equals(mipToLoad.TextureCacheName, StringComparison.InvariantCultureIgnoreCase)); if (fullPath != null) { filename = fullPath; } else { throw new FileNotFoundException(GetLocalizedCouldNotFindME1TexturePackageMessage(mipToLoad.TextureCacheName)); } } else { string archive = mipToLoad.TextureCacheName + @".tfc"; var localDirectoryTFCPath = Path.Combine(Path.GetDirectoryName(mipToLoad.Export.FileRef.FilePath), archive); if (File.Exists(localDirectoryTFCPath)) { filename = localDirectoryTFCPath; } else if (additionalTFCs != null && additionalTFCs.Any(x => Path.GetFileName(x).Equals(archive, StringComparison.InvariantCultureIgnoreCase))) { filename = additionalTFCs.First(x => Path.GetFileName(x).Equals(archive, StringComparison.InvariantCultureIgnoreCase)); } else { var tfcs = loadedFiles.Where(x => x.EndsWith(@".tfc")).ToList(); var fullPath = loadedFiles.FirstOrDefault(x => Path.GetFileName(x).Equals(archive, StringComparison.InvariantCultureIgnoreCase)); if (fullPath != null) { filename = fullPath; } else { throw new FileNotFoundException(GetLocalizedCouldNotFindME2ME3TextureCacheMessage(archive)); } } } //exceptions above will prevent filename from being null here try { using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) { try { fs.Seek(mipToLoad.externalOffset, SeekOrigin.Begin); if (mipToLoad.storageType == StorageTypes.extLZO || mipToLoad.storageType == StorageTypes.extZlib) { if (decompress) { using (MemoryStream tmpStream = fs.ReadToMemoryStream(mipToLoad.compressedSize)) { try { TextureCompression.DecompressTexture(imagebytes, tmpStream, mipToLoad.storageType, mipToLoad.uncompressedSize, mipToLoad.compressedSize); } catch (Exception e) { throw new Exception(GetLocalizedTextureExceptionExternalMessage(e.Message, filename, mipToLoad.storageType.ToString(), mipToLoad.externalOffset.ToString())); } } } else { fs.Read(imagebytes, 0, mipToLoad.compressedSize); } } else { fs.Read(imagebytes, 0, mipToLoad.uncompressedSize); } } catch (Exception e) { throw new Exception(GetLocalizedTextureExceptionExternalMessage(e.Message, filename, mipToLoad.storageType.ToString(), mipToLoad.externalOffset.ToString())); } } } catch (Exception e) { throw new Exception(GetLocalizedTextureExceptionExternalMessage(e.Message, filename, mipToLoad.storageType.ToString(), mipToLoad.externalOffset.ToString())); } } return(imagebytes); }