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