[英]Render Large Canvases in UserControl
我幾天來一直很難實現這一點。 關於我想做的事情,我已經廣泛搜索了類似的問題,但是我沒有遇到直接幫助我解決問題的問題。
基本上,我是在UserControl
類的網格上渲染圖塊。 這是針對我正在開發的基於Tile Engine的世界編輯器。 這是一個開放世界文檔的屏幕截圖,上面還刷了一些圖塊。
最初,我將在控件中使用一個Bitmap
,它將成為世界上的預覽畫布。 例如,使用畫筆工具,當您移動鼠標並向下按鼠標左鍵時,它將光標下方最近的圖塊設置為畫筆的圖塊,並將其繪制在layer
位圖上。 控件的OnPaint
方法將覆蓋到相對於繪畫事件的剪貼矩形繪制layer
位圖的位置。
這種方法的問題在於,當處理大世界時,位圖將非常大。 我需要此應用程序具有通用的大小,並且很明顯,每次在控件上失效時將大位圖呈現到控件上時,都會出現性能問題。
目前,我正在控件的重寫的OnPaint
事件中直接將切片繪制到控件上。 這很棒,因為它不需要很多內存。 例如,一個(1000, 1000)
1000,1000 (1000, 1000)
世界在每個圖塊( (20, 20)
(畫布總大小為(20000, 20000)
20000,20000 (20000, 20000)
)下,整個應用程序的內存約為18mb。 雖然不占用大量內存,但是卻占用大量處理器,因為每次控件無效時,它都會迭代視口中的每個圖塊。 這會產生非常煩人的閃爍。
我想完成的是一種在內存使用和性能方面相會的方法。 本質上是雙緩沖世界,以便在重繪控件時不會閃爍(窗體調整大小,焦點和模糊,滾動等)。 以Photoshop為例-溢出容器視口時如何渲染打開的文檔?
作為參考,這是我的控件的OnPaint
重寫,它使用上述直接繪制方法。
getRenderBounds
返回一個相對於PaintEventArgs.ClipRectangle
的矩形,該矩形用於呈現可見的圖塊,而不是遍歷世界上的所有圖塊並檢查其是否可見。
protected override void OnPaint(PaintEventArgs e)
{
WorldSettings settings = worldSettings();
Rectangle bounds = getRenderBounds(e.ClipRectangle),
drawLocation = new Rectangle(Point.Empty, settings.TileSize);
e.Graphics.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
e.Graphics.SmoothingMode =
System.Drawing.Drawing2D.SmoothingMode.None;
e.Graphics.PixelOffsetMode =
System.Drawing.Drawing2D.PixelOffsetMode.None;
e.Graphics.CompositingQuality =
System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
for (int x = bounds.X; x < bounds.Width; x++)
{
for (int y = bounds.Y; y < bounds.Height; y++)
{
if (!inWorld(x, y))
continue;
Tile tile = getTile(x, y);
if (tile == null)
continue;
drawLocation.X = x * settings.TileSize.Width;
drawLocation.Y = y * settings.TileSize.Height;
e.Graphics.DrawImage(img,
drawLocation,
tileRectangle,
GraphicsUnit.Pixel);
}
}
}
如果您需要我的代碼中的更多上下文,請發表評論。
訣竅是根本不使用大位圖。 您只需要一個覆蓋可見區域的位圖。 然后,您繪制可見的任何東西。
為此,您將需要與位圖分開維護數據。 它可以是一個簡單的數組,也可以是一個具有簡單類的數組/列表,其中包含用於每個塊的信息,例如世界位置。
當塊位於可見區域內時,您將其繪制。 您可能需要迭代整個數組,也可以不必遍歷整個數組,但這並不是真正的問題(您也可以在單獨的線程上計算可見數組)。 您還可以通過創建區域索引來使函數更智能,從而避免迭代所有塊。
要將新塊添加到數組,請計算其在世界坐標上的畫布位置,將其添加,然后再次渲染該數組(或繪制該塊的區域)。
這也是系統如何繪制具有可滾動區域的控件的方式。
啟用雙緩沖將使其清晰無閃爍。
在這種情況下,我還將使用帶有單獨滾動條的面板並計算滾動條的相對位置。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.