2025-04-22 17:16:40 +08:00

349 lines
9.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using UnityEditor;
using UnityEngine;
namespace Unity.HLODSystem.Utils
{
public static class MaterialExtension
{
public static WorkingMaterial ToWorkingMaterial(this Material mat, Allocator allocator)
{
WorkingMaterial wm = new WorkingMaterial(allocator, mat);
return wm;
}
}
public class WorkingMaterial : IDisposable
{
private NativeArray<int> m_detector = new NativeArray<int>(1, Allocator.Persistent);
private WorkingMaterialBuffer m_buffer;
public string Name
{
set { m_buffer.Name = value; }
get { return m_buffer.Name; }
}
public string Guid
{
get { return m_buffer.Guid; }
}
public int InstanceID
{
get { return m_buffer.InstanceID; }
}
public string Identifier
{
get { return m_buffer.Identifier; }
}
private WorkingMaterial()
{
}
public WorkingMaterial(Allocator allocator, Material mat)
{
m_buffer = WorkingMaterialBufferManager.Instance.Get(allocator, mat);
}
public WorkingMaterial(Allocator allocator, int materialId, string name)
{
m_buffer = WorkingMaterialBufferManager.Instance.Create(allocator, materialId, name);
}
public WorkingMaterial Clone()
{
WorkingMaterial nwm = new WorkingMaterial();
nwm.m_buffer = m_buffer;
nwm.m_buffer.AddRef();
return nwm;
}
public bool NeedWrite()
{
return m_buffer.NeedWrite();
}
public void AddTexture(string name, WorkingTexture texture)
{
m_buffer.AddTexture(name, texture);
}
public string[] GetTextureNames()
{
return m_buffer.GetTextureNames();
}
public void SetTexture(string name, WorkingTexture texture)
{
m_buffer.SetTexture(name, texture);
}
public WorkingTexture GetTexture(string name)
{
return m_buffer.GetTexture(name);
}
public Color GetColor(string name)
{
return m_buffer.GetColor(name);
}
public Material ToMaterial()
{
return m_buffer.ToMaterial();
}
public void Dispose()
{
m_buffer.Release();
m_buffer = null;
m_detector.Dispose();
}
}
public class WorkingMaterialBufferManager
{
private static WorkingMaterialBufferManager s_instance;
public static WorkingMaterialBufferManager Instance
{
get
{
if ( s_instance == null )
s_instance = new WorkingMaterialBufferManager();
return s_instance;
}
}
private Dictionary<string, WorkingMaterialBuffer> m_cache = new Dictionary<string, WorkingMaterialBuffer>();
public WorkingMaterialBuffer Get(Allocator allocator, Material material)
{
WorkingMaterialBuffer buffer = null;
string guid = "";
long localId = 0;
if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(material, out guid, out localId) == false)
{
//issue guid for just create
guid = System.Guid.NewGuid().ToString("N");
}
else
{
guid = guid + material.GetInstanceID();
}
if (m_cache.ContainsKey(guid) == false)
{
buffer = new WorkingMaterialBuffer(allocator, material);
m_cache[buffer.Identifier] = buffer;
guid = buffer.Identifier;
}
buffer = m_cache[guid];
buffer.AddRef();
return buffer;
}
public WorkingMaterialBuffer Create(Allocator allocator, int materialId, string name)
{
WorkingMaterialBuffer buffer = new WorkingMaterialBuffer(allocator, materialId, name);
buffer.AddRef();
m_cache[buffer.Identifier] = buffer;
return buffer;
}
public void Destroy(WorkingMaterialBuffer buffer)
{
m_cache.Remove(buffer.Identifier);
}
}
public class WorkingMaterialBuffer : IDisposable
{
private NativeArray<int> m_detector = new NativeArray<int>(1, Allocator.Persistent);
private int m_refCount;
private Allocator m_allocator;
private string m_name;
private string m_guid;
private int m_instanceID;
private DisposableDictionary<string, WorkingTexture> m_textures;
private Dictionary<string, Color> m_colors;
public string Name
{
get => m_name;
set => m_name = value;
}
public string Guid => m_guid;
public int InstanceID => m_instanceID;
public string Identifier
{
get
{
return Guid + InstanceID;
}
}
private WorkingMaterialBuffer(Allocator allocator)
{
m_allocator = allocator;
m_instanceID = 0;
m_textures = new DisposableDictionary<string, WorkingTexture>();
m_colors = new Dictionary<string, Color>();
m_guid = System.Guid.NewGuid().ToString("N");
}
public WorkingMaterialBuffer(Allocator allocator, Material mat) : this(allocator)
{
m_name = mat.name;
m_instanceID = mat.GetInstanceID();
m_textures.Dispose();
m_textures = new DisposableDictionary<string, WorkingTexture>();
m_colors = new Dictionary<string, Color>();
string path = AssetDatabase.GetAssetPath(mat.GetInstanceID());
m_guid = AssetDatabase.AssetPathToGUID(path);
if (string.IsNullOrEmpty(m_guid))
{
m_guid = System.Guid.NewGuid().ToString("N");
}
string[] names = mat.GetTexturePropertyNames();
for (int i = 0; i < names.Length; ++i)
{
Texture2D texture = mat.GetTexture(names[i]) as Texture2D;
if (texture == null)
continue;
m_textures.Add(names[i], texture.ToWorkingTexture(m_allocator));
}
var shader = mat.shader;
if (shader != null)
{
int propertyCount = ShaderUtil.GetPropertyCount(shader);
for (int i = 0; i < propertyCount; ++i)
{
if (ShaderUtil.GetPropertyType(shader, i) == ShaderUtil.ShaderPropertyType.Color)
{
string name = ShaderUtil.GetPropertyName(shader, i);
m_colors.Add(name, mat.GetColor(name));
}
}
}
}
public WorkingMaterialBuffer(Allocator allocator, int materialId, string name) : this(allocator)
{
m_name = name;
m_instanceID = materialId;
m_guid = System.Guid.NewGuid().ToString("N");
}
public void AddRef()
{
m_refCount += 1;
}
public void Release()
{
m_refCount -= 1;
if (m_refCount == 0)
{
WorkingMaterialBufferManager.Instance.Destroy(this);
Dispose();
}
}
public void Dispose()
{
m_textures.Dispose();
m_detector.Dispose();
}
public bool NeedWrite()
{
string path = AssetDatabase.GUIDToAssetPath(m_guid);
return string.IsNullOrEmpty(path);
}
public void AddTexture(string name, WorkingTexture texture)
{
lock (m_textures)
{
m_textures.Add(name, texture);
m_guid = System.Guid.NewGuid().ToString("N");
}
}
public string[] GetTextureNames()
{
lock (m_textures)
{
return m_textures.Keys.ToArray();
}
}
public void SetTexture(string name, WorkingTexture texture)
{
lock (m_textures)
{
if (m_textures.ContainsKey(name) == true && m_textures[name] != null )
m_textures[name].Dispose();
m_textures[name] = texture;
}
}
public WorkingTexture GetTexture(string name)
{
lock (m_textures)
{
WorkingTexture ret;
if (m_textures.TryGetValue(name, out ret))
return ret;
return null;
}
}
public Color GetColor(string name)
{
lock (m_colors)
{
if (m_colors.ContainsKey(name) == false)
return Color.white;
return m_colors[name];
}
}
public Material ToMaterial()
{
Material mat = EditorUtility.InstanceIDToObject(m_instanceID) as Material;
if (mat == null)
{
return new Material(Shader.Find("Standard"));
}
return mat;
}
}
}