저는 며칠 동안 이것을 구현하는 데 어려움을 겪고 있습니다. 비슷한 문제에 대해 광범위하게 조사해 왔지만 문제에 직접적으로 도움이되지는 않습니다.UserControl에서 큰 캔버스 렌더링
기본적으로 타일은 내 UserControl
클래스의 표에 렌더링됩니다. 이것은 내가 개발중인 Tile Engine 기반의 세계 편집자를위한 것입니다. 다음은 열린 세계 문서 및 기생 타일에 대한 스크린 샷입니다.
처음에, 나는 세상의 미리보기 캔버스 것이 내 컨트롤에 Bitmap
을 사용하려고했다. 예를 들어 브러시 도구를 사용하여 마우스를 움직이고 왼쪽 버튼을 누르면 커서 아래의 가장 가까운 타일을 브러시의 타일로 설정하고 layer
비트 맵에 칠합니다. 컨트롤의 OnPaint
메서드는 페인트 이벤트의 클리핑 사각형에 대해 layer
비트 맵이 그려지는 위치로 재정의됩니다.
큰 세상을 다룰 때 비트 맵은 매우 커질 수 있습니다. 이 응용 프로그램을 세계 크기로 다목적으로 사용할 필요가 있으며 무효화 될 때마다 큰 비트 맵을 컨트롤에 렌더링 할 때 성능 문제가 있다는 것은 명백합니다.
현재 컨트롤에 덮어 쓰여진 타일 OnPaint
에 직접 타일을 그려 넣습니다. 이것은 많은 메모리를 필요로하지 않기 때문에 좋습니다. 예를 들어 타일 당 (20, 20)
의 (1000, 1000)
세계 (전체 캔버스 크기는 (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);
}
}
}
내 코드의 컨텍스트가 더 필요하면 의견을 보내주십시오.
절대적으로 환상적입니다! 얼마나 오랫동안 내가 이것을 망쳐 놓았는지, 그것은 터널 전망이 가장 그렇기 때문에 나를 생각조차하지 못하게했다. 명확한 설명을위한 톤 감사합니다! –
문제가없는 친구입니다. 작은 증분으로 스크롤하는 경우 전체 캔버스를 다시 그릴 필요가 없다고 덧붙였습니다. 내용을 상하로 blit하고 새로운 노출 된 간격 만 다시 그립니다. – K3N
그래, 직접 드로잉 메서드로 구현하려고했지만이 메서드를 사용할 때 훨씬 더 의미가 있습니다. –