/// <inheritdoc /> public override void Render(SKCanvas canvas) { if (Disposed) { throw new ObjectDisposedException("Folder"); } // Ensure the folder is ready if (!Enabled || !Children.Any(c => c.Enabled) || Path == null) { return; } // No point rendering if none of the children are going to render if (!Children.Any(c => c is RenderProfileElement renderElement && !renderElement.Timeline.IsFinished)) { return; } lock (Timeline) { foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled)) { baseLayerEffect.BaseProperties?.Update(Timeline); baseLayerEffect.Update(Timeline.Delta.TotalSeconds); } try { canvas.Save(); Renderer.Open(Path, Parent as Folder); if (Renderer.Canvas == null || Renderer.Path == null || Renderer.Paint == null) { throw new ArtemisCoreException("Failed to open folder render context"); } SKRect rendererBounds = Renderer.Path.Bounds; foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled)) { baseLayerEffect.PreProcess(Renderer.Canvas, rendererBounds, Renderer.Paint); } // If required, apply the opacity override of the module to the root folder if (IsRootFolder && Profile.Module.OpacityOverride < 1) { double multiplier = Easings.SineEaseInOut(Profile.Module.OpacityOverride); Renderer.Paint.Color = Renderer.Paint.Color.WithAlpha((byte)(Renderer.Paint.Color.Alpha * multiplier)); } // No point rendering if the alpha was set to zero by one of the effects if (Renderer.Paint.Color.Alpha == 0) { return; } // Iterate the children in reverse because the first layer must be rendered last to end up on top for (int index = Children.Count - 1; index > -1; index--) { Children[index].Render(Renderer.Canvas); } foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled)) { baseLayerEffect.PostProcess(Renderer.Canvas, rendererBounds, Renderer.Paint); } canvas.DrawBitmap(Renderer.Bitmap, Renderer.TargetLocation, Renderer.Paint); } finally { canvas.Restore(); Renderer.Close(); } Timeline.ClearDelta(); } }