/****************************************************************************** * Spine Runtimes License Agreement * Last updated January 1, 2020. Replaces all prior versions. * * Copyright (c) 2013-2020, 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. *****************************************************************************/ using System; using System.Collections.Generic; using System.IO; using UnityEngine; using Spine; namespace Spine.Unity { [System.Serializable] public class BlendModeMaterials { [System.Serializable] public class ReplacementMaterial { public string pageName; public Material material; } [SerializeField, HideInInspector] protected bool requiresBlendModeMaterials = false; public bool applyAdditiveMaterial = false; public List additiveMaterials = new List(); public List multiplyMaterials = new List(); public List screenMaterials = new List(); public bool RequiresBlendModeMaterials { get { return requiresBlendModeMaterials; } set { requiresBlendModeMaterials = value; } } #if UNITY_EDITOR public void TransferSettingsFrom (BlendModeMaterialsAsset modifierAsset) { applyAdditiveMaterial = modifierAsset.applyAdditiveMaterial; } public bool UpdateBlendmodeMaterialsRequiredState (SkeletonData skeletonData) { requiresBlendModeMaterials = false; if (skeletonData == null) throw new ArgumentNullException("skeletonData"); var skinEntries = new List(); var slotsItems = skeletonData.Slots.Items; for (int slotIndex = 0, slotCount = skeletonData.Slots.Count; slotIndex < slotCount; slotIndex++) { var slot = slotsItems[slotIndex]; if (slot.blendMode == BlendMode.Normal) continue; if (!applyAdditiveMaterial && slot.blendMode == BlendMode.Additive) continue; skinEntries.Clear(); foreach (var skin in skeletonData.Skins) skin.GetAttachments(slotIndex, skinEntries); foreach (var entry in skinEntries) { if (entry.Attachment is IHasRendererObject) { requiresBlendModeMaterials = true; return true; } } } return false; } #endif public void ApplyMaterials (SkeletonData skeletonData) { if (skeletonData == null) throw new ArgumentNullException("skeletonData"); if (!requiresBlendModeMaterials) return; var skinEntries = new List(); var slotsItems = skeletonData.Slots.Items; for (int slotIndex = 0, slotCount = skeletonData.Slots.Count; slotIndex < slotCount; slotIndex++) { var slot = slotsItems[slotIndex]; if (slot.blendMode == BlendMode.Normal) continue; if (!applyAdditiveMaterial && slot.blendMode == BlendMode.Additive) continue; List replacementMaterials = null; switch (slot.blendMode) { case BlendMode.Multiply: replacementMaterials = multiplyMaterials; break; case BlendMode.Screen: replacementMaterials = screenMaterials; break; case BlendMode.Additive: replacementMaterials = additiveMaterials; break; } if (replacementMaterials == null) continue; skinEntries.Clear(); foreach (var skin in skeletonData.Skins) skin.GetAttachments(slotIndex, skinEntries); foreach (var entry in skinEntries) { var renderableAttachment = entry.Attachment as IHasRendererObject; if (renderableAttachment != null) { renderableAttachment.RendererObject = CloneAtlasRegionWithMaterial( (AtlasRegion)renderableAttachment.RendererObject, replacementMaterials); } } } } protected AtlasRegion CloneAtlasRegionWithMaterial (AtlasRegion originalRegion, List replacementMaterials) { var newRegion = originalRegion.Clone(); Material material = null; foreach (var replacement in replacementMaterials) { if (replacement.pageName == originalRegion.page.name) { material = replacement.material; break; } } AtlasPage originalPage = originalRegion.page; var newPage = originalPage.Clone(); newPage.rendererObject = material; newRegion.page = newPage; return newRegion; } } }