/// <summary> /// Third coord is num mipmaps. /// </summary> internal static void FindBestSizeAndMipCountAndFormatForTextureArrays(List <ShaderTextureProperty> texPropertyNames, int maxAtlasSize, MB_TextureArrayFormatSet targetFormatSet, MB_AtlasesAndRects[] resultAtlasesAndRectSlices, TexturePropertyData texturePropertyData) { texturePropertyData.sizes = new Vector2[texPropertyNames.Count]; texturePropertyData.doMips = new bool[texPropertyNames.Count]; texturePropertyData.numMipMaps = new int[texPropertyNames.Count]; texturePropertyData.formats = new TextureFormat[texPropertyNames.Count]; for (int propIdx = 0; propIdx < texPropertyNames.Count; propIdx++) { int numSlices = resultAtlasesAndRectSlices.Length; texturePropertyData.sizes[propIdx] = new Vector3(16, 16, 1); bool hasMips = false; int mipCount = 1; for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++) { Debug.Assert(resultAtlasesAndRectSlices[sliceIdx].atlases.Length == texPropertyNames.Count); Debug.Assert(resultAtlasesAndRectSlices[sliceIdx].texPropertyNames[propIdx] == texPropertyNames[propIdx].name); Texture2D sliceTex = resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx]; if (sliceTex != null) { if (sliceTex.mipmapCount > 1) { hasMips = true; } mipCount = Mathf.Max(mipCount, sliceTex.mipmapCount); texturePropertyData.sizes[propIdx].x = Mathf.Min(Mathf.Max(texturePropertyData.sizes[propIdx].x, sliceTex.width), maxAtlasSize); texturePropertyData.sizes[propIdx].y = Mathf.Min(Mathf.Max(texturePropertyData.sizes[propIdx].y, sliceTex.height), maxAtlasSize); //texturePropertyData.sizes[propIdx].z = Mathf.Max(texturePropertyData.sizes[propIdx].z, sliceTex.mipmapCount); texturePropertyData.formats[propIdx] = targetFormatSet.GetFormatForProperty(texPropertyNames[propIdx].name); } } int numberMipsForMaxAtlasSize = Mathf.CeilToInt(Mathf.Log(maxAtlasSize, 2)) + 1; texturePropertyData.numMipMaps[propIdx] = Mathf.Min(numberMipsForMaxAtlasSize, mipCount); texturePropertyData.doMips[propIdx] = hasMips; } }
/// <summary> /// Creates one texture array per texture property. /// </summary> /// <returns></returns> internal static Texture2DArray[] CreateTextureArraysForResultMaterial(TexturePropertyData texPropertyData, List <ShaderTextureProperty> masterListOfTexProperties, MB_AtlasesAndRects[] resultAtlasesAndRectSlices, bool[] hasTexForProperty, MB3_TextureCombiner combiner, MB2_LogLevel LOG_LEVEL) { Debug.Assert(texPropertyData.sizes.Length == hasTexForProperty.Length); // ASSUMPTION all slices in the same format and the same size, alpha channel and mipMapCount string[] texPropertyNames = resultAtlasesAndRectSlices[0].texPropertyNames; Debug.Assert(texPropertyNames.Length == hasTexForProperty.Length); Texture2DArray[] texArrays = new Texture2DArray[texPropertyNames.Length]; // Each texture property (_MainTex, _Bump, ...) becomes a Texture2DArray for (int propIdx = 0; propIdx < texPropertyNames.Length; propIdx++) { if (!hasTexForProperty[propIdx]) { continue; } string propName = texPropertyNames[propIdx]; int numSlices = resultAtlasesAndRectSlices.Length; int w = (int)texPropertyData.sizes[propIdx].x; int h = (int)texPropertyData.sizes[propIdx].y; int numMips = (int)texPropertyData.numMipMaps[propIdx]; TextureFormat format = texPropertyData.formats[propIdx]; bool doMipMaps = texPropertyData.doMips[propIdx]; Debug.Assert(QualitySettings.desiredColorSpace == QualitySettings.activeColorSpace, "Wanted to use color space " + QualitySettings.desiredColorSpace + " but the activeColorSpace was " + QualitySettings.activeColorSpace + " hardware may not support the desired color space."); bool isLinear = MBVersion.GetProjectColorSpace() == ColorSpace.Linear; { if (IsLinearProperty(masterListOfTexProperties, propName)) { isLinear = true; } else { isLinear = false; } } Texture2DArray texArray = new Texture2DArray(w, h, numSlices, format, doMipMaps, isLinear); if (LOG_LEVEL >= MB2_LogLevel.info) { Debug.LogFormat("Creating Texture2DArray for property: {0} w: {1} h: {2} format: {3} doMips: {4} isLinear: {5}", propName, w, h, format, doMipMaps, isLinear); } for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++) { Debug.Assert(resultAtlasesAndRectSlices[sliceIdx].atlases.Length == texPropertyNames.Length); Debug.Assert(resultAtlasesAndRectSlices[sliceIdx].texPropertyNames[propIdx] == propName); Texture2D srcTex = resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx]; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.LogFormat("Slice: {0} texture: {1}", sliceIdx, srcTex); } bool isCopy = false; if (srcTex == null) { if (LOG_LEVEL >= MB2_LogLevel.trace) { Debug.LogFormat("Texture is null for slice: {0} creating temporary texture", sliceIdx); } // Slices might not have all textures create a dummy if needed. srcTex = combiner._createTemporaryTexture(propName, w, h, format, doMipMaps, isLinear); } Debug.Assert(srcTex.width == texArray.width, "Source texture is not the same width as the texture array '" + srcTex + " srcWidth:" + srcTex.width + " texArrayWidth:" + texArray.width); Debug.Assert(srcTex.height == texArray.height, "Source texture is not the same height as the texture array " + srcTex + " srcWidth:" + srcTex.height + " texArrayWidth:" + texArray.height); Debug.Assert(srcTex.mipmapCount == numMips, "Source texture does have not the same number of mips as the texture array: " + srcTex + " numMipsTex: " + srcTex.mipmapCount + " numMipsTexArray: " + numMips + " texDims: " + srcTex.width + "x" + srcTex.height); Debug.Assert(srcTex.format == format, "Formats should have been converted before this. Texture: " + srcTex + "Source: " + srcTex.format + " Targ: " + format); for (int mipIdx = 0; mipIdx < numMips; mipIdx++) { Graphics.CopyTexture(srcTex, 0, mipIdx, texArray, sliceIdx, mipIdx); } if (isCopy) { MB_Utility.Destroy(srcTex); } } texArray.Apply(); texArrays[propIdx] = texArray; } return(texArrays); }
internal static bool ConvertTexturesToReadableFormat(TexturePropertyData texturePropertyData, MB_AtlasesAndRects[] resultAtlasesAndRectSlices, bool[] hasTexForProperty, List <ShaderTextureProperty> textureShaderProperties, MB3_TextureCombiner combiner, MB2_LogLevel logLevel, List <Texture2D> createdTemporaryTextureAssets, MB2_EditorMethodsInterface textureEditorMethods) { for (int propIdx = 0; propIdx < hasTexForProperty.Length; propIdx++) { if (!hasTexForProperty[propIdx]) { continue; } TextureFormat format = texturePropertyData.formats[propIdx]; if (!textureEditorMethods.TextureImporterFormatExistsForTextureFormat(format)) { Debug.LogError("Could not find target importer format matching " + format); return(false); } int numSlices = resultAtlasesAndRectSlices.Length; int targetWidth = (int)texturePropertyData.sizes[propIdx].x; int targetHeight = (int)texturePropertyData.sizes[propIdx].y; for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++) { Texture2D sliceTex = resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx]; Debug.Assert(sliceTex != null, "sliceIdx " + sliceIdx + " " + propIdx); if (sliceTex != null) { if (!MBVersion.IsTextureReadable(sliceTex)) { textureEditorMethods.SetReadWriteFlag(sliceTex, true, true); } bool isAsset = textureEditorMethods.IsAnAsset(sliceTex); if (logLevel >= MB2_LogLevel.trace) { Debug.Log("Considering format of texture: " + sliceTex + " format:" + sliceTex.format); } if ((sliceTex.width != targetWidth || sliceTex.height != targetHeight) || (!isAsset && sliceTex.format != format)) { // Do this the horrible hard way. It is only possible to resize textures in TrueColor formats, // And only possible to switch formats using the Texture importer. // Create a resized temporary texture asset in ARGB32 format. Then set its texture format and reimport resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx] = textureEditorMethods.CreateTemporaryAssetCopy(textureShaderProperties[propIdx], sliceTex, targetWidth, targetHeight, format, logLevel); createdTemporaryTextureAssets.Add(resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx]); } else if (sliceTex.format != format) { textureEditorMethods.ConvertTextureFormat_PlatformOverride(sliceTex, format, textureShaderProperties[propIdx].isNormalMap); } } else { } if (resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx].format != format) { Debug.LogError("Could not convert texture to format " + format + ". This can happen if the target build platform in build settings does not support textures in this format." + " It may be necessary to switch the build platform in order to build texture arrays in this format."); return(false); } } } return(true); }
/// <summary> /// Creates one texture array per texture property. /// </summary> /// <returns></returns> internal static Texture2DArray[] CreateTextureArraysForResultMaterial(TexturePropertyData texPropertyData, MB_AtlasesAndRects[] resultAtlasesAndRectSlices, bool[] hasTexForProperty, MB3_TextureCombiner combiner, MB2_LogLevel LOG_LEVEL) { Debug.Assert(texPropertyData.sizes.Length == hasTexForProperty.Length); // ASSUMPTION all slices in the same format and the same size, alpha channel and mipMapCount string[] texPropertyNames = resultAtlasesAndRectSlices[0].texPropertyNames; Debug.Assert(texPropertyNames.Length == hasTexForProperty.Length); Texture2DArray[] texArrays = new Texture2DArray[texPropertyNames.Length]; // Each texture property (_MainTex, _Bump, ...) becomes a Texture2DArray for (int propIdx = 0; propIdx < texPropertyNames.Length; propIdx++) { if (!hasTexForProperty[propIdx]) { continue; } int numSlices = resultAtlasesAndRectSlices.Length; int w = (int)texPropertyData.sizes[propIdx].x; int h = (int)texPropertyData.sizes[propIdx].y; int numMips = (int)texPropertyData.numMipMaps[propIdx]; TextureFormat format = texPropertyData.formats[propIdx]; bool doMipMaps = texPropertyData.doMips[propIdx]; Texture2DArray texArray = new Texture2DArray(w, h, numSlices, format, doMipMaps); if (LOG_LEVEL >= MB2_LogLevel.info) { Debug.LogFormat("Creating Texture2DArray for property: {0} w: {1} h: {2} format: {3} doMips: {4}", texPropertyNames[propIdx], w, h, format, doMipMaps); } for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++) { Debug.Assert(resultAtlasesAndRectSlices[sliceIdx].atlases.Length == texPropertyNames.Length); Debug.Assert(resultAtlasesAndRectSlices[sliceIdx].texPropertyNames[propIdx] == texPropertyNames[propIdx]); Texture2D srcTex = resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx]; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.LogFormat("Slice: {0} texture: {1}", sliceIdx, srcTex); } bool isCopy = false; if (srcTex == null) { // Slices might not have all textures create a dummy if needed. srcTex = combiner._createTemporaryTexture(texPropertyNames[propIdx], w, h, format, doMipMaps); } Debug.Assert(srcTex.width == texArray.width, "Source texture is not the same width as the texture array " + srcTex); Debug.Assert(srcTex.height == texArray.height, "Source texture is not the same height as the texture array " + srcTex); Debug.Assert(srcTex.mipmapCount == numMips, "Source texture does have not the same number of mips as the texture array: " + srcTex + " numMipsTex: " + srcTex.mipmapCount + " numMipsTexArray: " + numMips + " texDims: " + srcTex.width + "x" + srcTex.height); Debug.Assert(srcTex.format == format, "Formats should have been converted before this. Texture: " + srcTex + "Source: " + srcTex.format + " Targ: " + format); for (int mipIdx = 0; mipIdx < numMips; mipIdx++) { Graphics.CopyTexture(srcTex, 0, mipIdx, texArray, sliceIdx, mipIdx); } if (isCopy) { MB_Utility.Destroy(srcTex); } } texArray.Apply(); texArrays[propIdx] = texArray; } return(texArrays); }