Autor Beitrag
Raven280438
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 99



BeitragVerfasst: Sa 02.10.10 21:49 
Hi,

ich zeichne in eine PictureBox viele kleine Bilder, ca. 32x32px.
Wenn die PictureBox über den ganzen Bildschirm geht dauert das Ganze schonmal gut eine Sekunde.

Ich speichere die Images schon in einem Dictionary.
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
Dictionary<string, Image> cache = new Dictionary<string, Image>();
[...]

if (!cache.Keys.Contains(verzeichnis + bild))
{
   Image img = Image.FromFile(verzeichnis + bild);
   cache.Add(verzeichnis + bild, img);
}

e.Graphics.DrawImage(cache[verzeichnis + bild], punkt);


Gibt es eine Möglichkeit, das ganze noch zu beschleunigen?


Gruß
Greenberet
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 339
Erhaltene Danke: 20

Win 10
C# (VS 2012), C++ (VS 2012/GCC), PAWN(Notepad++), Java(NetBeans)
BeitragVerfasst: So 03.10.10 00:51 
Wenn sich die Bilder nicht ändern:
alle Bilder am Anfang einmalig in ein großes Bild zeichnen anschließend nur noch das große Bild zeichnen.

zusätzlich könntest du "verzeichnis + bild" schonmal in "bildpfad" abspeichern, das jedes mal zusammenzusetzen dauert halt auch seine Zeit.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: So 03.10.10 12:33 
Und Pfade solltest du mittels
ausblenden C#-Quelltext
1:
Path.Conmbine(verzeichnis, bild);					

zusammensetzen.

Da du die Bilder ja alle dynamisch zeichnest, solltest du auch eher ein "Panel" anstatt einer "PictureBox" nehmen.

Du benutzt auch das Dictionary beim Auslesen unperformant - statt "Keys.Contains" besser direkt
ausblenden C#-Quelltext
1:
cache.ContainsKey(...);					


Und zuletzt noch:
mittels "Image.FromFile" lockst du die Bilddatei, bis das Image wieder mittels "Dispose" freigegeben wird. Besser ist es dann einen Stream zu benutzen:
ausblenden C#-Quelltext
1:
2:
Stream stream = new MemoryStream(File.ReadAllBytes(path));
Image img = Image.FromStream(stream);

Solltest du ein Image nicht mehr benötigen, d.h. aus dem Cache entfernen, so solltest du dann zusätzlich noch "image.Dispose()" aufrufen (generell sollte für alle Objekte, welche IDisposable implementieren Dispose() aufgerufen werden!).
Raven280438 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 99



BeitragVerfasst: So 03.10.10 12:48 
Hi,

danke für die Hinweise, leider gibt das immernoch keinen Geschwindigkeitsschub.

Wie kann ich kleine Bilder in ein Großes zeichnen? Damit hab ich noch keine Erfahrung.

Im Moment zeichne ich nur die Bilder, die auch wirklich angezeigt werden, da die PictureBox mehr Bilder hat, als sie anzeigen kann (also mit Scrollbars).
Da müsste ich bei jedem Scrollen auch das große Bild neu zeichnen.


Gruß
Raven280438 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 99



BeitragVerfasst: So 03.10.10 18:19 
Hi,

kann man das ganze auch mit DirectX lösen? Ich hab da garkeine Erfahrung drin. ;)

Oder hat jemand noch eine Idee, wie ich das Ganze beschleunigen kann?



Gruß
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.10.10 18:33 
Du kannst viel mit DX machen, aber das wäre hier etwas überdimensioniert.

Beschreibe doch einmal genauer was mit den Bildern passieren soll. Sollen diese dynamisch anders angeordnet werden oder bleiben diese wie sie sind?

Du kannst zum Beispiel einige Bilder in ein größeres zusammenfassen und dann diese größeren beim Scrollen entsprechend benutzen. Dadurch fällt schon einmal einiges an Aufwand weg.
Raven280438 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 99



BeitragVerfasst: So 03.10.10 19:28 
Hi,

also ich bin grade dabei, C# zu lernen. Als großes Lern-Projekt arbeite ich im Moment an einem Map-Editor für ein 2D RPG was ich später mal mit DirectX programmieren will ;)
Nicht kommerzielles, einfach nur zum Lernen.

Dazu hab ich eine 2-Dimensionale Liste mit den Hintergrund-Texturen.
ausblenden C#-Quelltext
1:
private List<List<string>> grundebene = new List<List<string>>();					

Später kommen noch andere Ebenen hinzu, die übereinander gezeichnet werden sollen.

Meine Paint-Funktion für die PictureBox sieht im Moment so aus:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
private int tile_size = 32;             //Höhe und Breite einer Tile
private int tiles_width;                //Anzahl Tiles horizontal
private int tiles_height;               //Anzahl Tiles vertikal

private int hOffset = 0;                //Offset einer Tile horizontal
private int vOffset = 0;                //Offset einer Tile vertikal
private int hscroll = 0;                //horizontaler Scroll
private int vscroll = 0;                //verticaler Scroll

private static Dictionary<string, Image> cache = new Dictionary<string, Image>();

private void pBMap_Paint(object sender, PaintEventArgs e)
{
   Font drawFont = new System.Drawing.Font("Arial"8);
   SolidBrush drawBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
   Pen raster = new Pen(Color.Black);

   //Start-Tile horizontal
   double d_start_i = hscroll / tile_size;
   int start_i = Convert.ToInt32(Math.Floor(d_start_i));

   //Start-Tile vertikal
   double d_start_j = vscroll / tile_size;
   int start_j = Convert.ToInt32(Math.Floor(d_start_j));

   //End-Tile horizontal
   double d_ende_i = this.pBMap.Width / tile_size;
   int ende_i = Convert.ToInt32(Math.Floor(d_ende_i)) + 10 + start_i;    //10 Tiles weiterrechnen
   if (ende_i > tiles_width) ende_i = tiles_width;

   //End-Tile vertikal
   double d_ende_j = this.pBMap.Height / tile_size;
   int ende_j = Convert.ToInt32(Math.Floor(d_ende_j)) + 10 + start_j;    //10 Tiles weiterrechnen
   if (ende_j > tiles_height) ende_j = tiles_height;

   int x = 0;
   for (int i = start_i; i < ende_i; i++)
   {
       int y = 0;
       for (int j = start_j; j < ende_j; j++)
       {
           Point punkt = new Point(x - hOffset, y - vOffset);
           //Grundebene zeichnen
           String grundebene_textur = grundebene[i][j];
           String bild = Path.Combine(textur_verzeichnis,grundebene_textur);
           if (Directory.Exists(textur_verzeichnis) && grundebene_textur.Length > 0)
           {
               FileInfo fi = new FileInfo(bild);
               if (fi.Exists)
               {
                   if (!cache.ContainsKey(bild))
                   {
                       Stream stream = new MemoryStream(File.ReadAllBytes(bild));
                       Image img = Image.FromStream(stream);

                       //Image img = Image.FromFile(bild);
                       cache.Add(bild, img);
                   }
                   for (int z = 0; z < 11; z++)    //Jede Tile 10 mal Zeichnen, als Leistungstest
                   {
                       e.Graphics.DrawImage(cache[bild], punkt);
                   }
               }
           }
           //Raster zeichnen
           e.Graphics.DrawRectangle(raster, x - hOffset, y - vOffset, tile_size, tile_size);
           e.Graphics.DrawString(i.ToString() + ":" + j.ToString(), drawFont, drawBrush, x - hOffset + 3, y - vOffset + 3);
           y += tile_size;
        }
        x += tile_size;
    }
}


Die PictureBox hat 2 Scrollbars:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
    this.hscroll = this.hScrollBar1.Value;
    if (this.hScrollBar1.Value > 0)
    {
        this.hOffset = this.hScrollBar1.Value % this.tile_size;
    }
    else
    {
        this.hOffset = 0;
    }
    this.pBMap.Refresh();
}

private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
    this.vscroll = this.vScrollBar1.Value;
    if (this.vScrollBar1.Value > 0)
    {
        this.vOffset = this.vScrollBar1.Value % this.tile_size;
    }
    else
    {
        this.vOffset = 0;
    }
    this.pBMap.Refresh();
}


Später soll dann noch das MouseMove ausgewertet werden, und um die Tile auf der die Maus ist ein rotes Viereck gezeichnet werden. Aber so weit bin ich noch nicht ;)

Falls sich jemand die Zeit nimmt, und sich das Projekt ansehen will, ich habs mal testweise hier hochgeladen:
www.roman-drechsel.de/Upload/ST.rar

Vielleicht hilft das jemand weiter. ;)


Gruß
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.10.10 19:32 
user profile iconRaven280438 hat folgendes geschrieben Zum zitierten Posting springen:
Später kommen noch andere Ebenen hinzu, die übereinander gezeichnet werden sollen.
Ok, dann wäre DirectX schon sinnvoll, denn das kümmert sich dann selbst um die Darstellung und Überlappung der Ebenen usw., außerdem kommen bei solch einem Editor vielleicht ja auch noch Effekte usw. hinzu.
Raven280438 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 99



BeitragVerfasst: So 03.10.10 19:46 
Hi,

das hab ich mir gedacht ;)

Kann man DirectX auch nur für einen bestimmten Bereich in einem Form nutzen? Ich würde gerne die Scrollbars weiter dafür nutzen und nichts eigenes dafür programmieren müssen.
Ich hab im Internet bisher nur Beispiele gefunden, die einen kompletten Form mit DirectX erstellen.

Folgendes Tutorial habe ich gefunden:
www.euclideanspace.c...9cs/basics/index.htm

Da wird aber mit Fullscreen gearbeitet. Wie kann ich das auf Windowed umstellen? Wenn ich
ausblenden C#-Quelltext
1:
dddevice.SetCooperativeLevel(this, CooperativeLevelFlags.Normal);					

einstelle, bekomm ich einen Fehler, sobald ich das Programm starte, in der Zeile:
ausblenden C#-Quelltext
1:
psurface = new Surface(sdesc, dddevice);					



Ich hab mir schon ein Buch zu C# und DirectX bestellt, aber das kommt erst nächste Woche ;)



Gruß