Entwickler-Ecke
Windows API - procedure beschleunigen(asm und so)
MathiasH - Do 31.10.02 10:35
Titel: procedure beschleunigen(asm und so)
ich hab mir für ein
Spiel eine funktion geschrieben, die Images blended, mein Problem danei, sie ist nicht schnell genug, ich habs schon mit assembler versucht, aber da brauchte sie 3 msec länger, also: Hat hier jemand ein paar tips, wie ich dat ding schneller machen kann?
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:
| procedure blendimage(var image1, image2: TImage;Value: word); var i,j: Integer; colvalue: word; OrigRow, DestRow: pRGBArray; begin for i := 0 to Image1.Picture.Height - 1 do begin OrigRow := Image1.Picture.Bitmap.ScanLine[i]; DestRow := Image2.Picture.Bitmap.ScanLine[i]; for j := 0 to Image1.Picture.Width - 1 do begin if (value > 0 )then begin DestRow[j].rgbtRed := min(255, OrigRow[j].rgbtRed + Value); DestRow[j].rgbtBlue := min(255, OrigRow[j].rgbtRed + Value); DestRow[j].rgbtGreen := min(255, OrigRow[j].rgbtRed + Value);
end else begin DestRow[j].rgbtRed := max(255, OrigRow[j].rgbtRed + Value); DestRow[j].rgbtBlue := max(255, OrigRow[j].rgbtRed + Value); DestRow[j].rgbtGreen := max(255, OrigRow[j].rgbtRed + Value); end; end; end; end; |
Ich hoffe da weis wer was dazu :roll:
MathiasH
AndyB - Do 31.10.02 16:07
Die ScanLine-Abfragen beanspruchen sehr viel Rechenleistung, da dabei jedesmal die kompletten Bilddaten kopiert werden.
MathiasH - Do 31.10.02 17:15
soll ich es mit Pixels[x, y] machen? :shock:
dann wach ich auf und er iss immernochnicht fertig
oder hast du was schnelleres als Scanline???????
es wird doch eh nicht zu oft abgefragt
MathiasH
AndyB - Do 31.10.02 18:19
"nicht zu oft" ist gut. Für jede Zeile einmal für Image1 und einmal für Image2. Das macht 2x pro Zeile, wobei ScanLine jedesmal das gesamte Bild kopiert.
Wie wäre es, wenn du für jedes Image nur 1x dir die ScanLine holst, und dann einfach den Array-Zeiger um Width*3 Bytes erhöhst.
Wenn es nur so einfach wäre. Dummerweise kann es vorkommen (und das sogar sehr häufig), dass die Bildzeilen verkehrtherum im Speicher liegen. Die erste ScanLine liegt somit am Ende Speicherbereichs, wohingegen die letzte ScanLine am Anfang liegt.
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function GetFirstScanLine(Bitmap: TBitmap): PRGBTriple; var p: PRGBTriple; begin Result := PRGBTriple(Bitmap.ScanLine[0]); if Bitmap.Height > 1 then begin p := PRGBTriple(Bitmap.ScanLine[Bitmap.Height - 1]); if DWord(Result) > DWord(p) then Result := p; end; end; |
Mit dieser Funktion bekommst du die ScanLine, die im Speicher ganz oben liegt.
Matthias - Fr 01.11.02 03:54
Hallo,
bei großen BMP's ist es zudem sinnvoll die Werte vorher zu berechnen, in einem array abzulegen und später über das array zu indizieren:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| var Values : array[0..255] of byte;
... for n := 0 to 255 do begin if Value > 0 then Values[n] := min(255, n + Value) else Values[n] := max(255, n + Value) end; |
Zuweisung in der Schleife
Quelltext
1: 2: 3:
| DestRow[j].rgbtRed := Values[OrigRow[j].rgbtRed]; DestRow[j].rgbtBlue := Values[OrigRow[j].rgbtBlue]; ... |
ciao
Matthias
(01.11.02 20:29 Tino) Code-Tags hinzugefügt.
OregonGhost - Fr 01.11.02 19:31
Anstatt Scanline zu verwenden, kannst du auch direkt mit DIBs arbeiten. Da ein TImage meines Wissens auch nicht viel mehr macht als sein Image auf den Bildschirm zu blitten kannst du das auch von Hand machen. Wenn du deine Bitmap zum Beispiel mit CreateDIBSection() erstellst, bekommst du schon bei der Erstellung einen Zeiger auf die Pixeldaten und da muss nix kopiert werden. Dann musst du nur noch das Array korrekt indizieren, nämlich mit [(y * Width + x)*sizeof(Pixel)], wobei sizeof(Pixel) natürlich einfach für die Datengröße eines Pixels steht.
Wenn du bei CreateDIBSection() als Höhe für die Bitmap einen negativen Wert angibst, stehen die Scanlines auch richtig herum im Speicher.
Wenn du den Zeiger in einen Zeiger auf DWORD konvertierst, kannst du auch ziemlich einfach 3DNow! oder MMX nutzen.
Wenn du die if-Abfrage vor die Forschleife stellst, also zwei Forschleifen verwendest, kannst du die Geschwindigkeit minimal erhöhen. Statt min() und max() solltest du entweder wie bereits beschreiben ein Array nutzen oder eine if-Abfrage, weil es sich dabei um Funktionen handelt und diese Overhead bedeuten, schätze ich jedenfalls mal, weil Object Pascal weder inline-Funktionen noch Makros kennt.
So, und jetzt hoffe ich einfach mal, dass ich nicht zuviel Blödsinn erzählt habe ;c) Zumindest beim ersten Absatz bin ich mir 100%ig sicher.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!