// SPDX-FileCopyrightText: 2023 Unity Technologies and the glTFast authors // SPDX-License-Identifier: Apache-2.0 using System; using System.IO; using UnityEngine; using UnityEngine.Experimental.Rendering; #if UNITY_EDITOR using UnityEditor; #endif namespace GLTFast.Export { /// class ImageExport : ImageExportBase { static Material s_ColorBlitMaterial; /// /// Main source texture /// protected readonly Texture2D m_Texture; /// /// Preferred image format /// protected ImageFormat m_ImageFormat; #if UNITY_EDITOR /// /// Asset's path /// protected string m_AssetPath; /// /// True if is a valid path /// protected bool ValidAssetPath => !string.IsNullOrEmpty(m_AssetPath) && File.Exists(m_AssetPath); #endif /// /// Default constructor /// /// Main source texture /// Export image format public ImageExport(Texture2D texture, ImageFormat imageFormat = ImageFormat.Unknown) { m_Texture = texture; m_ImageFormat = imageFormat; #if UNITY_EDITOR m_AssetPath = AssetDatabase.GetAssetPath(texture); #endif } /// /// Final export imageFormat /// protected virtual ImageFormat ImageFormat { get { if (m_ImageFormat != ImageFormat.Unknown) return m_ImageFormat; return HasAlpha(m_Texture) ? ImageFormat.Png : ImageFormat.Jpg; } } /// public override string FileName { get { #if UNITY_EDITOR if (ValidAssetPath) { var nameWithoutExtension = Path.GetFileNameWithoutExtension(m_AssetPath); return $"{nameWithoutExtension}.{FileExtension}"; } #endif var name = m_Texture.name; if (string.IsNullOrEmpty(name)) { name = "texture"; } return $"{name}.{FileExtension}"; } } /// public override FilterMode FilterMode => m_Texture != null ? m_Texture.filterMode : FilterMode.Bilinear; /// public override TextureWrapMode WrapModeU => m_Texture != null ? m_Texture.wrapModeU : TextureWrapMode.Repeat; /// public override TextureWrapMode WrapModeV => m_Texture != null ? m_Texture.wrapModeV : TextureWrapMode.Repeat; /// public override string MimeType { get { switch (ImageFormat) { case ImageFormat.Jpg: return Constants.mimeTypeJPG; case ImageFormat.Png: return Constants.mimeTypePNG; case ImageFormat.Unknown: default: throw new ArgumentOutOfRangeException(); } } } /// /// File extension according to image format /// /// protected string FileExtension { get { switch (ImageFormat) { case ImageFormat.Jpg: return "jpg"; case ImageFormat.Png: return "png"; case ImageFormat.Unknown: default: throw new ArgumentOutOfRangeException(); } } } /// /// Encodes the export texture /// /// Destination buffer /// True if encoding succeeded, false otherwise protected virtual bool GenerateTexture(out byte[] imageData) { if (m_Texture != null) { imageData = EncodeTexture(m_Texture, ImageFormat, JpgQuality, blitMaterial: GetColorBlitMaterial()); return imageData != null; } imageData = null; return false; } /// public override bool Write(string filePath, bool overwrite) { #if UNITY_EDITOR if (ValidAssetPath && GetFormatFromExtension(m_AssetPath)==ImageFormat) { File.Copy(m_AssetPath, filePath, overwrite); return true; } #endif if (GenerateTexture(out var imageData)) { File.WriteAllBytes(filePath, imageData); return true; } return false; } /// public override byte[] GetData() { #if UNITY_EDITOR if (ValidAssetPath && GetFormatFromExtension(m_AssetPath)==ImageFormat) { return File.ReadAllBytes(m_AssetPath); } #endif GenerateTexture(out var imageData); return imageData; } /// /// Default hash function. /// /// A hash code for the current object. public override int GetHashCode() { var hash = 13; if (m_Texture != null) { hash = hash * 7 + m_Texture.GetHashCode(); } return hash; } /// /// Determines whether two object instances are equal. /// /// The object to compare with the current object. /// true if the specified object is equal to the current object; otherwise, false. public override bool Equals(object obj) { //Check for null and compare run-time types. if (obj == null || GetType() != obj.GetType()) { return false; } return Equals((ImageExport)obj); } bool Equals(ImageExport other) { return m_Texture == other.m_Texture; } /// /// Creates a blit material from a shader name /// /// Name of the shader to be used (without the "Hidden/" prefix) /// Blit material with requested Shader or null, if Shader wasn't found protected static Material LoadBlitMaterial(string shaderName) { var shader = Shader.Find($"Hidden/{shaderName}"); if (shader == null) { Debug.LogError($"Missing Shader {shaderName}"); return null; } return new Material(shader); } static bool HasAlpha(Texture2D texture) { return GraphicsFormatUtility.HasAlphaChannel(GraphicsFormatUtility.GetGraphicsFormat(texture.format, false)); } #if UNITY_EDITOR static ImageFormat GetFormatFromExtension(string assetPath) { if (assetPath.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) { return ImageFormat.Png; } if (assetPath.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || assetPath.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase)) { return ImageFormat.Jpg; } return ImageFormat.Unknown; } #endif static Material GetColorBlitMaterial() { if (s_ColorBlitMaterial == null) { s_ColorBlitMaterial = LoadBlitMaterial("glTFExportColor"); } return s_ColorBlitMaterial; } } }