Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / image / ImageCanvas_Static.cs
@小李xl 小李xl on 25 Nov 2023 11 KB 液体消散效果
  1.  
  2.  
  3. using System;
  4. using System.Collections.Generic;
  5. using Godot;
  6.  
  7. public partial class ImageCanvas
  8. {
  9. public class AreaPlaceholder
  10. {
  11. public AreaPlaceholder(int start, int end)
  12. {
  13. Start = start;
  14. End = end;
  15. }
  16.  
  17. public int Start { get; }
  18. public int End { get; }
  19.  
  20. public int Width => End - Start + 1;
  21. }
  22. /// <summary>
  23. /// 同一帧下将队列里的image绘制到指定画布下最大消耗时间, 如果绘制的时间超过了这个值, 则队列中后面的image将会放到下一帧绘制
  24. /// </summary>
  25. public static float MaxHandlerTime { get; set; } = 4f;
  26. /// <summary>
  27. /// 渲染窗口
  28. /// </summary>
  29. public static SubViewport RenderViewport { get; private set; }
  30.  
  31. /// <summary>
  32. /// 渲染窗口大小
  33. /// </summary>
  34. public static Vector2I RenderViewportSize { get; private set; }
  35. //预渲染队列, 这里不用 Queue 是因为大图尝试添加到渲染队列可能失败, 为了不影响渲染顺序, 所以使用 List
  36. private static readonly List<ImageRenderData> _queueItems = new List<ImageRenderData>();
  37. //渲染中的队列
  38. private static readonly Queue<ImageRenderData> _drawingQueueItems = new Queue<ImageRenderData>();
  39. //负责渲染的Sprite回收堆栈
  40. private static readonly Stack<ImageRenderSprite> _renderSpriteStack = new Stack<ImageRenderSprite>();
  41.  
  42. private static readonly List<AreaPlaceholder> _placeholders = new List<AreaPlaceholder>();
  43. private static ViewportTexture _viewportTexture;
  44.  
  45. /// <summary>
  46. /// 初始化 viewport
  47. /// </summary>
  48. public static void Init(Node root)
  49. {
  50. RenderViewportSize = new Vector2I(1024, 185);
  51. RenderViewport = new SubViewport();
  52. RenderViewport.Name = "ImageCanvasViewport";
  53. RenderViewport.Size = RenderViewportSize;
  54. RenderViewport.RenderTargetUpdateMode = SubViewport.UpdateMode.Always;
  55. RenderViewport.TransparentBg = true;
  56. RenderViewport.CanvasItemDefaultTextureFilter = Viewport.DefaultCanvasItemTextureFilter.Nearest;
  57. var camera = new Camera2D();
  58. camera.Name = "ImageCanvasCamera";
  59. camera.AnchorMode = Camera2D.AnchorModeEnum.FixedTopLeft;
  60. RenderViewport.AddChild(camera);
  61. _viewportTexture = RenderViewport.GetTexture();
  62.  
  63. root.AddChild(RenderViewport);
  64. RenderingServer.FramePostDraw += OnFramePostDraw;
  65. }
  66.  
  67. private static AreaPlaceholder FindNotchPlaceholder(int width)
  68. {
  69. if (_placeholders.Count == 0)
  70. {
  71. var result = new AreaPlaceholder(0, width - 1);
  72. _placeholders.Add(result);
  73. return result;
  74. }
  75.  
  76. for (var i = 0; i < _placeholders.Count; i++)
  77. {
  78. if (i == _placeholders.Count - 1) //最后一个
  79. {
  80. var item = _placeholders[i];
  81. var end = item.End + width;
  82. if (end < RenderViewportSize.X)
  83. {
  84. var result = new AreaPlaceholder(item.End + 1, end);
  85. _placeholders.Add(result);
  86. return result;
  87. }
  88. }
  89. else if (i == 0) //第一个
  90. {
  91. var item = _placeholders[i];
  92. var end = width - 1;
  93. if (end < item.Start)
  94. {
  95. var result = new AreaPlaceholder(0, end);
  96. _placeholders.Insert(0, result);
  97. return result;
  98. }
  99. }
  100. else //中间
  101. {
  102. var prev = _placeholders[i - 1];
  103. var next = _placeholders[i];
  104. var end = prev.End + width;
  105. if (end < next.Start + 1)
  106. {
  107. var result = new AreaPlaceholder(prev.End + 1, end);
  108. _placeholders.Insert(i, result);
  109. return result;
  110. }
  111. }
  112. }
  113.  
  114. return null;
  115. }
  116.  
  117. private static void RemovePlaceholder(AreaPlaceholder placeholder)
  118. {
  119. if (!_placeholders.Remove(placeholder))
  120. {
  121. Debug.LogError("移除 AreaPlaceholder 失败!");
  122. }
  123. }
  124. private static ImageRenderSprite GetRenderSprite(Vector2 position)
  125. {
  126. ImageRenderSprite renderSprite;
  127. if (_renderSpriteStack.Count > 0)
  128. {
  129. renderSprite = _renderSpriteStack.Pop();
  130. }
  131. else
  132. {
  133. renderSprite = new ImageRenderSprite();
  134. }
  135.  
  136. renderSprite.Sprite.Position = position;
  137. RenderViewport.AddChild(renderSprite.Sprite);
  138. return renderSprite;
  139. }
  140.  
  141. private static void ReclaimRenderSprite(ImageRenderSprite renderSprite)
  142. {
  143. RenderViewport.RemoveChild(renderSprite.Sprite);
  144. _renderSpriteStack.Push(renderSprite);
  145. renderSprite.Sprite.Material = null;
  146. }
  147.  
  148. private static void OnFramePostDraw()
  149. {
  150. //最大处理时间, 如果超过了, 那就下一帧再画其它的吧
  151. float step1Time;
  152. float step2Time;
  153. if (_drawingQueueItems.Count == 0)
  154. {
  155. step1Time = 0;
  156. step2Time = MaxHandlerTime;
  157. }
  158. else if (_queueItems.Count == 0)
  159. {
  160. step1Time = MaxHandlerTime;
  161. step2Time = 0;
  162. }
  163. else
  164. {
  165. step1Time = step2Time = MaxHandlerTime / 2;
  166. }
  167.  
  168. //上一帧绘制的image
  169. if (_drawingQueueItems.Count > 0)
  170. {
  171. var redrawCanvas = new HashSet<ImageCanvas>();
  172. List<ImageRenderData> callDrawingCompleteList = null;
  173. using (var image = _viewportTexture.GetImage())
  174. {
  175. var startTime = DateTime.UtcNow;
  176. //File.WriteAllBytes("d:/image.png", image.SavePngToBuffer());
  177. //绘制完成需要调用回调的列表
  178. do
  179. {
  180. var item = _drawingQueueItems.Dequeue();
  181. if (!item.ImageCanvas.IsDestroyed)
  182. {
  183. redrawCanvas.Add(item.ImageCanvas);
  184. //处理绘图
  185. HandleDrawing(image, item);
  186. if (item.OnDrawingComplete != null)
  187. {
  188. if (callDrawingCompleteList == null)
  189. {
  190. callDrawingCompleteList = new List<ImageRenderData>();
  191. }
  192. callDrawingCompleteList.Add(item);
  193. }
  194. }
  195.  
  196. //移除站位符
  197. if (item.AreaPlaceholder != null)
  198. {
  199. RemovePlaceholder(item.AreaPlaceholder);
  200. item.AreaPlaceholder = null;
  201. }
  202.  
  203. //回收 RenderSprite
  204. if (item.RenderSprite != null)
  205. {
  206. ReclaimRenderSprite(item.RenderSprite);
  207. item.RenderSprite = null;
  208. }
  209. } while (_drawingQueueItems.Count > 0 && (DateTime.UtcNow - startTime).TotalMilliseconds < step1Time);
  210.  
  211. //Debug.Log($"当前帧绘制完成数量: {index}, 绘制队列数量: {_drawingQueueItems.Count}, 用时: {(DateTime.UtcNow - startTime).TotalMilliseconds}毫秒");
  212. }
  213.  
  214. //重绘画布
  215. foreach (var drawCanvas in redrawCanvas)
  216. {
  217. drawCanvas.Redraw();
  218. }
  219. //调用完成回调
  220. if (callDrawingCompleteList != null)
  221. {
  222. foreach (var imageRenderData in callDrawingCompleteList)
  223. {
  224. try
  225. {
  226. imageRenderData.OnDrawingComplete();
  227. }
  228. catch (Exception e)
  229. {
  230. Debug.LogError("在ImageCanvas中调用回调OnDrawingComplete()发生异常: " + e);
  231. }
  232. }
  233. }
  234. }
  235.  
  236. //处理下一批image
  237. if (_queueItems.Count > 0)
  238. {
  239. var startTime = DateTime.UtcNow;
  240. var hasFail = false;
  241. //执行绘制操作
  242. for (var i = 0; i < _queueItems.Count; i++)
  243. {
  244. var item = _queueItems[i];
  245. if (!item.ImageCanvas.IsDestroyed)
  246. {
  247. if (hasFail && !item.EnableQueueCutting) //禁用插队
  248. {
  249. continue;
  250. }
  251. //排队绘制
  252. if (HandleEnqueueDrawing(item))
  253. {
  254. _queueItems.RemoveAt(i);
  255. i--;
  256. }
  257. else //进入渲染队列失败
  258. {
  259. hasFail = true;
  260. }
  261. }
  262. else
  263. {
  264. _queueItems.RemoveAt(i);
  265. i--;
  266. }
  267. //计算超时
  268. if ((DateTime.UtcNow - startTime).TotalMilliseconds >= step2Time)
  269. {
  270. break;
  271. }
  272. }
  273. //Debug.Log($"当前帧进入绘制绘队列数量: {index}, 待绘制队列数量: {_queueItems.Count}, 绘制队列数量: {_drawingQueueItems.Count}, 用时: {(DateTime.UtcNow - startTime).TotalMilliseconds}毫秒");
  274. }
  275. }
  276.  
  277. private static void HandleDrawing(Image image, ImageRenderData item)
  278. {
  279. //截取Viewport像素点
  280. item.ImageCanvas._canvas.BlendRect(image,
  281. new Rect2I(item.AreaPlaceholder.Start, 0,item.RenderWidth, item.RenderHeight),
  282. new Vector2I(item.X - item.RenderOffsetX, item.Y - item.RenderOffsetY)
  283. );
  284.  
  285. item.SrcImage.Dispose();
  286. item.SrcImage = null;
  287. }
  288. //处理排队绘制
  289. private static bool HandleEnqueueDrawing(ImageRenderData item)
  290. {
  291. var placeholder = FindNotchPlaceholder(item.RenderWidth);
  292. if (placeholder == null) //没有找到合适的位置
  293. {
  294. return false;
  295. }
  296.  
  297. item.AreaPlaceholder = placeholder;
  298.  
  299. item.RenderX = placeholder.Start + item.RenderOffsetX;
  300. item.RenderY = item.RenderOffsetY;
  301. var renderSprite = GetRenderSprite(new Vector2(item.RenderX, item.RenderY));
  302. item.RenderSprite = renderSprite;
  303. if (item.RotationGreaterThanPi) //角度大于180度
  304. {
  305. item.SrcImage.FlipX();
  306. if (!item.FlipY)
  307. {
  308. item.SrcImage.FlipY();
  309. }
  310. }
  311. else
  312. {
  313. if (item.FlipY)
  314. {
  315. item.SrcImage.FlipY();
  316. }
  317. }
  318.  
  319. renderSprite.Sprite.Material = item.Material;
  320. renderSprite.Sprite.Offset = new Vector2(-item.CenterX, -item.CenterY);
  321. //设置旋转
  322. renderSprite.Sprite.Rotation = item.Rotation;
  323.  
  324. renderSprite.SetImage(item.SrcImage);
  325. _drawingQueueItems.Enqueue(item);
  326. return true;
  327. }
  328. }