rimworld-animation-studio/Library/PackageCache/com.unity.2d.animation@3.2.6/Editor/SpriteOutlineRenderer/SpriteOutlineRenderer.cs
2022-09-13 00:36:34 -05:00

212 lines
8.8 KiB
C#

using System.Collections.Generic;
using UnityEditor.U2D.Sprites;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class SpriteOutlineRenderer
{
class OutlineRenderTexture
{
public Texture outlineTexture;
public bool dirty;
}
Material m_OutlineMaterial;
Material m_BitMaskMaterial;
Dictionary<string, OutlineRenderTexture> m_OutlineTextureCache = new Dictionary<string, OutlineRenderTexture>();
ISpriteEditorDataProvider m_CurrentDataProvider;
SkinningEvents m_EventSystem;
ISpriteEditor m_SpriteEditor;
public SpriteOutlineRenderer(ISpriteEditor spriteEditor, SkinningEvents eventSystem)
{
m_BitMaskMaterial = new Material(Shader.Find("com.unity3d.animation/SpriteBitmask"));
m_BitMaskMaterial.hideFlags = HideFlags.HideAndDontSave;
m_OutlineMaterial = new Material(Shader.Find("com.unity3d.animation/SpriteOutline"));
m_OutlineMaterial.hideFlags = HideFlags.HideAndDontSave;
m_SpriteEditor = spriteEditor;
m_EventSystem = eventSystem;
m_EventSystem.meshPreviewChanged.AddListener(OnMeshPreviewChanged);
m_EventSystem.selectedSpriteChanged.AddListener(OnSelectionChanged);
CheckDataProviderChanged();
}
public void Dispose()
{
if (m_BitMaskMaterial != null)
Object.DestroyImmediate(m_BitMaskMaterial);
if (m_OutlineMaterial != null)
Object.DestroyImmediate(m_OutlineMaterial);
m_EventSystem.meshPreviewChanged.RemoveListener(OnMeshPreviewChanged);
m_EventSystem.selectedSpriteChanged.RemoveListener(OnSelectionChanged);
DestoryTextures();
}
private void OnMeshPreviewChanged(MeshPreviewCache mesh)
{
AddOrUpdateMaskTexture(mesh.sprite, true);
}
private void OnSelectionChanged(SpriteCache spriteCache)
{
CheckDataProviderChanged();
AddOrUpdateMaskTexture(spriteCache, false);
}
private void DestoryTextures()
{
if (m_OutlineTextureCache != null)
{
foreach (var value in m_OutlineTextureCache.Values)
{
if (value != null && value.outlineTexture != null)
Texture.DestroyImmediate(value.outlineTexture);
}
m_OutlineTextureCache.Clear();
}
}
private void AddOrUpdateMaskTexture(SpriteCache sprite, bool regenerate)
{
SpriteCache selectedSprite = null;
if (sprite != null)
selectedSprite = sprite.skinningCache.selectedSprite;
if (m_OutlineTextureCache != null && sprite != null)
{
if (!m_OutlineTextureCache.ContainsKey(sprite.id))
m_OutlineTextureCache.Add(sprite.id, new OutlineRenderTexture() {dirty = true});
var outlineTextureCache = m_OutlineTextureCache[sprite.id];
outlineTextureCache.dirty |= regenerate;
if (sprite == selectedSprite)
{
if (outlineTextureCache.dirty || outlineTextureCache.outlineTexture == null)
{
outlineTextureCache.outlineTexture = GenerateOutlineTexture(m_SpriteEditor, sprite, (RenderTexture)outlineTextureCache.outlineTexture);
if (outlineTextureCache.outlineTexture != null)
{
outlineTextureCache.outlineTexture.hideFlags = HideFlags.HideAndDontSave;
outlineTextureCache.dirty = false;
}
}
m_OutlineMaterial.mainTexture = outlineTextureCache.outlineTexture;
}
}
}
private void CheckDataProviderChanged()
{
var dp = m_SpriteEditor.GetDataProvider<ISpriteEditorDataProvider>();
if (dp != m_CurrentDataProvider)
{
DestoryTextures();
m_OutlineTextureCache.Clear();
m_CurrentDataProvider = dp;
}
}
internal void RenderSpriteOutline(ISpriteEditor spriteEditor, SpriteCache sprite)
{
if (sprite == null)
return;
if (Event.current.type == EventType.Repaint)
{
UnityEngine.Profiling.Profiler.BeginSample("SpriteOutlineRenderer::RenderSpriteOutline");
m_OutlineMaterial.SetColor("_OutlineColor", SelectionOutlineSettings.outlineColor);
m_OutlineMaterial.SetFloat("_AdjustLinearForGamma", PlayerSettings.colorSpace == ColorSpace.Linear ? 1.0f : 0.0f);
var texture = spriteEditor.GetDataProvider<ITextureDataProvider>().texture;
float outlineSize = Mathf.Max(texture.width, texture.height) * SelectionOutlineSettings.selectedSpriteOutlineSize / 1024.0f;
m_OutlineMaterial.SetFloat("_OutlineSize", outlineSize);
var mesh = GetMesh(sprite);
m_OutlineMaterial.SetPass(0);
GL.PushMatrix();
GL.MultMatrix(Handles.matrix * sprite.GetLocalToWorldMatrixFromMode());
Rect r = new Rect(mesh.bounds.min.x, mesh.bounds.min.y, mesh.bounds.size.x, mesh.bounds.size.y);
GL.Begin(GL.QUADS);
GL.Color(Color.white);
GL.TexCoord(new Vector3(0, 0, 0));
GL.Vertex3(r.xMin, r.yMin, 0);
GL.TexCoord(new Vector3(1, 0, 0));
GL.Vertex3(r.xMax, r.yMin, 0);
GL.TexCoord(new Vector3(1, 1, 0));
GL.Vertex3(r.xMax, r.yMax, 0);
GL.TexCoord(new Vector3(0, 1, 0));
GL.Vertex3(r.xMin, r.yMax, 0);
GL.End();
GL.PopMatrix();
UnityEngine.Profiling.Profiler.EndSample();
}
}
private Texture GenerateOutlineTexture(ISpriteEditor spriteEditor, SpriteCache spriteCache, RenderTexture reuseRT)
{
if (spriteCache != null && spriteCache.textureRect.width != 0 && spriteCache.textureRect.height != 0)
{
UnityEngine.Profiling.Profiler.BeginSample("SpriteOutlineRenderer::GenerateOutlineTexture");
var mesh = GetMesh(spriteCache);
var b = mesh.bounds;
if (reuseRT == null)
{
UnityEngine.Profiling.Profiler.BeginSample("SpriteOutlineRenderer::CreateRTNew");
reuseRT = new RenderTexture((int)b.size.x, (int)b.size.y, 24, RenderTextureFormat.ARGBHalf);
UnityEngine.Profiling.Profiler.EndSample();
}
else if (reuseRT.width != (int)b.size.x || reuseRT.height != (int)b.size.y)
{
UnityEngine.Profiling.Profiler.BeginSample("SpriteOutlineRenderer::CreateRTReuse");
Object.DestroyImmediate(reuseRT);
reuseRT = new RenderTexture((int)b.size.x, (int)b.size.y, 24, RenderTextureFormat.ARGBHalf);
UnityEngine.Profiling.Profiler.EndSample();
}
m_BitMaskMaterial.mainTexture = spriteEditor.GetDataProvider<ITextureDataProvider>().texture;
var oldRT = RenderTexture.active;
Graphics.SetRenderTarget(reuseRT);
m_BitMaskMaterial.SetPass(0);
UnityEngine.Profiling.Profiler.BeginSample("SpriteOutlineRenderer::DrawMesh");
GL.Clear(false, true, new Color(0, 0, 0, 0));
GL.PushMatrix();
GL.LoadOrtho();
var h = b.size.y * 0.5f;
var w = h * (b.size.x / b.size.y);
GL.LoadProjectionMatrix(Matrix4x4.Ortho(-w, w, -h, h, -1, 1));
GL.Begin(GL.QUADS);
GL.Color(Color.white);
Graphics.DrawMeshNow(mesh, Matrix4x4.Translate(-b.center));
GL.End();
GL.PopMatrix();
Graphics.SetRenderTarget(oldRT);
UnityEngine.Profiling.Profiler.EndSample();
UnityEngine.Profiling.Profiler.EndSample();
return reuseRT;
}
return null;
}
private Mesh GetMesh(SpriteCache sprite)
{
var meshPreview = sprite.GetMeshPreview();
var skeleton = sprite.skinningCache.GetEffectiveSkeleton(sprite);
Debug.Assert(meshPreview != null);
Debug.Assert(skeleton != null);
if (meshPreview.canSkin && skeleton.isPosePreview)
return meshPreview.mesh;
return meshPreview.defaultMesh;
}
}
}