Code structure cleanup.
This commit is contained in:
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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user