Code structure cleanup.
This commit is contained in:
9
Assets/Cryville/Crtr/Skin/Components.meta
Normal file
9
Assets/Cryville/Crtr/Skin/Components.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ccb6283af616de43881e90749df8f19
|
||||
folderAsset: yes
|
||||
timeCreated: 1609142378
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
66
Assets/Cryville/Crtr/Skin/Components/MeshBase.cs
Normal file
66
Assets/Cryville/Crtr/Skin/Components/MeshBase.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
[DisallowMultipleComponent]
|
||||
public abstract class MeshBase : SkinComponent {
|
||||
public MeshBase() {
|
||||
SubmitProperty("color", new PropOp.Color(v => Color = v));
|
||||
SubmitProperty("opacity", new PropOp.Float(v => {
|
||||
var c = Color;
|
||||
c.a *= v;
|
||||
Color = c;
|
||||
}));
|
||||
SubmitProperty("zindex", new PropOp.Integer(v => ZIndex = (short)v));
|
||||
}
|
||||
|
||||
protected MeshWrapper mesh = new MeshWrapper();
|
||||
protected Material[] materials;
|
||||
|
||||
short _zindex;
|
||||
public short ZIndex {
|
||||
get {
|
||||
return _zindex;
|
||||
}
|
||||
set {
|
||||
if (value < 0 || value > 5000)
|
||||
throw new ArgumentOutOfRangeException("value", "Z-index must be in [0..5000]");
|
||||
_zindex = value;
|
||||
UpdateZIndex();
|
||||
}
|
||||
}
|
||||
protected void UpdateZIndex() {
|
||||
if (!mesh.Initialized) return;
|
||||
foreach (var mat in materials) {
|
||||
mat.renderQueue = _zindex;
|
||||
}
|
||||
}
|
||||
|
||||
Color _color = Color.white;
|
||||
public Color Color {
|
||||
get { return _color; }
|
||||
set {
|
||||
_color = value;
|
||||
UpdateColor();
|
||||
}
|
||||
}
|
||||
protected virtual void UpdateColor() {
|
||||
if (!mesh.Initialized) return;
|
||||
foreach (var mat in materials) {
|
||||
mat.color = _color;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDestroy() {
|
||||
DestroyMaterials();
|
||||
mesh.Destroy();
|
||||
}
|
||||
|
||||
protected void DestroyMaterials() {
|
||||
if (materials == null) return;
|
||||
foreach (var mat in materials) {
|
||||
Material.Destroy(mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/Components/MeshBase.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/Components/MeshBase.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75daba44e5811b943a08e6f137cc2b0c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
51
Assets/Cryville/Crtr/Skin/Components/MeshWrapper.cs
Normal file
51
Assets/Cryville/Crtr/Skin/Components/MeshWrapper.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
public class MeshWrapper {
|
||||
public GameObject MeshObject {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public MeshFilter MeshFilter {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
Mesh m_mesh;
|
||||
public Mesh Mesh {
|
||||
get { return m_mesh; }
|
||||
set { MeshFilter.sharedMesh = m_mesh = value; }
|
||||
}
|
||||
public Transform MeshTransform {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public Renderer Renderer {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public bool Initialized {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public static Material NewMaterial() {
|
||||
return Material.Instantiate(BuiltinResources.Materials["-SpriteMat"]);
|
||||
}
|
||||
public void Init(Transform parent) {
|
||||
MeshObject = new GameObject("__mesh__");
|
||||
MeshTransform = MeshObject.transform;
|
||||
MeshTransform.SetParent(parent, false);
|
||||
if (MeshObject.GetComponent<MeshFilter>() == null)
|
||||
MeshObject.AddComponent<MeshFilter>();
|
||||
if (MeshObject.GetComponent<MeshRenderer>() == null)
|
||||
MeshObject.AddComponent<MeshRenderer>();
|
||||
MeshFilter = MeshObject.GetComponent<MeshFilter>();
|
||||
Renderer = MeshObject.GetComponent<Renderer>();
|
||||
Initialized = true;
|
||||
}
|
||||
public void Destroy() {
|
||||
Mesh.Destroy(m_mesh);
|
||||
m_mesh = null;
|
||||
GameObject.Destroy(MeshObject);
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Skin/Components/MeshWrapper.cs.meta
Normal file
12
Assets/Cryville/Crtr/Skin/Components/MeshWrapper.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39e842e4379944f46ae46577bd5f51d4
|
||||
timeCreated: 1636616568
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
227
Assets/Cryville/Crtr/Skin/Components/PolygonSGO.cs
Normal file
227
Assets/Cryville/Crtr/Skin/Components/PolygonSGO.cs
Normal file
@@ -0,0 +1,227 @@
|
||||
using Cryville.Common.Buffers;
|
||||
using Cryville.Common.Pdt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
public class PolygonSGO : SectionalGameObject {
|
||||
static readonly SimpleObjectPool<List<Vector3>> _ptPool = new SimpleObjectPool<List<Vector3>>(1024);
|
||||
static readonly SimpleObjectPool<List<float>> _lPool = new SimpleObjectPool<List<float>>(1024);
|
||||
|
||||
static readonly ListPool<int> _indexPool = new ListPool<int>();
|
||||
static readonly ListPool<Vector3> _vertPool = new ListPool<Vector3>();
|
||||
static readonly ListPool<Vector2> _uvPool = new ListPool<Vector2>();
|
||||
static readonly ArrayPool<Vector2> _shapePool = new ArrayPool<Vector2>(0x100, 0x10000);
|
||||
|
||||
public PolygonSGO() {
|
||||
SubmitProperty("head", new PropOp.String(v => head.FrameName = v));
|
||||
SubmitProperty("body", new PropOp.String(v => body.FrameName = v));
|
||||
SubmitProperty("tail", new PropOp.String(v => tail.FrameName = v));
|
||||
SubmitProperty("shape", new op_set_shape(this), 2);
|
||||
}
|
||||
|
||||
#pragma warning disable IDE1006
|
||||
public class op_set_shape : PdtOperator {
|
||||
readonly PolygonSGO _self;
|
||||
public op_set_shape(PolygonSGO self) : base(1) {
|
||||
_self = self;
|
||||
}
|
||||
protected override unsafe void Execute() {
|
||||
var o = GetOperand(0);
|
||||
if (o.Type != PdtInternalType.Vector) throw new ArgumentException("Not a vector");
|
||||
_self._shapeLength = (o.Length - sizeof(int)) / sizeof(Vector2);
|
||||
if (_self._shape != null) _shapePool.Return(_self._shape);
|
||||
_self._shape = _shapePool.Rent(_self._shapeLength);
|
||||
for (int i = 0; i < _self._shapeLength; i++) {
|
||||
_self._shape[i] = o.As<Vector2>(i * sizeof(Vector2));
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore IDE1006
|
||||
|
||||
int _shapeLength = 0;
|
||||
Vector2[] _shape = null;
|
||||
float GetWidth() {
|
||||
float r = 0;
|
||||
for (int i = 1; i < _shapeLength; i++) {
|
||||
r += (_shape[i] - _shape[i-1]).magnitude;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public SpriteInfo head = new SpriteInfo();
|
||||
public SpriteInfo body = new SpriteInfo();
|
||||
public SpriteInfo tail = new SpriteInfo();
|
||||
|
||||
List<Vector3> vertices;
|
||||
List<float> lengths;
|
||||
float sumLength = 0;
|
||||
|
||||
public override void Init() {
|
||||
mesh.Init(transform);
|
||||
mesh.Mesh = new Mesh();
|
||||
|
||||
mesh.Renderer.sharedMaterials = materials = new Material[] {
|
||||
MeshWrapper.NewMaterial(),
|
||||
MeshWrapper.NewMaterial(),
|
||||
MeshWrapper.NewMaterial(),
|
||||
};
|
||||
head.Bind(materials[0]);
|
||||
body.Bind(materials[1]);
|
||||
tail.Bind(materials[2]);
|
||||
|
||||
base.Init();
|
||||
}
|
||||
|
||||
protected override void OnDestroy() {
|
||||
if (_shape != null) _shapePool.Return(_shape);
|
||||
if (vertices != null) {
|
||||
_ptPool.Return(vertices);
|
||||
_lPool.Return(lengths);
|
||||
}
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
protected override void AppendPointInternal(Vector3 p, Quaternion r) {
|
||||
if (vertices == null) {
|
||||
vertices = _ptPool.Rent();
|
||||
lengths = _lPool.Rent();
|
||||
}
|
||||
|
||||
for (int i = 0; i < _shapeLength; i++) {
|
||||
Vector2 sp = r * _shape[i];
|
||||
vertices.Add(p + (Vector3)sp);
|
||||
}
|
||||
|
||||
if (prevpt != null) {
|
||||
float len = (p - prevpt.Value).magnitude;
|
||||
lengths.Add(len);
|
||||
sumLength += len;
|
||||
}
|
||||
}
|
||||
|
||||
List<Vector3> verts;
|
||||
List<Vector2> uvs;
|
||||
List<int> trih = null, trib = null, trit = null;
|
||||
static readonly List<int> _emptyTris = new List<int>();
|
||||
|
||||
public override void Seal() {
|
||||
if (vertCount <= 1 || sumLength == 0) return;
|
||||
int vcpsec = _shapeLength; // Vertex Count Per Section
|
||||
float width = GetWidth();
|
||||
float headLength = 0;
|
||||
if (head.Frame != null) headLength = width / head.Ratio;
|
||||
float tailLength = 0;
|
||||
if (tail.Frame != null) tailLength = width / tail.Ratio;
|
||||
float endLength = headLength + tailLength;
|
||||
if (sumLength <= endLength) {
|
||||
// The total length of the two ends is longer than the whole mesh, squeeze the two ends
|
||||
float ratio = sumLength / endLength;
|
||||
headLength *= ratio;
|
||||
tailLength *= ratio;
|
||||
}
|
||||
|
||||
// Find the vertex counts needed for the three parts from the head
|
||||
float l0 = 0;
|
||||
int hvc = 0;
|
||||
for (; l0 < headLength && hvc < lengths.Count; hvc++)
|
||||
l0 += lengths[hvc];
|
||||
int bvc = 0;
|
||||
for (; l0 < sumLength - tailLength && hvc + bvc < lengths.Count; bvc++)
|
||||
l0 += lengths[hvc + bvc];
|
||||
int tvc = lengths.Count - hvc - bvc + 1;
|
||||
if (hvc > 0) {
|
||||
hvc++;
|
||||
bvc++;
|
||||
}
|
||||
bvc++;
|
||||
int vc = hvc + bvc + tvc;
|
||||
|
||||
verts = _vertPool.Rent(vc * vcpsec);
|
||||
uvs = _uvPool.Rent(vc * vcpsec);
|
||||
int i = 0; int t = 0; float l = 0;
|
||||
if (head.Frame != null) { GenerateMeshTo(verts, uvs, out trih, head, ref i, ref t, ref l, 0, headLength, vcpsec, hvc); }
|
||||
GenerateMeshTo(verts, uvs, out trib, body, ref i, ref t, ref l, headLength, sumLength - tailLength, vcpsec, hvc + bvc);
|
||||
if (tail.Frame != null) { GenerateMeshTo(verts, uvs, out trit, tail, ref i, ref t, ref l, sumLength - tailLength, sumLength, vcpsec, vc); }
|
||||
|
||||
mesh.Mesh.subMeshCount = 3;
|
||||
int m = 0;
|
||||
mesh.Mesh.SetVertices(verts);
|
||||
mesh.Mesh.SetUVs(0, uvs);
|
||||
mesh.Mesh.SetTriangles(head.Frame == null ? _emptyTris : trih, m++);
|
||||
mesh.Mesh.SetTriangles(trib, m++);
|
||||
mesh.Mesh.SetTriangles(tail.Frame == null ? _emptyTris : trit, m++);
|
||||
mesh.Mesh.RecalculateNormals();
|
||||
|
||||
_vertPool.Return(verts); verts = null;
|
||||
_uvPool.Return(uvs); uvs = null;
|
||||
if (trih != null) { _indexPool.Return(trih); trih = null; }
|
||||
if (trib != null) { _indexPool.Return(trib); trib = null; }
|
||||
if (trit != null) { _indexPool.Return(trit); trit = null; }
|
||||
}
|
||||
|
||||
void GenerateMeshTo(List<Vector3> verts, List<Vector2> uvs, out List<int> tris, SpriteInfo info, ref int i, ref int t, ref float l, float startl, float endl, int vcpsec, int vend) {
|
||||
if (i > lengths.Count) {
|
||||
tris = _indexPool.Rent(0);
|
||||
return;
|
||||
}
|
||||
|
||||
int t0 = t;
|
||||
var frame = info.Frame;
|
||||
|
||||
if (startl != 0) {
|
||||
float pl2 = l - lengths[i - 1];
|
||||
float fr2 = (startl - pl2) / (l - pl2);
|
||||
for (int j = 0; j < vcpsec; j++, t++) {
|
||||
verts[t] =
|
||||
vertices[vcpsec*(i-1)+j] * (1-fr2)
|
||||
+ vertices[vcpsec*i+j] * fr2;
|
||||
var u = j / (vcpsec - 1);
|
||||
if (frame != null) uvs[t] = frame.GetUV(u, 0);
|
||||
}
|
||||
}
|
||||
for (; t / vcpsec < vend - 1; i++) {
|
||||
var v = (l - startl) / (endl - startl);
|
||||
for (int j = 0; j < vcpsec; j++, t++) {
|
||||
verts[t] = vertices[vcpsec*i+j];
|
||||
var u = j / (vcpsec - 1);
|
||||
if (frame != null) uvs[t] = frame.GetUV(u, v);
|
||||
}
|
||||
l += lengths[i];
|
||||
}
|
||||
float pl = l - lengths[i - 1];
|
||||
float fr = (endl - pl) / (l - pl);
|
||||
for (int j = 0; j < vcpsec; j++, t++) {
|
||||
verts[t] =
|
||||
vertices[vcpsec*(i-1)+j] * (1-fr)
|
||||
+ vertices[vcpsec*i+j] * fr;
|
||||
var u = j / (vcpsec - 1);
|
||||
if (frame != null) uvs[t] = frame.GetUV(u, 1);
|
||||
}
|
||||
|
||||
tris = _indexPool.Rent((vend - t0 / vcpsec - 1) * (vcpsec - 1) * 6);
|
||||
int i3 = 0;
|
||||
for (int i1 = t0 + vcpsec + 1; i1 < t; i1++) {
|
||||
if (i1 % vcpsec == 0) continue;
|
||||
int i2 = i1 - vcpsec;
|
||||
tris[i3++] = i1 - 1;
|
||||
tris[i3++] = i2;
|
||||
tris[i3++] = i2 - 1;
|
||||
tris[i3++] = i1 - 1;
|
||||
tris[i3++] = i1;
|
||||
tris[i3++] = i2;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Reset() {
|
||||
base.Reset();
|
||||
if (mesh.Initialized) mesh.Mesh.Clear();
|
||||
if (vertices != null) {
|
||||
vertices.Clear();
|
||||
lengths.Clear();
|
||||
}
|
||||
sumLength = 0;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/Components/PolygonSGO.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/Components/PolygonSGO.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed3932875286a2947b9c600ba47f1066
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
50
Assets/Cryville/Crtr/Skin/Components/SectionalGameObject.cs
Normal file
50
Assets/Cryville/Crtr/Skin/Components/SectionalGameObject.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
public abstract class SectionalGameObject : MeshBase {
|
||||
protected Vector3? prevpt;
|
||||
protected Quaternion? prevrot;
|
||||
protected int vertCount = 0;
|
||||
Part part = Part.whole;
|
||||
enum Part {
|
||||
whole = 0,
|
||||
idle = 1,
|
||||
start = 2,
|
||||
end = 3,
|
||||
}
|
||||
|
||||
public SectionalGameObject() {
|
||||
SubmitProperty("partial", new PropOp.Boolean(v => part = Part.idle));
|
||||
SubmitProperty("part", new PropOp.Enum<Part>(v => part = v, v => (Part)v), 2);
|
||||
}
|
||||
|
||||
public override void Init() {
|
||||
UpdateZIndex();
|
||||
UpdateColor();
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void AppendPoint(Vector3 p) {
|
||||
AppendPoint(p, Quaternion.identity);
|
||||
}
|
||||
|
||||
public void AppendPoint(Vector3 p, Quaternion r) {
|
||||
if (prevpt == p && prevrot == r || ((int)part & 1) == 1) return;
|
||||
AppendPointInternal(p, r);
|
||||
// if (!headGenerated) Logger.Log("main", 0, "Skin/Polysec", "{0}", r);
|
||||
prevpt = p;
|
||||
prevrot = r;
|
||||
vertCount++;
|
||||
}
|
||||
|
||||
protected abstract void AppendPointInternal(Vector3 wp, Quaternion r);
|
||||
|
||||
public abstract void Seal();
|
||||
|
||||
public virtual void Reset() {
|
||||
vertCount = 0;
|
||||
prevpt = null;
|
||||
prevrot = null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f2666d577419bd43aec55ad614a43f4
|
||||
timeCreated: 1596633346
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
89
Assets/Cryville/Crtr/Skin/Components/SkinAnimation.cs
Normal file
89
Assets/Cryville/Crtr/Skin/Components/SkinAnimation.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using Cryville.Common;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Logger = Cryville.Common.Logging.Logger;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
public class SkinAnimation : SkinComponent {
|
||||
public SkinAnimation() {
|
||||
SubmitProperty("name", new PropOp.Identifier(v => Name = v));
|
||||
SubmitProperty("duration", new PropOp.Float(v => Duration = v));
|
||||
SubmitProperty("iteration", new PropOp.Float(v => Iteration = v));
|
||||
SubmitProperty("direction", new PropOp.Enum<AnimationDirection>(v => Direction = v, v => (AnimationDirection)v));
|
||||
SubmitProperty("delay", new PropOp.Float(v => Delay = v));
|
||||
Iteration = 1;
|
||||
}
|
||||
|
||||
SkinContext _skinContext;
|
||||
Transform _writeTransform;
|
||||
|
||||
AnimationSpan _anim;
|
||||
int _name;
|
||||
public int Name {
|
||||
set {
|
||||
if (_name == value) return;
|
||||
_name = value;
|
||||
if (value == 0) {
|
||||
_anim = null;
|
||||
}
|
||||
else {
|
||||
var id = new Identifier(value);
|
||||
AnimationSpan anim;
|
||||
if (!ChartPlayer.pskin.animations.TryGetValue(id, out anim)) {
|
||||
Logger.Log("main", 4, "Skin", "Animation {0} not found", id.Name);
|
||||
_anim = null;
|
||||
return;
|
||||
}
|
||||
_anim = anim;
|
||||
}
|
||||
}
|
||||
}
|
||||
public float Duration { get; private set; }
|
||||
public float Iteration { get; private set; }
|
||||
public AnimationDirection Direction { get; private set; }
|
||||
public float Delay { get; private set; }
|
||||
|
||||
double _startTime;
|
||||
|
||||
public override void Init() {
|
||||
_skinContext = new SkinContext(transform);
|
||||
}
|
||||
public override void Rewind(double time, Transform target) {
|
||||
_startTime = time;
|
||||
if (target == null) target = transform;
|
||||
_writeTransform = target;
|
||||
}
|
||||
public override void Tick(SkinContainer c, double time) {
|
||||
float _rtime = (float)(time - _startTime - Delay) / Duration;
|
||||
if (_rtime < 0) _rtime = 0;
|
||||
else if (_rtime > Iteration) {
|
||||
if (Direction.HasFlag(AnimationDirection.alternate)) {
|
||||
_rtime = Iteration % 2;
|
||||
if (_rtime > 1) _rtime = 2 - _rtime;
|
||||
}
|
||||
else {
|
||||
_rtime = Iteration % 1;
|
||||
if (_rtime == 0) _rtime = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Direction.HasFlag(AnimationDirection.alternate)) {
|
||||
_rtime %= 2;
|
||||
if (_rtime > 1) _rtime = 2 - _rtime;
|
||||
}
|
||||
else {
|
||||
_rtime %= 1;
|
||||
}
|
||||
}
|
||||
if (Direction.HasFlag(AnimationDirection.reverse)) _rtime = 1 - _rtime;
|
||||
if (_anim != null) c.MatchAnimation(_anim, _rtime, new RuntimeSkinContext(_skinContext, _writeTransform));
|
||||
}
|
||||
protected override void OnDestroy() { }
|
||||
}
|
||||
[Flags]
|
||||
public enum AnimationDirection {
|
||||
normal = 0,
|
||||
reverse = 1,
|
||||
alternate = 2,
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/Components/SkinAnimation.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/Components/SkinAnimation.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80318e36af5412345871bdbf80d49ef2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
41
Assets/Cryville/Crtr/Skin/Components/SkinComponent.cs
Normal file
41
Assets/Cryville/Crtr/Skin/Components/SkinComponent.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Cryville.Common;
|
||||
using Cryville.Common.Collections.Specialized;
|
||||
using Cryville.Common.Pdt;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
public abstract class SkinComponent : MonoBehaviour {
|
||||
/// <summary>
|
||||
/// The property operators of the component.
|
||||
/// </summary>
|
||||
public IntKeyedDictionary<SkinProperty> Properties { get; private set; }
|
||||
/// <summary>
|
||||
/// Submits a property.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the property.</param>
|
||||
/// <param name="property">The property.</param>
|
||||
protected void SubmitProperty(string name, PdtOperator property, int udl = 1) {
|
||||
Properties.Add(IdentifierManager.Shared.Request(name), new SkinProperty(property, udl));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a skin component.
|
||||
/// </summary>
|
||||
protected SkinComponent() {
|
||||
Properties = new IntKeyedDictionary<SkinProperty>();
|
||||
}
|
||||
|
||||
public virtual void Init() { }
|
||||
public virtual void Rewind(double time, Transform target) { }
|
||||
public virtual void Tick(SkinContainer c, double time) { }
|
||||
protected abstract void OnDestroy();
|
||||
}
|
||||
public struct SkinProperty {
|
||||
public PdtOperator Operator { get; set; }
|
||||
public int UpdateDynamicLevel { get; set; }
|
||||
public SkinProperty(PdtOperator op, int udl = 0) {
|
||||
Operator = op;
|
||||
UpdateDynamicLevel = udl;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Skin/Components/SkinComponent.cs.meta
Normal file
12
Assets/Cryville/Crtr/Skin/Components/SkinComponent.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a54d8e3558a89f8499fc049afd84e959
|
||||
timeCreated: 1623576806
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
98
Assets/Cryville/Crtr/Skin/Components/SpriteBase.cs
Normal file
98
Assets/Cryville/Crtr/Skin/Components/SpriteBase.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using Cryville.Common.Pdt;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
public abstract class SpriteBase : MeshBase {
|
||||
public SpriteBase() {
|
||||
SubmitProperty("bound", new op_set_bound(this));
|
||||
SubmitProperty("pivot", new PropOp.Vector2(v => Pivot = v));
|
||||
SubmitProperty("scale", new PropOp.Vector2(v => Scale = v));
|
||||
SubmitProperty("ui", new PropOp.Boolean(v => UI = v));
|
||||
}
|
||||
|
||||
#pragma warning disable IDE1006
|
||||
class op_set_bound : PdtOperator {
|
||||
readonly SpriteBase _self;
|
||||
public op_set_bound(SpriteBase self) : base(2) {
|
||||
_self = self;
|
||||
}
|
||||
protected override void Execute() {
|
||||
_self.SetBound(
|
||||
GetOperand(0).As<Vector2>(),
|
||||
GetOperand(1).As<Vector3>()
|
||||
);
|
||||
}
|
||||
}
|
||||
#pragma warning restore IDE1006
|
||||
|
||||
Vector2 _scale = Vector2.one;
|
||||
public Vector2 Scale {
|
||||
get { return _scale; }
|
||||
set {
|
||||
_scale = value;
|
||||
UpdateScale();
|
||||
}
|
||||
}
|
||||
protected virtual void UpdateScale() {
|
||||
if (!mesh.Initialized) return;
|
||||
var s = BaseScale;
|
||||
var ss = new Vector3(_scale.x, 1, _scale.y);
|
||||
s.Scale(ss);
|
||||
mesh.MeshTransform.localScale = s;
|
||||
OnPivotUpdate();
|
||||
}
|
||||
protected abstract Vector3 BaseScale {
|
||||
get;
|
||||
}
|
||||
protected virtual Vector3 BaseSize {
|
||||
get { return Vector3.one; }
|
||||
}
|
||||
|
||||
Vector2 _pivot;
|
||||
public Vector2 Pivot {
|
||||
get { return _pivot; }
|
||||
set {
|
||||
_pivot = value;
|
||||
OnPivotUpdate();
|
||||
}
|
||||
}
|
||||
protected void OnPivotUpdate() {
|
||||
if (!mesh.Initialized) return;
|
||||
var r = new Vector3(_pivot.x - BasePivot.x, 0, _pivot.y - BasePivot.y);
|
||||
r.Scale(mesh.MeshTransform.localScale);
|
||||
r.Scale(BaseSize);
|
||||
mesh.MeshTransform.localPosition = -r;
|
||||
}
|
||||
protected virtual Vector2 BasePivot {
|
||||
get { return Vector2.zero; }
|
||||
}
|
||||
|
||||
public void SetBound(Vector2 piv, Vector3 pos) {
|
||||
var r = Quaternion.Inverse(transform.rotation);
|
||||
var da = piv - Pivot;
|
||||
var dp = r * (pos - transform.localPosition);
|
||||
if (da.x != 0) _scale.x = dp.x / da.x;
|
||||
if (da.y != 0) _scale.y = dp.z / da.y;
|
||||
}
|
||||
|
||||
static readonly Quaternion uirot
|
||||
= Quaternion.Euler(new Vector3(-90, 0, 0));
|
||||
bool _ui;
|
||||
public bool UI {
|
||||
get { return _ui; }
|
||||
set {
|
||||
_ui = value;
|
||||
if (_ui) transform.localRotation = uirot;
|
||||
}
|
||||
}
|
||||
|
||||
protected void InternalInit(string meshName = "quad") {
|
||||
mesh.Init(transform);
|
||||
mesh.Renderer.sharedMaterials = materials = new Material[] { MeshWrapper.NewMaterial() };
|
||||
mesh.Mesh = Mesh.Instantiate(BuiltinResources.Meshes[meshName]);
|
||||
UpdateColor();
|
||||
UpdateScale();
|
||||
UpdateZIndex();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Skin/Components/SpriteBase.cs.meta
Normal file
12
Assets/Cryville/Crtr/Skin/Components/SpriteBase.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 248ab93b20a0ac9439afaee32357ed5c
|
||||
timeCreated: 1614907140
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
188
Assets/Cryville/Crtr/Skin/Components/SpritePlane.cs
Normal file
188
Assets/Cryville/Crtr/Skin/Components/SpritePlane.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Logger = Cryville.Common.Logging.Logger;
|
||||
|
||||
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; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The ratio of width divided by height.
|
||||
/// </summary>
|
||||
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 {
|
||||
Logger.Log("main", 4, "Skin", "Texture {0} not found", FrameName);
|
||||
Frame = null;
|
||||
}
|
||||
}
|
||||
else Frame = null;
|
||||
if (_mat != null) {
|
||||
_mat.mainTexture = Frame == null ? null : 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<FitMode>(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 SpriteInfo() };
|
||||
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 {
|
||||
switch (m_fit) {
|
||||
case FitMode.none: return Vector3.one;
|
||||
case FitMode.width: return new Vector3(1, 1, 1 / CurrentFrame.Ratio);
|
||||
case FitMode.height: return new Vector3(CurrentFrame.Ratio, 1, 1);
|
||||
default: throw new NotSupportedException("Unsupported fit mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Init() {
|
||||
InternalInit();
|
||||
OnFrameUpdate();
|
||||
UpdateShader();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Skin/Components/SpritePlane.cs.meta
Normal file
12
Assets/Cryville/Crtr/Skin/Components/SpritePlane.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76053cf6896b7304fb0ec26546de1ace
|
||||
timeCreated: 1609142271
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
15
Assets/Cryville/Crtr/Skin/Components/SpriteRect.cs
Normal file
15
Assets/Cryville/Crtr/Skin/Components/SpriteRect.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
public class SpriteRect : SpriteBase {
|
||||
public SpriteRect() { }
|
||||
|
||||
protected override Vector3 BaseScale {
|
||||
get { return Vector3.one; }
|
||||
}
|
||||
|
||||
public override void Init() {
|
||||
InternalInit();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Skin/Components/SpriteRect.cs.meta
Normal file
12
Assets/Cryville/Crtr/Skin/Components/SpriteRect.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a902fb77646e6eb4eb96d8ac86b3ee0e
|
||||
timeCreated: 1614821846
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
89
Assets/Cryville/Crtr/Skin/Components/SpriteScale3.cs
Normal file
89
Assets/Cryville/Crtr/Skin/Components/SpriteScale3.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
public class SpriteScale3 : SpritePlane {
|
||||
public SpriteScale3() {
|
||||
SubmitProperty("border", new PropOp.Vector2(v => Border = v));
|
||||
}
|
||||
|
||||
static readonly Dictionary<float, int> uvrefl
|
||||
= new Dictionary<float, int>() {
|
||||
{-0.5f, 0}, {-0.4f, 1}, {0.4f, 2}, {0.5f, 3},
|
||||
};
|
||||
static Vector2[] _origuv;
|
||||
protected static new Vector2[] OriginalUV {
|
||||
get {
|
||||
if (_origuv == null) {
|
||||
var m = BuiltinResources.Meshes["quad_scale3h"];
|
||||
Vector2[] uv = new Vector2[m.vertices.Length];
|
||||
for (int i = 0; i < uv.Length; i++) {
|
||||
uv[i] = new Vector2(
|
||||
uvrefl[m.vertices[i].x],
|
||||
uvrefl[m.vertices[i].z]
|
||||
);
|
||||
}
|
||||
_origuv = uv;
|
||||
}
|
||||
return _origuv;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 _border = new Vector2(0, 1);
|
||||
public Vector2 Border {
|
||||
get { return _border; }
|
||||
set {
|
||||
_border = value;
|
||||
UpdateScale();
|
||||
}
|
||||
}
|
||||
protected override void UpdateScale() {
|
||||
base.UpdateScale();
|
||||
if (!mesh.Initialized) return;
|
||||
UpdateUV();
|
||||
}
|
||||
|
||||
readonly Vector2[] _uvs = new Vector2[8];
|
||||
readonly Vector3[] _verts = new Vector3[8];
|
||||
protected override void UpdateUV() {
|
||||
var frame = CurrentFrame;
|
||||
if (SpriteInfo.IsNullOrEmpty(frame)) return;
|
||||
|
||||
Vector2[] muv = OriginalUV;
|
||||
|
||||
var or = frame.Ratio;
|
||||
var sr = Scale.x / Scale.y;
|
||||
var rr = or / sr;
|
||||
var b1 = rr * _border.x;
|
||||
var b2 = 1 - rr * (1 - _border.y);
|
||||
|
||||
for (int i = 0; i < muv.Length; i++) {
|
||||
float x; float bx;
|
||||
switch ((int)muv[i].x) {
|
||||
case 0: x = 0; bx = 0; break;
|
||||
case 1: x = _border.x; bx = b1; break;
|
||||
case 2: x = _border.y; bx = b2; break;
|
||||
case 3: x = 1; bx = 1; break;
|
||||
default: throw new NotSupportedException("Built-in resource corrupted");
|
||||
}
|
||||
float y;
|
||||
switch ((int)muv[i].y) {
|
||||
case 0: y = 0; break;
|
||||
case 3: y = 1; break;
|
||||
default: throw new NotSupportedException("Built-in resource corrupted");
|
||||
}
|
||||
_uvs[i] = frame.Frame.GetUV(x, y);
|
||||
bx -= 0.5f; y -= 0.5f;
|
||||
_verts[i] = new Vector3(bx, 0, y);
|
||||
}
|
||||
mesh.Mesh.uv = _uvs;
|
||||
mesh.Mesh.vertices = _verts;
|
||||
}
|
||||
|
||||
public override void Init() {
|
||||
InternalInit("quad_scale3h");
|
||||
OnFrameUpdate();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Skin/Components/SpriteScale3.cs.meta
Normal file
12
Assets/Cryville/Crtr/Skin/Components/SpriteScale3.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31dc4a947b5c7c645aa8fc2b82b4fba7
|
||||
timeCreated: 1615333501
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
175
Assets/Cryville/Crtr/Skin/Components/SpriteText.cs
Normal file
175
Assets/Cryville/Crtr/Skin/Components/SpriteText.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
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);
|
||||
int arrtype; int len;
|
||||
values.GetArraySuffix(out arrtype, out 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<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();
|
||||
}
|
||||
|
||||
Dictionary<char, SpriteInfo> m_frames;
|
||||
public Dictionary<char, SpriteInfo> Frames {
|
||||
get { return m_frames; }
|
||||
set { m_frames = value; UpdateFrames(); }
|
||||
}
|
||||
|
||||
readonly TargetString m_value = new TargetString();
|
||||
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<Vector3>());
|
||||
uvs.Add(tex, new List<Vector2>());
|
||||
tris.Add(tex, new List<int>());
|
||||
}
|
||||
}
|
||||
UpdateColor();
|
||||
UpdateScale();
|
||||
}
|
||||
|
||||
float sum_x;
|
||||
readonly Dictionary<Texture2D, MeshWrapper> meshes = new Dictionary<Texture2D, MeshWrapper>();
|
||||
readonly Dictionary<Texture2D, List<Vector3>> verts = new Dictionary<Texture2D, List<Vector3>>();
|
||||
readonly Dictionary<Texture2D, List<Vector2>> uvs = new Dictionary<Texture2D, List<Vector2>>();
|
||||
readonly Dictionary<Texture2D, List<int>> tris = new Dictionary<Texture2D, List<int>>();
|
||||
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) {
|
||||
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) {
|
||||
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.OnUpdate += UpdateScale;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Skin/Components/SpriteText.cs.meta
Normal file
12
Assets/Cryville/Crtr/Skin/Components/SpriteText.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c3781c012a298849b9276df00b6f59c
|
||||
timeCreated: 1636509150
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
59
Assets/Cryville/Crtr/Skin/Components/TrackLine.cs
Normal file
59
Assets/Cryville/Crtr/Skin/Components/TrackLine.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
public class TrackLine : SectionalGameObject {
|
||||
readonly List<Vector3> vertices = new List<Vector3>();
|
||||
|
||||
LineRenderer lineRenderer;
|
||||
|
||||
public TrackLine() {
|
||||
SubmitProperty("width", new PropOp.Float(v => Width = v));
|
||||
}
|
||||
|
||||
private float m_width;
|
||||
public float Width {
|
||||
get { return m_width; }
|
||||
set {
|
||||
m_width = value;
|
||||
if (lineRenderer != null) {
|
||||
lineRenderer.startWidth = value;
|
||||
lineRenderer.endWidth = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Init() {
|
||||
lineRenderer = gameObject.AddComponent<LineRenderer>();
|
||||
lineRenderer.materials = materials = new Material[] { MeshWrapper.NewMaterial() };
|
||||
Width = Width;
|
||||
base.Init();
|
||||
}
|
||||
|
||||
protected override void UpdateColor() {
|
||||
base.UpdateColor();
|
||||
if (lineRenderer != null) {
|
||||
lineRenderer.startColor = Color;
|
||||
lineRenderer.endColor = Color;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void AppendPointInternal(Vector3 p, Quaternion r) {
|
||||
vertices.Add(p);
|
||||
}
|
||||
|
||||
public override void Seal() {
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
lineRenderer.positionCount = vertices.Count;
|
||||
#else
|
||||
lineRenderer.SetVertexCount(vertices.Count);
|
||||
#endif
|
||||
for (int i = 0; i < vertices.Count; i++) lineRenderer.SetPosition(i, vertices[i]);
|
||||
}
|
||||
|
||||
public override void Reset() {
|
||||
base.Reset();
|
||||
vertices.Clear();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Skin/Components/TrackLine.cs.meta
Normal file
12
Assets/Cryville/Crtr/Skin/Components/TrackLine.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7806feaea6d6c2540b2cb950286d379c
|
||||
timeCreated: 1596635435
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
12
Assets/Cryville/Crtr/Skin/Components/TransformInterface.cs
Normal file
12
Assets/Cryville/Crtr/Skin/Components/TransformInterface.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin.Components {
|
||||
public class TransformInterface : SkinComponent {
|
||||
public TransformInterface() {
|
||||
SubmitProperty("pos", new PropOp.Vector3(v => transform.localPosition = v));
|
||||
SubmitProperty("rot", new PropOp.Vector3(v => transform.localRotation = Quaternion.Euler(v)));
|
||||
SubmitProperty("scale", new PropOp.Vector3(v => transform.localScale = v));
|
||||
}
|
||||
protected override void OnDestroy() { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a8a184616fd97d4a877c59c2ff76ba3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
75
Assets/Cryville/Crtr/Skin/EffectGroup.cs
Normal file
75
Assets/Cryville/Crtr/Skin/EffectGroup.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using Cryville.Common.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin {
|
||||
public class EffectGroup {
|
||||
public EffectDefinition Definition { get; private set; }
|
||||
readonly EffectPool _pool;
|
||||
class EffectPool : ObjectPool<EffectInstance> {
|
||||
readonly List<EffectInstance> _instances
|
||||
= new List<EffectInstance>();
|
||||
readonly EffectGroup _group;
|
||||
public EffectPool(EffectGroup group) : base(256) {
|
||||
_group = group;
|
||||
}
|
||||
protected override EffectInstance Construct() {
|
||||
var result = new EffectInstance(_group.Definition);
|
||||
_instances.Add(result);
|
||||
return result;
|
||||
}
|
||||
public void DisposeAll() {
|
||||
foreach (var i in _instances) i.Dispose();
|
||||
}
|
||||
}
|
||||
readonly Dictionary<float, EffectInstance> _instances
|
||||
= new Dictionary<float, EffectInstance>();
|
||||
readonly List<EffectInstance> _endQueue
|
||||
= new List<EffectInstance>();
|
||||
public EffectGroup(EffectDefinition def) {
|
||||
Definition = def;
|
||||
_pool = new EffectPool(this);
|
||||
}
|
||||
double _time;
|
||||
public void Tick(double time) {
|
||||
_time = time;
|
||||
while (_endQueue.Count > 0) {
|
||||
var item = _endQueue[0];
|
||||
if (item.EndTime > _time) break;
|
||||
_endQueue.RemoveAt(0);
|
||||
if (item.OnStateDone()) {
|
||||
QueueInstance(item);
|
||||
}
|
||||
else {
|
||||
item.Tick(time);
|
||||
_instances.Remove(item.Index);
|
||||
_pool.Return(item);
|
||||
}
|
||||
}
|
||||
foreach (var instance in _instances) {
|
||||
instance.Value.Tick(time);
|
||||
}
|
||||
}
|
||||
public void Emit(float index, Transform target = null) {
|
||||
EffectInstance instance;
|
||||
bool flag = _instances.TryGetValue(index, out instance);
|
||||
if (!flag) _instances.Add(index, instance = _pool.Rent());
|
||||
instance.Index = index;
|
||||
if (instance.CanEmit()) {
|
||||
if (flag) {
|
||||
var i = _endQueue.BinarySearch(instance);
|
||||
_endQueue.RemoveAt(i);
|
||||
}
|
||||
instance.OnEmit(_time, target);
|
||||
QueueInstance(instance);
|
||||
}
|
||||
}
|
||||
void QueueInstance(EffectInstance i) {
|
||||
var index = ~_endQueue.BinarySearch(i);
|
||||
_endQueue.Insert(index, i);
|
||||
}
|
||||
public void Dispose() {
|
||||
_pool.DisposeAll();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/EffectGroup.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/EffectGroup.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1fb5011d1fabf204c93bf6e12c842141
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
116
Assets/Cryville/Crtr/Skin/EffectInstance.cs
Normal file
116
Assets/Cryville/Crtr/Skin/EffectInstance.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using Cryville.Common;
|
||||
using Cryville.Crtr.Skin.Components;
|
||||
using Cryville.Crtr.Event;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin {
|
||||
public class EffectInstance : ISkinnableGroup, IComparable<EffectInstance> {
|
||||
readonly EffectDefinition _def;
|
||||
readonly SkinContainer _skinContainer;
|
||||
public Transform RootTransform { get; private set; }
|
||||
readonly SkinComponent[] _comps;
|
||||
public EffectInstance(EffectDefinition def) {
|
||||
_def = def;
|
||||
_skinContainer = new SkinContainer(this, _def.elements);
|
||||
RootTransform = new GameObject("effect:" + GetHashCode().ToString(CultureInfo.InvariantCulture)).transform;
|
||||
SkinContext = new SkinContext(RootTransform);
|
||||
PdtEvaluator.Instance.ContextCascadeInsertBlock();
|
||||
_skinContainer.MatchStatic();
|
||||
PdtEvaluator.Instance.ContextCascadeDiscardBlock();
|
||||
_comps = RootTransform.GetComponentsInChildren<SkinComponent>();
|
||||
foreach (var i in _comps) i.Init();
|
||||
_durationOp = new PropOp.Float(v => _duration = v);
|
||||
}
|
||||
public void Rewind(double time, Transform target) {
|
||||
_startTime = time;
|
||||
foreach (var i in _comps) i.Rewind(time, target);
|
||||
}
|
||||
Transform _currentTarget;
|
||||
Identifier _currentStateName = Identifier.Empty;
|
||||
EffectState _currentState;
|
||||
ChartEvent _ctxev;
|
||||
ContainerState _ctxstate;
|
||||
internal static readonly int _VAR_EFFECT_INDEX = IdentifierManager.Shared.Request("effect_index");
|
||||
readonly PropStores.Float _indexst = new PropStores.Float();
|
||||
public float Index {
|
||||
get { return _indexst.Value; }
|
||||
set { _indexst.Value = value; }
|
||||
}
|
||||
double _startTime;
|
||||
float _duration;
|
||||
readonly PropOp _durationOp;
|
||||
public double EndTime { get { return _startTime + _duration; } }
|
||||
public void Tick(double time) {
|
||||
foreach (var i in _comps) i.Tick(_skinContainer, time);
|
||||
}
|
||||
public bool CanEmit() {
|
||||
return _currentStateName.Key == 0 || _currentState.rewind.Key != 0;
|
||||
}
|
||||
public void OnEmit(double time, Transform target) {
|
||||
_currentTarget = target;
|
||||
_ctxev = PdtEvaluator.Instance.ContextEvent;
|
||||
_ctxstate = PdtEvaluator.Instance.ContextState;
|
||||
_skinContainer.MatchDynamic(0, true);
|
||||
if (_currentStateName.Key == 0) {
|
||||
EnterState(_def.init, time, _currentTarget, true);
|
||||
}
|
||||
else {
|
||||
if (_currentState.rewind.Key == 0) throw new InvalidOperationException("Cannot rewind");
|
||||
EnterState(_currentState.rewind, time, _currentTarget, true);
|
||||
}
|
||||
}
|
||||
void EnterState(Identifier name, double time, Transform target, bool emitting) {
|
||||
_currentStateName = name;
|
||||
_currentState = _def.states[name];
|
||||
Rewind(time, target);
|
||||
RootTransform.gameObject.SetActive(true);
|
||||
PdtEvaluator.Instance.ContextCascadeInsert();
|
||||
PdtEvaluator.Instance.ContextCascadeUpdate(_VAR_EFFECT_INDEX, _indexst.Source);
|
||||
PdtEvaluator.Instance.Evaluate(_durationOp, _currentState.duration);
|
||||
_skinContainer.MatchDynamic(1, emitting);
|
||||
PdtEvaluator.Instance.ContextCascadeDiscard();
|
||||
}
|
||||
public bool OnStateDone() {
|
||||
if (_currentState.next.Key == 0) {
|
||||
RootTransform.gameObject.SetActive(false);
|
||||
_currentStateName = Identifier.Empty;
|
||||
_currentState = null;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
PdtEvaluator.Instance.ContextEvent = _ctxev;
|
||||
PdtEvaluator.Instance.ContextState = _ctxstate;
|
||||
EnterState(_currentState.next, EndTime, _currentTarget, false);
|
||||
PdtEvaluator.Instance.ContextEvent = null;
|
||||
PdtEvaluator.Instance.ContextState = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public void Dispose() {
|
||||
GameObject.Destroy(RootTransform.gameObject);
|
||||
}
|
||||
|
||||
public string TypeName { get { throw new InvalidOperationException("Type name undefined"); } }
|
||||
public SkinContext SkinContext { get; private set; }
|
||||
public int AtAnchorDynamicLevel { get { return 1; } }
|
||||
public int OpenedAnchorName { get { return _currentStateName.Key; } }
|
||||
public void PushAnchorEvent(double time, int name) {
|
||||
throw new InvalidOperationException("Anchor not supported");
|
||||
}
|
||||
public void RegisterAnchor(int name) {
|
||||
throw new InvalidOperationException("Anchor not supported");
|
||||
}
|
||||
public bool TryGetAnchorsByName(int name, out IReadOnlyCollection<Anchor> result) {
|
||||
throw new InvalidOperationException("Anchor not supported");
|
||||
}
|
||||
|
||||
public int CompareTo(EffectInstance other) {
|
||||
int r = EndTime.CompareTo(other.EndTime);
|
||||
if (r != 0) return r;
|
||||
return GetHashCode().CompareTo(other.GetHashCode());
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/EffectInstance.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/EffectInstance.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f8a68f9f36942e40974e0477d44113a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
33
Assets/Cryville/Crtr/Skin/EffectManager.cs
Normal file
33
Assets/Cryville/Crtr/Skin/EffectManager.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Cryville.Common;
|
||||
using Cryville.Common.Collections.Specialized;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin {
|
||||
public class EffectManager {
|
||||
readonly IntKeyedDictionary<EffectGroup> _groups
|
||||
= new IntKeyedDictionary<EffectGroup>();
|
||||
public EffectManager(PdtSkin skin) {
|
||||
foreach (var e in skin.effects) {
|
||||
_groups.Add(e.Key.Key, new EffectGroup(e.Value));
|
||||
}
|
||||
}
|
||||
public void Tick(double time) {
|
||||
foreach (var g in _groups) g.Value.Tick(time);
|
||||
}
|
||||
public void Emit(int id, float index) {
|
||||
GetGroup(id).Emit(index);
|
||||
}
|
||||
public void EmitSelf(int id, float index, Transform target) {
|
||||
GetGroup(id).Emit(index, target);
|
||||
}
|
||||
EffectGroup GetGroup(int id) {
|
||||
EffectGroup result;
|
||||
if (_groups.TryGetValue(id, out result)) return result;
|
||||
throw new ArgumentException(string.Format("The effect \"{0}\" is not found", IdentifierManager.Shared.Retrieve(id)));
|
||||
}
|
||||
public void Dispose() {
|
||||
foreach (var g in _groups) g.Value.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/EffectManager.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/EffectManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cade9521fea2fc941b59b5973ee79c3c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
215
Assets/Cryville/Crtr/Skin/SkinContainer.cs
Normal file
215
Assets/Cryville/Crtr/Skin/SkinContainer.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using Cryville.Common.Collections.Specialized;
|
||||
using Cryville.Common.Pdt;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace Cryville.Crtr.Skin {
|
||||
public class SkinContainer {
|
||||
readonly ISkinnableGroup _group;
|
||||
readonly SkinElement _rootElement;
|
||||
readonly DynamicStack[] _stacks = new DynamicStack[3];
|
||||
readonly HashSet<SkinPropertyKey> _once = new HashSet<SkinPropertyKey>();
|
||||
public readonly IntKeyedDictionary<PropStores.Float> Variables = new IntKeyedDictionary<PropStores.Float>();
|
||||
|
||||
class DynamicStack {
|
||||
public readonly List<DynamicProperty> Properties = new List<DynamicProperty>();
|
||||
public readonly List<DynamicElement> Elements = new List<DynamicElement>();
|
||||
public void Clear() {
|
||||
Properties.Clear();
|
||||
Elements.Clear();
|
||||
}
|
||||
}
|
||||
struct DynamicProperty {
|
||||
public RuntimeSkinContext Context { get; set; }
|
||||
public SkinPropertyKey Key { get; set; }
|
||||
public PdtExpression Value { get; set; }
|
||||
}
|
||||
struct DynamicElement {
|
||||
public RuntimeSkinContext Context { get; set; }
|
||||
public SkinSelectors Selectors { get; set; }
|
||||
public SkinElement Element { get; set; }
|
||||
}
|
||||
public SkinContainer(ISkinnableGroup group, SkinElement rootElement) {
|
||||
_group = group;
|
||||
_rootElement = rootElement;
|
||||
for (int i = 0; i < _stacks.Length; i++) _stacks[i] = new DynamicStack();
|
||||
}
|
||||
public void MatchStatic() {
|
||||
var stack = _stacks[0];
|
||||
stack.Clear();
|
||||
MatchStatic(_rootElement, stack, new RuntimeSkinContext(_group.SkinContext));
|
||||
}
|
||||
void MatchStatic(SkinElement rel, DynamicStack stack, RuntimeSkinContext ctx) {
|
||||
var rc = ctx.ReadContext;
|
||||
PdtEvaluator.Instance.ContextTransform = rc.Transform;
|
||||
if (rc.PropSrcs != null) PdtEvaluator.Instance.ContextCascadeInsert(rc.PropSrcs);
|
||||
foreach (var p in rel.properties) {
|
||||
try {
|
||||
p.Key.ExecuteStatic(_group, ctx, p.Value, Variables);
|
||||
}
|
||||
catch (EvaluationFailureException) { }
|
||||
if (p.Key.IsValueRequired && !p.Value.IsConstant) stack.Properties.Add(
|
||||
new DynamicProperty { Context = ctx, Key = p.Key, Value = p.Value }
|
||||
);
|
||||
}
|
||||
PdtEvaluator.Instance.ContextTransform = null;
|
||||
foreach (var e in rel.elements) {
|
||||
try {
|
||||
var nctxs = e.Key.MatchStatic(_group, rc);
|
||||
if (nctxs != null) {
|
||||
var roflag = e.Key.annotations.Contains("if");
|
||||
var woflag = e.Key.annotations.Contains("then");
|
||||
foreach (var nctx in nctxs) {
|
||||
var nrctx = new RuntimeSkinContext(nctx, ctx, roflag, woflag);
|
||||
MatchStatic(e.Value, stack, nrctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SelectorNotAvailableException) {
|
||||
stack.Elements.Add(
|
||||
new DynamicElement { Context = ctx, Selectors = e.Key, Element = e.Value }
|
||||
);
|
||||
}
|
||||
}
|
||||
if (rc.PropSrcs != null) PdtEvaluator.Instance.ContextCascadeDiscard();
|
||||
}
|
||||
public void MatchDynamic(int dl, bool recursive = false) {
|
||||
var stack = _stacks[dl];
|
||||
if (stack.Properties.Count == 0 && stack.Elements.Count == 0) return;
|
||||
var nstack = dl + 1 < _stacks.Length ? _stacks[dl + 1] : null;
|
||||
if (nstack != null) nstack.Clear();
|
||||
Profiler.BeginSample("SkinContainer.MatchDynamic");
|
||||
if (!recursive) PdtEvaluator.Instance.ContextSkinContainer = this;
|
||||
for (int i = 0; i < stack.Properties.Count; i++) {
|
||||
DynamicProperty p = stack.Properties[i];
|
||||
p.Key.ExecuteDynamic(_group, p.Context, p.Value, Variables, dl);
|
||||
if (p.Key.annotations.Contains("once")) {
|
||||
stack.Properties.RemoveAt(i--);
|
||||
}
|
||||
if (p.Key.IsValueRequired && !p.Value.IsConstant && dl < 1) nstack.Properties.Add(p);
|
||||
}
|
||||
for (int i = 0; i < stack.Elements.Count; i++) {
|
||||
DynamicElement e = stack.Elements[i];
|
||||
var psrcs = e.Context.ReadContext.PropSrcs;
|
||||
if (psrcs != null) PdtEvaluator.Instance.ContextCascadeInsert(psrcs);
|
||||
if (e.Selectors.IsUpdatable(_group, dl)) {
|
||||
try {
|
||||
var nctx = e.Selectors.MatchDynamic(_group, e.Context.ReadContext);
|
||||
if (nctx != null) {
|
||||
MatchDynamic(e.Element, dl, nstack, new RuntimeSkinContext(
|
||||
nctx, e.Context, e.Selectors.annotations.Contains("if"), e.Selectors.annotations.Contains("then")
|
||||
));
|
||||
if (e.Selectors.annotations.Contains("once")) {
|
||||
stack.Elements.RemoveAt(i--);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SelectorNotAvailableException) {
|
||||
if (nstack == null) throw;
|
||||
nstack.Elements.Add(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (nstack == null) throw new SelectorNotAvailableException();
|
||||
nstack.Elements.Add(e);
|
||||
}
|
||||
if (psrcs != null) PdtEvaluator.Instance.ContextCascadeDiscard();
|
||||
}
|
||||
if (!recursive) PdtEvaluator.Instance.ContextSkinContainer = null;
|
||||
Profiler.EndSample();
|
||||
}
|
||||
void MatchDynamic(SkinElement rel, int dl, DynamicStack stack, RuntimeSkinContext ctx) {
|
||||
var rc = ctx.ReadContext;
|
||||
PdtEvaluator.Instance.ContextTransform = rc.Transform;
|
||||
if (rc.PropSrcs != null) PdtEvaluator.Instance.ContextCascadeInsert(rc.PropSrcs);
|
||||
foreach (var p in rel.properties) {
|
||||
if (p.Key.annotations.Contains("once")) {
|
||||
if (_once.Contains(p.Key)) continue;
|
||||
p.Key.ExecuteDynamic(_group, ctx, p.Value, Variables, dl);
|
||||
_once.Add(p.Key);
|
||||
}
|
||||
else {
|
||||
p.Key.ExecuteDynamic(_group, ctx, p.Value, Variables, dl);
|
||||
}
|
||||
}
|
||||
PdtEvaluator.Instance.ContextTransform = null;
|
||||
foreach (var e in rel.elements) {
|
||||
if (e.Key.IsUpdatable(_group, dl)) {
|
||||
SkinContext nctx = e.Key.MatchDynamic(_group, rc);
|
||||
if (nctx != null) MatchDynamic(e.Value, dl, stack, new RuntimeSkinContext(
|
||||
nctx, ctx, e.Key.annotations.Contains("if"), e.Key.annotations.Contains("then")
|
||||
));
|
||||
}
|
||||
else {
|
||||
if (stack == null) throw new SelectorNotAvailableException();
|
||||
stack.Elements.Add(
|
||||
new DynamicElement { Context = ctx, Selectors = e.Key, Element = e.Value }
|
||||
);
|
||||
}
|
||||
}
|
||||
if (rc.PropSrcs != null) PdtEvaluator.Instance.ContextCascadeDiscard();
|
||||
}
|
||||
readonly PropStores.Float _rtimest = new PropStores.Float();
|
||||
public void MatchAnimation(AnimationSpan span, float rtime, RuntimeSkinContext ctx) {
|
||||
PdtEvaluator.Instance.ContextSkinContainer = this;
|
||||
PdtEvaluator.Instance.ContextSelfValue = _rtimest.Source;
|
||||
MatchAnimationInternal(span, rtime, ctx);
|
||||
PdtEvaluator.Instance.ContextSelfValue = null;
|
||||
PdtEvaluator.Instance.ContextSkinContainer = null;
|
||||
}
|
||||
void MatchAnimationInternal(AnimationSpan span, float rtime, RuntimeSkinContext ctx) {
|
||||
_rtimest.Value = rtime;
|
||||
foreach (var p in span.properties) {
|
||||
p.Key.ExecuteDynamic(_group, ctx, p.Value, Variables, 0);
|
||||
}
|
||||
foreach (var s in span.spans) {
|
||||
if (rtime < s.Key.Behind || rtime >= s.Key.Ahead) continue;
|
||||
MatchAnimationInternal(s.Value, (rtime - s.Key.Behind) / (s.Key.Ahead - s.Key.Behind), ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class SkinContext {
|
||||
public Transform Transform { get; private set; }
|
||||
public IntKeyedDictionary<PropSrc> PropSrcs { get; private set; }
|
||||
public SkinContext(Transform transform, IntKeyedDictionary<PropSrc> propSrcs = null) {
|
||||
Transform = transform;
|
||||
PropSrcs = propSrcs;
|
||||
}
|
||||
}
|
||||
public struct RuntimeSkinContext {
|
||||
public SkinContext ReadContext { get; private set; }
|
||||
public Transform WriteTransform { get; private set; }
|
||||
public RuntimeSkinContext(SkinContext rw) {
|
||||
ReadContext = rw;
|
||||
WriteTransform = rw.Transform;
|
||||
}
|
||||
public RuntimeSkinContext(SkinContext r, Transform w) {
|
||||
ReadContext = r;
|
||||
WriteTransform = w;
|
||||
}
|
||||
public RuntimeSkinContext(SkinContext newctx, RuntimeSkinContext oldctx, bool roflag, bool woflag) {
|
||||
if (roflag) {
|
||||
ReadContext = newctx;
|
||||
WriteTransform = oldctx.WriteTransform;
|
||||
}
|
||||
else if (woflag) {
|
||||
ReadContext = oldctx.ReadContext;
|
||||
WriteTransform = newctx.Transform;
|
||||
}
|
||||
else {
|
||||
ReadContext = newctx;
|
||||
WriteTransform = newctx.Transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
public interface ISkinnableGroup {
|
||||
string TypeName { get; }
|
||||
SkinContext SkinContext { get; }
|
||||
int AtAnchorDynamicLevel { get; }
|
||||
int OpenedAnchorName { get; }
|
||||
bool TryGetAnchorsByName(int name, out IReadOnlyCollection<Anchor> result);
|
||||
void RegisterAnchor(int name);
|
||||
void PushAnchorEvent(double time, int name);
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/SkinContainer.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/SkinContainer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0631a620264a986468fbee7340b688de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
147
Assets/Cryville/Crtr/Skin/SkinDefinition.cs
Normal file
147
Assets/Cryville/Crtr/Skin/SkinDefinition.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using Cryville.Common;
|
||||
using Cryville.Common.Collections.Generic;
|
||||
using Cryville.Common.Pdt;
|
||||
using Cryville.Crtr.Extension;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Cryville.Crtr.Skin {
|
||||
public class SkinDefinition : MetaInfo {
|
||||
public const long CURRENT_FORMAT = 2;
|
||||
|
||||
[JsonRequired]
|
||||
public long format;
|
||||
|
||||
public string @base;
|
||||
|
||||
[JsonRequired]
|
||||
public string ruleset;
|
||||
|
||||
public List<string> frames = new List<string>();
|
||||
|
||||
[JsonIgnore]
|
||||
public PdtSkin Root { get; private set; }
|
||||
|
||||
public void LoadPdt(DirectoryInfo dir) {
|
||||
using (StreamReader pdtreader = new StreamReader(dir.FullName + "/" + data + ".pdt", Encoding.UTF8)) {
|
||||
var src = pdtreader.ReadToEnd();
|
||||
var interpreter = new SkinInterpreter(src, null);
|
||||
var format = interpreter.GetFormatVersion();
|
||||
if (format.Length == 1) {
|
||||
Root = new PdtSkin();
|
||||
Root.elements = (SkinElement)new SkinInterpreter(src, new PdtBinder()).Interpret(typeof(SkinElement));
|
||||
}
|
||||
else {
|
||||
switch (format[1]) {
|
||||
case 1:
|
||||
Root = (PdtSkin)new SkinInterpreter(src, new PdtBinder()).Interpret(typeof(PdtSkin));
|
||||
break;
|
||||
default: throw new NotSupportedException("Unsupported skin format");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PdtSkin {
|
||||
public Dictionary<Identifier, AnimationSpan> animations
|
||||
= new Dictionary<Identifier, AnimationSpan>();
|
||||
public Dictionary<Identifier, EffectDefinition> effects
|
||||
= new Dictionary<Identifier, EffectDefinition>();
|
||||
public SkinElement elements;
|
||||
|
||||
public void Optimize(PdtEvaluator etor) {
|
||||
foreach (var a in animations) {
|
||||
a.Value.Optimize(etor);
|
||||
}
|
||||
foreach (var e in effects) {
|
||||
var effect = e.Value;
|
||||
etor.ContextCascadeInsert();
|
||||
etor.ContextCascadeUpdate(EffectInstance._VAR_EFFECT_INDEX, PropSrc.Error);
|
||||
foreach(var s in effect.states) {
|
||||
etor.Optimize(s.Value.duration);
|
||||
}
|
||||
effect.elements.Optimize(etor);
|
||||
etor.ContextCascadeDiscard();
|
||||
}
|
||||
elements.Optimize(etor);
|
||||
}
|
||||
}
|
||||
|
||||
public class SkinElement {
|
||||
[ElementList]
|
||||
public PairList<SkinSelectors, SkinElement> elements
|
||||
= new PairList<SkinSelectors, SkinElement>();
|
||||
|
||||
[PropertyList]
|
||||
public PairList<SkinPropertyKey, PdtExpression> properties
|
||||
= new PairList<SkinPropertyKey, PdtExpression>();
|
||||
|
||||
public bool IsDynamic {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public void Optimize(PdtEvaluatorBase etor) {
|
||||
IsDynamic = true;
|
||||
foreach (var e in properties) {
|
||||
etor.Optimize(e.Value);
|
||||
if (!e.Value.IsConstant)
|
||||
IsDynamic = true;
|
||||
}
|
||||
foreach (var e in elements) {
|
||||
e.Key.Optimize(etor);
|
||||
e.Value.Optimize(etor);
|
||||
if (e.Value.IsDynamic)
|
||||
IsDynamic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class EffectDefinition {
|
||||
static readonly Identifier _ident_init = new Identifier("<init>");
|
||||
#pragma warning disable IDE1006
|
||||
public PdtExpression duration {
|
||||
set {
|
||||
EffectState s;
|
||||
if (!states.TryGetValue(_ident_init, out s))
|
||||
throw new InvalidOperationException("Cannot set duration and states at the same time");
|
||||
s.duration = value;
|
||||
}
|
||||
}
|
||||
#pragma warning restore IDE1006
|
||||
public Identifier init = _ident_init;
|
||||
public Dictionary<Identifier, EffectState> states = new Dictionary<Identifier, EffectState> {
|
||||
{ _ident_init, new EffectState() { rewind = _ident_init } }
|
||||
};
|
||||
public SkinElement elements;
|
||||
}
|
||||
|
||||
public class EffectState {
|
||||
public PdtExpression duration;
|
||||
public Identifier rewind;
|
||||
public Identifier next;
|
||||
}
|
||||
|
||||
public class AnimationSpan {
|
||||
[ElementList]
|
||||
public PairList<Clip, AnimationSpan> spans
|
||||
= new PairList<Clip, AnimationSpan>();
|
||||
|
||||
[PropertyList]
|
||||
public PairList<SkinPropertyKey, PdtExpression> properties
|
||||
= new PairList<SkinPropertyKey, PdtExpression>();
|
||||
|
||||
public void Optimize(PdtEvaluator etor) {
|
||||
foreach (var p in properties) {
|
||||
etor.Optimize(p.Value);
|
||||
}
|
||||
foreach (var e in spans) {
|
||||
e.Value.Optimize(etor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/SkinDefinition.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/SkinDefinition.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 808174467cb90134096a62e4d45d3b0a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
122
Assets/Cryville/Crtr/Skin/SkinInterpreter.cs
Normal file
122
Assets/Cryville/Crtr/Skin/SkinInterpreter.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using Cryville.Common.Pdt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Cryville.Crtr.Skin {
|
||||
public class SkinInterpreter : PdtInterpreter {
|
||||
public SkinInterpreter(string src, Binder binder) : base(src, binder) { }
|
||||
|
||||
readonly List<SkinSelector> s = new List<SkinSelector>();
|
||||
readonly HashSet<string> a = new HashSet<string>();
|
||||
readonly List<string> k = new List<string>(2);
|
||||
protected override object InterpretKey(Type type) {
|
||||
if (typeof(SkinElement).IsAssignableFrom(type))
|
||||
return InterpretSkinElementKey();
|
||||
else if (typeof(AnimationSpan).IsAssignableFrom(type))
|
||||
return InterpretAnimationSpanKey();
|
||||
else
|
||||
return base.InterpretKey(type);
|
||||
}
|
||||
object InterpretSkinElementKey() {
|
||||
s.Clear(); a.Clear(); k.Clear();
|
||||
bool invalidKeyFlag = false, compKeyFlag = false;
|
||||
while (true) {
|
||||
int pp = Position;
|
||||
switch (cc) {
|
||||
case '@':
|
||||
GetChar();
|
||||
a.Add(GetIdentifier());
|
||||
break;
|
||||
case '$':
|
||||
GetChar();
|
||||
s.Add(new SkinSelector.CreateObject());
|
||||
invalidKeyFlag = true;
|
||||
break;
|
||||
case '.':
|
||||
GetChar();
|
||||
if (cc == '.') {
|
||||
GetChar();
|
||||
s.Add(new SkinSelector.AtAnchor(GetIdentifier()));
|
||||
invalidKeyFlag = true;
|
||||
}
|
||||
else {
|
||||
var p3 = GetIdentifier();
|
||||
s.Add(new SkinSelector.Anchor(p3));
|
||||
if (!invalidKeyFlag) {
|
||||
if (k.Count != 1) invalidKeyFlag = true;
|
||||
else k.Add(p3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
GetChar();
|
||||
s.Add(new SkinSelector.Property(GetExp()));
|
||||
break;
|
||||
case ';':
|
||||
case ':':
|
||||
if (invalidKeyFlag) throw new FormatException("Invalid key format");
|
||||
return SkinPropertyKey.Construct(a, k, compKeyFlag);
|
||||
case '{':
|
||||
return new SkinSelectors(s, a);
|
||||
case '}':
|
||||
throw new FormatException("Invalid token");
|
||||
case '*':
|
||||
GetChar();
|
||||
compKeyFlag = true;
|
||||
break;
|
||||
default:
|
||||
var p4 = GetIdentifier();
|
||||
s.Add(new SkinSelector.ElementType(p4));
|
||||
if (!invalidKeyFlag) {
|
||||
if (k.Count != 0) invalidKeyFlag = true;
|
||||
else k.Add(p4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
ws();
|
||||
if (Position == pp) throw new FormatException("Invalid selector or key format");
|
||||
}
|
||||
}
|
||||
object InterpretAnimationSpanKey() {
|
||||
if ((ct & 0x0040) != 0 || cc == ',') {
|
||||
float start = 0, end = 1;
|
||||
if (cc != ',') {
|
||||
start = float.Parse(GetNumber());
|
||||
ws(); if (cc != ',') throw new FormatException("Invalid span format");
|
||||
}
|
||||
GetChar(); ws();
|
||||
if (cc != '{') end = float.Parse(GetNumber());
|
||||
ws();
|
||||
if (cc != '{') throw new FormatException("Invalid span format");
|
||||
return new Clip(start, end);
|
||||
}
|
||||
a.Clear(); k.Clear();
|
||||
while (true) {
|
||||
int pp = Position;
|
||||
switch (cc) {
|
||||
case '.':
|
||||
GetChar();
|
||||
if (k.Count != 1)
|
||||
throw new FormatException("Invalid key format");
|
||||
k.Add(GetIdentifier());
|
||||
break;
|
||||
case ';':
|
||||
case ':':
|
||||
return SkinPropertyKey.Construct(a, k, false);
|
||||
case '{':
|
||||
throw new FormatException("Invalid token");
|
||||
case '}':
|
||||
throw new FormatException("Invalid token");
|
||||
default:
|
||||
if (k.Count != 0)
|
||||
throw new FormatException("Invalid key format");
|
||||
k.Add(GetIdentifier());
|
||||
break;
|
||||
}
|
||||
ws();
|
||||
if (Position == pp) throw new FormatException("Invalid selector or key format");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/SkinInterpreter.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/SkinInterpreter.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6612c95458a84014dba8a31142def2b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
204
Assets/Cryville/Crtr/Skin/SkinPropertyKey.cs
Normal file
204
Assets/Cryville/Crtr/Skin/SkinPropertyKey.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using Cryville.Common;
|
||||
using Cryville.Common.Collections.Specialized;
|
||||
using Cryville.Common.Pdt;
|
||||
using Cryville.Crtr.Skin.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Skin {
|
||||
public abstract class SkinPropertyKey {
|
||||
public static SkinPropertyKey Construct(HashSet<string> a, IReadOnlyList<string> k, bool compKeyFlag) {
|
||||
if (a.Remove("has")) {
|
||||
if (k.Count != 1) throw new FormatException("Invalid anchor name");
|
||||
return new CreateAnchor(a, IdentifierManager.Shared.Request(k[0]));
|
||||
}
|
||||
else if (a.Remove("at")) {
|
||||
if (k.Count != 1) throw new FormatException("Invalid anchor name");
|
||||
return new SetAnchor(a, IdentifierManager.Shared.Request(k[0]));
|
||||
}
|
||||
else if (a.Remove("emit")) {
|
||||
if (k.Count != 1) throw new FormatException("Invalid effect name");
|
||||
return new EmitEffect(a, IdentifierManager.Shared.Request(k[0]));
|
||||
}
|
||||
else if (a.Remove("emit_self")) {
|
||||
if (k.Count != 1) throw new FormatException("Invalid effect name");
|
||||
return new EmitEffect(a, IdentifierManager.Shared.Request(k[0]), true);
|
||||
}
|
||||
else if (a.Remove("var")) {
|
||||
if (k.Count != 1) throw new FormatException("Invalid variable name");
|
||||
return new SetVariable(a, IdentifierManager.Shared.Request(k[0]));
|
||||
}
|
||||
switch (k.Count) {
|
||||
case 1:
|
||||
if (compKeyFlag) return new CreateComponent(a, GetComponentByName(k[0]));
|
||||
else return new SetProperty(a, typeof(TransformInterface), IdentifierManager.Shared.Request(k[0]));
|
||||
case 2:
|
||||
return new SetProperty(a, GetComponentByName(k[0]), IdentifierManager.Shared.Request(k[1]));
|
||||
default:
|
||||
throw new FormatException("Unknown error");
|
||||
}
|
||||
static Type GetComponentByName(string name) {
|
||||
Type result;
|
||||
if (BuiltinResources.Components.TryGetValue(name, out result)) return result;
|
||||
throw new ArgumentException(string.Format("Component type \"{0}\" not found", name));
|
||||
}
|
||||
}
|
||||
public readonly HashSet<string> annotations;
|
||||
public SkinPropertyKey(IEnumerable<string> a) {
|
||||
annotations = a.ToHashSet();
|
||||
}
|
||||
public abstract override string ToString();
|
||||
public abstract bool IsValueRequired { get; }
|
||||
public abstract void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars);
|
||||
public abstract void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl);
|
||||
public class CreateComponent : SkinPropertyKey {
|
||||
public Type Component { get; private set; }
|
||||
public CreateComponent(IEnumerable<string> a, Type component) : base(a) {
|
||||
Component = component;
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("*{0}", Component.Name);
|
||||
}
|
||||
public override bool IsValueRequired { get { return false; } }
|
||||
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
||||
ctx.WriteTransform.gameObject.AddComponent(Component);
|
||||
}
|
||||
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
||||
throw new InvalidOperationException("Component creation in dynamic context is not allowed");
|
||||
}
|
||||
}
|
||||
public class SetProperty : SkinPropertyKey {
|
||||
public Type Component { get; private set; }
|
||||
public int Name { get; private set; }
|
||||
public SetProperty(IEnumerable<string> a, Type component, int name) : base(a) {
|
||||
Component = component;
|
||||
Name = name;
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("{0}.{1}", Component.Name, IdentifierManager.Shared.Retrieve(Name));
|
||||
}
|
||||
public override bool IsValueRequired { get { return true; } }
|
||||
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
||||
Execute(ctx, GetPropOp(ctx.WriteTransform).Operator, exp);
|
||||
}
|
||||
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
||||
var prop = GetPropOp(ctx.WriteTransform);
|
||||
if (dl > prop.UpdateDynamicLevel) return;
|
||||
Execute(ctx, prop.Operator, exp);
|
||||
}
|
||||
void Execute(RuntimeSkinContext ctx, PdtOperator op, PdtExpression exp) {
|
||||
var psrcs = ctx.ReadContext.PropSrcs;
|
||||
if (psrcs != null) PdtEvaluator.Instance.ContextCascadeInsert(psrcs);
|
||||
if (!PdtEvaluator.Instance.Evaluate(op, exp))
|
||||
throw new EvaluationFailureException();
|
||||
if (psrcs != null) PdtEvaluator.Instance.ContextCascadeDiscard();
|
||||
}
|
||||
SkinProperty GetPropOp(Transform obj) {
|
||||
var ctype = Component;
|
||||
var comp = (SkinComponent)obj.GetComponent(ctype);
|
||||
if (comp == null) throw new InvalidOperationException(string.Format(
|
||||
"Trying to set property \"{0}\" but the component is not found",
|
||||
IdentifierManager.Shared.Retrieve(Name)
|
||||
));
|
||||
SkinProperty result;
|
||||
if (!comp.Properties.TryGetValue(Name, out result))
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Property \"{0}\" not found on component",
|
||||
IdentifierManager.Shared.Retrieve(Name)
|
||||
));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
public class CreateAnchor : SkinPropertyKey {
|
||||
public int Name { get; private set; }
|
||||
public CreateAnchor(IEnumerable<string> a, int name) : base(a) {
|
||||
Name = name;
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("@has {0}", IdentifierManager.Shared.Retrieve(Name));
|
||||
}
|
||||
public override bool IsValueRequired { get { return false; } }
|
||||
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
||||
group.RegisterAnchor(Name);
|
||||
}
|
||||
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
||||
throw new InvalidOperationException("Anchor creation in dynamic context is not allowed");
|
||||
}
|
||||
}
|
||||
public class SetAnchor : SkinPropertyKey {
|
||||
public int Name { get; private set; }
|
||||
public SetAnchor(IEnumerable<string> a, int name) : base(a) {
|
||||
Name = name;
|
||||
_timeOp = new PropOp.Float(v => _time = v);
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("@at {0}", IdentifierManager.Shared.Retrieve(Name));
|
||||
}
|
||||
public override bool IsValueRequired { get { return true; } }
|
||||
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
||||
throw new InvalidOperationException("Setting anchor in static context is not allowed");
|
||||
}
|
||||
float _time;
|
||||
readonly PropOp _timeOp;
|
||||
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
||||
if (dl != 1) return;
|
||||
var psrcs = ctx.ReadContext.PropSrcs;
|
||||
if (psrcs != null) PdtEvaluator.Instance.ContextCascadeInsert(psrcs);
|
||||
if (!PdtEvaluator.Instance.Evaluate(_timeOp, exp))
|
||||
throw new EvaluationFailureException();
|
||||
if (psrcs != null) PdtEvaluator.Instance.ContextCascadeDiscard();
|
||||
group.PushAnchorEvent(_time, Name);
|
||||
}
|
||||
}
|
||||
public class EmitEffect : SkinPropertyKey {
|
||||
public int Name { get; private set; }
|
||||
public bool IsSelf { get; private set; }
|
||||
public EmitEffect(IEnumerable<string> a, int name, bool isSelf = false) : base(a) {
|
||||
Name = name;
|
||||
IsSelf = isSelf;
|
||||
_op = new PropOp.Float(v => _index = v);
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format(IsSelf ? "@emit_self {0}" : "@emit {0}", IdentifierManager.Shared.Retrieve(Name));
|
||||
}
|
||||
public override bool IsValueRequired { get { return true; } }
|
||||
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
||||
throw new InvalidOperationException("Emitting effect in static context is not allowed");
|
||||
}
|
||||
float _index;
|
||||
readonly PropOp _op;
|
||||
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
||||
if (!PdtEvaluator.Instance.Evaluate(_op, exp))
|
||||
throw new EvaluationFailureException();
|
||||
if (IsSelf) ChartPlayer.effectManager.EmitSelf(Name, _index, ctx.WriteTransform);
|
||||
else ChartPlayer.effectManager.Emit(Name, _index);
|
||||
}
|
||||
}
|
||||
public class SetVariable : SkinPropertyKey {
|
||||
public int Name { get; private set; }
|
||||
public SetVariable(IEnumerable<string> a, int name) : base(a) {
|
||||
Name = name;
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("@var {0}", IdentifierManager.Shared.Retrieve(Name));
|
||||
}
|
||||
public override bool IsValueRequired { get { return true; } }
|
||||
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
||||
PropStores.Float v;
|
||||
if (!vars.TryGetValue(Name, out v))
|
||||
vars.Add(Name, v = new PropStores.Float());
|
||||
if (!PdtEvaluator.Instance.Evaluate(v.Target, exp))
|
||||
throw new EvaluationFailureException();
|
||||
}
|
||||
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
||||
PropStores.Float v;
|
||||
if (!vars.TryGetValue(Name, out v))
|
||||
throw new InvalidOperationException(string.Format("Variable \"{0}\" not defined", IdentifierManager.Shared.Retrieve(Name)));
|
||||
if (!PdtEvaluator.Instance.Evaluate(v.Target, exp))
|
||||
throw new EvaluationFailureException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/SkinPropertyKey.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/SkinPropertyKey.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0026616450e99143966fbd5c84eee9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
162
Assets/Cryville/Crtr/Skin/SkinSelectors.cs
Normal file
162
Assets/Cryville/Crtr/Skin/SkinSelectors.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using Cryville.Common;
|
||||
using Cryville.Common.Pdt;
|
||||
using Cryville.Crtr.Skin.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using UnityEngine;
|
||||
using CAnchor = Cryville.Crtr.Anchor;
|
||||
|
||||
namespace Cryville.Crtr.Skin {
|
||||
public class SkinSelectors {
|
||||
readonly SkinSelector[] selectors;
|
||||
public readonly HashSet<string> annotations;
|
||||
|
||||
public SkinSelectors(IEnumerable<SkinSelector> s, IEnumerable<string> a) {
|
||||
selectors = s.ToArray();
|
||||
annotations = a.ToHashSet();
|
||||
}
|
||||
public override string ToString() {
|
||||
if (selectors.Length == 0) return "";
|
||||
bool flag = false;
|
||||
string r = "";
|
||||
foreach (var a in annotations) {
|
||||
if (flag) r += " @" + a;
|
||||
else { r += "@" + a; flag = true; }
|
||||
}
|
||||
foreach (var s in selectors) {
|
||||
if (flag) r += " " + s.ToString();
|
||||
else { r += s.ToString(); flag = true; }
|
||||
}
|
||||
return r;
|
||||
}
|
||||
public void Optimize(PdtEvaluatorBase etor) {
|
||||
for (int i = 0; i < selectors.Length; i++) {
|
||||
selectors[i].Optimize(etor);
|
||||
}
|
||||
}
|
||||
public IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext ctx) {
|
||||
IEnumerable<SkinContext> result = new SkinContext[] { ctx };
|
||||
foreach (var s in selectors) {
|
||||
result = result.SelectMany(l => s.MatchStatic(g, l));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public bool IsUpdatable(ISkinnableGroup g, int dl) {
|
||||
foreach (var s in selectors)
|
||||
if (!s.IsUpdatable(g, dl)) return false;
|
||||
return true;
|
||||
}
|
||||
public SkinContext MatchDynamic(ISkinnableGroup g, SkinContext ctx) {
|
||||
foreach (var s in selectors) {
|
||||
ctx = s.MatchDynamic(g, ctx);
|
||||
if (ctx == null) return null;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class SkinSelector {
|
||||
protected SkinSelector() { }
|
||||
public abstract override string ToString();
|
||||
|
||||
public virtual void Optimize(PdtEvaluatorBase etor) { }
|
||||
public virtual IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext c) { throw new SelectorNotAvailableException(); }
|
||||
public virtual SkinContext MatchDynamic(ISkinnableGroup g, SkinContext c) { throw new SelectorNotAvailableException(); }
|
||||
public virtual bool IsUpdatable(ISkinnableGroup g, int dl) {
|
||||
return true;
|
||||
}
|
||||
public class CreateObject : SkinSelector {
|
||||
public CreateObject() { }
|
||||
public override string ToString() { return "$"; }
|
||||
|
||||
public override IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext c) {
|
||||
var obj = new GameObject("__obj__");
|
||||
obj.transform.SetParent(c.Transform, false);
|
||||
obj.AddComponent<TransformInterface>();
|
||||
return new SkinContext[] { new SkinContext(obj.transform) };
|
||||
}
|
||||
}
|
||||
public class Anchor : SkinSelector {
|
||||
public int Name { get; private set; }
|
||||
public Anchor(string name) {
|
||||
Name = IdentifierManager.Shared.Request(name);
|
||||
}
|
||||
public override string ToString() { return string.Format(".{0}", IdentifierManager.Shared.Retrieve(Name)); }
|
||||
|
||||
public override IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext c) {
|
||||
IReadOnlyCollection<CAnchor> anchors;
|
||||
if (g.TryGetAnchorsByName(Name, out anchors)) {
|
||||
return anchors.Select(a => a.SkinContext);
|
||||
}
|
||||
else return Enumerable.Empty<SkinContext>();
|
||||
}
|
||||
}
|
||||
public class AtAnchor : SkinSelector {
|
||||
public int Name { get; private set; }
|
||||
public AtAnchor(string name) {
|
||||
Name = IdentifierManager.Shared.Request(name);
|
||||
}
|
||||
public override string ToString() { return string.Format("..{0}", IdentifierManager.Shared.Retrieve(Name)); }
|
||||
|
||||
public override SkinContext MatchDynamic(ISkinnableGroup g, SkinContext c) {
|
||||
return g.OpenedAnchorName == Name ? c : null;
|
||||
}
|
||||
public override bool IsUpdatable(ISkinnableGroup g, int dl) {
|
||||
return dl >= g.AtAnchorDynamicLevel;
|
||||
}
|
||||
}
|
||||
public class Property : SkinSelector {
|
||||
readonly PdtExpression _exp;
|
||||
readonly PdtOperator _op;
|
||||
bool _flag;
|
||||
public Property(PdtExpression exp) {
|
||||
_exp = exp;
|
||||
_op = new PropOp.Boolean(v => _flag = v);
|
||||
}
|
||||
public override string ToString() { return string.Format("> {{{0}}}", _exp); }
|
||||
|
||||
public override void Optimize(PdtEvaluatorBase etor) {
|
||||
etor.Optimize(_exp);
|
||||
}
|
||||
public override IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext c) {
|
||||
var result = Match(c);
|
||||
if (result != null) return new SkinContext[] { result };
|
||||
else return Enumerable.Empty<SkinContext>();
|
||||
}
|
||||
public override SkinContext MatchDynamic(ISkinnableGroup g, SkinContext c) {
|
||||
return Match(c);
|
||||
}
|
||||
public SkinContext Match(SkinContext a) {
|
||||
PdtEvaluator.Instance.ContextTransform = a.Transform;
|
||||
try {
|
||||
if (!PdtEvaluator.Instance.Evaluate(_op, _exp))
|
||||
throw new EvaluationFailureException();
|
||||
return _flag ? a : null;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new SelectorNotAvailableException("The expression is not evaluatable under the current context", ex);
|
||||
}
|
||||
finally {
|
||||
PdtEvaluator.Instance.ContextTransform = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
public class ElementType : SkinSelector {
|
||||
readonly string _type;
|
||||
public ElementType(string type) { _type = type; }
|
||||
public override string ToString() { return _type; }
|
||||
|
||||
public override IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext c) {
|
||||
return g.TypeName == _type ? new SkinContext[] { c } : Enumerable.Empty<SkinContext>();
|
||||
}
|
||||
}
|
||||
}
|
||||
public class SelectorNotAvailableException : Exception {
|
||||
public SelectorNotAvailableException() : base("The selector is not available under the current context") { }
|
||||
public SelectorNotAvailableException(string message) : base(message) { }
|
||||
public SelectorNotAvailableException(string message, Exception innerException) : base(message, innerException) { }
|
||||
protected SelectorNotAvailableException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Skin/SkinSelectors.cs.meta
Normal file
11
Assets/Cryville/Crtr/Skin/SkinSelectors.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22030fa6d07750d4aa6bbf67722fb1ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user