Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / image / ImageCanvas_Static.cs
@lijincheng lijincheng on 15 Jul 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. GD.PrintErr("移除 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.Now;
  176. //File.WriteAllBytes("d:/image.png", image.SavePngToBuffer());
  177. //绘制完成需要调用回调的列表
  178. var index = 0;
  179. do
  180. {
  181. var item = _drawingQueueItems.Dequeue();
  182. if (!item.ImageCanvas.IsDestroyed)
  183. {
  184. redrawCanvas.Add(item.ImageCanvas);
  185. //处理绘图
  186. HandleDrawing(image, item);
  187. index++;
  188. if (item.OnDrawingComplete != null)
  189. {
  190. if (callDrawingCompleteList == null)
  191. {
  192. callDrawingCompleteList = new List<ImageRenderData>();
  193. }
  194. callDrawingCompleteList.Add(item);
  195. }
  196. }
  197.  
  198. //移除站位符
  199. if (item.AreaPlaceholder != null)
  200. {
  201. RemovePlaceholder(item.AreaPlaceholder);
  202. item.AreaPlaceholder = null;
  203. }
  204.  
  205. //回收 RenderSprite
  206. if (item.RenderSprite != null)
  207. {
  208. ReclaimRenderSprite(item.RenderSprite);
  209. item.RenderSprite = null;
  210. }
  211. } while (_drawingQueueItems.Count > 0 && (DateTime.Now - startTime).TotalMilliseconds < step1Time);
  212.  
  213. //GD.Print($"当前帧绘制完成数量: {index}, 绘制队列数量: {_drawingQueueItems.Count}, 用时: {(DateTime.Now - startTime).TotalMilliseconds}毫秒");
  214. }
  215.  
  216. //重绘画布
  217. foreach (var drawCanvas in redrawCanvas)
  218. {
  219. drawCanvas.Redraw();
  220. }
  221. //调用完成回调
  222. if (callDrawingCompleteList != null)
  223. {
  224. foreach (var imageRenderData in callDrawingCompleteList)
  225. {
  226. try
  227. {
  228. imageRenderData.OnDrawingComplete();
  229. }
  230. catch (Exception e)
  231. {
  232. GD.PrintErr("在ImageCanvas中调用回调OnDrawingComplete()发生异常: " + e);
  233. }
  234. }
  235. }
  236. }
  237.  
  238. //处理下一批image
  239. if (_queueItems.Count > 0)
  240. {
  241. var startTime = DateTime.Now;
  242. var hasFail = false;
  243. //执行绘制操作
  244. var index = 0;
  245. for (var i = 0; i < _queueItems.Count; i++)
  246. {
  247. var item = _queueItems[i];
  248. if (!item.ImageCanvas.IsDestroyed)
  249. {
  250. if (hasFail && !item.EnableQueueCutting) //禁用插队
  251. {
  252. continue;
  253. }
  254. //排队绘制
  255. if (HandleEnqueueDrawing(item))
  256. {
  257. _queueItems.RemoveAt(i);
  258. i--;
  259. index++;
  260. }
  261. else //进入渲染队列失败
  262. {
  263. hasFail = true;
  264. }
  265. }
  266. else
  267. {
  268. _queueItems.RemoveAt(i);
  269. i--;
  270. }
  271. //计算超时
  272. if ((DateTime.Now - startTime).TotalMilliseconds >= step2Time)
  273. {
  274. break;
  275. }
  276. }
  277. //GD.Print($"当前帧进入绘制绘队列数量: {index}, 待绘制队列数量: {_queueItems.Count}, 绘制队列数量: {_drawingQueueItems.Count}, 用时: {(DateTime.Now - startTime).TotalMilliseconds}毫秒");
  278. }
  279. }
  280.  
  281. private static void HandleDrawing(Image image, ImageRenderData item)
  282. {
  283. //截取Viewport像素点
  284. item.ImageCanvas._canvas.BlendRect(image,
  285. new Rect2I(item.AreaPlaceholder.Start, 0,item.RenderWidth, item.RenderHeight),
  286. new Vector2I(item.X - item.RenderOffsetX, item.Y - item.RenderOffsetY)
  287. );
  288.  
  289. item.SrcImage.Dispose();
  290. item.SrcImage = null;
  291. }
  292. //处理排队绘制
  293. private static bool HandleEnqueueDrawing(ImageRenderData item)
  294. {
  295. var placeholder = FindNotchPlaceholder(item.RenderWidth);
  296. if (placeholder == null) //没有找到合适的位置
  297. {
  298. return false;
  299. }
  300.  
  301. item.AreaPlaceholder = placeholder;
  302.  
  303. item.RenderX = placeholder.Start + item.RenderOffsetX;
  304. item.RenderY = item.RenderOffsetY;
  305. var renderSprite = GetRenderSprite(new Vector2(item.RenderX, item.RenderY));
  306. item.RenderSprite = renderSprite;
  307. if (item.RotationGreaterThanPi) //角度大于180度
  308. {
  309. item.SrcImage.FlipX();
  310. if (!item.FlipY)
  311. {
  312. item.SrcImage.FlipY();
  313. }
  314. }
  315. else
  316. {
  317. if (item.FlipY)
  318. {
  319. item.SrcImage.FlipY();
  320. }
  321. }
  322.  
  323. renderSprite.Sprite.Material = item.Material;
  324. renderSprite.Sprite.Offset = new Vector2(-item.CenterX, -item.CenterY);
  325. //设置旋转
  326. renderSprite.Sprite.Rotation = item.Rotation;
  327.  
  328. renderSprite.SetImage(item.SrcImage);
  329. _drawingQueueItems.Enqueue(item);
  330. return true;
  331. }
  332. }