using System; using UnityEngine; namespace Cryville.Crtr.Skin.Components { public class SpriteInfo { string m_frameName; public string FrameName { get { return m_frameName; } set { m_frameName = value; Reload(); } } public SpriteFrame Frame { get; private set; } public Rect Rect { get { return Frame.Frame; } } /// /// The ratio of width divided by height. /// public float Ratio { get { return Rect.width / Rect.height; } } Material _mat; public void Bind(Material mat) { _mat = mat; Reload(); } public void Reload() { if (!string.IsNullOrEmpty(FrameName)) { if (ChartPlayer.frames.ContainsKey(FrameName)) { Frame = ChartPlayer.frames[FrameName]; } else { Game.MainLogger.Log(4, "Skin", "Texture {0} not found", FrameName); Frame = null; } } else Frame = null; if (_mat != null) { _mat.mainTexture = Frame?.Texture; } } public static bool IsNullOrEmpty(SpriteInfo sprite) { return sprite == null || sprite.Frame == null; } } public class SpritePlane : SpriteBase { public SpritePlane() { SubmitProperty("frame", new PropOp.String(v => Frame = v)); SubmitProperty("frames", new PropOp.StringArray(v => Frames = v)); SubmitProperty("index", new PropOp.Integer(v => Index = v)); SubmitProperty("fit", new PropOp.Enum(v => Fit = v, v => (FitMode)v)); SubmitProperty("shader", new PropOp.String(v => Shader = v)); } static Vector2[] _origuv; protected static Vector2[] OriginalUV { get { if (_origuv == null) { var m = BuiltinResources.Meshes["quad"]; Vector2[] uv = new Vector2[m.vertices.Length]; for (int i = 0; i < uv.Length; i++) { uv[i] = new Vector2( m.vertices[i].x == 0.5 ? 1 : 0, m.vertices[i].z == 0.5 ? 1 : 0 ); } _origuv = uv; } return _origuv; } } int m_index; public int Index { get { return m_index; } set { m_index = value; OnFrameUpdate(); } } SpriteInfo[] m_frames = new SpriteInfo[] { new() }; public string[] Frames { set { m_frames = new SpriteInfo[value.Length]; for (int i = 0; i < value.Length; i++) { m_frames[i] = new SpriteInfo() { FrameName = value[i] }; } OnFrameUpdate(); } } public string Frame { set { if (value == CurrentFrame.FrameName) return; CurrentFrame.FrameName = value; OnFrameUpdate(); } } protected SpriteInfo CurrentFrame { get { if (m_frames.Length == 0) return null; if (m_index < 0) m_index = 0; else if (m_index >= m_frames.Length) m_index = m_frames.Length - 1; return m_frames[m_index]; } } protected void OnFrameUpdate() { if (!mesh.Initialized) return; var frame = CurrentFrame; if (SpriteInfo.IsNullOrEmpty(frame)) { mesh.Renderer.enabled = false; return; } mesh.Renderer.enabled = true; mesh.Renderer.sharedMaterial.mainTexture = frame.Frame.Texture; UpdateUV(); UpdateScale(); } Shader m_shader; public string Shader { set { m_shader = BuiltinResources.Shaders[value]; UpdateShader(); } } void UpdateShader() { if (!mesh.Initialized) return; if (m_shader == null) m_shader = BuiltinResources.Shaders["default"]; mesh.Renderer.sharedMaterial.shader = m_shader; UpdateZIndex(); } readonly Vector2[] _uvs = new Vector2[4]; protected virtual void UpdateUV() { var frame = CurrentFrame; if (SpriteInfo.IsNullOrEmpty(frame)) return; Vector2[] muv = OriginalUV; for (int i = 0; i < _uvs.Length; i++) { _uvs[i] = frame.Frame.GetUV(muv[i]); } mesh.Mesh.uv = _uvs; } private FitMode m_fit = FitMode.height; public FitMode Fit { get { return m_fit; } set { m_fit = value; if (m_fit != FitMode.none && Scale.x != Scale.y) m_fit = FitMode.none; } } public enum FitMode { none, width, height } protected override void UpdateScale() { if (SpriteInfo.IsNullOrEmpty(CurrentFrame)) return; base.UpdateScale(); if (m_fit != FitMode.none && Scale.x != Scale.y) m_fit = FitMode.none; } protected override Vector3 BaseScale { get { return m_fit switch { FitMode.none => Vector3.one, FitMode.width => new Vector3(1, 1, 1 / CurrentFrame.Ratio), FitMode.height => new Vector3(CurrentFrame.Ratio, 1, 1), _ => throw new NotSupportedException("Unsupported fit mode"), }; } } public override void Init() { InternalInit(); OnFrameUpdate(); UpdateShader(); } } }