mirror of
https://github.com/ZuneDev/MicrosoftIris.git
synced 2026-07-27 13:13:29 -07:00
Start UIX.RenderApi OpenGL implementation
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Iris.Render.OpenGL
|
||||
{
|
||||
/// <summary>
|
||||
/// Shared state machine for animations: play/pause/reset, repeat counting and the
|
||||
/// async-notify event. Target property interpolation is intentionally minimal here
|
||||
/// (see <see cref="GLKeyframeAnimation"/>); full per-frame evaluation is a stage-3 TODO.
|
||||
/// </summary>
|
||||
public abstract class GLAnimation : SharedRenderObject, IAnimation
|
||||
{
|
||||
public int RepeatCount { get; set; }
|
||||
public bool IsPlaying { get; private set; }
|
||||
public bool IsActive { get; private set; }
|
||||
public bool AutoReset { get; set; }
|
||||
public AnimationResetBehavior ResetBehavior { get; set; } = AnimationResetBehavior.LeaveCurrent;
|
||||
|
||||
public event AsyncNotifyHandler? AsyncNotifyEvent;
|
||||
|
||||
public virtual void Play()
|
||||
{
|
||||
IsPlaying = true;
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public virtual void Pause() => IsPlaying = false;
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
IsPlaying = false;
|
||||
IsActive = false;
|
||||
}
|
||||
|
||||
public virtual void InstantAdvance(float advanceTime) { }
|
||||
|
||||
public virtual void InstantFinish()
|
||||
{
|
||||
IsPlaying = false;
|
||||
IsActive = false;
|
||||
}
|
||||
|
||||
protected void RaiseAsyncNotify(int cookie) => AsyncNotifyEvent?.Invoke(cookie);
|
||||
|
||||
/// <summary>Advance internal time. Called by the animation system each pulse.</summary>
|
||||
internal virtual void Advance(int advanceMs) { }
|
||||
}
|
||||
|
||||
public sealed class GLAnimationGroup : GLAnimation, IAnimationGroup
|
||||
{
|
||||
private readonly List<GLAnimation> m_members = new List<GLAnimation>();
|
||||
|
||||
public override void Play()
|
||||
{
|
||||
base.Play();
|
||||
foreach (GLAnimation a in m_members)
|
||||
a.Play();
|
||||
}
|
||||
|
||||
internal void Add(GLAnimation animation) => m_members.Add(animation);
|
||||
|
||||
internal override void Advance(int advanceMs)
|
||||
{
|
||||
foreach (GLAnimation a in m_members)
|
||||
a.Advance(advanceMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Iris.Render.OpenGL
|
||||
{
|
||||
/// <summary>
|
||||
/// Owns the set of live animations and advances them on each pulse. Pause/step/resume
|
||||
/// gate whether time flows. Objects are created here so the session stays a thin factory.
|
||||
/// </summary>
|
||||
public sealed class GLAnimationSystem : IAnimationSystem
|
||||
{
|
||||
private readonly List<GLAnimation> m_animations = new List<GLAnimation>();
|
||||
private bool m_paused;
|
||||
|
||||
public int UpdatesPerSecond { get; set; } = 60;
|
||||
public float SpeedAdjustment { get; set; } = 1f;
|
||||
public bool BackCompat { set { /* compatibility flag; no behavioral change */ } }
|
||||
|
||||
public IKeyframeAnimation CreateKeyframeAnimation(object objUser, AnimationInput initialValue)
|
||||
{
|
||||
var a = new GLKeyframeAnimation(initialValue);
|
||||
m_animations.Add(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
public IAnimationGroup CreateAnimationGroup(object objUser)
|
||||
{
|
||||
var g = new GLAnimationGroup();
|
||||
m_animations.Add(g);
|
||||
return g;
|
||||
}
|
||||
|
||||
public IExternalAnimationInput CreateExternalAnimationInput(object objUser, IAnimationPropertyMap propertyMap)
|
||||
=> new GLExternalAnimationInput(propertyMap);
|
||||
|
||||
public void PulseTimeAdvance(int nAdvanceMs)
|
||||
{
|
||||
if (m_paused)
|
||||
return;
|
||||
int scaled = (int)(nAdvanceMs * SpeedAdjustment);
|
||||
foreach (GLAnimation a in m_animations)
|
||||
{
|
||||
if (a.IsPlaying)
|
||||
a.Advance(scaled);
|
||||
}
|
||||
}
|
||||
|
||||
public void PauseAnimations() => m_paused = true;
|
||||
|
||||
public void StepAnimations(int nAdvanceMs)
|
||||
{
|
||||
foreach (GLAnimation a in m_animations)
|
||||
{
|
||||
if (a.IsPlaying)
|
||||
a.Advance(nAdvanceMs);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResumeAnimations() => m_paused = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Iris.Render.OpenGL
|
||||
{
|
||||
/// <summary>
|
||||
/// An externally-driven animation input. Providers publish named values that
|
||||
/// animations can reference. We store the published values; wiring them into
|
||||
/// keyframe evaluation is a stage-3 TODO alongside full animation support.
|
||||
/// </summary>
|
||||
public sealed class GLExternalAnimationInput : SharedRenderObject, IExternalAnimationInput
|
||||
{
|
||||
private static uint s_nextId = 1;
|
||||
|
||||
public GLExternalAnimationInput(IAnimationPropertyMap? propertyMap)
|
||||
{
|
||||
UniqueId = s_nextId++;
|
||||
PropertyMap = propertyMap;
|
||||
}
|
||||
|
||||
public uint UniqueId { get; }
|
||||
internal IAnimationPropertyMap? PropertyMap { get; }
|
||||
|
||||
public IAnimationInputProvider CreateProvider(object objUser) => new GLAnimationInputProvider();
|
||||
}
|
||||
|
||||
public sealed class GLAnimationInputProvider : SharedRenderObject, IAnimationInputProvider
|
||||
{
|
||||
private readonly Dictionary<string, object> m_values = new Dictionary<string, object>();
|
||||
|
||||
public void PublishFloat(string propertyName, float value) => m_values[propertyName] = value;
|
||||
public void PublishVector2(string propertyName, Vector2 value) => m_values[propertyName] = value;
|
||||
public void PublishVector3(string propertyName, Vector3 value) => m_values[propertyName] = value;
|
||||
public void PublishVector4(string propertyName, Vector4 value) => m_values[propertyName] = value;
|
||||
public void PublishQuaternion(string propertyName, Quaternion value) => m_values[propertyName] = value;
|
||||
|
||||
public void RevokeFloat(string propertyName) => m_values.Remove(propertyName);
|
||||
public void RevokeVector2(string propertyName) => m_values.Remove(propertyName);
|
||||
public void RevokeVector3(string propertyName) => m_values.Remove(propertyName);
|
||||
public void RevokeVector4(string propertyName) => m_values.Remove(propertyName);
|
||||
public void RevokeQuaternion(string propertyName) => m_values.Remove(propertyName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Iris.Render.OpenGL
|
||||
{
|
||||
/// <summary>
|
||||
/// Keyframe animation. Stores keyframes, targets and events and runs the play-state
|
||||
/// machine. Smooth per-frame evaluation and target property mutation are a stage-3
|
||||
/// TODO; today it drives lifecycle/events so higher layers sequence correctly.
|
||||
/// </summary>
|
||||
public sealed class GLKeyframeAnimation : GLAnimation, IKeyframeAnimation
|
||||
{
|
||||
private readonly struct Target
|
||||
{
|
||||
public readonly IAnimatable Object;
|
||||
public readonly string Property;
|
||||
public readonly string? Mask;
|
||||
public Target(IAnimatable o, string property, string? mask)
|
||||
{
|
||||
Object = o;
|
||||
Property = property;
|
||||
Mask = mask;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<AnimationKeyframe> m_keyframes = new List<AnimationKeyframe>();
|
||||
private readonly List<Target> m_targets = new List<Target>();
|
||||
private readonly List<AnimationEvent> m_events = new List<AnimationEvent>();
|
||||
|
||||
public GLKeyframeAnimation(AnimationInput initialValue)
|
||||
{
|
||||
InitialValue = initialValue;
|
||||
Type = initialValue.InputType;
|
||||
}
|
||||
|
||||
public int KeyframeCount => m_keyframes.Count;
|
||||
public AnimationInput InitialValue { get; }
|
||||
public AnimationInput Reference { get; set; } = null!;
|
||||
public AnimationInput Scale { get; set; } = null!;
|
||||
public AnimationInputType Type { get; }
|
||||
|
||||
public void AddKeyframe(AnimationKeyframe keyframe) => m_keyframes.Add(keyframe);
|
||||
|
||||
public AnimationKeyframe GetKeyframe(int keyframeIndex) => m_keyframes[keyframeIndex];
|
||||
|
||||
public void SetKeyframe(int keyframeIndex, AnimationKeyframe keyframe) => m_keyframes[keyframeIndex] = keyframe;
|
||||
|
||||
public void AddTarget(IAnimatable targetObject, string targetProperty)
|
||||
=> m_targets.Add(new Target(targetObject, targetProperty, null));
|
||||
|
||||
public void AddTarget(IAnimatable targetObject, string targetProperty, string targetPropertyMask)
|
||||
=> m_targets.Add(new Target(targetObject, targetProperty, targetPropertyMask));
|
||||
|
||||
public void RemoveTarget(IAnimatable targetObject, string targetProperty, string targetPropertyMask)
|
||||
=> m_targets.RemoveAll(t => ReferenceEquals(t.Object, targetObject)
|
||||
&& t.Property == targetProperty && t.Mask == targetPropertyMask);
|
||||
|
||||
public void RemoveAllTargets() => m_targets.Clear();
|
||||
|
||||
public void AddStageEvent(AnimationStage animationStage, AnimationEvent animationEvent) => m_events.Add(animationEvent);
|
||||
public void AddTimeEvent(float absoluteTime, AnimationEvent animationEvent) => m_events.Add(animationEvent);
|
||||
public void AddProgressEvent(float progress, AnimationEvent animationEvent) => m_events.Add(animationEvent);
|
||||
public void AddValueEvent(ValueEventCondition condition, AnimationInput reference, AnimationEvent animationEvent) => m_events.Add(animationEvent);
|
||||
public void RemoveEvent(AnimationEvent animationEvent) => m_events.Remove(animationEvent);
|
||||
public void RemoveAllEvents() => m_events.Clear();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user