Scroll-Mechanismus oder wandernde Figur mit tCanvas.CopyRect

Für Probleme bezüglich Grafik, Audio, GL, ACS, ...
Antworten
Martin V
Beiträge: 142
Registriert: Sa 30. Jan 2010, 19:35
OS, Lazarus, FPC: Linux64, Wiindows32, MacOS, Lazarus 1.8.2
CPU-Target: xxBit

Scroll-Mechanismus oder wandernde Figur mit tCanvas.CopyRect

Beitrag von Martin V »

Ich möchte in meinem Canvas einen Scroll-Mechanismus einbauen oder, im Prinzip wäre das dieselbe Fragestellung, z. B. eine Figur über den Bildschirm wandern lassen. Also muss ich mit CopyRect einen Rectangle Canvas-Ausschnitt an einer separaten Stelle im Speicher abspeichern, den freiwerdenden Streifen konventionell neu zeichnen (ggfs. mit ClipRect, damit nur der obsolete Bereich gezeichnet wird) und den Bildschirmbereich an der anderen Stelle wieder zeichnen lassen, indem ich das gespeicherte Rectangle mit CopyRect an die neue Stelle kopiere.

Ich habe so etwas noch nicht gemacht, aber ich brauche wohl zwei CopyRect Aufrufe und einen Zwischenspeicher. Oder gibt es eine einfachere und schnellere Variante? Ich frage mich allerdiings, wo ich das zwischenspeichern soll. Es soll möglichst schnell gehen. Brauche ich ein Bitmap-Objekt oder einfach nur einen freien Speicherbereich, also einen Speicher im Heap? Wenn ich es direkt ohne Zwischenpuffer kopieren würde, hängt es davon ab, in welcher Reihenfolge der Pixel-Reihen und -Spalten der Kopiervorgang passiert, das ist wahrscheinlich zu riskant. Bei Computerspielen ist das ja ständig gefragt, also denke ich dass es eine elgante und sehr schnelle vorgefertigte Lösung geben sollte.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.Copy

Beitrag von Mathias »

Verstehe ich richtig, du willst Sprites darstellen ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.Copy

Beitrag von af0815 »

Im Lazarusfolder unter Examples sollte sich ein Spritdemo befinden. In Lazarus unter Tools->Example Projects zu finden.
Dateianhänge
Anmerkung 2020-04-05 150718.jpg
Anmerkung 2020-04-05 150718.jpg (39.94 KiB) 4528 mal betrachtet
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.Copy

Beitrag von Winni »

Hi!

In den BGRAControls ist eine Komponente namens BGRASpriteAnimation.

Die BGRAControls kannst Du mit dem Online Package Manager runterladen.

Winni

Martin V
Beiträge: 142
Registriert: Sa 30. Jan 2010, 19:35
OS, Lazarus, FPC: Linux64, Wiindows32, MacOS, Lazarus 1.8.2
CPU-Target: xxBit

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.Copy

Beitrag von Martin V »

Nein, eigentlich will ich in einem Texteditor das Scrollen geschwindigkeitsmäßig optimieren. Das ganze sollte in normalem Delphi-Code geschrieben sein, ohne Lazarus-spezifische Befehle, weil es auch in einer anderen Delphi-ähnlichen Entwicklungsumgebung (WDsibyl) laufen soll. Wenn man in einem Editor um eine Zeile hoch- bzw. runterscrollt, dann muss ja nur die unterste bzw. oberste Zeile neu geschrieben werden. Alle anderen Zeilen kann man als großes Rectangle vom vorherigen Zustand kopieren, was wesentlich schneller ist, als jedes Mal alle Zeilen neu zu schreiben. Es ist also eigentlich recht simpel: Altes rect in den Heap speichern, neues rect um eiine Zeilenhöhe versetzt neu zeichnen und die wirklich neue unterste bzw. oberste Zeile des Editors dann konventionell neu erzeugen. Das Beispiel mit dem Spiel habe ich nur zur Veständlichkeit gebracht. Ich brauche also die dargestellte "Zu-Fuß" Vorgehensweise mit direkten Canvas Befehlen, und vor allem die Frage, wo ich das zwischenspeichern soll.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.Copy

Beitrag von af0815 »

Dann ist das Beispiel in Lazarus eher was. wobei die canvas implementation zwischen Lazarus und WDsibyl unterschiedlich sein kann. Ist oft auch bei Lazarus selbst in der Tiefe zwischen den Wigetsets nicht so einfach.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.Copy

Beitrag von Winni »

Hi!

Also im Prinzip so:
Platz für eine neue oberste Zeile machen:

Code: Alles auswählen

.....
var FontHi : Integer;
     bmp: TBitmap;
 
begin
FontHi := Memo1.Font.Height;
tmp := TBitMap.Create;
tmp.SetSize (Memo1.width, Memo1.height - FontHi;
tmp.Canvas.CopyRect (Rect (0,0,tmp.width,tmp.height), memo1.Canvas, Rect (0,0,tmp.width,tmp.height) );
Memo1.Canvas.CopyRect( Rect(0,FontHi,tmp.width,tmp.height+FontHi), tmp.canvas, Rect(0,0,tmp.width,tmp.height) );
tmp.free;
....
end;


Jetzt muss nur noch die oberste Zeile mit Textout geschrieben werden.

Winni

Martin V
Beiträge: 142
Registriert: Sa 30. Jan 2010, 19:35
OS, Lazarus, FPC: Linux64, Wiindows32, MacOS, Lazarus 1.8.2
CPU-Target: xxBit

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.Copy

Beitrag von Martin V »

Ja, genau das war es was ich wissen wollte. Also ich brauche ein temporäres Bitmap-Objekt. Ich kann dann das Bitmap-Objekt auch stehenlassen und das SetSize nur machen, wenn sich etwas geändert hat. Weil das beim schnellen Scrollen ständig gebraucht wird, zählt jede Millisekunde und es schont dann den Heap-Speicher. Danke Winni !

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1430
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.Copy

Beitrag von fliegermichl »

Für deinen Anwendungsfall reicht das. Wenn du aber wirklich eine Figur die nicht rechteckig ist über den Hintergrund schieben willst, brauchst du 3 Copyrect Befehle und 3 Bitmaps.

Die erste Bitmap ist deine Figur mit allen umliegenden Pixeln in weiß (Farbwert 255).
Die zweite ist exakt gleich, wobei alle Pixel deiner Figur schwarz sein müssen (Farbwert 0). Diese wird Maske genannt.
Die dritte Bitmap ist dein Hintergrund.

Der erste CopyRect Befehl zeichnet den Hintergrund auf die Paintbox.
Der zweite zeichnet die Maske (Bitmap 2) mit dem CopyMode SRCAND in die Paintbox und zuletzt die erste mit CopyMode MergePaint (OR Operation)

Ich hab mal eine kleine Demo gemacht. Anstatt da eine Hintergrund Grafik mit rein zu packen, generiere ich die im FormCreate, indem einfach Kreise reingemalt werden.
il ist eine ImageList in der meine Figur und die Maske sind. (Das bin ich mit meinem Hündchen :-)

Code: Alles auswählen

 
procedure TForm1.pbMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var bmp : TBitmap;
    mask : TBitmap;
    mw, mh : integer;
begin
  bmp := TBitmap.Create;
  mask := TBitmap.Create;
  try
    bmp.Assign(fBackGround);
    bmp.canvas.CopyMode := SRCAND;
    il.GetBitmap(1, mask); // Maske laden
    mw := mask.Width;
    mh := mask.Height;
    bmp.Canvas.CopyRect(Rect(x, y, x+mw, y+mh), mask.canvas, Rect(0, 0, mw, mh));
    il.GetBitmap(0, mask); // Figur laden
    bmp.Canvas.CopyMode := MergePaint;
    bmp.Canvas.CopyRect(Rect(x, y, x+mw, y+mh), mask.canvas, Rect(0, 0, mw, mh));
    pb.canvas.copyrect(pb.clientrect, bmp.canvas, Rect(0, 0, bmp.width, bmp.height))
  finally
   mask.Free;
    bmp.Free;
  end;
end;
 


So schaut es dann aus:
ga.zip
Demoprojekt Grafik Animation
(139.17 KiB) 173-mal heruntergeladen
Dateianhänge
Figur
Figur
yoshi_and_me.png (16.07 KiB) 4412 mal betrachtet

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.Copy

Beitrag von kupferstecher »

Martin V hat geschrieben:Wenn man in einem Editor um eine Zeile hoch- bzw. runterscrollt, dann muss ja nur die unterste bzw. oberste Zeile neu geschrieben werden. Alle anderen Zeilen kann man als großes Rectangle vom vorherigen Zustand kopieren, was wesentlich schneller ist, als jedes Mal alle Zeilen neu zu schreiben.

Bist du dir da sicher? Beim Kopieren werden die kompletten Daten gelesen und wieder geschrieben, also doppelter Speicherzugriff. Da wird der Speicherzugriff schnell zum Flaschenhals. Anders sieht es vielleicht aus, wenn jede Zeile ein eigenes Control ist und verschoben wird, dann kann die Grafikkarte beim Verschieben unterstützen.

Martin V
Beiträge: 142
Registriert: Sa 30. Jan 2010, 19:35
OS, Lazarus, FPC: Linux64, Wiindows32, MacOS, Lazarus 1.8.2
CPU-Target: xxBit

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.CopyRect

Beitrag von Martin V »

Ich habe nun folgendes herausgefunden:

Zumindest bei WDsibyl wird auch ein darüberliegendes Fenster mitkopiert und es muss somit kontrolliert werden, dass das Fenster, wo schnell gescrollt werden soll, wirklich zuoberst liegt. Aus dem Bildschirm herausragen darf es auch nicht. In diesen Fällen funktioniert das Bildschirmspeicher-Kopieren nicht. In den meisten Fällen braucht man keinen Zwischenspeicher, aber es gibt Fälle, wo es doch nötig ist. Ich vermute, dass das bei Lazarus alles genauso ist.

Bei Lazarus benötigt man zur Kontrolle, ob das Fenster wirklich oben liegt (nicht nur bzgl. der App, sondern systemweit), ChangeBounds. Doch das ist in meiner älteren Lazarus Version 1.8.3 buggy, so dass ich die Routine zurückgestellt habe. (Ich habe mehrere Lazarus-Installationen auf mehreren Betriebssystemen und Computern, der Upgrade Aufwand ist bei mir hoch.)

Es gibt also doch einiges an Haken und Ösen. Der Geschwindigkeitseffekt ist nicht so groß wie ich erhoffte. Es ist schneller, aber nicht so viel schneller wie ich erwartete. Kupferstecher hat Recht, dass es nicht klar ist, dass es schneller ist. Das hängt vielleicht auch von Computer und Grafikkarte ab. Der Canvas-Speicher scheint nur dort zu existieren bzw. den richtigen Inhalt zu enthalten, wo es wirklich am Bildschirm auch abgebildet ist.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Scroll-Mechanismus oder wandernde Figur mit tCanvas.CopyRect

Beitrag von Mathias »

Wen du richtig Power willst, führt kein Weg an OpenGL vorbei. 😉
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten