Browse Source

Remove timing class and create Clock classes that can hook into the render loop.

pull/1715/head
Jeremy Koritzinsky 8 years ago
parent
commit
6fe8dba8d9
  1. 5
      src/Avalonia.Animation/AnimationInstance`1.cs
  2. 47
      src/Avalonia.Animation/Clock.cs
  3. 51
      src/Avalonia.Animation/Timing.cs
  4. 7
      src/Avalonia.Animation/TransitionInstance.cs
  5. 21
      src/Avalonia.Visuals/Animation/RenderLoopClock.cs
  6. 2
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  7. 15
      src/Avalonia.Visuals/Rendering/IRenderLoopTask.cs
  8. 17
      src/Avalonia.Visuals/Rendering/RenderLoop.cs
  9. 6
      src/Windows/Avalonia.Win32/Win32Platform.cs

5
src/Avalonia.Animation/AnimationInstance`1.cs

@ -82,8 +82,7 @@ namespace Avalonia.Animation
protected override void Subscribed()
{
_timerSubscription = Timing.AnimationsTimer
.Subscribe(p => this.Step(p));
_timerSubscription = Clock.GlobalClock.Subscribe(Step);
}
public void Step(TimeSpan frameTick)
@ -225,4 +224,4 @@ namespace Avalonia.Animation
}
}
}
}
}

47
src/Avalonia.Animation/Clock.cs

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Text;
using Avalonia.Reactive;
namespace Avalonia.Animation
{
public class Clock : IObservable<TimeSpan>
{
public static Clock GlobalClock => AvaloniaLocator.Current.GetService<Clock>();
private ClockObservable _observable;
private IObservable<TimeSpan> _connectedObservable;
public Clock()
{
_observable = new ClockObservable();
_connectedObservable = _observable.Publish().RefCount();
}
public bool HasSubscriptions => _observable.HasSubscriptions;
public TimeSpan CurrentTime { get; private set; }
public void Pulse(long tickCount)
{
var time = TimeSpan.FromMilliseconds(tickCount);
_observable.Pulse(time);
CurrentTime = time;
}
public IDisposable Subscribe(IObserver<TimeSpan> observer)
{
return _connectedObservable.Subscribe(observer);
}
private class ClockObservable : LightweightObservableBase<TimeSpan>
{
public bool HasSubscriptions { get; private set; }
public void Pulse(TimeSpan tickCount) => PublishNext(tickCount);
protected override void Initialize() => HasSubscriptions = true;
protected override void Deinitialize() => HasSubscriptions = false;
}
}
}

51
src/Avalonia.Animation/Timing.cs

@ -1,51 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Reactive;
using Avalonia.Threading;
namespace Avalonia.Animation
{
/// <summary>
/// Provides global timing functions for animations.
/// </summary>
public class Timing
{
static TimerObservable _timer = new TimerObservable();
/// <summary>
/// Initializes static members of the <see cref="Timing"/> class.
/// </summary>
static Timing()
{
AnimationsTimer = _timer
.Publish()
.RefCount();
}
public static bool HasSubscriptions => _timer.HasSubscriptions;
internal static TimeSpan GetTickCount() => TimeSpan.FromMilliseconds(Environment.TickCount);
/// <summary>
/// Gets the animation timer.
/// </summary>
internal static IObservable<TimeSpan> AnimationsTimer
{
get;
}
public static void Pulse(long tickCount) => _timer.Pulse(tickCount);
private class TimerObservable : LightweightObservableBase<TimeSpan>
{
public bool HasSubscriptions { get; private set; }
public void Pulse(long tickCount) => PublishNext(TimeSpan.FromMilliseconds(tickCount));
protected override void Initialize() => HasSubscriptions = true;
protected override void Deinitialize() => HasSubscriptions = false;
}
}
}

7
src/Avalonia.Animation/TransitionInstance.cs

@ -45,10 +45,9 @@ namespace Avalonia.Animation
protected override void Subscribed()
{
startTime = Timing.GetTickCount();
timerSubscription = Timing.AnimationsTimer
.Subscribe(t => TimerTick(t));
startTime = Clock.GlobalClock.CurrentTime;
timerSubscription = Clock.GlobalClock.Subscribe(TimerTick);
PublishNext(0.0d);
}
}
}
}

21
src/Avalonia.Visuals/Animation/RenderLoopClock.cs

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Rendering;
namespace Avalonia.Animation
{
public class RenderLoopClock : Clock, IRenderLoopTask
{
bool IRenderLoopTask.NeedsUpdate => HasSubscriptions;
void IRenderLoopTask.Render()
{
}
void IRenderLoopTask.Update(long tickCount)
{
Pulse(tickCount);
}
}
}

2
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -166,7 +166,7 @@ namespace Avalonia.Rendering
bool IRenderLoopTask.NeedsUpdate => _dirty == null || _dirty.Count > 0;
void IRenderLoopTask.Update() => UpdateScene();
void IRenderLoopTask.Update(long tickCount) => UpdateScene();
void IRenderLoopTask.Render()
{

15
src/Avalonia.Visuals/Rendering/IRenderLoopTask.cs

@ -6,7 +6,20 @@ namespace Avalonia.Rendering
public interface IRenderLoopTask
{
bool NeedsUpdate { get; }
void Update();
void Update(long tickCount);
void Render();
}
public class MockRenderLoopTask : IRenderLoopTask
{
public bool NeedsUpdate => true;
public void Render()
{
}
public void Update(long tickCount)
{
}
}
}

17
src/Avalonia.Visuals/Rendering/RenderLoop.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Avalonia.Logging;
using Avalonia.Threading;
@ -17,7 +18,7 @@ namespace Avalonia.Rendering
private readonly IDispatcher _dispatcher;
private List<IRenderLoopTask> _items = new List<IRenderLoopTask>();
private IRenderTimer _timer;
private bool inTick;
private int inTick;
/// <summary>
/// Initializes a new instance of the <see cref="RenderLoop"/> class.
@ -84,13 +85,11 @@ namespace Avalonia.Rendering
private async void TimerTick(long tickCount)
{
if (!inTick)
if (Interlocked.CompareExchange(ref inTick, 1, 0) == 0)
{
inTick = true;
try
{
var needsUpdate = Animation.Timing.HasSubscriptions;
var needsUpdate = false;
foreach (var i in _items)
{
@ -105,13 +104,11 @@ namespace Avalonia.Rendering
{
await _dispatcher.InvokeAsync(() =>
{
Animation.Timing.Pulse(tickCount);
foreach (var i in _items)
{
i.Update();
i.Update(tickCount);
}
});
}).ConfigureAwait(false);
}
foreach (var i in _items)
@ -125,7 +122,7 @@ namespace Avalonia.Rendering
}
finally
{
inTick = false;
Interlocked.Exchange(ref inTick, 0);
}
}
}

6
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -9,6 +9,7 @@ using System.IO;
using System.Reactive.Disposables;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Input;
@ -76,6 +77,8 @@ namespace Avalonia.Win32
public static void Initialize(bool deferredRendering = true)
{
var clock = new RenderLoopClock();
AvaloniaLocator.CurrentMutable
.Bind<IClipboard>().ToSingleton<ClipboardImpl>()
.Bind<IStandardCursorFactory>().ToConstant(CursorFactory.Instance)
@ -84,6 +87,7 @@ namespace Avalonia.Win32
.Bind<IPlatformThreadingInterface>().ToConstant(s_instance)
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<IRenderTimer>().ToConstant(new RenderTimer(60))
.Bind<Clock>().ToConstant(clock)
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<IPlatformIconLoader>().ToConstant(s_instance);
@ -93,6 +97,8 @@ namespace Avalonia.Win32
if (OleContext.Current != null)
AvaloniaLocator.CurrentMutable.Bind<IPlatformDragSource>().ToSingleton<DragSource>();
AvaloniaLocator.Current.GetService<IRenderLoop>().Add(clock);
}
public bool HasMessages()

Loading…
Cancel
Save