Улучшение производительности рисования плиточных растровых изображений в wpf - PullRequest
2 голосов
/ 02 июня 2011

Я ищу способ улучшить производительность некоторых чертежей, которые я делаю.В настоящее время я рисую сетку плиток размером 32x32.Используя следующий код для рисования в контексте рисования

for (int x = startX; x < endX; x++)
        {
            for (int y = startY; y < endY; y++)
            {
                dg.Children.Add(
                    new ImageDrawing(_mapTiles[GameWorldObject.GameMap[x, y].GraphicsTile.TileStartPoint],
                        new Rect(CountX * 8, CountY * 8, 8, 8)
                        ));

                dg.Children.Add(
                    new GeometryDrawing(
                        null,
                        new Pen(
                            new SolidColorBrush(
                                Color.FromRgb(255, 0, 20)), .3), 
                                new RectangleGeometry(
                                    new Rect(CountX * 8, CountY * 8, 8, 8)
                                )
                            )
                        );

                CountY++;
            }
            CountY = 0;
            CountX++;
        }

        dc.DrawDrawing(dg);

Рисуемое изображение является CachedBitmap.Даже используя CachedBitmap, у меня все равно есть задержка около половины секунды каждый раз, когда мне нужно перерисовать Canvas.

Не уверен, что есть более эффективный способ обработки рисования в этой сетке.В конце концов я хочу расширить элемент управления, чтобы он функционировал как мини-карта, поэтому я должен помнить об этом.

Кроме того, ранее я пытался просто нарисовать каждое растровое изображение непосредственно в контексте рисования, но это кажется немного медленнее,

Ответы [ 3 ]

1 голос
/ 04 июня 2011

Я добавил DrawingGroup.Freeze () перед рисованием, и это, похоже, помогло с производительностью.

0 голосов
/ 04 июня 2011

Вот пример использования WriteableBitmap, производительность которого в основном связана с размером всей карты, тогда как ваш оригинальный метод больше зависит от количества плиток. Вы можете изменить его, чтобы иметь альфа-смешанную границу между плитками, но оставить зазор между ними было бы проще и эффективнее. Вам не понадобится код, который рандомизирует плитки, но у вас должен быть какой-нибудь грязный флаг, чтобы вы перерисовывали растровое изображение только после его изменения.

Вы также можете посмотреть мой ответ и другие на этот вопрос . Тем не менее, у вас не так много предметов, и 32x32 с использованием вашего метода не было медленным для меня.

<local:Map x:Name="map" />
<RepeatButton Click="Button_Click" Content="Change" />


private void Button_Click(object sender, RoutedEventArgs e)
{
    map.seed++;
    map.InvalidateVisual();
}


public class Map : FrameworkElement
{
    private int[][] _mapTiles;

    public Map()
    {
        _mapTiles = Directory.GetFiles(@"C:\Users\Public\Pictures\Sample Pictures", "*.jpg").Select(x =>
        {
            var b = new BitmapImage(new Uri(x));
            var transform = new TransformedBitmap(b, new ScaleTransform((1.0 / b.PixelWidth)*tileSize,(1.0 / b.PixelHeight)*tileSize));
            var conv = new FormatConvertedBitmap(transform, PixelFormats.Pbgra32, null, 0);
            int[] data = new int[tileSize * tileSize];
            conv.CopyPixels(data, tileSize * 4, 0);
            return data;
        }).ToArray();

        bmp = new WriteableBitmap(w * tileSize, h * tileSize, 96, 96, PixelFormats.Pbgra32, null);
        destData = new int[bmp.PixelWidth * bmp.PixelHeight];
    }

    const int w = 64, h = 64, tileSize = 8;
    public int seed = 72141;
    private int oldSeed = -1;
    private WriteableBitmap bmp;
    int[] destData;

    protected override void OnRender(DrawingContext dc)
    {
        if(seed != oldSeed)
        {
            oldSeed = seed;
            int startX = 0, endX = w;
            int startY = 0, endY = h;
            Random rnd = new Random(seed);

            for(int x = startX; x < endX; x++)
            {
                for(int y = startY; y < endY; y++)
                {
                    var tile = _mapTiles[rnd.Next(_mapTiles.Length)];
                    var rect = new Int32Rect(x * tileSize, y * tileSize, tileSize, tileSize);
                    for(int sourceY = 0; sourceY < tileSize; sourceY++)
                    {
                        int destY = ((rect.Y + sourceY) * (w * tileSize)) + rect.X;
                        Array.Copy(tile, sourceY * tileSize, destData, destY, tileSize);
                    }
                }
            }

            bmp.WritePixels(new Int32Rect(0, 0, w * tileSize, h * tileSize), destData, w * tileSize * 4, 0);
        }

        dc.DrawImage(bmp,new Rect(0,0,w*tileSize,h*tileSize));
    }
}
0 голосов
/ 02 июня 2011

Если это в основном статическая миникарта, нарисуйте ее в изображение и нарисуйте это изображение. Или вы можете сделать большое изображение, в котором вы рисуете всю карту и просто рисуете его видимую часть.

Редактировать : И, может быть, этот блог стоит проверить, рисуете ли вы его с программным или аппаратным ускорением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...