diff --git a/DungeonShooting_Godot/src/framework/map/image/ImageCanvas.cs b/DungeonShooting_Godot/src/framework/map/image/ImageCanvas.cs
index 5a1d349..c320f91 100644
--- a/DungeonShooting_Godot/src/framework/map/image/ImageCanvas.cs
+++ b/DungeonShooting_Godot/src/framework/map/image/ImageCanvas.cs
@@ -1,11 +1,22 @@
+using System;
+using System.Collections.Generic;
using Godot;
-public partial class ImageCanvas : Sprite2D
+public partial class ImageCanvas : Sprite2D, IDestroy
{
+ ///
+ /// 画布大小
+ ///
public int Width { get; }
+
+ ///
+ /// 画布高度
+ ///
public int Height { get; }
+ public bool IsDestroyed { get; private set; }
+
private Image _canvas;
private ImageTexture _texture;
@@ -15,6 +26,7 @@
Height = height;
_canvas = Image.Create(width, height, false, Image.Format.Rgba8);
+ _texture = ImageTexture.CreateFromImage(_canvas);
_canvas.Fill(Colors.Gray);
var w = _canvas.GetWidth();
@@ -33,39 +45,93 @@
public override void _Ready()
{
Centered = false;
-
- var imageTexture = ImageTexture.CreateFromImage(_canvas);
- Texture = imageTexture;
+ Texture = _texture;
}
+ ///
+ /// 添加到预渲染队列中
+ ///
+ /// 需要渲染的纹理
+ /// 离画布左上角x坐标
+ /// 离画布左上角y坐标
+ /// 旋转角度, 角度制
+ /// 旋转中心点x
+ /// 旋转中心点y
+ /// 是否翻转y轴
public void DrawImageInCanvas(Texture2D texture, int x, int y, float angle, int centerX, int centerY, bool flipY)
{
- var image = texture.GetImage();
- if (flipY)
+ var item = new EnqueueItem();
+ item.Canvas = this;
+ item.Image = texture.GetImage();
+ item.X = x;
+ item.Y = y;
+ item.Angle = angle;
+ item.CenterX = centerX;
+ item.CenterY = centerY;
+ item.FlipY = flipY;
+
+ _enqueueItems.Enqueue(item);
+ }
+
+ public void Destroy()
+ {
+ if (IsDestroyed)
{
- image.FlipY();
+ return;
}
- var newAngle = Mathf.RoundToInt(Utils.ConvertAngle(angle));
+ IsDestroyed = true;
+ }
+
+ private void Redraw()
+ {
+ _texture.Update(_canvas);
+ }
+
+ private void HandlerDrawImageInCanvas(EnqueueItem item)
+ {
+ var image = item.Image;
+ var newAngle = Mathf.RoundToInt(Utils.ConvertAngle(item.Angle));
if (newAngle == 0) //原图, 直接画上去
{
- _canvas.BlitRect(image, new Rect2I(0, 0, image.GetWidth(), image.GetHeight()),
- new Vector2I(x - centerX, y - centerY));
+ if (item.FlipY)
+ {
+ image.FlipY();
+ }
+
+ _canvas.BlendRect(image, new Rect2I(0, 0, image.GetWidth(), image.GetHeight()),
+ new Vector2I(item.X - item.CenterX, item.Y - item.CenterY));
}
else //其他角度
{
if (newAngle <= 180)
{
- DrawRotateImage(image, x, y, newAngle, centerX, centerY);
+ if (item.FlipY)
+ {
+ image.FlipY();
+ }
+
+ DrawRotateImage(image, item.X, item.Y, newAngle, item.CenterX, item.CenterY);
}
else
{
image.FlipX();
- image.FlipY();
- DrawRotateImage(image, x, y, (newAngle - 180), image.GetWidth() - centerX - 1, image.GetHeight() - centerY - 1);
+ if (!item.FlipY)
+ {
+ image.FlipY();
+ }
+
+ DrawRotateImage(
+ image, item.X, item.Y,
+ newAngle - 180,
+ image.GetWidth() - item.CenterX - 1, image.GetHeight() - item.CenterY - 1
+ );
}
}
+
+ image.Dispose();
+ item.Image = null;
}
private void DrawRotateImage(Image origin, int x, int y, int angle, int centerX, int centerY)
@@ -90,43 +156,112 @@
var newHeight = Mathf.RoundToInt(width * sinAngle + height * Mathf.Abs(cosAngle));
var offsetX =
- (int)((centerX / sinAngle +
- (0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height) /
- cosAngle -
- (-0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width) /
- sinAngle - centerY / cosAngle) /
- (cosAngle / sinAngle + sinAngle / cosAngle));
+ Mathf.RoundToInt((centerX / sinAngle +
+ (0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height) /
+ cosAngle -
+ (-0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width) /
+ sinAngle - centerY / cosAngle) /
+ (cosAngle / sinAngle + sinAngle / cosAngle));
var offsetY =
- (int)((centerX / cosAngle -
- (-0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width) /
- cosAngle -
- (0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height) /
- sinAngle + centerY / sinAngle) /
- (sinAngle / cosAngle + cosAngle / sinAngle));
+ Mathf.RoundToInt((centerX / cosAngle -
+ (-0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width) /
+ cosAngle -
+ (0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height) /
+ sinAngle + centerY / sinAngle) /
+ (sinAngle / cosAngle + cosAngle / sinAngle));
var num1 = -0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width;
var num2 = 0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height;
- for (int x2 = 0; x2 < newWidth; x2++)
+ var cw = _canvas.GetWidth();
+ var ch = _canvas.GetHeight();
+ for (var x2 = 0; x2 < newWidth; x2++)
{
- for (int y2 = 0; y2 < newHeight; y2++)
+ for (var y2 = 0; y2 < newHeight; y2++)
{
- //如果(x1,y1)不在原图宽高所表示范围内,则(x2,y2)处的像素值设置为0或255
var x1 = Mathf.RoundToInt(x2 * cosAngle + y2 * sinAngle + num1);
var y1 = Mathf.RoundToInt(-x2 * sinAngle + y2 * cosAngle + num2);
if (x1 < 0 || x1 >= width || y1 < 0 || y1 >= height)
{
- //image.SetPixel(x, y, new Color(0, 0, 0, 0));
//在图片外
continue;
}
- //如果(x1,y1)在原图宽高所表示范围内,使用最近邻插值或双线性插值,求出(x2,y2)处的像素值
- _canvas.SetPixel(x2 + x - offsetX, y2 + y - offsetY, origin.GetPixel(x1, y1));
+ var cx = x2 + x - offsetX;
+ if (cx < 0 || cx >= cw)
+ {
+ continue;
+ }
+
+ var cy = y2 + y - offsetY;
+ if (cy < 0 || cy >= ch)
+ {
+ continue;
+ }
+
+ _canvas.SetPixel(cx, cy, _canvas.GetPixel(cx, cy).Blend(origin.GetPixel(x1, y1)));
}
}
}
+
+ //--------------------------------------------------------------------------------------------------------------
+ private class EnqueueItem
+ {
+ public ImageCanvas Canvas;
+ public Image Image;
+ public int X;
+ public int Y;
+ public float Angle;
+ public int CenterX;
+ public int CenterY;
+ public bool FlipY;
+ }
+
+ private static readonly Queue _enqueueItems = new Queue();
+ private static readonly HashSet _redrawCanvas = new HashSet();
+
+ ///
+ /// 根据重绘队列更新画布
+ ///
+ public static void UpdateImageCanvas(float delta)
+ {
+ if (_enqueueItems.Count > 0)
+ {
+ _redrawCanvas.Clear();
+ var startTime = DateTime.Now;
+
+ var c = _enqueueItems.Count;
+ //执行绘制操作
+ //绘制的总时间不能超过2毫秒, 如果超过了, 那就下一帧再画其它的吧
+ do
+ {
+ var item = _enqueueItems.Dequeue();
+ if (!item.Canvas.IsDestroyed)
+ {
+ item.Canvas.HandlerDrawImageInCanvas(item);
+ _redrawCanvas.Add(item.Canvas);
+ }
+ } while (_enqueueItems.Count > 0 && (DateTime.Now - startTime).TotalMilliseconds < 2);
+
+ if (_enqueueItems.Count > 0)
+ {
+ GD.Print($"ImageCanvas: 还剩下{_enqueueItems.Count}个, 已经处理了{c - _enqueueItems.Count}个, 重绘画布{_redrawCanvas.Count}张");
+ }
+ else
+ {
+ GD.Print($"ImageCanvas: 全部画完, 已经处理了{c - _enqueueItems.Count}个, 重绘画布{_redrawCanvas.Count}张");
+ }
+
+ //重绘画布
+ foreach (var drawCanvas in _redrawCanvas)
+ {
+ drawCanvas.Redraw();
+ }
+
+ _redrawCanvas.Clear();
+ }
+ }
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/test/TestOptimizeSprite.cs b/DungeonShooting_Godot/src/test/TestOptimizeSprite.cs
index 95cbda4..490f373 100644
--- a/DungeonShooting_Godot/src/test/TestOptimizeSprite.cs
+++ b/DungeonShooting_Godot/src/test/TestOptimizeSprite.cs
@@ -1,4 +1,3 @@
-using System;
using Godot;
public partial class TestOptimizeSprite : Node2D
@@ -7,60 +6,38 @@
public override void _Ready()
{
- var imageCanvas = new ImageCanvas(200, 200);
+ var imageCanvas = new ImageCanvas(1920, 1080);
imageCanvas.Scale = new Vector2(4, 4);
- imageCanvas.DrawImageInCanvas(Texture2D, 10, 30, 0, 0, 0, false);
- var time = DateTime.Now;
+ //imageCanvas.DrawImageInCanvas(Texture2D, 10, 30, 0, 0, 0, false);
+ //var time = DateTime.Now;
//imageCanvas.DrawImageInCanvas(Texture2D, 50, 30, 30, 0, 0, true);
- GD.Print("useTime: " + (DateTime.Now - time).TotalMilliseconds);
- var time2 = DateTime.Now;
- //imageCanvas.DrawImageInCanvas(Texture2D, 100, 100, 0, 0, 0, false);
- //imageCanvas.DrawImageInCanvas(Texture2D, 100, 100, 90, Texture2D.GetWidth() / 2, Texture2D.GetHeight() / 2, false);
- imageCanvas.DrawImageInCanvas(Texture2D, 100, 100, 300, 0, 0, false);
- //imageCanvas.DrawImageInCanvas(Texture2D, 100, 100, 145, (int)(Texture2D.GetWidth() * 0.2f), (int)(Texture2D.GetHeight() * 0.2f), false);
- //imageCanvas.DrawImageInCanvas(Texture2D, 140, 30, 270, 0, 0, true);
+ // GD.Print("useTime: " + (DateTime.Now - time).TotalMilliseconds);
+ // var time2 = DateTime.Now;
+ // //imageCanvas.DrawImageInCanvas(Texture2D, 100, 100, 0, 0, 0, false);
+ // //imageCanvas.DrawImageInCanvas(Texture2D, 100, 100, 90, Texture2D.GetWidth() / 2, Texture2D.GetHeight() / 2, false);
+ // imageCanvas.DrawImageInCanvas(Texture2D, 100, 100, 270, 0, 0, false);
+ // //imageCanvas.DrawImageInCanvas(Texture2D, 100, 100, 90, 0, 0, false);
+ // //imageCanvas.DrawImageInCanvas(Texture2D, 100, 100, 145, (int)(Texture2D.GetWidth() * 0.2f), (int)(Texture2D.GetHeight() * 0.2f), false);
+ // //imageCanvas.DrawImageInCanvas(Texture2D, 140, 30, 270, 0, 0, true);
+ //
+ // GD.Print("useTime: " + (DateTime.Now - time2).TotalMilliseconds);
- GD.Print("useTime: " + (DateTime.Now - time2).TotalMilliseconds);
+ for (int i = 0; i < 50; i++)
+ {
+ for (int j = 0; j < 50; j++)
+ {
+ var centerX = Utils.RandomRangeInt(0, Texture2D.GetWidth() - 1);
+ var centerY = Utils.RandomRangeInt(0, Texture2D.GetHeight() - 1);
+ imageCanvas.DrawImageInCanvas(Texture2D, 30 + (i + 1) * 10, 30 + (j + 1) * 10, Utils.RandomRangeInt(0, 360), centerX, centerY, Utils.RandomBoolean());
+ }
+ }
+
AddChild(imageCanvas);
}
- private void Test1()
+
+ public override void _Process(double delta)
{
- var canvas = Image.Create(150, 150, false, Image.Format.Rgba8);
-
- for (int x = 0; x < 150; x++)
- {
- for (int y = 0; y < 150; y++)
- {
- canvas.SetPixel(x, y, Colors.Gray);
- }
- }
-
- var image = Texture2D.GetImage();
- image.FlipX();
- image.Rotate180();
- canvas.BlitRect(image, new Rect2I(0, 0, image.GetWidth(), image.GetHeight()), new Vector2I(10, 10));
- //RotateImage(image, canvas, 50, 50, 30, image.GetWidth(), image.GetHeight());
-
- //RotateImage(imgData, image, 0);
-
- for (int i = 0; i < canvas.GetWidth(); i++)
- {
- canvas.SetPixel(i, 50, Colors.Black);
- canvas.SetPixel(i, 50 + image.GetHeight() / 2, Colors.Green);
- }
-
- for (int i = 0; i < canvas.GetHeight(); i++)
- {
- canvas.SetPixel(50, i, Colors.Black);
- canvas.SetPixel(50 + image.GetWidth() / 2, i, Colors.Green);
- }
-
- var imageTexture = ImageTexture.CreateFromImage(canvas);
- var sprite2D = new Sprite2D();
- sprite2D.Texture = imageTexture;
- sprite2D.Position = new Vector2(900, 500);
- sprite2D.Scale = new Vector2(5, 5);
- AddChild(sprite2D);
+ ImageCanvas.UpdateImageCanvas((float)delta);
}
}