Files
AR-Menu/Library/PackageCache/com.needle.engine-exporter@8c046140a1d9/Gltf/Editor/TextureSettings/TextureCompressionHandler.cs
2025-11-30 08:35:03 +02:00

225 lines
7.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
using Needle.Engine.Gltf.Experimental;
using Needle.Engine.Gltf.Experimental.progressive;
using Needle.Engine.Utils;
using UnityEngine;
using UnityGLTF;
using Object = UnityEngine.Object;
namespace Needle.Engine.Gltf
{
[UsedImplicitly]
public class TextureCompressionHandler : GltfExtensionHandlerBase, ITextureExportHandler
{
private static NeedleCompressionSettings defaultCompressionSettings;
public override void OnBeforeExport(GltfExportContext context)
{
base.OnBeforeExport(context);
TextureExportHandlerRegistry.Register(this);
if (!defaultCompressionSettings)
defaultCompressionSettings = Object.FindAnyObjectByType<NeedleCompressionSettings>();
}
public bool OnTextureExport(GltfExportContext context,
ref TextureExportSettings textureSettings,
string textureSlot,
List<object> extensions)
{
var texture = textureSettings.Texture;
if (!texture)
{
return false;
}
if (texture is RenderTexture rt)
{
extensions.Add(new NEEDLE_progressive_texture_settings(rt.GetId(), -1, false));
return true;
}
if (texture.IsHDR())
{
return false;
}
var lm = LightmapSettings.lightmaps;
foreach (var lightmap in lm)
{
if (texture == lightmap.lightmapColor)
{
return false;
}
}
// First check if we have a use progressive textures component on the exported asset
var compressionSettings = defaultCompressionSettings;
if (context.Root.TryGetComponent(out NeedleCompressionSettings rootSettings))
{
compressionSettings = rootSettings;
}
// Set the texture max size for UnityGltf
if (compressionSettings)
textureSettings.MaxSize = Mathf.Min(textureSettings.MaxSize, compressionSettings.TextureMaxSize);
var ext = CreateCompressionSettings(context, compressionSettings, ref textureSettings, textureSlot);
if (ext != null) extensions.Add(ext);
if (texture is Texture2D tex2d && compressionSettings != null)
{
// Texture LODs are disabled:
if (compressionSettings.GenerateTextureLODs == false)
{
// Workaround to disable progressive textures: setting an invalid max size to -1
extensions.Add(new NEEDLE_progressive_texture_settings(tex2d.GetId(), -1, false));
}
else
{
// We only need to load it progressively if the texture is larger than the max size
if (compressionSettings.LODsMaxSize < Mathf.Max(tex2d.width, tex2d.height))
{
extensions.Add(new NEEDLE_progressive_texture_settings(tex2d.GetId(),
compressionSettings.LODsMaxSize));
}
}
}
return true;
}
private static NEEDLE_compression_texture CreateCompressionSettings(IExportContext context,
NeedleCompressionSettings compressionSettings,
ref TextureExportSettings exportSettings,
string textureSlot)
{
#if UNITY_EDITOR
if (compressionSettings && compressionSettings.DefaultTextureFormat == TextureCompressionMode.None)
{
return new NEEDLE_compression_texture(TextureCompressionMode.None.Serialize(), textureSlot);
}
#if !UNITY_6000_0_OR_NEWER
// Get importer settings. This feature is discontinued in Unity 6
if (NeedleAssetSettingsProvider.TryGetTextureSettings(exportSettings.Texture, out var needleSettings) &&
needleSettings.Override)
{
var compressionMode = needleSettings.CompressionMode.Serialize();
switch (needleSettings.CompressionMode)
{
case TextureCompressionMode.Automatic:
case TextureCompressionMode.Product:
case TextureCompressionMode.World:
compressionMode = GetCompressionModeFromSlot(compressionSettings, exportSettings, textureSlot);
break;
}
if (compressionMode != null)
{
var quality = needleSettings.CompressionQualitySupported
? (needleSettings.CompressionQuality / 100f)
: -1;
var settings = new NEEDLE_compression_texture(compressionMode, textureSlot, quality);
settings.maxSize = needleSettings.MaxSize;
exportSettings.MaxSize = needleSettings.MaxSize;
return settings;
}
}
#endif
var texturePath = UnityEditor.AssetDatabase.GetAssetPath(exportSettings.Texture);
if (!string.IsNullOrEmpty(texturePath))
{
// check asset tags
var tags = UnityEditor.AssetDatabase.GetLabels(exportSettings.Texture);
if (TryGetCompressionModeFromAssetLabels(tags, out var mode))
return new NEEDLE_compression_texture(mode, textureSlot);
if (UnityEditor.EditorUtility.IsPersistent(context.Root))
{
var rootTags = UnityEditor.AssetDatabase.GetLabels(context.Root);
if (TryGetCompressionModeFromAssetLabels(rootTags, out mode))
return new NEEDLE_compression_texture(mode, textureSlot);
}
// Export sprite textures using UASTC
var importer = UnityEditor.AssetImporter.GetAtPath(texturePath) as UnityEditor.TextureImporter;
if (importer && importer.textureType == UnityEditor.TextureImporterType.Sprite)
{
return new NEEDLE_compression_texture(TextureCompressionMode.UASTC.Serialize(), textureSlot);
}
}
#endif
// Auto: we don't insert any extension into the texture here because this should be all determined by the build pipeline
// We don't want multiple tools having an opinion here
return null;
}
private static bool TryGetCompressionModeFromAssetLabels(string[] labels, out string mode)
{
if (labels != null)
{
foreach (var tag in labels)
{
if (tag.Equals(TextureCompressionMode.UASTC.Serialize(), StringComparison.OrdinalIgnoreCase))
{
mode = TextureCompressionMode.UASTC.Serialize();
return true;
}
if (tag.Equals(TextureCompressionMode.ETC1S.Serialize(), StringComparison.OrdinalIgnoreCase))
{
mode = TextureCompressionMode.ETC1S.Serialize();
return true;
}
if (tag.Equals(TextureCompressionMode.WebP.Serialize(), StringComparison.OrdinalIgnoreCase))
{
mode = TextureCompressionMode.WebP.Serialize();
return true;
}
}
}
mode = null;
return false;
}
private static string GetCompressionModeFromSlot(NeedleCompressionSettings settings,
TextureExportSettings textureExportSettings,
string textureSlot)
{
switch (textureSlot)
{
case GLTFSceneExporter.TextureMapType.BaseColor:
case GLTFSceneExporter.TextureMapType.Emissive:
case GLTFSceneExporter.TextureMapType.Occlusion:
case GLTFSceneExporter.TextureMapType.sRGB:
return TextureCompressionMode.ETC1S.Serialize();
case GLTFSceneExporter.TextureMapType.Normal:
case GLTFSceneExporter.TextureMapType.MetallicRoughness:
case GLTFSceneExporter.TextureMapType.Linear:
if (settings && settings.DefaultTextureFormat == TextureCompressionMode.Product)
return TextureCompressionMode.WebP.Serialize();
return TextureCompressionMode.UASTC.Serialize();
}
// if we haven't catched the right slot above, we differentiate by linear setting
if (textureExportSettings.Linear)
{
if (settings && settings.DefaultTextureFormat == TextureCompressionMode.Product)
return TextureCompressionMode.WebP.Serialize();
return TextureCompressionMode.UASTC.Serialize();
}
return TextureCompressionMode.ETC1S.Serialize();
}
}
}