Files
crtr/Assets/Cryville/Crtr/Components/SpriteText.cs
2022-11-14 16:05:44 +08:00

181 lines
4.9 KiB
C#

using Cryville.Common.Pdt;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr.Components {
public class SpriteText : SpriteBase {
public SpriteText() {
SubmitProperty("frames", new op_set_frames(this));
SubmitProperty("value", new PropOp.String(v => Value = v));
SubmitProperty("size", new PropOp.Float(v => Size = v));
SubmitProperty("spacing", new PropOp.Float(v => Spacing = v));
SubmitProperty("opacity", new PropOp.Float(v => Opacity = v));
}
#pragma warning disable IDE1006
class op_set_frames : PdtOperator {
readonly SpriteText _self;
public op_set_frames(SpriteText self) : base(2) {
_self = self;
}
protected unsafe override void Execute() {
var keys = GetOperand(0).AsString();
var values = GetOperand(1);
int arrtype; int len;
values.GetArraySuffix(out arrtype, out len);
var result = new Dictionary<char, SpriteInfo>(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();
}
readonly Dictionary<Texture2D, MeshWrapper> meshes = new Dictionary<Texture2D, MeshWrapper>();
Dictionary<char, SpriteInfo> m_frames;
public Dictionary<char, SpriteInfo> Frames {
get { return m_frames; }
set { m_frames = value; UpdateFrames(); UpdateScale(); }
}
public string m_value;
public string Value {
get { return m_value; }
set {
if (m_value == value) return;
m_value = value; UpdateScale();
}
}
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();
foreach (var f in m_frames) {
f.Value.Load();
if (frameHeight == 0) frameHeight = f.Value.Rect.height;
else if (frameHeight != f.Value.Rect.height) throw new Exception("Inconsistent frame height");
if (!meshes.ContainsKey(f.Value.Frame.Texture)) {
var m = new MeshWrapper();
m.Init(mesh.MeshTransform, transparent);
m.Mesh = new Mesh();
m.Renderer.material.mainTexture = f.Value.Frame.Texture;
meshes.Add(f.Value.Frame.Texture, m);
}
}
}
float sum_x;
void UpdateMeshes() {
// TODO optimize GC
if (meshes.Count == 0) return;
sum_x = 0;
int vc = m_value.Length * 4;
Dictionary<Texture2D, List<Vector3>> verts = new Dictionary<Texture2D, List<Vector3>>();
Dictionary<Texture2D, List<Vector2>> uvs = new Dictionary<Texture2D, List<Vector2>>();
foreach (var t in meshes.Keys) {
verts.Add(t, new List<Vector3>(vc));
uvs.Add(t, new List<Vector2>(vc));
}
foreach (var c in m_value) {
var f = m_frames[c];
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.Keys) {
var m = meshes[t].Mesh;
m.Clear();
int cc = verts[t].Count / 4;
int[] tris = new int[cc * 6];
for (int i = 0; i < cc; i++) {
tris[i * 6 ] = i * 4 ;
tris[i * 6 + 1] = i * 4 + 3;
tris[i * 6 + 2] = i * 4 + 1;
tris[i * 6 + 3] = i * 4 + 1;
tris[i * 6 + 4] = i * 4 + 3;
tris[i * 6 + 5] = i * 4 + 2;
}
m.vertices = verts[t].ToArray();
m.uv = uvs[t].ToArray();
m.triangles = tris;
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); }
}
float _opacity = 1;
public float Opacity {
get { return _opacity; }
set {
_opacity = value;
UpdateOpacity();
}
}
void UpdateOpacity() {
if (!mesh.Initialized) return;
foreach (var m in meshes.Values) {
var c = m.Renderer.material.color;
c.a = _opacity;
m.Renderer.material.color = c;
}
}
public override void Init() {
InternalInit();
UpdateFrames();
mesh.Mesh.Clear();
UpdateScale();
}
}
}