Forráskód Böngészése

[unity] Fixed on-demand loading of blend mode materials. See #1890.

Harald Csaszar 10 hónapja
szülő
commit
12bc8ae24d

+ 5 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/OnDemandTextureLoader.cs

@@ -36,6 +36,11 @@ using UnityEngine;
 namespace Spine.Unity {
 	public abstract class OnDemandTextureLoader : ScriptableObject {
 		public AtlasAssetBase atlasAsset;
+		/// <summary>
+		/// Additional <see cref="SkeletonDataAsset"/> reference, currently only used to cover blend mode materials
+		/// which are not stored at <c>atlasAsset</c>.
+		/// </summary>
+		public SkeletonDataAsset skeletonDataAsset;
 
 		/// <param name="originalTextureName">Original texture name without extension.</param>
 		/// <returns>The placeholder texture's name for a given original target texture name.</returns>

+ 1 - 1
spine-unity/Assets/Spine/package.json

@@ -2,7 +2,7 @@
 	"name": "com.esotericsoftware.spine.spine-unity",
 	"displayName": "spine-unity Runtime",
 	"description": "This plugin provides the spine-unity runtime core.",
-	"version": "4.2.88",
+	"version": "4.2.89",
 	"unity": "2018.3",
 	"author": {
 		"name": "Esoteric Software",

+ 36 - 0
spine-unity/Modules/com.esotericsoftware.spine.on-demand-loading/Editor/GenericOnDemandTextureLoaderInspector.cs

@@ -59,6 +59,7 @@ namespace Spine.Unity.Editor {
 		where TextureRequest : Spine.Unity.IOnDemandRequest {
 
 		protected SerializedProperty atlasAsset;
+		protected SerializedProperty skeletonDataAsset;
 		protected SerializedProperty maxPlaceholderSize;
 		protected SerializedProperty placeholderMap;
 		protected SerializedProperty unloadAfterSecondsUnused;
@@ -172,6 +173,39 @@ namespace Spine.Unity.Editor {
 				// assign late since CreatePlaceholderTextureFor(texture) method above might save assets and clear these values.
 				loader.placeholderMap = materialMap;
 				loader.atlasAsset = atlasAsset;
+				if (loader.skeletonDataAsset == null)
+					AssignSkeletonDataAsset(loader, atlasAsset);
+			}
+
+			protected void AssignSkeletonDataAsset(GenericOnDemandTextureLoader<TargetReference, TextureRequest> loader, AtlasAssetBase atlasAsset) {
+				string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset);
+				string parentFolder = System.IO.Path.GetDirectoryName(atlasAssetPath);
+
+				SkeletonDataAsset skeletonDataAsset = FindSkeletonDataAsset(parentFolder, atlasAsset);
+				if (skeletonDataAsset) {
+					loader.skeletonDataAsset = skeletonDataAsset;
+					return;
+				}
+				string nextParentFolder = System.IO.Path.GetDirectoryName(parentFolder);
+				skeletonDataAsset = FindSkeletonDataAsset(nextParentFolder, atlasAsset);
+				if (skeletonDataAsset) {
+					loader.skeletonDataAsset = skeletonDataAsset;
+					return;
+				}
+			}
+
+			protected SkeletonDataAsset FindSkeletonDataAsset (string searchFolder, AtlasAssetBase atlasAsset) {
+				string[] guids = AssetDatabase.FindAssets("t:SkeletonDataAsset", new[] { searchFolder });
+				foreach (string guid in guids) {
+					string assetPath = AssetDatabase.GUIDToAssetPath(guid);
+					SkeletonDataAsset skeletonDataAsset = AssetDatabase.LoadAssetAtPath<SkeletonDataAsset>(assetPath);
+					if (skeletonDataAsset != null) {
+						if (skeletonDataAsset.atlasAssets.Contains(atlasAsset)) {
+							return skeletonDataAsset;
+						}
+					}
+				}
+				return null;
 			}
 
 			public virtual Texture CreatePlaceholderTextureFor (Texture originalTexture, int maxPlaceholderSize,
@@ -244,6 +278,7 @@ namespace Spine.Unity.Editor {
 
 		void OnEnable () {
 			atlasAsset = serializedObject.FindProperty("atlasAsset");
+			skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset");
 			maxPlaceholderSize = serializedObject.FindProperty("maxPlaceholderSize");
 			placeholderMap = serializedObject.FindProperty("placeholderMap");
 			unloadAfterSecondsUnused = serializedObject.FindProperty("unloadAfterSecondsUnused");
@@ -352,6 +387,7 @@ namespace Spine.Unity.Editor {
 			serializedObject.Update();
 
 			EditorGUILayout.PropertyField(atlasAsset);
+			EditorGUILayout.PropertyField(skeletonDataAsset);
 			EditorGUILayout.PropertyField(maxPlaceholderSize);
 			EditorGUILayout.PropertyField(unloadAfterSecondsUnused);
 

+ 111 - 24
spine-unity/Modules/com.esotericsoftware.spine.on-demand-loading/Runtime/GenericOnDemandTextureLoader.cs

@@ -33,10 +33,12 @@
 
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using UnityEngine;
 
 namespace Spine.Unity {
+	using ReplacementMaterial = BlendModeMaterials.ReplacementMaterial;
 
 	/// <summary>
 	/// Interface to derive a concrete target reference struct from which holds
@@ -114,9 +116,11 @@ namespace Spine.Unity {
 			modifiedMaterials = null;
 			if (!atlasAsset) return false;
 
+			int normalMaterialCount = atlasAsset.Materials.Count();
+			IEnumerable<Material> inputMaterials = GetInputMaterials();
 			int materialIndex = 0;
-			foreach (Material targetMaterial in atlasAsset.Materials) {
-				if (materialIndex >= placeholderMap.Length) {
+			foreach (Material targetMaterial in inputMaterials) {
+				if ((materialIndex < normalMaterialCount) && (materialIndex >= placeholderMap.Length)) {
 					Debug.LogError(string.Format("Failed to assign placeholder textures at {0}, material #{1} {2}. " +
 						"It seems like the GenericOnDemandTextureLoader asset was not setup accordingly for the AtlasAsset.",
 						atlasAsset, materialIndex + 1, targetMaterial), this);
@@ -134,17 +138,19 @@ namespace Spine.Unity {
 						mapIndex = foundMapIndex;
 				}
 #endif
-				Texture placeholderTexture = placeholderMap[mapIndex].textures[textureIndex].placeholderTexture;
-				if (placeholderTexture == null) {
-					Debug.LogWarning(string.Format("Placeholder texture set to null at {0}, for material #{1} {2}. " +
-						"It seems like the GenericOnDemandTextureLoader asset was not setup accordingly for the AtlasAsset.",
-						atlasAsset, materialIndex + 1, targetMaterial), this);
-				} else {
-					targetMaterial.mainTexture = placeholderTexture;
+				if (mapIndex < normalMaterialCount) {
+					Texture placeholderTexture = placeholderMap[mapIndex].textures[textureIndex].placeholderTexture;
+					if (placeholderTexture == null) {
+						Debug.LogWarning(string.Format("Placeholder texture set to null at {0}, for material #{1} {2}. " +
+							"It seems like the GenericOnDemandTextureLoader asset was not setup accordingly for the AtlasAsset.",
+							atlasAsset, materialIndex + 1, targetMaterial), this);
+					} else {
+						targetMaterial.mainTexture = placeholderTexture;
+					}
 				}
 				++materialIndex;
 			}
-			modifiedMaterials = atlasAsset.Materials;
+			modifiedMaterials = inputMaterials;
 			return true;
 		}
 
@@ -153,18 +159,14 @@ namespace Spine.Unity {
 			if (!atlasAsset) return false;
 
 			bool anyPlaceholderAssigned = false;
-
-			int materialIndex = 0;
-			foreach (Material material in atlasAsset.Materials) {
-				if (materialIndex >= placeholderMap.Length)
-					return false;
+			IEnumerable<Material> inputMaterials = GetInputMaterials();
+			foreach (Material material in inputMaterials) {
 				bool hasPlaceholderAssigned = HasPlaceholderAssigned(material);
 				if (hasPlaceholderAssigned) {
 					anyPlaceholderAssigned = true;
 					if (placeholderMaterials == null) placeholderMaterials = new List<Material>();
 					placeholderMaterials.Add(material);
 				}
-				materialIndex++;
 			}
 			return anyPlaceholderAssigned;
 		}
@@ -173,22 +175,64 @@ namespace Spine.Unity {
 			modifiedMaterials = null;
 			if (!atlasAsset) return false;
 			BeginCustomTextureLoading();
-			int i = 0;
-			foreach (Material targetMaterial in atlasAsset.Materials) {
-				if (i >= placeholderMap.Length) {
+
+			int normalMaterialCount = atlasAsset.Materials.Count();
+			IEnumerable<Material> inputMaterials = GetInputMaterials();
+
+			// process normal materials
+			int materialIndex = 0;
+			foreach (Material targetMaterial in inputMaterials) {
+				if (materialIndex > normalMaterialCount - 1) break;
+
+				if (materialIndex >= placeholderMap.Length) {
 					Debug.LogError(string.Format("Failed to assign target textures at {0}, material #{1} {2}. " +
 						"It seems like the OnDemandTextureLoader asset was not setup accordingly for the AtlasAsset.",
-						atlasAsset, i + 1, targetMaterial), this);
+						atlasAsset, materialIndex + 1, targetMaterial), this);
 					return false;
 				}
-				AssignTargetTextures(targetMaterial, i);
-				++i;
+
+				AssignTargetTextures(targetMaterial, materialIndex);
+				++materialIndex;
+			}
+			// process blend mode materials
+			if (skeletonDataAsset != null) {
+				foreach (ReplacementMaterial replacement in skeletonDataAsset.blendModeMaterials.additiveMaterials) {
+					AssignBlendModeTargetTextures(replacement.material, replacement);
+				}
+				foreach (ReplacementMaterial replacement in skeletonDataAsset.blendModeMaterials.multiplyMaterials) {
+					AssignBlendModeTargetTextures(replacement.material, replacement);
+				}
+				foreach (ReplacementMaterial replacement in skeletonDataAsset.blendModeMaterials.screenMaterials) {
+					AssignBlendModeTargetTextures(replacement.material, replacement);
+				}
 			}
-			modifiedMaterials = atlasAsset.Materials;
+
+			modifiedMaterials = inputMaterials;
 			EndCustomTextureLoading();
 			return true;
 		}
 
+		protected IEnumerable<Material> GetInputMaterials () {
+			int normalMaterialCount = atlasAsset.Materials.Count();
+			IEnumerable<Material> inputMaterials = atlasAsset.Materials;
+			if (skeletonDataAsset != null) {
+				BlendModeMaterials blendModeMaterials = skeletonDataAsset.blendModeMaterials;
+				int additiveCount = blendModeMaterials.additiveMaterials.Count;
+				int multiplyCount = blendModeMaterials.multiplyMaterials.Count;
+				int screenCount = blendModeMaterials.screenMaterials.Count;
+				int totalBlendModeMaterialCount = additiveCount + multiplyCount + screenCount;
+				if (totalBlendModeMaterialCount > 0) {
+					List<Material> materialsList = new List<Material>(normalMaterialCount + totalBlendModeMaterialCount);
+					materialsList.AddRange(atlasAsset.Materials);
+					materialsList.AddRange(blendModeMaterials.additiveMaterials.Where(r => r.material != null).Select(r => r.material));
+					materialsList.AddRange(blendModeMaterials.multiplyMaterials.Where(r => r.material != null).Select(r => r.material));
+					materialsList.AddRange(blendModeMaterials.screenMaterials.Where(r => r.material != null).Select(r => r.material));
+					inputMaterials = materialsList;
+				}
+			}
+			return inputMaterials;
+		}
+
 		public override void BeginCustomTextureLoading () {
 			if (loadedDataAtMaterial == null || (loadedDataAtMaterial.Length == 0 && placeholderMap.Length > 0)) {
 				loadedDataAtMaterial = new MaterialOnDemandData[placeholderMap.Length];
@@ -262,9 +306,29 @@ namespace Spine.Unity {
 
 		protected void AssignTargetTextures (Material material, int materialIndex) {
 			int textureIndex = 0; // Todo: currently only main texture is supported.
+			if (materialIndex > placeholderMap.Length - 1) return;
 			RequestLoadTexture(material, materialIndex, textureIndex, null);
 		}
 
+		protected void AssignBlendModeTargetTextures (Material blendModeMaterial, ReplacementMaterial replacementMaterial) {
+			int textureIndex = 0; // Todo: currently only main texture is supported.
+			int mainMaterialIndex = 0;
+			if (blendModeMaterial.mainTexture != null) {
+				mainMaterialIndex = Array.FindIndex(placeholderMap,
+					entry => entry.textures[textureIndex].placeholderTexture == blendModeMaterial.mainTexture);
+				if (mainMaterialIndex < 0)
+					return;
+			} else {
+				string textureNameFull = Path.GetFileNameWithoutExtension(replacementMaterial.pageName);
+				string placeholderTextureName = GetPlaceholderTextureName(textureNameFull);
+				mainMaterialIndex = Array.FindIndex(placeholderMap,
+					entry => entry.textures[textureIndex].placeholderTexture.name == placeholderTextureName);
+				if (mainMaterialIndex < 0)
+					return;
+			}
+			RequestLoadTexture(blendModeMaterial, mainMaterialIndex, textureIndex, null);
+		}
+
 		protected virtual Texture RequestLoadTexture (Material material, int materialIndex, int textureIndex,
 			System.Action<Texture> onTextureLoaded) {
 
@@ -336,11 +400,34 @@ namespace Spine.Unity {
 
 			// reset material textures to placeholder textures.
 			Material targetMaterial = atlasAsset.Materials.ElementAt(materialIndex);
+			Texture targetTexture = null;
+			Texture placeholderTexture = null;
 			if (targetMaterial) {
-				targetMaterial.mainTexture = placeholderTextures[textureIndex].placeholderTexture;
+				targetTexture = targetMaterial.mainTexture;
+				placeholderTexture = placeholderTextures[textureIndex].placeholderTexture;
+				targetMaterial.mainTexture = placeholderTexture;
 				if (wasReleased)
 					OnTextureUnloaded(targetMaterial, textureIndex);
 			}
+			// also reset material textures of blend mode materials
+			if (targetTexture != null && skeletonDataAsset != null) {
+				BlendModeMaterials blendModeMaterials = skeletonDataAsset.blendModeMaterials;
+				foreach (ReplacementMaterial replacementMaterial in blendModeMaterials.additiveMaterials) {
+					replacementMaterial.material.mainTexture = placeholderTexture;
+					if (wasReleased && replacementMaterial.material.mainTexture == targetTexture)
+						OnTextureUnloaded(targetMaterial, textureIndex);
+				}
+				foreach (ReplacementMaterial replacementMaterial in blendModeMaterials.multiplyMaterials) {
+					replacementMaterial.material.mainTexture = placeholderTexture;
+					if (wasReleased && replacementMaterial.material.mainTexture == targetTexture)
+						OnTextureUnloaded(targetMaterial, textureIndex);
+				}
+				foreach (ReplacementMaterial replacementMaterial in blendModeMaterials.screenMaterials) {
+					replacementMaterial.material.mainTexture = placeholderTexture;
+					if (wasReleased && replacementMaterial.material.mainTexture == targetTexture)
+						OnTextureUnloaded(targetMaterial, textureIndex);
+				}
+			}
 		}
 
 		public int maxPlaceholderSize = 128;

+ 2 - 2
spine-unity/Modules/com.esotericsoftware.spine.on-demand-loading/package.json

@@ -2,7 +2,7 @@
 	"name": "com.esotericsoftware.spine.on-demand-loading",
 	"displayName": "Spine On-Demand Loading Extensions [Experimental]",
 	"description": "This experimental plugin provides a generic basic implementation of on-demand texture loading for the spine-unity runtime. You might want to use the available com.esotericsoftware.spine.addressables package which depends on this package.\nPlease be sure to test this package first and create backups of your project before using.\n\nPrerequisites:\nIt requires a working installation of the spine-unity runtime (via the spine-unity unitypackage), version 4.2.\n(See http://esotericsoftware.com/git/spine-runtimes/spine-unity)",
-	"version": "4.2.0-preview.4",
+	"version": "4.2.0-preview.5",
 	"unity": "2018.3",
 	"author": {
 		"name": "Esoteric Software",
@@ -10,7 +10,7 @@
 		"url": "http://esotericsoftware.com/"
 	},
 	"dependencies": {
-		"com.esotericsoftware.spine.spine-unity": "4.2.21"
+		"com.esotericsoftware.spine.spine-unity": "4.2.89"
 	},
 	"keywords": [
 		"spine",