|
@@ -0,0 +1,390 @@
|
|
|
+/******************************************************************************
|
|
|
+ * Spine Runtimes License Agreement
|
|
|
+ * Last updated July 28, 2023. Replaces all prior versions.
|
|
|
+ *
|
|
|
+ * Copyright (c) 2013-2023, Esoteric Software LLC
|
|
|
+ *
|
|
|
+ * Integration of the Spine Runtimes into software or otherwise creating
|
|
|
+ * derivative works of the Spine Runtimes is permitted under the terms and
|
|
|
+ * conditions of Section 2 of the Spine Editor License Agreement:
|
|
|
+ * http://esotericsoftware.com/spine-editor-license
|
|
|
+ *
|
|
|
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
|
|
|
+ * otherwise create derivative works of the Spine Runtimes (collectively,
|
|
|
+ * "Products"), provided that each user of the Products must obtain their own
|
|
|
+ * Spine Editor license and redistribution of the Products in any form must
|
|
|
+ * include this license and copyright notice.
|
|
|
+ *
|
|
|
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
|
|
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
|
|
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
|
|
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
|
|
|
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
+ *****************************************************************************/
|
|
|
+
|
|
|
+#if UNITY_2017_2_OR_NEWER
|
|
|
+#define NEWPLAYMODECALLBACKS
|
|
|
+#endif
|
|
|
+
|
|
|
+#define SPINE_OPTIONAL_ON_DEMAND_LOADING
|
|
|
+
|
|
|
+#if SPINE_OPTIONAL_ON_DEMAND_LOADING
|
|
|
+
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using UnityEditor;
|
|
|
+using UnityEngine;
|
|
|
+
|
|
|
+namespace Spine.Unity.Editor {
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Base class for GenericOnDemandTextureLoader Inspector subclasses.
|
|
|
+ /// For reference, see the <see cref="AddressablesTextureLoaderInspector"/> class available
|
|
|
+ /// in the com.esotericsoftware.spine.addressables UPM package.
|
|
|
+ /// </summary>
|
|
|
+ /// <typeparam name="TargetReference">The implementation struct which holds an on-demand loading reference
|
|
|
+ /// to the target texture to be loaded, derived from ITargetTextureReference.</typeparam>
|
|
|
+ /// <typeparam name="TextureRequest">The implementation struct covering a single texture loading request,
|
|
|
+ /// derived from IOnDemandRequest</typeparam>
|
|
|
+ [InitializeOnLoad]
|
|
|
+ [CustomEditor(typeof(GenericOnDemandTextureLoader<,>)), CanEditMultipleObjects]
|
|
|
+ public abstract class GenericOnDemandTextureLoaderInspector<TargetReference, TextureRequest> : UnityEditor.Editor
|
|
|
+ where TargetReference : Spine.Unity.ITargetTextureReference
|
|
|
+ where TextureRequest : Spine.Unity.IOnDemandRequest {
|
|
|
+
|
|
|
+ protected SerializedProperty atlasAsset;
|
|
|
+ protected SerializedProperty maxPlaceholderSize;
|
|
|
+ protected SerializedProperty placeholderMap;
|
|
|
+ protected SerializedProperty unloadAfterSecondsUnused;
|
|
|
+ static protected bool placeholdersFoldout = true;
|
|
|
+ protected SerializedProperty loadedDataAtMaterial;
|
|
|
+ protected GenericOnDemandTextureLoader<TargetReference, TextureRequest> loader;
|
|
|
+ protected GUIContent placeholderTexturesLabel;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Called via InitializeOnLoad attribute upon Editor startup or compilation.
|
|
|
+ /// </summary>
|
|
|
+ static GenericOnDemandTextureLoaderInspector () {
|
|
|
+#if NEWPLAYMODECALLBACKS
|
|
|
+ EditorApplication.playModeStateChanged += OnPlaymodeChanged;
|
|
|
+#else
|
|
|
+ EditorApplication.playmodeStateChanged += OnPlaymodeChanged;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Derive your implementation subclass of this class and implement the respective abstract methods.
|
|
|
+ /// Note: Unfortunately the Unity menu entries are created via static methods, so this is a workaround
|
|
|
+ /// to provide virtual static functions in old C# versions.
|
|
|
+ /// </summary>
|
|
|
+ public abstract class StaticMethodImplementations {
|
|
|
+
|
|
|
+ public abstract GenericOnDemandTextureLoader<TargetReference, TextureRequest> GetOrCreateLoader (string loaderPath);
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Returns the on-demand loader asset's filename suffix. The filename
|
|
|
+ /// is determined by the AtlasAsset, while this suffix replaces the "_Atlas" suffix.
|
|
|
+ /// When set to e.g. "_Addressable", the loader asset created for
|
|
|
+ /// the "Skeleton_Atlas" asset is named "Skeleton_Addressable".
|
|
|
+ /// </summary>
|
|
|
+ public string LoaderSuffix { get; }
|
|
|
+
|
|
|
+ public abstract bool SetupOnDemandLoadingReference (
|
|
|
+ ref TargetReference targetTextureReference, Texture targetTexture);
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Create a context menu wrapper in the main class for this generic implementation using the code below.
|
|
|
+ /// <code>
|
|
|
+ /// [MenuItem("CONTEXT/AtlasAssetBase/Add YourSubclass Loader")]
|
|
|
+ /// static void AddYourSubclassLoader (MenuCommand cmd) {
|
|
|
+ /// if (staticMethods == null)
|
|
|
+ /// staticMethods = new YourSubclassMethodImplementations ();
|
|
|
+ /// staticMethods.AddOnDemandLoader(cmd);
|
|
|
+ /// }
|
|
|
+ /// </code>
|
|
|
+ /// </summary>
|
|
|
+ public virtual void AddOnDemandLoader (MenuCommand cmd) {
|
|
|
+ AtlasAssetBase atlasAsset = cmd.context as AtlasAssetBase;
|
|
|
+ Debug.Log("Adding On-Demand Loader for " + atlasAsset.name, atlasAsset);
|
|
|
+
|
|
|
+ if (atlasAsset.OnDemandTextureLoader != null) {
|
|
|
+ Debug.LogWarning("AtlasAsset On-Demand TextureLoader is already set. " +
|
|
|
+ "Please clear it if you want to assign a different one.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ atlasAsset.TextureLoadingMode = AtlasAssetBase.LoadingMode.OnDemand;
|
|
|
+ EditorUtility.SetDirty(atlasAsset);
|
|
|
+
|
|
|
+ string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset);
|
|
|
+ string loaderPath = atlasAssetPath.Replace(AssetUtility.AtlasSuffix, LoaderSuffix);
|
|
|
+
|
|
|
+ GenericOnDemandTextureLoader<TargetReference, TextureRequest> loader = staticMethods.GetOrCreateLoader(loaderPath);
|
|
|
+ staticMethods.SetupForAtlasAsset(loader, atlasAsset);
|
|
|
+
|
|
|
+ EditorUtility.SetDirty(loader);
|
|
|
+ AssetDatabase.SaveAssets();
|
|
|
+ }
|
|
|
+
|
|
|
+ public virtual void SetupForAtlasAsset (GenericOnDemandTextureLoader<TargetReference, TextureRequest> loader, AtlasAssetBase atlasAsset) {
|
|
|
+ if (loader.placeholderMap != null && loader.placeholderMap.Length > 0) {
|
|
|
+ IEnumerable<Material> modifiedMaterials;
|
|
|
+ loader.AssignTargetTextures(out modifiedMaterials); // start from normal textures
|
|
|
+ }
|
|
|
+
|
|
|
+ if (atlasAsset == null) {
|
|
|
+ Debug.LogError("AddressableTextureLoader.SetupForAtlasAsset: atlasAsset was null, aborting setup.", atlasAsset);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ int materialCount = atlasAsset.MaterialCount;
|
|
|
+ loader.placeholderMap = new GenericOnDemandTextureLoader<TargetReference, TextureRequest>.PlaceholderMaterialMapping[materialCount];
|
|
|
+ GenericOnDemandTextureLoader<TargetReference, TextureRequest>.PlaceholderMaterialMapping[] materialMap = loader.placeholderMap;
|
|
|
+
|
|
|
+ atlasAsset.OnDemandTextureLoader = loader;
|
|
|
+ int maxPlaceholderSize = loader.maxPlaceholderSize;
|
|
|
+
|
|
|
+ int i = 0;
|
|
|
+ foreach (Material targetMaterial in atlasAsset.Materials) {
|
|
|
+ Texture targetTexture = targetMaterial.mainTexture;
|
|
|
+ materialMap[i].textures = new GenericOnDemandTextureLoader<TargetReference, TextureRequest>.PlaceholderTextureMapping[1]; // Todo: currently only main texture is supported.
|
|
|
+ int textureIndex = 0;
|
|
|
+
|
|
|
+ GenericOnDemandTextureLoader<TargetReference, TextureRequest>.PlaceholderTextureMapping[] texturesMap = materialMap[i].textures;
|
|
|
+ if (texturesMap[textureIndex].placeholderTexture != targetTexture) { // otherwise already set to placeholder
|
|
|
+ SetupOnDemandLoadingReference(ref texturesMap[textureIndex].targetTextureReference, targetTexture);
|
|
|
+ texturesMap[textureIndex].placeholderTexture = CreatePlaceholderTextureFor(targetTexture, maxPlaceholderSize, loader);
|
|
|
+ }
|
|
|
+ ++i;
|
|
|
+ }
|
|
|
+ // assign late since CreatePlaceholderTextureFor(texture) method above might save assets and clear these values.
|
|
|
+ loader.placeholderMap = materialMap;
|
|
|
+ loader.atlasAsset = atlasAsset;
|
|
|
+ }
|
|
|
+
|
|
|
+ public virtual Texture CreatePlaceholderTextureFor (Texture originalTexture, int maxPlaceholderSize,
|
|
|
+ GenericOnDemandTextureLoader<TargetReference, TextureRequest> loader) {
|
|
|
+
|
|
|
+ const string AssetFolderName = "LoadingPlaceholderAssets";
|
|
|
+ string originalPath = AssetDatabase.GetAssetPath(originalTexture);
|
|
|
+ string parentFolder = System.IO.Path.GetDirectoryName(originalPath);
|
|
|
+ string dataPath = parentFolder + "/" + AssetFolderName;
|
|
|
+ if (!AssetDatabase.IsValidFolder(dataPath)) {
|
|
|
+ AssetDatabase.CreateFolder(parentFolder, AssetFolderName);
|
|
|
+ }
|
|
|
+
|
|
|
+ string originalTextureName = System.IO.Path.GetFileNameWithoutExtension(originalPath);
|
|
|
+ string texturePath = string.Format("{0}/{1}.png", dataPath, loader.GetPlaceholderTextureName(originalTextureName));
|
|
|
+ Texture placeholderTexture = AssetDatabase.LoadAssetAtPath<Texture>(texturePath);
|
|
|
+ if (placeholderTexture == null) {
|
|
|
+ AssetDatabase.CopyAsset(originalPath, texturePath);
|
|
|
+
|
|
|
+ const bool resizePhysically = true;
|
|
|
+
|
|
|
+ TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(texturePath);
|
|
|
+ const string defaultPlatform = "Default";
|
|
|
+ TextureImporterPlatformSettings settings = importer.GetPlatformTextureSettings(defaultPlatform);
|
|
|
+ settings.maxTextureSize = maxPlaceholderSize;
|
|
|
+ importer.SetPlatformTextureSettings(settings);
|
|
|
+ importer.maxTextureSize = maxPlaceholderSize;
|
|
|
+ importer.isReadable = resizePhysically;
|
|
|
+ importer.SaveAndReimport();
|
|
|
+
|
|
|
+ if (resizePhysically) {
|
|
|
+ Texture2D texture2D = AssetDatabase.LoadAssetAtPath<Texture2D>(texturePath);
|
|
|
+ if (texture2D) {
|
|
|
+ Color[] maxTextureSizePixels = texture2D.GetPixels();
|
|
|
+ texture2D.SetPixels(maxTextureSizePixels);
|
|
|
+
|
|
|
+ var bytes = texture2D.EncodeToPNG();
|
|
|
+ string targetPath = Application.dataPath + "/../" + texturePath;
|
|
|
+ System.IO.File.WriteAllBytes(targetPath, bytes);
|
|
|
+ texture2D.Apply(updateMipmaps: true, makeNoLongerReadable: true);
|
|
|
+ EditorUtility.SetDirty(texture2D);
|
|
|
+ AssetDatabase.SaveAssets();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ placeholderTexture = AssetDatabase.LoadAssetAtPath<Texture>(texturePath);
|
|
|
+ }
|
|
|
+
|
|
|
+ UnityEngine.Object folderObject = AssetDatabase.LoadAssetAtPath(dataPath, typeof(UnityEngine.Object));
|
|
|
+ if (folderObject != null) {
|
|
|
+ EditorGUIUtility.PingObject(folderObject);
|
|
|
+ }
|
|
|
+
|
|
|
+ return placeholderTexture;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public static StaticMethodImplementations staticMethods;
|
|
|
+
|
|
|
+ void OnEnable () {
|
|
|
+ atlasAsset = serializedObject.FindProperty("atlasAsset");
|
|
|
+ maxPlaceholderSize = serializedObject.FindProperty("maxPlaceholderSize");
|
|
|
+ placeholderMap = serializedObject.FindProperty("placeholderMap");
|
|
|
+ unloadAfterSecondsUnused = serializedObject.FindProperty("unloadAfterSecondsUnused");
|
|
|
+ loadedDataAtMaterial = serializedObject.FindProperty("loadedDataAtMaterial");
|
|
|
+ placeholderTexturesLabel = new GUIContent("Placeholder Textures");
|
|
|
+ loader = (GenericOnDemandTextureLoader<TargetReference, TextureRequest>)target;
|
|
|
+
|
|
|
+ if (staticMethods == null)
|
|
|
+ staticMethods = CreateStaticMethodImplementations ();
|
|
|
+ }
|
|
|
+
|
|
|
+#if NEWPLAYMODECALLBACKS
|
|
|
+ static void OnPlaymodeChanged (PlayModeStateChange mode) {
|
|
|
+ bool assignTargetTextures = mode == PlayModeStateChange.ExitingPlayMode;
|
|
|
+#else
|
|
|
+ static void OnPlaymodeChanged () {
|
|
|
+ bool assignTargetTextures = !Application.isPlaying;
|
|
|
+#endif
|
|
|
+ if (assignTargetTextures) {
|
|
|
+ AssignTargetTexturesAtAllLoaders();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void AssignTargetTexturesAtAllLoaders () {
|
|
|
+
|
|
|
+ string[] loaderAssets = AssetDatabase.FindAssets("t:OnDemandTextureLoader");
|
|
|
+ foreach (string loaderAsset in loaderAssets) {
|
|
|
+ string assetPath = AssetDatabase.GUIDToAssetPath(loaderAsset);
|
|
|
+ OnDemandTextureLoader loader = AssetDatabase.LoadAssetAtPath<OnDemandTextureLoader>(assetPath);
|
|
|
+ AssignTargetTexturesAtLoader(loader);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void AssignTargetTexturesAtLoader (OnDemandTextureLoader loader) {
|
|
|
+ List<Material> placeholderMaterials;
|
|
|
+ bool anyPlaceholdersAssigned = loader.HasPlaceholderTexturesAssigned(out placeholderMaterials);
|
|
|
+ if (anyPlaceholdersAssigned) {
|
|
|
+ Debug.Log("OnDemandTextureLoader detected placeholders assigned at one or more materials. Resetting to target textures.", loader);
|
|
|
+ AssetDatabase.StartAssetEditing();
|
|
|
+ IEnumerable<Material> modifiedMaterials;
|
|
|
+ loader.AssignTargetTextures(out modifiedMaterials);
|
|
|
+ foreach (Material placeholderMaterial in placeholderMaterials) {
|
|
|
+ EditorUtility.SetDirty(placeholderMaterial);
|
|
|
+ }
|
|
|
+ AssetDatabase.StopAssetEditing();
|
|
|
+ AssetDatabase.SaveAssets();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Override this method in your implementation subclass as follows.
|
|
|
+ /// <code>
|
|
|
+ /// protected override StaticMethodImplementations CreateStaticMethodImplementations () {
|
|
|
+ /// return new YourStaticMethodImplementationsSubclass();
|
|
|
+ /// }
|
|
|
+ /// </code>
|
|
|
+ /// </summary>
|
|
|
+ protected abstract StaticMethodImplementations CreateStaticMethodImplementations ();
|
|
|
+
|
|
|
+ /// <summary>Draws a single texture mapping entry in the Inspector.
|
|
|
+ /// Can be overridden in subclasses where needed. Note that DrawSingleLineTargetTextureProperty
|
|
|
+ /// can be overridden as well instead of overriding this method.
|
|
|
+ /// Note that for the sake of space it should be drawn as a single line if possible.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="textureMapping">SerializedProperty pointing to a
|
|
|
+ /// PlaceholderTextureMapping object of the placeholderMap array.</param>
|
|
|
+ protected virtual void DrawPlaceholderMapping (SerializedProperty textureMapping) {
|
|
|
+ EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5));
|
|
|
+ var placeholderTextureProp = textureMapping.FindPropertyRelative("placeholderTexture");
|
|
|
+ var targetTextureProp = textureMapping.FindPropertyRelative("targetTextureReference");
|
|
|
+ GUILayout.Space(16f);
|
|
|
+ EditorGUILayout.PropertyField(placeholderTextureProp, GUIContent.none);
|
|
|
+ EditorGUIUtility.labelWidth = 1; // workaround since GUIContent.none below seems to be ignored
|
|
|
+
|
|
|
+ DrawSingleLineTargetTextureProperty(targetTextureProp);
|
|
|
+ EditorGUIUtility.labelWidth = 0; // change back to default
|
|
|
+ EditorGUILayout.EndHorizontal();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>Draws a single texture mapping TargetReference in the Inspector.
|
|
|
+ /// Can be overridden in subclasses where needed. Note that this method is
|
|
|
+ /// called inside a horizontal Inspector line of a BeginHorizontal() / EndHorizontal()
|
|
|
+ /// pair, so it is limited to approximately half Inspector width.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="property">SerializedProperty pointing to a
|
|
|
+ /// TargetReference object of the PlaceholderTextureMapping entry.</param>
|
|
|
+ protected virtual void DrawSingleLineTargetTextureProperty (SerializedProperty property) {
|
|
|
+ EditorGUILayout.PropertyField(property, GUIContent.none, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void OnInspectorGUI () {
|
|
|
+ if (serializedObject.isEditingMultipleObjects) {
|
|
|
+ DrawDefaultInspector();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ serializedObject.Update();
|
|
|
+
|
|
|
+ EditorGUILayout.PropertyField(atlasAsset);
|
|
|
+ EditorGUILayout.PropertyField(maxPlaceholderSize);
|
|
|
+ EditorGUILayout.PropertyField(unloadAfterSecondsUnused);
|
|
|
+
|
|
|
+ placeholdersFoldout = EditorGUILayout.Foldout(placeholdersFoldout, placeholderTexturesLabel, true);
|
|
|
+ if (placeholdersFoldout) {
|
|
|
+ for (int m = 0, materialCount = placeholderMap.arraySize; m < materialCount; ++m) {
|
|
|
+ // line below equals: PlaceholderTextureMapping[] materialTextures = placeholderMap[m].textures;
|
|
|
+ SerializedProperty materialTextures = placeholderMap.GetArrayElementAtIndex(m).FindPropertyRelative("textures");
|
|
|
+
|
|
|
+ for (int t = 0, textureCount = materialTextures.arraySize; t < textureCount; ++t) {
|
|
|
+ // line below equals: PlaceholderTextureMapping textureMapping = materialTextures[t];
|
|
|
+ SerializedProperty textureMapping = materialTextures.GetArrayElementAtIndex(t);
|
|
|
+ DrawPlaceholderMapping(textureMapping);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (GUILayout.Button(new GUIContent("Regenerate", "Re-initialize the placeholder texture maps."), EditorStyles.miniButton, GUILayout.Width(160f)))
|
|
|
+ ReinitPlaceholderTextures(loader);
|
|
|
+
|
|
|
+ GUILayout.Space(16f);
|
|
|
+ EditorGUILayout.LabelField("Testing", EditorStyles.boldLabel);
|
|
|
+ EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5));
|
|
|
+ if (GUILayout.Button(new GUIContent("Assign Placeholders", "Assign placeholder textures (for testing)."), EditorStyles.miniButton, GUILayout.Width(160f)))
|
|
|
+ AssignPlaceholderTextures(loader);
|
|
|
+ if (GUILayout.Button(new GUIContent("Assign Normal Textures", "Re-assign target textures."), EditorStyles.miniButton, GUILayout.Width(160f)))
|
|
|
+ AssignTargetTextures(loader);
|
|
|
+ EditorGUILayout.EndHorizontal();
|
|
|
+
|
|
|
+ if (!Application.isPlaying)
|
|
|
+ serializedObject.ApplyModifiedProperties();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void DeletePlaceholderTextures (GenericOnDemandTextureLoader<TargetReference, TextureRequest> loader) {
|
|
|
+ foreach (var materialMap in loader.placeholderMap) {
|
|
|
+ Texture texture = materialMap.textures[0].placeholderTexture;
|
|
|
+ if (texture)
|
|
|
+ AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(texture));
|
|
|
+ }
|
|
|
+ loader.Clear(clearAtlasAsset: false);
|
|
|
+ AssetDatabase.SaveAssets();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void ReinitPlaceholderTextures (GenericOnDemandTextureLoader<TargetReference, TextureRequest> loader) {
|
|
|
+ AssignTargetTextures(loader);
|
|
|
+ DeletePlaceholderTextures(loader);
|
|
|
+ staticMethods.SetupForAtlasAsset(loader, loader.atlasAsset);
|
|
|
+ EditorUtility.SetDirty(loader);
|
|
|
+ AssetDatabase.SaveAssets();
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool AssignPlaceholderTextures (GenericOnDemandTextureLoader<TargetReference, TextureRequest> loader) {
|
|
|
+ // re-setup placeholders to ensure the mapping is up to date.
|
|
|
+ staticMethods.SetupForAtlasAsset(loader, loader.atlasAsset);
|
|
|
+ IEnumerable<Material> modifiedMaterials;
|
|
|
+ return loader.AssignPlaceholderTextures(out modifiedMaterials);
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool AssignTargetTextures (GenericOnDemandTextureLoader<TargetReference, TextureRequest> loader) {
|
|
|
+ IEnumerable<Material> modifiedMaterials;
|
|
|
+ return loader.AssignTargetTextures(out modifiedMaterials);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif
|