Files
crtr/Assets/Cryville/Crtr/Event/TransformHandler.cs

144 lines
3.9 KiB
C#

using Cryville.Crtr.Skin.Components;
using System.Linq;
using UnityEngine;
namespace Cryville.Crtr.Event {
public abstract class TransformHandler : ContainerHandler {
protected abstract TransformHandler Parent { get; }
public override void Init() {
base.Init();
sgos = Components.OfType<SectionalGameObject>().ToArray();
}
SectionalGameObject[] sgos;
bool sflag; // Did pre-graphical update
Vector3 spos; // Start position offset
Vector3 ppt = Vector3.zero; // Previous screen point
Vector3 plp = Vector3.zero; // Previous local point
Vector3 pwp = Vector3.zero; // Previous world point
Vector3 ppwp = Vector3.zero; // Previous parent world point
double ptime; // Previous time
float length;
public override void StartPhysicalUpdate(ContainerState s) {
base.StartPhysicalUpdate(s);
if (CanDoGraphicalUpdate(s)) {
TransformAwake(s);
}
}
protected override void StartPreGraphicalUpdate(ContainerState s) {
base.StartPreGraphicalUpdate(s);
spos = Vector3.zero;
sflag = true;
pwp = Parent != null ? Parent.Position : Vector3.zero;
TransformAwake(s);
}
protected override void StartGraphicalUpdate(ContainerState s) {
base.StartGraphicalUpdate(s);
if (RootTransform) {
if (!sflag && Parent != null) { // No pre-graphical update; inherit from parent
spos = Parent.Position + (Vector3)s.ScreenPoint - (Vector3)s.Parent.ScreenPoint;
}
TransformAwake(s);
var p = Position;
foreach (var i in sgos) {
i.Reset();
i.AppendPoint(p, Rotation);
}
}
}
void TransformAwake(ContainerState s) {
plp = s.ScreenPoint;
pwp = Vector3.zero;
ptime = s.Time;
Position = spos;
Rotation = s.QuatDir;
}
public override void Update(ContainerState s, StampedEvent ev) {
base.Update(s, ev);
if (CanDoGraphicalUpdate(s)) {
ppt = s.ScreenPoint;
var tsv = s.ScrollVelocity;
Vector3 dpt = ppt - plp; // Delta 2D point
dpt.z = (float)((s.Time - ptime) * ChartPlayer.sv * tsv); // Delta Z
Quaternion rotq = Quaternion.Euler(s.Direction); // Rotation
var dwp = rotq * dpt; // Delta world point
var nl = length + dwp.magnitude; // New length
var tdist = s.Distance;
if (nl >= tdist) { // TODO Fix dist
s.Break();
return;
}
length = nl;
var wp = pwp + dwp; // World point
pwp = wp;
if (Parent != null) ppwp = Parent.Position;
plp += dpt;
ptime = s.Time;
Position = pwp + spos;
Rotation = s.QuatDir;
if (!RootTransform || s.CloneType == 3) return;
foreach (var i in sgos)
i.AppendPoint(Position, Rotation);
}
else UpdatePosition(s);
}
void UpdatePosition(ContainerState s) {
plp = s.ScreenPoint;
pwp = Vector3.zero;
ptime = s.Time;
length = 0;
Position = pwp + spos;
Rotation = s.QuatDir;
}
// TODO Fix anchor rotation
public override void Anchor() {
base.Anchor();
spos = ppt - Position;
if (ptime < cs.Time) { // Pre-graphical update ends before anchor, compensate from parent
var dspos = ppwp - (Parent != null ? Parent.Position : Vector3.zero);
spos += dspos;
Position -= dspos;
}
}
protected override void EndGraphicalUpdate(ContainerState s) {
base.EndGraphicalUpdate(s);
EndUpdatePosition(s);
var p = Position;
foreach (var i in sgos) {
i.AppendPoint(p, Rotation);
i.Seal();
}
sflag = false;
}
void EndUpdatePosition(ContainerState s) {
ppt = s.ScreenPoint;
var tsv = s.ScrollVelocity;
Vector3 dpt = ppt - plp;
dpt.z = (float)((s.Time - ptime) * ChartPlayer.sv * tsv);
Quaternion rotq = Quaternion.Euler(s.Direction);
var dwp = rotq * dpt; // Delta world point
var nl = length + dwp.magnitude; // New length
var tdist = s.Distance;
if (nl >= tdist)
dwp *= (tdist - length) / (nl - length);
length = nl;
var wp = pwp + dwp; // World point
pwp = wp;
plp += dpt;
Position = pwp + spos;
Rotation = s.QuatDir;
}
}
}