ImageLayerNode.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. using PixiEditor.ChangeableDocument.Changeables.Animations;
  2. using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
  3. using PixiEditor.ChangeableDocument.Changeables.Interfaces;
  4. using PixiEditor.ChangeableDocument.Helpers;
  5. using PixiEditor.ChangeableDocument.Rendering;
  6. using Drawie.Backend.Core;
  7. using Drawie.Backend.Core.ColorsImpl;
  8. using Drawie.Backend.Core.Surfaces;
  9. using Drawie.Backend.Core.Surfaces.ImageData;
  10. using Drawie.Backend.Core.Surfaces.PaintImpl;
  11. using Drawie.Numerics;
  12. namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
  13. [NodeInfo("ImageLayer")]
  14. public class ImageLayerNode : LayerNode, IReadOnlyImageNode
  15. {
  16. public const string ImageFramesKey = "Frames";
  17. public const string ImageLayerKey = "LayerImage";
  18. public override VecD GetScenePosition(KeyFrameTime time) => layerImage.CommittedSize / 2f;
  19. public override VecD GetSceneSize(KeyFrameTime time) => layerImage.CommittedSize;
  20. public bool LockTransparency { get; set; }
  21. private VecI startSize;
  22. private ColorSpace colorSpace;
  23. private ChunkyImage layerImage => keyFrames[0]?.Data as ChunkyImage;
  24. private Texture fullResrenderedSurface;
  25. private int renderedSurfaceFrame = -1;
  26. public ImageLayerNode(VecI size, ColorSpace colorSpace)
  27. {
  28. if (keyFrames.Count == 0)
  29. {
  30. keyFrames.Add(new KeyFrameData(Guid.NewGuid(), 0, 0, ImageLayerKey) { Data = new ChunkyImage(size, colorSpace) });
  31. }
  32. this.startSize = size;
  33. this.colorSpace = colorSpace;
  34. }
  35. public override RectD? GetTightBounds(KeyFrameTime frameTime)
  36. {
  37. return (RectD?)GetLayerImageAtFrame(frameTime.Frame).FindTightCommittedBounds();
  38. }
  39. protected override VecI GetTargetSize(RenderContext ctx)
  40. {
  41. return (GetFrameWithImage(ctx.FrameTime).Data as ChunkyImage).LatestSize;
  42. }
  43. protected internal override void DrawLayerInScene(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
  44. bool useFilters = true)
  45. {
  46. int scaled = workingSurface.Canvas.Save();
  47. float multiplier = (float)ctx.ChunkResolution.InvertedMultiplier();
  48. workingSurface.Canvas.Translate(GetScenePosition(ctx.FrameTime));
  49. base.DrawLayerInScene(ctx, workingSurface, useFilters);
  50. workingSurface.Canvas.RestoreToCount(scaled);
  51. }
  52. protected internal override void DrawLayerOnTexture(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
  53. bool useFilters)
  54. {
  55. int scaled = workingSurface.Canvas.Save();
  56. workingSurface.Canvas.Translate(GetScenePosition(ctx.FrameTime) * ctx.ChunkResolution.Multiplier());
  57. workingSurface.Canvas.Scale((float)ctx.ChunkResolution.Multiplier());
  58. DrawLayerOnto(ctx, workingSurface, useFilters);
  59. workingSurface.Canvas.RestoreToCount(scaled);
  60. }
  61. protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
  62. Paint paint)
  63. {
  64. DrawLayer(workingSurface, paint, ctx);
  65. }
  66. protected override void DrawWithFilters(SceneObjectRenderContext context, DrawingSurface workingSurface,
  67. Paint paint)
  68. {
  69. DrawLayer(workingSurface, paint, context);
  70. }
  71. private void DrawLayer(DrawingSurface workingSurface, Paint paint, SceneObjectRenderContext ctx)
  72. {
  73. int saved = workingSurface.Canvas.Save();
  74. var sceneSize = GetSceneSize(ctx.FrameTime);
  75. VecD topLeft = sceneSize / 2f;
  76. if (renderedSurfaceFrame == null || ctx.FullRerender || ctx.FrameTime.Frame != renderedSurfaceFrame)
  77. {
  78. GetLayerImageAtFrame(ctx.FrameTime.Frame).DrawMostUpToDateRegionOn(
  79. new RectI(0, 0, layerImage.LatestSize.X, layerImage.LatestSize.Y),
  80. ChunkResolution.Full,
  81. workingSurface, -(VecI)topLeft, paint);
  82. }
  83. else
  84. {
  85. workingSurface.Canvas.DrawSurface(fullResrenderedSurface.DrawingSurface, -topLeft, paint);
  86. }
  87. workingSurface.Canvas.RestoreToCount(saved);
  88. }
  89. public override RectD? GetPreviewBounds(int frame, string elementFor = "")
  90. {
  91. if (IsDisposed)
  92. {
  93. return null;
  94. }
  95. if (elementFor == nameof(EmbeddedMask))
  96. {
  97. return base.GetPreviewBounds(frame, elementFor);
  98. }
  99. if (Guid.TryParse(elementFor, out Guid guid))
  100. {
  101. var keyFrame = keyFrames.FirstOrDefault(x => x.KeyFrameGuid == guid);
  102. if (keyFrame != null)
  103. {
  104. return (RectD?)GetLayerImageByKeyFrameGuid(keyFrame.KeyFrameGuid).FindTightCommittedBounds();
  105. }
  106. }
  107. try
  108. {
  109. return (RectD?)GetLayerImageAtFrame(frame).FindTightCommittedBounds();
  110. }
  111. catch (ObjectDisposedException)
  112. {
  113. return null;
  114. }
  115. }
  116. public override bool RenderPreview(DrawingSurface renderOnto, RenderContext context,
  117. string elementToRenderName)
  118. {
  119. if (IsDisposed)
  120. {
  121. return false;
  122. }
  123. if (elementToRenderName == nameof(EmbeddedMask))
  124. {
  125. return base.RenderPreview(renderOnto, context, elementToRenderName);
  126. }
  127. var img = GetLayerImageAtFrame(context.FrameTime.Frame);
  128. if (Guid.TryParse(elementToRenderName, out Guid guid))
  129. {
  130. var keyFrame = keyFrames.FirstOrDefault(x => x.KeyFrameGuid == guid);
  131. if (keyFrame != null)
  132. {
  133. img = GetLayerImageByKeyFrameGuid(keyFrame.KeyFrameGuid);
  134. }
  135. }
  136. if (img is null)
  137. {
  138. return false;
  139. }
  140. if (renderedSurfaceFrame == context.FrameTime.Frame)
  141. {
  142. renderOnto.Canvas.DrawSurface(fullResrenderedSurface.DrawingSurface, VecI.Zero, blendPaint);
  143. }
  144. else
  145. {
  146. img.DrawMostUpToDateRegionOn(
  147. new RectI(0, 0, img.LatestSize.X, img.LatestSize.Y),
  148. context.ChunkResolution,
  149. renderOnto, VecI.Zero, blendPaint);
  150. }
  151. return true;
  152. }
  153. private KeyFrameData GetFrameWithImage(KeyFrameTime frame)
  154. {
  155. var imageFrame = keyFrames.OrderBy(x => x.StartFrame).LastOrDefault(x => x.IsInFrame(frame.Frame));
  156. if (imageFrame?.Data is not ChunkyImage)
  157. {
  158. return keyFrames[0];
  159. }
  160. var frameImage = imageFrame;
  161. return frameImage;
  162. }
  163. protected override bool CacheChanged(RenderContext context)
  164. {
  165. var frame = GetFrameWithImage(context.FrameTime);
  166. return base.CacheChanged(context) || frame?.RequiresUpdate == true;
  167. }
  168. protected override void UpdateCache(RenderContext context)
  169. {
  170. base.UpdateCache(context);
  171. var imageFrame = GetFrameWithImage(context.FrameTime);
  172. if (imageFrame is not null && imageFrame.RequiresUpdate)
  173. {
  174. imageFrame.RequiresUpdate = false;
  175. }
  176. }
  177. public override Node CreateCopy()
  178. {
  179. var image = new ImageLayerNode(startSize, colorSpace) { MemberName = this.MemberName, };
  180. image.keyFrames.Clear();
  181. return image;
  182. }
  183. public override void Dispose()
  184. {
  185. base.Dispose();
  186. foreach (var workingSurface in workingSurfaces)
  187. {
  188. workingSurface.Value.Dispose();
  189. }
  190. }
  191. IReadOnlyChunkyImage IReadOnlyImageNode.GetLayerImageAtFrame(int frame) => GetLayerImageAtFrame(frame);
  192. IReadOnlyChunkyImage IReadOnlyImageNode.GetLayerImageByKeyFrameGuid(Guid keyFrameGuid) =>
  193. GetLayerImageByKeyFrameGuid(keyFrameGuid);
  194. void IReadOnlyImageNode.SetLayerImageAtFrame(int frame, IReadOnlyChunkyImage newLayerImage) =>
  195. SetLayerImageAtFrame(frame, (ChunkyImage)newLayerImage);
  196. void IReadOnlyImageNode.ForEveryFrame(Action<IReadOnlyChunkyImage> action) => ForEveryFrame(action);
  197. public override void RenderChunk(VecI chunkPos, ChunkResolution resolution, KeyFrameTime frameTime, ColorSpace processColorSpace)
  198. {
  199. base.RenderChunk(chunkPos, resolution, frameTime, processColorSpace);
  200. var img = GetLayerImageAtFrame(frameTime.Frame);
  201. RenderChunkyImageChunk(chunkPos, resolution, img, 85, processColorSpace, ref fullResrenderedSurface);
  202. renderedSurfaceFrame = frameTime.Frame;
  203. }
  204. public void ForEveryFrame(Action<ChunkyImage> action)
  205. {
  206. foreach (var frame in keyFrames)
  207. {
  208. if (frame.Data is ChunkyImage imageFrame)
  209. {
  210. action(imageFrame);
  211. }
  212. }
  213. }
  214. public ChunkyImage GetLayerImageAtFrame(int frame)
  215. {
  216. return GetFrameWithImage(frame).Data as ChunkyImage;
  217. }
  218. public ChunkyImage GetLayerImageByKeyFrameGuid(Guid keyFrameGuid)
  219. {
  220. foreach (var keyFrame in keyFrames)
  221. {
  222. if (keyFrame.KeyFrameGuid == keyFrameGuid)
  223. {
  224. return keyFrame.Data as ChunkyImage;
  225. }
  226. }
  227. return layerImage;
  228. }
  229. public void SetLayerImageAtFrame(int frame, ChunkyImage newLayerImage)
  230. {
  231. var existingFrame = keyFrames.FirstOrDefault(x => x.IsInFrame(frame));
  232. if (existingFrame is not null && existingFrame.Data is ChunkyImage)
  233. {
  234. existingFrame.Dispose();
  235. existingFrame.Data = newLayerImage;
  236. }
  237. }
  238. }