2011-06-02 2 views
2

Je cherche un moyen d'améliorer la performance de certains dessins que je fais. Actuellement, il s'agit d'une grille de carreaux 32x32 que je dessine. Utilisation du code suivant pour dessiner sur le contexte de dessinAméliorer les performances du dessin Bitmaps en mosaïque dans wpf

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); 

L'image que je dessine est un CachedBitmap. Même en utilisant un CachedBitmap, j'ai toujours un délai d'environ une demi-seconde chaque fois que j'ai besoin de redessiner le Canvas.

Vous ne savez pas s'il existe un moyen plus performant de gérer le dessin sur cette grille. Finalement, je veux étendre le contrôle pour fonctionner comme une mini-carte, donc je dois garder cela à l'esprit.

En outre, j'ai essayé précédemment de dessiner chaque bitmap directement dans le contexte de dessin, mais cela semble un peu plus lent.

+0

Pour une grille 32x32, j'ai trouvé que votre méthode était rapide, je peux poster une solution en utilisant un WriteableBitmap qui fonctionne bien pour les petites tuiles comme les carrés de 8px dans le code que vous avez posté. Le code de 'GameWorldObject.GameMap [x, y] .GraphicsTile.TileStartPoint' est-il un simple accès? et est-ce une grille de 32x32 avec des tuiles de taille 8px qui fonctionne lentement? – Kris

+0

_maptiles est un dictionnaire qui contient tous les bitmaps possibles. C'est une grille de 32x32 que je rétrécis de sa taille d'origine. Les carreaux sont en réalité 64x64. Je me demande s'il serait plus rapide de réduire une seule image après sa construction plutôt que chaque image –

Répondre

1

I ajouté DrawingGroup.Freeze() avant de tirer, et il semblait aider à la performance.

0

Si c'est la plupart du temps statique, dessinez-la dans une image et dessinez cette image. Ou vous pouvez faire une grande image, où vous dessinez la carte entière, et dessinez simplement la partie visible actuelle de celle-ci.

Édition: Et peut-être vaut this blog post une vérification, si vous dessinez avec l'accélération logicielle ou matérielle sur.

+0

Le problème ici est qu'il s'agit d'un éditeur, et la minicarte peut changer lorsque les choses sont en cours d'édition. Si la carte n'était pas si grande, alors ce serait une solution acceptable. Cependant, la carte est trop grande pour dessiner une image statique et la mettre à jour chaque fois qu'il y a un changement. –

0

Voici un exemple utilisant WriteableBitmap, la performance de ceci est principalement liée à la taille de la carte entière alors que votre méthode originale est plus dépendante de la quantité de tuiles. Vous pouvez le modifier pour avoir une bordure alpha-mélangée entre les tuiles, mais en laissant un écart entre eux serait plus facile et plus performant. Vous n'aurez pas besoin du code randomisant les tuiles mais vous devriez avoir un drapeau sale pour que vous ne redessiniez que le bitmap quand il a changé. Vous pouvez également regarder ma réponse et les autres à cette question. Cela dit, vous n'avez pas autant d'éléments et 32x32 en utilisant votre méthode n'était pas lent pour moi.

<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

Oui, ça ne marchera probablement pas. La carte globale est juste trop grande. C'est la raison pour laquelle j'ai dû carreler la carte pour commencer. –

+0

Il a fallu 35 ms pour une grille avec 200 par 200 tuiles de 8px chacune. Avec 64 tuiles de 8px, il devrait être assez rapide. Vous pouvez exécuter le code que j'ai posté sans le modifier pour voir comment il fonctionne pour vous. – Kris

+0

Essayez quelque chose de plus sur les lignes de 50 000 x 50 000 tuiles et voyez comment ça fonctionne.C'est ce que je voulais dire par le fait qu'il y avait trop de carreaux. Votre bitmap atteindrait un mur de limite de mémoire, et il serait extrêmement lent à rendre la première fois. Une méthode hybride pourrait fonctionner, mais elle serait lente et compliquée. –

Questions connexes