public void DrawOnMe(SKSurface surface) { if (_currentRenderedFrame != null) { _currentRenderedFrame.DrawFunction(surface, _currentRenderedFrame.FramePoints); _currentRenderedFrame = null; } else { using (var c = surface.Canvas) { c.Clear(); } } }
private async Task RestartActionBlock() { while (_keepLoopAlive) { _animationFlow = new AnimationFlow((arg) => { _currentRenderedFrame = arg; _currentDisplay.SignalRedraw(); }, _uiTaskScheduler); if (_shouldStartRandomAnim) { _animationFlow.StartRandomAnimationsLoop(_randomAnimationTime); //only start one at a time _shouldStartRandomAnim = false; } var completionTask = await Task.WhenAny(_animationFlow.CompletionTask); var message = "Animation Loop Has Closed: it "; switch (completionTask.Status) { case TaskStatus.RanToCompletion: message += "ran to completion"; break; case TaskStatus.Canceled: message += "was canceled"; break; case TaskStatus.Faulted: message += "has faulted"; Debug.WriteLine(completionTask.Exception.InnerException.InnerException.InnerException); break; } Debug.WriteLine("\n" + message); } }
public AnimationFlow(Action <RenderedFrame> notifyFrameReady, TaskScheduler uiScheduler) : base(DataflowOptions.Default) { _animations = new CurrentAnimationsBlock(); _frameQueue = new FrameQueueBlock <AnimationBase[]>(new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }); _renderFrame = new TransformBlock <AnimationBase[], RenderedFrame>((arg) => { var animFrame = new List <HashSet <AnimatedPoint> >(); foreach (var anim in arg) { if (!anim.IsSetup) { anim.SetupAnimation(); } HashSet <AnimatedPoint> x = new HashSet <AnimatedPoint>(); //dont render a frame that won't be drawn if (anim.CurrentFrame <= anim.NumFrames) { x = anim.RenderFrame(anim.CurrentFrame); } animFrame.Add(x); } //allows any derived draw function //newest animation determines how all current animations will be drawn var rend = new RenderedFrame(arg[arg.Length - 1].DrawPointFrame); //no use in "combining" animations unless there is more than 1 anim for this frame if (animFrame.Count > 1) { var dict = new Dictionary <SKPoint, AnimatedPoint>(); //for each animation render for this frame foreach (var frame in animFrame) { //for each point changed in the rendered animation foreach (var pointChange in frame) { //if point has been previously animated, update it if (dict.ContainsKey(pointChange.Point)) { dict[pointChange.Point].XDisplacement += pointChange.XDisplacement; dict[pointChange.Point].YDisplacement += pointChange.YDisplacement; } //or add it else { dict[pointChange.Point] = pointChange; } } } //check each point after its duplicates have been accumulated foreach (var point in dict.Values) { var p = dict[point.Point]; //only want to limit to max displacement if it has been specified if (p.LimitDisplacement) { if (Math.Abs(p.XDisplacement) > p.MaxXDisplacement) { var oldDisp = p.XDisplacement; p.XDisplacement = p.MaxXDisplacement; if (oldDisp < 0) { p.XDisplacement *= -1; } } if (Math.Abs(p.YDisplacement) > p.MaxYDisplacement) { var oldDisp = p.YDisplacement; p.YDisplacement = p.MaxYDisplacement; if (oldDisp < 0) { p.YDisplacement *= -1; } } } } rend.FramePoints = dict.Values.ToList(); } else { rend.FramePoints = animFrame[0].ToList(); } _animations.FrameRendered(); return(rend); }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }); //limit parallelism so that only one redraw update can occur _signalFrameRendered = new ActionBlock <RenderedFrame>(notifyFrameReady, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1, TaskScheduler = uiScheduler }); _animations.LinkTo(_frameQueue, new DataflowLinkOptions { PropagateCompletion = true }); _frameQueue.LinkTo(_renderFrame, new DataflowLinkOptions { PropagateCompletion = true }); _renderFrame.LinkTo(_signalFrameRendered, new DataflowLinkOptions { PropagateCompletion = true }); RegisterChild(_animations); RegisterChild(_frameQueue); RegisterChild(_renderFrame); RegisterChild(_signalFrameRendered); }