|
@@ -42,28 +42,70 @@ namespace Spine.Unity.Modules {
|
|
|
public Material material;
|
|
|
}
|
|
|
|
|
|
- static Dictionary<MaterialTexturePair, Material> materialTable;
|
|
|
- internal static Dictionary<MaterialTexturePair, Material> MaterialTable {
|
|
|
+ internal class MaterialWithRefcount {
|
|
|
+ public Material materialClone;
|
|
|
+ public int refcount = 1;
|
|
|
+
|
|
|
+ public MaterialWithRefcount(Material mat) {
|
|
|
+ this.materialClone = mat;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ static Dictionary<MaterialTexturePair, MaterialWithRefcount> materialTable;
|
|
|
+ internal static Dictionary<MaterialTexturePair, MaterialWithRefcount> MaterialTable {
|
|
|
get {
|
|
|
- if (materialTable == null) materialTable = new Dictionary<MaterialTexturePair, Material>();
|
|
|
+ if (materialTable == null) materialTable = new Dictionary<MaterialTexturePair, MaterialWithRefcount>();
|
|
|
return materialTable;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- internal static Material GetMaterialFor (Material materialSource, Texture2D texture) {
|
|
|
+ internal struct SlotMaterialTextureTuple {
|
|
|
+ public Slot slot;
|
|
|
+ public Texture2D texture2D;
|
|
|
+ public Material material;
|
|
|
+
|
|
|
+ public SlotMaterialTextureTuple(Slot slot, Material material, Texture2D texture) {
|
|
|
+ this.slot = slot;
|
|
|
+ this.material = material;
|
|
|
+ this.texture2D = texture;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ internal static Material GetOrAddMaterialFor(Material materialSource, Texture2D texture) {
|
|
|
if (materialSource == null || texture == null) return null;
|
|
|
|
|
|
var mt = SlotBlendModes.MaterialTable;
|
|
|
- Material m;
|
|
|
+ MaterialWithRefcount matWithRefcount;
|
|
|
var key = new MaterialTexturePair { material = materialSource, texture2D = texture };
|
|
|
- if (!mt.TryGetValue(key, out m)) {
|
|
|
- m = new Material(materialSource);
|
|
|
+ if (!mt.TryGetValue(key, out matWithRefcount)) {
|
|
|
+ matWithRefcount = new MaterialWithRefcount(new Material(materialSource));
|
|
|
+ var m = matWithRefcount.materialClone;
|
|
|
m.name = "(Clone)" + texture.name + "-" + materialSource.name;
|
|
|
m.mainTexture = texture;
|
|
|
- mt[key] = m;
|
|
|
+ mt[key] = matWithRefcount;
|
|
|
}
|
|
|
+ else {
|
|
|
+ matWithRefcount.refcount++;
|
|
|
+ }
|
|
|
+ return matWithRefcount.materialClone;
|
|
|
+ }
|
|
|
|
|
|
- return m;
|
|
|
+ internal static MaterialWithRefcount GetExistingMaterialFor(Material materialSource, Texture2D texture)
|
|
|
+ {
|
|
|
+ if (materialSource == null || texture == null) return null;
|
|
|
+
|
|
|
+ var mt = SlotBlendModes.MaterialTable;
|
|
|
+ MaterialWithRefcount matWithRefcount;
|
|
|
+ var key = new MaterialTexturePair { material = materialSource, texture2D = texture };
|
|
|
+ if (!mt.TryGetValue(key, out matWithRefcount)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return matWithRefcount;
|
|
|
+ }
|
|
|
+
|
|
|
+ internal static void RemoveMaterialFromTable(Material materialSource, Texture2D texture) {
|
|
|
+ var mt = SlotBlendModes.MaterialTable;
|
|
|
+ var key = new MaterialTexturePair { material = materialSource, texture2D = texture };
|
|
|
+ mt.Remove(key);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
@@ -74,17 +116,19 @@ namespace Spine.Unity.Modules {
|
|
|
Texture2D texture;
|
|
|
#endregion
|
|
|
|
|
|
+ SlotMaterialTextureTuple[] slotsWithCustomMaterial = new SlotMaterialTextureTuple[0];
|
|
|
+
|
|
|
public bool Applied { get; private set; }
|
|
|
|
|
|
- void Start () {
|
|
|
+ void Start() {
|
|
|
if (!Applied) Apply();
|
|
|
}
|
|
|
|
|
|
- void OnDestroy () {
|
|
|
+ void OnDestroy() {
|
|
|
if (Applied) Remove();
|
|
|
}
|
|
|
|
|
|
- public void Apply () {
|
|
|
+ public void Apply() {
|
|
|
GetTexture();
|
|
|
if (texture == null) return;
|
|
|
|
|
@@ -93,13 +137,36 @@ namespace Spine.Unity.Modules {
|
|
|
|
|
|
var slotMaterials = skeletonRenderer.CustomSlotMaterials;
|
|
|
|
|
|
+ int numSlotsWithCustomMaterial = 0;
|
|
|
foreach (var s in skeletonRenderer.Skeleton.Slots) {
|
|
|
switch (s.data.blendMode) {
|
|
|
case BlendMode.Multiply:
|
|
|
- if (multiplyMaterialSource != null) slotMaterials[s] = GetMaterialFor(multiplyMaterialSource, texture);
|
|
|
+ if (multiplyMaterialSource != null) {
|
|
|
+ slotMaterials[s] = GetOrAddMaterialFor(multiplyMaterialSource, texture);
|
|
|
+ ++numSlotsWithCustomMaterial;
|
|
|
+ }
|
|
|
break;
|
|
|
case BlendMode.Screen:
|
|
|
- if (screenMaterialSource != null) slotMaterials[s] = GetMaterialFor(screenMaterialSource, texture);
|
|
|
+ if (screenMaterialSource != null) {
|
|
|
+ slotMaterials[s] = GetOrAddMaterialFor(screenMaterialSource, texture);
|
|
|
+ ++numSlotsWithCustomMaterial;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ slotsWithCustomMaterial = new SlotMaterialTextureTuple[numSlotsWithCustomMaterial];
|
|
|
+ int storedSlotIndex = 0;
|
|
|
+ foreach (var s in skeletonRenderer.Skeleton.Slots) {
|
|
|
+ switch (s.data.blendMode) {
|
|
|
+ case BlendMode.Multiply:
|
|
|
+ if (multiplyMaterialSource != null) {
|
|
|
+ slotsWithCustomMaterial[storedSlotIndex++] = new SlotMaterialTextureTuple(s, multiplyMaterialSource, texture);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case BlendMode.Screen:
|
|
|
+ if (screenMaterialSource != null) {
|
|
|
+ slotsWithCustomMaterial[storedSlotIndex++] = new SlotMaterialTextureTuple(s, screenMaterialSource, texture);
|
|
|
+ }
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -108,7 +175,7 @@ namespace Spine.Unity.Modules {
|
|
|
skeletonRenderer.LateUpdate();
|
|
|
}
|
|
|
|
|
|
- public void Remove () {
|
|
|
+ public void Remove() {
|
|
|
GetTexture();
|
|
|
if (texture == null) return;
|
|
|
|
|
@@ -117,26 +184,32 @@ namespace Spine.Unity.Modules {
|
|
|
|
|
|
var slotMaterials = skeletonRenderer.CustomSlotMaterials;
|
|
|
|
|
|
- foreach (var s in skeletonRenderer.Skeleton.Slots) {
|
|
|
- Material m = null;
|
|
|
+ foreach (var slotWithCustomMat in slotsWithCustomMaterial) {
|
|
|
|
|
|
- switch (s.data.blendMode) {
|
|
|
- case BlendMode.Multiply:
|
|
|
- if (slotMaterials.TryGetValue(s, out m) && Material.ReferenceEquals(m, GetMaterialFor(multiplyMaterialSource, texture)))
|
|
|
- slotMaterials.Remove(s);
|
|
|
- break;
|
|
|
- case BlendMode.Screen:
|
|
|
- if (slotMaterials.TryGetValue(s, out m) && Material.ReferenceEquals(m, GetMaterialFor(screenMaterialSource, texture)))
|
|
|
+ Slot s = slotWithCustomMat.slot;
|
|
|
+ Material storedMaterialSource = slotWithCustomMat.material;
|
|
|
+ Texture2D storedTexture = slotWithCustomMat.texture2D;
|
|
|
+
|
|
|
+ var matWithRefcount = GetExistingMaterialFor(storedMaterialSource, storedTexture);
|
|
|
+ if (--matWithRefcount.refcount == 0) {
|
|
|
+ RemoveMaterialFromTable(storedMaterialSource, storedTexture);
|
|
|
+ }
|
|
|
+ // we don't want to remove slotMaterials[s] if it has been changed in the meantime.
|
|
|
+ Material m;
|
|
|
+ if (slotMaterials.TryGetValue(s, out m)) {
|
|
|
+ var existingMat = matWithRefcount == null ? null : matWithRefcount.materialClone;
|
|
|
+ if (Material.ReferenceEquals(m, existingMat)) {
|
|
|
slotMaterials.Remove(s);
|
|
|
- break;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+ slotsWithCustomMaterial = null;
|
|
|
+
|
|
|
Applied = false;
|
|
|
if (skeletonRenderer.valid) skeletonRenderer.LateUpdate();
|
|
|
}
|
|
|
|
|
|
- public void GetTexture () {
|
|
|
+ public void GetTexture() {
|
|
|
if (texture == null) {
|
|
|
var sr = GetComponent<SkeletonRenderer>(); if (sr == null) return;
|
|
|
var sda = sr.skeletonDataAsset; if (sda == null) return;
|
|
@@ -146,7 +219,6 @@ namespace Spine.Unity.Modules {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
}
|
|
|
}
|
|
|
|