123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- using PixiEditor.ChangeableDocument.Changeables.Animations;
- using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
- using PixiEditor.ChangeableDocument.Changeables.Interfaces;
- using PixiEditor.ChangeableDocument.Helpers;
- using PixiEditor.ChangeableDocument.Rendering;
- using Drawie.Backend.Core;
- using Drawie.Backend.Core.ColorsImpl;
- using Drawie.Backend.Core.Surfaces;
- using Drawie.Backend.Core.Surfaces.ImageData;
- using Drawie.Backend.Core.Surfaces.PaintImpl;
- using Drawie.Numerics;
- namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
- [NodeInfo("ImageLayer")]
- public class ImageLayerNode : LayerNode, IReadOnlyImageNode
- {
- public const string ImageFramesKey = "Frames";
- public const string ImageLayerKey = "LayerImage";
- public override VecD GetScenePosition(KeyFrameTime time) => layerImage.CommittedSize / 2f;
- public override VecD GetSceneSize(KeyFrameTime time) => layerImage.CommittedSize;
- public bool LockTransparency { get; set; }
- private VecI startSize;
- private ColorSpace colorSpace;
- private ChunkyImage layerImage => keyFrames[0]?.Data as ChunkyImage;
- private Texture fullResrenderedSurface;
- private int renderedSurfaceFrame = -1;
- public ImageLayerNode(VecI size, ColorSpace colorSpace)
- {
- if (keyFrames.Count == 0)
- {
- keyFrames.Add(new KeyFrameData(Guid.NewGuid(), 0, 0, ImageLayerKey) { Data = new ChunkyImage(size, colorSpace) });
- }
- this.startSize = size;
- this.colorSpace = colorSpace;
- }
- public override RectD? GetTightBounds(KeyFrameTime frameTime)
- {
- return (RectD?)GetLayerImageAtFrame(frameTime.Frame).FindTightCommittedBounds();
- }
- protected override VecI GetTargetSize(RenderContext ctx)
- {
- return (GetFrameWithImage(ctx.FrameTime).Data as ChunkyImage).LatestSize;
- }
- protected internal override void DrawLayerInScene(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
- bool useFilters = true)
- {
- int scaled = workingSurface.Canvas.Save();
- float multiplier = (float)ctx.ChunkResolution.InvertedMultiplier();
- workingSurface.Canvas.Translate(GetScenePosition(ctx.FrameTime));
- base.DrawLayerInScene(ctx, workingSurface, useFilters);
- workingSurface.Canvas.RestoreToCount(scaled);
- }
- protected internal override void DrawLayerOnTexture(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
- bool useFilters)
- {
- int scaled = workingSurface.Canvas.Save();
- workingSurface.Canvas.Translate(GetScenePosition(ctx.FrameTime) * ctx.ChunkResolution.Multiplier());
- workingSurface.Canvas.Scale((float)ctx.ChunkResolution.Multiplier());
- DrawLayerOnto(ctx, workingSurface, useFilters);
- workingSurface.Canvas.RestoreToCount(scaled);
- }
- protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
- Paint paint)
- {
- DrawLayer(workingSurface, paint, ctx);
- }
- protected override void DrawWithFilters(SceneObjectRenderContext context, DrawingSurface workingSurface,
- Paint paint)
- {
- DrawLayer(workingSurface, paint, context);
- }
- private void DrawLayer(DrawingSurface workingSurface, Paint paint, SceneObjectRenderContext ctx)
- {
- int saved = workingSurface.Canvas.Save();
- var sceneSize = GetSceneSize(ctx.FrameTime);
- VecD topLeft = sceneSize / 2f;
- if (renderedSurfaceFrame == null || ctx.FullRerender || ctx.FrameTime.Frame != renderedSurfaceFrame)
- {
- GetLayerImageAtFrame(ctx.FrameTime.Frame).DrawMostUpToDateRegionOn(
- new RectI(0, 0, layerImage.LatestSize.X, layerImage.LatestSize.Y),
- ChunkResolution.Full,
- workingSurface, -(VecI)topLeft, paint);
- }
- else
- {
- workingSurface.Canvas.DrawSurface(fullResrenderedSurface.DrawingSurface, -topLeft, paint);
- }
- workingSurface.Canvas.RestoreToCount(saved);
- }
- public override RectD? GetPreviewBounds(int frame, string elementFor = "")
- {
- if (IsDisposed)
- {
- return null;
- }
- if (elementFor == nameof(EmbeddedMask))
- {
- return base.GetPreviewBounds(frame, elementFor);
- }
- if (Guid.TryParse(elementFor, out Guid guid))
- {
- var keyFrame = keyFrames.FirstOrDefault(x => x.KeyFrameGuid == guid);
- if (keyFrame != null)
- {
- return (RectD?)GetLayerImageByKeyFrameGuid(keyFrame.KeyFrameGuid).FindTightCommittedBounds();
- }
- }
- try
- {
- return (RectD?)GetLayerImageAtFrame(frame).FindTightCommittedBounds();
- }
- catch (ObjectDisposedException)
- {
- return null;
- }
- }
- public override bool RenderPreview(DrawingSurface renderOnto, RenderContext context,
- string elementToRenderName)
- {
- if (IsDisposed)
- {
- return false;
- }
- if (elementToRenderName == nameof(EmbeddedMask))
- {
- return base.RenderPreview(renderOnto, context, elementToRenderName);
- }
- var img = GetLayerImageAtFrame(context.FrameTime.Frame);
- if (Guid.TryParse(elementToRenderName, out Guid guid))
- {
- var keyFrame = keyFrames.FirstOrDefault(x => x.KeyFrameGuid == guid);
- if (keyFrame != null)
- {
- img = GetLayerImageByKeyFrameGuid(keyFrame.KeyFrameGuid);
- }
- }
- if (img is null)
- {
- return false;
- }
- if (renderedSurfaceFrame == context.FrameTime.Frame)
- {
- renderOnto.Canvas.DrawSurface(fullResrenderedSurface.DrawingSurface, VecI.Zero, blendPaint);
- }
- else
- {
- img.DrawMostUpToDateRegionOn(
- new RectI(0, 0, img.LatestSize.X, img.LatestSize.Y),
- context.ChunkResolution,
- renderOnto, VecI.Zero, blendPaint);
- }
- return true;
- }
- private KeyFrameData GetFrameWithImage(KeyFrameTime frame)
- {
- var imageFrame = keyFrames.OrderBy(x => x.StartFrame).LastOrDefault(x => x.IsInFrame(frame.Frame));
- if (imageFrame?.Data is not ChunkyImage)
- {
- return keyFrames[0];
- }
- var frameImage = imageFrame;
- return frameImage;
- }
- protected override bool CacheChanged(RenderContext context)
- {
- var frame = GetFrameWithImage(context.FrameTime);
- return base.CacheChanged(context) || frame?.RequiresUpdate == true;
- }
- protected override void UpdateCache(RenderContext context)
- {
- base.UpdateCache(context);
- var imageFrame = GetFrameWithImage(context.FrameTime);
- if (imageFrame is not null && imageFrame.RequiresUpdate)
- {
- imageFrame.RequiresUpdate = false;
- }
- }
- public override Node CreateCopy()
- {
- var image = new ImageLayerNode(startSize, colorSpace) { MemberName = this.MemberName, };
- image.keyFrames.Clear();
- return image;
- }
- public override void Dispose()
- {
- base.Dispose();
- foreach (var workingSurface in workingSurfaces)
- {
- workingSurface.Value.Dispose();
- }
- }
- IReadOnlyChunkyImage IReadOnlyImageNode.GetLayerImageAtFrame(int frame) => GetLayerImageAtFrame(frame);
- IReadOnlyChunkyImage IReadOnlyImageNode.GetLayerImageByKeyFrameGuid(Guid keyFrameGuid) =>
- GetLayerImageByKeyFrameGuid(keyFrameGuid);
- void IReadOnlyImageNode.SetLayerImageAtFrame(int frame, IReadOnlyChunkyImage newLayerImage) =>
- SetLayerImageAtFrame(frame, (ChunkyImage)newLayerImage);
- void IReadOnlyImageNode.ForEveryFrame(Action<IReadOnlyChunkyImage> action) => ForEveryFrame(action);
- public override void RenderChunk(VecI chunkPos, ChunkResolution resolution, KeyFrameTime frameTime, ColorSpace processColorSpace)
- {
- base.RenderChunk(chunkPos, resolution, frameTime, processColorSpace);
- var img = GetLayerImageAtFrame(frameTime.Frame);
- RenderChunkyImageChunk(chunkPos, resolution, img, 85, processColorSpace, ref fullResrenderedSurface);
- renderedSurfaceFrame = frameTime.Frame;
- }
- public void ForEveryFrame(Action<ChunkyImage> action)
- {
- foreach (var frame in keyFrames)
- {
- if (frame.Data is ChunkyImage imageFrame)
- {
- action(imageFrame);
- }
- }
- }
- public ChunkyImage GetLayerImageAtFrame(int frame)
- {
- return GetFrameWithImage(frame).Data as ChunkyImage;
- }
- public ChunkyImage GetLayerImageByKeyFrameGuid(Guid keyFrameGuid)
- {
- foreach (var keyFrame in keyFrames)
- {
- if (keyFrame.KeyFrameGuid == keyFrameGuid)
- {
- return keyFrame.Data as ChunkyImage;
- }
- }
- return layerImage;
- }
- public void SetLayerImageAtFrame(int frame, ChunkyImage newLayerImage)
- {
- var existingFrame = keyFrames.FirstOrDefault(x => x.IsInFrame(frame));
- if (existingFrame is not null && existingFrame.Data is ChunkyImage)
- {
- existingFrame.Dispose();
- existingFrame.Data = newLayerImage;
- }
- }
- }
|