Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / image / ImageCanvas_Static.cs
@小李xl 小李xl on 20 Jun 2023 10 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 Vector2 RenderViewportSize { get; private set; }
  35. //预渲染队列
  36. private static readonly Queue<ImageRenderData> _queueItems = new Queue<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(SubViewport renderViewport)
  49. {
  50. RenderViewportSize = renderViewport.Size;
  51. RenderViewport = renderViewport;
  52. _viewportTexture = renderViewport.GetTexture();
  53. RenderingServer.FramePostDraw += OnFramePostDraw;
  54. }
  55.  
  56. private static AreaPlaceholder FindNotchPlaceholder(int width)
  57. {
  58. if (_placeholders.Count == 0)
  59. {
  60. var result = new AreaPlaceholder(0, width - 1);
  61. _placeholders.Add(result);
  62. return result;
  63. }
  64.  
  65. for (var i = 0; i < _placeholders.Count; i++)
  66. {
  67. if (i == _placeholders.Count - 1) //最后一个
  68. {
  69. var item = _placeholders[i];
  70. var end = item.End + width;
  71. if (end < RenderViewportSize.X)
  72. {
  73. var result = new AreaPlaceholder(item.End + 1, end);
  74. _placeholders.Add(result);
  75. return result;
  76. }
  77. }
  78. else if (i == 0) //第一个
  79. {
  80. var item = _placeholders[i];
  81. var end = width - 1;
  82. if (end < item.Start)
  83. {
  84. var result = new AreaPlaceholder(0, end);
  85. _placeholders.Insert(0, result);
  86. return result;
  87. }
  88. }
  89. else //中间
  90. {
  91. var prev = _placeholders[i - 1];
  92. var next = _placeholders[i];
  93. var end = prev.End + width;
  94. if (end < next.Start + 1)
  95. {
  96. var result = new AreaPlaceholder(prev.End + 1, end);
  97. _placeholders.Insert(i, result);
  98. return result;
  99. }
  100. }
  101. }
  102.  
  103. return null;
  104. }
  105.  
  106. private static void RemovePlaceholder(AreaPlaceholder placeholder)
  107. {
  108. if (!_placeholders.Remove(placeholder))
  109. {
  110. GD.PrintErr("移除 AreaPlaceholder 失败!");
  111. }
  112. }
  113. private static ImageRenderSprite GetRenderSprite(Vector2 position)
  114. {
  115. ImageRenderSprite renderSprite;
  116. if (_renderSpriteStack.Count > 0)
  117. {
  118. renderSprite = _renderSpriteStack.Pop();
  119. }
  120. else
  121. {
  122. renderSprite = new ImageRenderSprite();
  123. }
  124.  
  125. renderSprite.Sprite.Position = position;
  126. RenderViewport.AddChild(renderSprite.Sprite);
  127. return renderSprite;
  128. }
  129.  
  130. private static void ReclaimRenderSprite(ImageRenderSprite renderSprite)
  131. {
  132. RenderViewport.RemoveChild(renderSprite.Sprite);
  133. _renderSpriteStack.Push(renderSprite);
  134. }
  135.  
  136. private static void OnFramePostDraw()
  137. {
  138. //最大处理时间, 如果超过了, 那就下一帧再画其它的吧
  139. float step1Time;
  140. float step2Time;
  141. if (_drawingQueueItems.Count == 0)
  142. {
  143. step1Time = 0;
  144. step2Time = MaxHandlerTime;
  145. }
  146. else if (_queueItems.Count == 0)
  147. {
  148. step1Time = MaxHandlerTime;
  149. step2Time = 0;
  150. }
  151. else
  152. {
  153. step1Time = step2Time = MaxHandlerTime / 2;
  154. }
  155.  
  156. //上一帧绘制的image
  157. if (_drawingQueueItems.Count > 0)
  158. {
  159. var redrawCanvas = new HashSet<ImageCanvas>();
  160. List<ImageRenderData> callDrawingCompleteList = null;
  161. using (var image = _viewportTexture.GetImage())
  162. {
  163. var startTime = DateTime.Now;
  164. //File.WriteAllBytes("d:/image.png", image.SavePngToBuffer());
  165. //绘制完成需要调用回调的列表
  166. var index = 0;
  167. do
  168. {
  169. var item = _drawingQueueItems.Dequeue();
  170. if (!item.ImageCanvas.IsDestroyed)
  171. {
  172. redrawCanvas.Add(item.ImageCanvas);
  173. //处理绘图
  174. HandleDrawing(index, image, item);
  175. index++;
  176. if (item.OnDrawingComplete != null)
  177. {
  178. if (callDrawingCompleteList == null)
  179. {
  180. callDrawingCompleteList = new List<ImageRenderData>();
  181. }
  182. callDrawingCompleteList.Add(item);
  183. }
  184. }
  185.  
  186. //移除站位符
  187. if (item.AreaPlaceholder != null)
  188. {
  189. RemovePlaceholder(item.AreaPlaceholder);
  190. item.AreaPlaceholder = null;
  191. }
  192.  
  193. //回收 RenderSprite
  194. if (item.RenderSprite != null)
  195. {
  196. ReclaimRenderSprite(item.RenderSprite);
  197. item.RenderSprite = null;
  198. }
  199. } while (_drawingQueueItems.Count > 0 && (DateTime.Now - startTime).TotalMilliseconds < step1Time);
  200.  
  201. GD.Print($"当前帧绘制完成数量: {index}, 绘制队列数量: {_drawingQueueItems.Count}, 用时: {(DateTime.Now - startTime).TotalMilliseconds}毫秒");
  202. }
  203.  
  204. //重绘画布
  205. foreach (var drawCanvas in redrawCanvas)
  206. {
  207. drawCanvas.Redraw();
  208. }
  209. //调用完成回调
  210. if (callDrawingCompleteList != null)
  211. {
  212. foreach (var imageRenderData in callDrawingCompleteList)
  213. {
  214. try
  215. {
  216. imageRenderData.OnDrawingComplete();
  217. }
  218. catch (Exception e)
  219. {
  220. GD.PrintErr("在ImageCanvas中调用回调OnDrawingComplete()发生异常: " + e);
  221. }
  222. }
  223. }
  224. }
  225.  
  226. //处理下一批image
  227. if (_queueItems.Count > 0)
  228. {
  229. var startTime = DateTime.Now;
  230. List<ImageRenderData> retryList = null;
  231. var index = 0;
  232. //执行绘制操作
  233. do
  234. {
  235. var item = _queueItems.Dequeue();
  236. if (!item.ImageCanvas.IsDestroyed)
  237. {
  238. //排队绘制
  239. if (HandleEnqueueDrawing(index, item))
  240. {
  241. index++;
  242. }
  243. else //添加失败
  244. {
  245. if (retryList == null)
  246. {
  247. retryList = new List<ImageRenderData>();
  248. }
  249. retryList.Add(item);
  250. }
  251. }
  252.  
  253. } while (_queueItems.Count > 0 && (DateTime.Now - startTime).TotalMilliseconds < step2Time);
  254.  
  255. if (retryList != null)
  256. {
  257. foreach (var renderData in retryList)
  258. {
  259. _queueItems.Enqueue(renderData);
  260. }
  261. }
  262. GD.Print($"当前帧进入绘制绘队列数量: {index}, 待绘制队列数量: {_queueItems.Count}, 绘制队列数量: {_drawingQueueItems.Count}, 用时: {(DateTime.Now - startTime).TotalMilliseconds}毫秒");
  263. }
  264. }
  265.  
  266. private static void HandleDrawing(int index, Image image, ImageRenderData item)
  267. {
  268. //截取Viewport像素点
  269. item.ImageCanvas._canvas.BlendRect(image,
  270. new Rect2I(item.AreaPlaceholder.Start, 0,item.RenderWidth, item.RenderHeight),
  271. new Vector2I(item.X - item.RenderOffsetX, item.Y - item.RenderOffsetY)
  272. );
  273.  
  274. item.SrcImage.Dispose();
  275. item.SrcImage = null;
  276. }
  277. //处理排队绘制
  278. private static bool HandleEnqueueDrawing(int index, ImageRenderData item)
  279. {
  280. var placeholder = FindNotchPlaceholder(item.RenderWidth);
  281. if (placeholder == null) //没有找到合适的位置
  282. {
  283. return false;
  284. }
  285.  
  286. item.AreaPlaceholder = placeholder;
  287.  
  288. item.RenderX = placeholder.Start + item.RenderOffsetX;
  289. item.RenderY = item.RenderOffsetY;
  290. var renderSprite = GetRenderSprite(new Vector2(item.RenderX, item.RenderY));
  291. item.RenderSprite = renderSprite;
  292. if (item.RotationGreaterThanPi) //角度大于180度
  293. {
  294. item.SrcImage.FlipX();
  295. if (!item.FlipY)
  296. {
  297. item.SrcImage.FlipY();
  298. }
  299. }
  300. else
  301. {
  302. if (item.FlipY)
  303. {
  304. item.SrcImage.FlipY();
  305. }
  306. }
  307. renderSprite.Sprite.Offset = new Vector2(-item.CenterX, -item.CenterY);
  308. //设置旋转
  309. renderSprite.Sprite.Rotation = item.Rotation;
  310.  
  311. renderSprite.SetImage(item.SrcImage);
  312. _drawingQueueItems.Enqueue(item);
  313. return true;
  314. }
  315. }