Autor |
Beitrag |
MathiasH
      
Beiträge: 699
WinXP, Win98SE, Debian, Win95
D5 Stand, D6 Prof
|
Verfasst: Do 31.10.02 10:35
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
MathiasH
_________________ "Viel von sich reden, kann auch ein Mittel sein, sich zu verbergen."
Friedrich Nietzsche
|
|
AndyB
      
Beiträge: 1173
Erhaltene Danke: 14
RAD Studio XE2
|
Verfasst: Do 31.10.02 16:07
Die ScanLine-Abfragen beanspruchen sehr viel Rechenleistung, da dabei jedesmal die kompletten Bilddaten kopiert werden.
_________________ Ist Zeit wirklich Geld?
|
|
MathiasH 
      
Beiträge: 699
WinXP, Win98SE, Debian, Win95
D5 Stand, D6 Prof
|
Verfasst: Do 31.10.02 17:15
soll ich es mit Pixels[x, y] machen?
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
_________________ "Viel von sich reden, kann auch ein Mittel sein, sich zu verbergen."
Friedrich Nietzsche
|
|
AndyB
      
Beiträge: 1173
Erhaltene Danke: 14
RAD Studio XE2
|
Verfasst: 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.
_________________ Ist Zeit wirklich Geld?
|
|
Matthias
      
Beiträge: 121
|
Verfasst: 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
      
Beiträge: 215
|
Verfasst: 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.
_________________ Oregon Ghost
---
Wenn NULL besonders groß ist, ist es fast schon wie ein bisschen eins.
|
|
|