You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
5.2 KiB
129 lines
5.2 KiB
/****************************************************************************** |
|
* 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; |
|
using System.Collections.Generic; |
|
using UnityEngine; |
|
|
|
using Spine; |
|
using Spine.Unity; |
|
|
|
namespace Spine.Unity { |
|
[CreateAssetMenu(menuName = "Spine/SkeletonData Modifiers/Blend Mode Materials", order = 200)] |
|
public class BlendModeMaterialsAsset : SkeletonDataModifierAsset { |
|
public Material multiplyMaterialTemplate; |
|
public Material screenMaterialTemplate; |
|
public Material additiveMaterialTemplate; |
|
|
|
public bool applyAdditiveMaterial = true; |
|
|
|
public override void Apply (SkeletonData skeletonData) { |
|
ApplyMaterials(skeletonData, multiplyMaterialTemplate, screenMaterialTemplate, additiveMaterialTemplate, applyAdditiveMaterial); |
|
} |
|
|
|
public static void ApplyMaterials (SkeletonData skeletonData, Material multiplyTemplate, Material screenTemplate, Material additiveTemplate, bool includeAdditiveSlots) { |
|
if (skeletonData == null) throw new ArgumentNullException("skeletonData"); |
|
|
|
using (var materialCache = new AtlasMaterialCache()) { |
|
var entryBuffer = new List<Skin.SkinEntry>(); |
|
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 (!includeAdditiveSlots && slot.blendMode == BlendMode.Additive) continue; |
|
|
|
entryBuffer.Clear(); |
|
foreach (var skin in skeletonData.Skins) |
|
skin.GetAttachments(slotIndex, entryBuffer); |
|
|
|
Material templateMaterial = null; |
|
switch (slot.blendMode) { |
|
case BlendMode.Multiply: |
|
templateMaterial = multiplyTemplate; |
|
break; |
|
case BlendMode.Screen: |
|
templateMaterial = screenTemplate; |
|
break; |
|
case BlendMode.Additive: |
|
templateMaterial = additiveTemplate; |
|
break; |
|
} |
|
if (templateMaterial == null) continue; |
|
|
|
foreach (var entry in entryBuffer) { |
|
var renderableAttachment = entry.Attachment as IHasRendererObject; |
|
if (renderableAttachment != null) { |
|
renderableAttachment.RendererObject = materialCache.CloneAtlasRegionWithMaterial((AtlasRegion)renderableAttachment.RendererObject, templateMaterial); |
|
} |
|
} |
|
} |
|
|
|
} |
|
//attachmentBuffer.Clear(); |
|
} |
|
|
|
class AtlasMaterialCache : IDisposable { |
|
readonly Dictionary<KeyValuePair<AtlasPage, Material>, AtlasPage> cache = new Dictionary<KeyValuePair<AtlasPage, Material>, AtlasPage>(); |
|
|
|
/// <summary>Creates a clone of an AtlasRegion that uses different Material settings, while retaining the original texture.</summary> |
|
public AtlasRegion CloneAtlasRegionWithMaterial (AtlasRegion originalRegion, Material materialTemplate) { |
|
var newRegion = originalRegion.Clone(); |
|
newRegion.page = GetAtlasPageWithMaterial(originalRegion.page, materialTemplate); |
|
return newRegion; |
|
} |
|
|
|
AtlasPage GetAtlasPageWithMaterial (AtlasPage originalPage, Material materialTemplate) { |
|
if (originalPage == null) throw new ArgumentNullException("originalPage"); |
|
|
|
AtlasPage newPage = null; |
|
var key = new KeyValuePair<AtlasPage, Material>(originalPage, materialTemplate); |
|
cache.TryGetValue(key, out newPage); |
|
|
|
if (newPage == null) { |
|
newPage = originalPage.Clone(); |
|
var originalMaterial = originalPage.rendererObject as Material; |
|
newPage.rendererObject = new Material(materialTemplate) { |
|
name = originalMaterial.name + " " + materialTemplate.name, |
|
mainTexture = originalMaterial.mainTexture |
|
}; |
|
cache.Add(key, newPage); |
|
} |
|
|
|
return newPage; |
|
} |
|
|
|
public void Dispose () { |
|
cache.Clear(); |
|
} |
|
} |
|
|
|
} |
|
|
|
}
|
|
|