MayHeCome/Assets/Exoa/TutorialEngine/Masking/Scripts/MaterialReplacements.cs
2024-12-18 17:55:34 +08:00

90 lines
3.0 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
namespace Maskable {
class MaterialReplacements {
readonly IMaterialReplacer _replacer;
readonly Action<Material> _applyParameters;
readonly List<MaterialOverride> _overrides = new List<MaterialOverride>();
public MaterialReplacements(IMaterialReplacer replacer, Action<Material> applyParameters) {
_replacer = replacer;
_applyParameters = applyParameters;
}
public Material Get(Material original) {
for (int i = 0; i < _overrides.Count; ++i) {
var entry = _overrides[i];
if (ReferenceEquals(entry.original, original)) {
var existing = entry.Get();
if (existing) { // null may be stored in _overrides
existing.CopyPropertiesFromMaterial(original);
_applyParameters(existing);
}
return existing;
}
}
var replacement = _replacer.Replace(original);
if (replacement) {
Assert.AreNotEqual(original, replacement, "IMaterialRepalcer should not return the original material");
replacement.hideFlags = HideFlags.HideAndDontSave;
_applyParameters(replacement);
}
_overrides.Add(new MaterialOverride(original, replacement));
return replacement;
}
public void Release(Material replacement) {
for (int i = 0; i < _overrides.Count; ++i) {
var entry = _overrides[i];
if (entry.replacement == replacement)
if (entry.Release()) {
UnityEngine.Object.DestroyImmediate(replacement);
_overrides.RemoveAt(i);
return;
}
}
}
public void ApplyAll() {
for (int i = 0; i < _overrides.Count; ++i) {
var mat = _overrides[i].replacement;
if (mat)
_applyParameters(mat);
}
}
public void DestroyAllAndClear() {
for (int i = 0; i < _overrides.Count; ++i)
UnityEngine.Object.DestroyImmediate(_overrides[i].replacement);
_overrides.Clear();
}
class MaterialOverride {
int _useCount;
public MaterialOverride(Material original, Material replacement) {
this.original = original;
this.replacement = replacement;
_useCount = 1;
}
public Material original { get; private set; }
public Material replacement { get; private set; }
public Material Get() {
++_useCount;
return replacement;
}
public bool Release() {
Assert.IsTrue(_useCount > 0);
return --_useCount == 0;
}
}
}
}