using Cryville.Common.Buffers; using Cryville.Common.Pdt; using System; using System.Collections.Generic; using UnityEngine; namespace Cryville.Crtr.Skin.Components { public class SpriteText : SpriteBase { public SpriteText() { SubmitProperty("frames", new op_set_frames(this)); SubmitProperty("value", new PropOp.TargetString(() => Value)); SubmitProperty("size", new PropOp.Float(v => Size = v)); SubmitProperty("spacing", new PropOp.Float(v => Spacing = v)); } #pragma warning disable IDE1006 class op_set_frames : PdtOperator { readonly SpriteText _self; public op_set_frames(SpriteText self) : base(2) { _self = self; } protected override unsafe void Execute() { var keys = GetOperand(0).AsString(); var values = GetOperand(1); values.GetArraySuffix(out int arrtype, out int len); if (arrtype != PdtInternalType.String) throw new InvalidCastException("Not an array of strings"); if (len != keys.Length) throw new ArgumentException("Length of key not equal to frame count"); var result = new Dictionary(len); int o = 0; for (int i = 0; i < len; i++) { string v = values.AsString(o); o += v.Length * sizeof(char) + sizeof(int); result.Add(keys[i], new SpriteInfo { FrameName = v }); } _self.Frames = result; } } #pragma warning restore IDE1006 protected override void OnDestroy() { base.OnDestroy(); foreach (var m in meshes) m.Value.Destroy(); } Dictionary m_frames; public Dictionary Frames { get { return m_frames; } set { m_frames = value; UpdateFrames(); } } readonly TargetString m_value = new(); public TargetString Value { get { return m_value; } } public float m_size; public float Size { get { return m_size; } set { m_size = value; UpdateScale(); } } public float m_spacing; public float Spacing { get { return m_spacing; } set { m_spacing = value; UpdateScale(); } } protected override void UpdateScale() { if (!mesh.Initialized) return; UpdateMeshes(); base.UpdateScale(); } void UpdateFrames() { if (!mesh.Initialized) return; float frameHeight = 0; foreach (var m in meshes) m.Value.Destroy(); meshes.Clear(); verts.Clear(); uvs.Clear(); DestroyMaterials(); materials = new Material[m_frames.Count]; int i = 0; foreach (var f in m_frames) { if (SpriteInfo.IsNullOrEmpty(f.Value)) continue; if (frameHeight == 0) frameHeight = f.Value.Rect.height; else if (frameHeight != f.Value.Rect.height) throw new Exception("Inconsistent frame height for text component"); var tex = f.Value.Frame.Texture; if (!meshes.ContainsKey(tex)) { var m = new MeshWrapper(); m.Init(mesh.MeshTransform); m.Mesh = new Mesh(); var mat = MeshWrapper.NewMaterial(); mat.mainTexture = tex; m.Renderer.sharedMaterial = materials[i++] = mat; meshes.Add(tex, m); verts.Add(tex, new List()); uvs.Add(tex, new List()); tris.Add(tex, new List()); } } UpdateColor(); UpdateScale(); } float sum_x; readonly Dictionary meshes = new(); readonly Dictionary> verts = new(); readonly Dictionary> uvs = new(); readonly Dictionary> tris = new(); void UpdateMeshes() { if (meshes.Count == 0) return; sum_x = 0; foreach (var t in meshes) { var key = t.Key; verts[key].Clear(); uvs[key].Clear(); tris[key].Clear(); } foreach (var c in m_value) { if (!m_frames.TryGetValue(c, out SpriteInfo f)) { Game.MainLogger.Log(3, "Skin", "Could not render the character '{0}' in the string \"{1}\" on the text component because no image is assigned to that character.", c, m_value); continue; } var t = f.Frame.Texture; float w = f.Ratio * m_size; verts[t].Add(new Vector3(sum_x , 0, 0)); verts[t].Add(new Vector3(sum_x + w, 0, 0)); verts[t].Add(new Vector3(sum_x + w, 0, m_size)); verts[t].Add(new Vector3(sum_x , 0, m_size)); uvs[t].Add(f.Frame.GetUV(new Vector2(0, 0))); uvs[t].Add(f.Frame.GetUV(new Vector2(1, 0))); uvs[t].Add(f.Frame.GetUV(new Vector2(1, 1))); uvs[t].Add(f.Frame.GetUV(new Vector2(0, 1))); sum_x += w + m_spacing; } foreach (var t in meshes) { var key = t.Key; var m = meshes[key].Mesh; m.Clear(); int cc = verts[key].Count / 4; var _tris = tris[key]; for (int i = 0; i < cc; i++) { _tris.Add(i * 4); _tris.Add(i * 4 + 3); _tris.Add(i * 4 + 1); _tris.Add(i * 4 + 1); _tris.Add(i * 4 + 3); _tris.Add(i * 4 + 2); } m.SetVertices(verts[key]); m.SetUVs(0, uvs[key]); m.SetTriangles(tris[key], 0); m.RecalculateNormals(); } sum_x -= m_spacing; } protected override Vector3 BaseSize { get { return new Vector3(sum_x, 1, m_size); } } protected override Vector3 BaseScale { get { return Vector3.one; } } protected override Vector2 BasePivot { get { return new Vector2(-0.5f, -0.5f); } } public override void Init() { InternalInit(); UpdateFrames(); mesh.Mesh.Clear(); UpdateScale(); Value.Updated += UpdateScale; } } }