amiga-news DEUTSCHE VERSION
.
Links| Forums| Comments| Report news
.
Chat| Polls| Newsticker| Archive
.

amiga-news.de Forum > Programmierung > Neue Frage zu Überdeckungen [ - Search - New posts - Register - Login - ]

1 2 -3- 4 5 6 [ - Post reply - ]

2011-07-04, 23:43 h

Reth
Posts: 1858
User
So, nochmal zu dem Thema hier:
  • BeginRefresh rufen
  • InstallClipRegion rufen
  • mir die zurückgegebene Region merken
  • meine zu aktualisierenden Bereiche zu dieser alten Region hinzu-ODERn
  • wieder InstallClipRegion mit dieser neu ermittelten Region rufen
  • alles blitten
  • die alte gemerkte Region wieder installieren
  • EndRefresh rufen

Bei allen Beispielen, die ich bisher fand (z.B. auf innoidea) kam BeginRefresh() nach InstallClipRegion(), genauso wie EndRefresh! Aber wie soll ich denn dann an die gerade aktive ClipRegion kommen, um meine Bereiche hinzuzufügen?

Aber auch im anderen Fall, also wenn ich BeginRefresh() zuerst rufe: Muss ich denn immer eine Region mit InstallClipRegion setzen, damit ich an die gerade aktuelle ClipRegion komme? Gibt es keine andere Möglichkeit, die aktuelle ClipRegion des RastPorts zu ermitteln, damit ich meine Bereiche hinzufügen kann?!

Das mit dem Thema fehlende High-Level-API stresst immer mehr! Was man sich abmühen muss, nur um ein "paar lumpige Bildchen" animiert darstellen zu können ist abnormal! Und bei dem Aufwand, den ich da treiben muss mit Sicherheit höllisch unperformant!
Ich frage mich immer wieder, wie man das bei so Sachen wie SWIV und NAPALM hinbekommen hat?! Assembler aufs Übelste? Die Zeiten sollten doch hoffentlich vorbei sein! Ich finde, man sollte auch auf dem Amiga heute ein halbwegs normales Spiel in einer Hochsprache performant schreiben können! Befürchte aber, das geht wahrscheinlich nicht (oder nicht so leicht)!

Ja, ja, der Frust macht sich gerade breit hier!

[ - Answer - Quote - Direct link - ]

2011-07-05, 12:54 h

Holger
Posts: 8116
User
Zitat:
Original von Reth:
Bei allen Beispielen, die ich bisher fand (z.B. auf innoidea) kam BeginRefresh() nach InstallClipRegion(), genauso wie EndRefresh! Aber wie soll ich denn dann an die gerade aktive ClipRegion kommen, um meine Bereiche hinzuzufügen?

Gar nicht. Vor BeginRefresh gibt es noch keine ClipRegion, es sei denn, Du hättest sie selbst installiert. Möglicherweise erzeugt BeginRefresh ja von selbst eine Verknüpfung der Regionen. Aber in der Dokumention habe ich bislang nichts dergleichen gelesen.
Zitat:
Aber auch im anderen Fall, also wenn ich BeginRefresh() zuerst rufe: Muss ich denn immer eine Region mit InstallClipRegion setzen, damit ich an die gerade aktuelle ClipRegion komme?
Die aktuelle ClipRegion steht im Layer.
Zitat:
Das mit dem Thema fehlende High-Level-API stresst immer mehr! Was man sich abmühen muss, nur um ein "paar lumpige Bildchen" animiert darstellen zu können ist abnormal! Und bei dem Aufwand, den ich da treiben muss mit Sicherheit höllisch unperformant!
Der Aufwand dient doch der Performance. Es geht auch einfacher, z.B. ohne sich über das Clipping Gedanken zu machen.
Zitat:
Ich frage mich immer wieder, wie man das bei so Sachen wie SWIV und NAPALM hinbekommen hat?!
Na ja, keine Interaktion mit dem Betriebssystem an dieser Stelle. Und kein Clipping, sondern kontinuierliches Neuzeichnen. Und Napalm ist nicht gerade sparsam, was Ressourcen angeht.

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2011-07-05, 16:10 h

Thore
Posts: 2266
User
> Das mit dem Thema fehlende High-Level-API stresst immer mehr! Was man sich abmühen muss, nur um ein "paar lumpige Bildchen" animiert darstellen zu können ist abnormal! Und bei dem Aufwand, den ich da treiben muss mit Sicherheit höllisch unperformant!
Denkst Du hinter den APIs der "anderen" steckt weniger Code? Nur weil der Programmierer weniger Schreibarbeit hat, heißt es noch lange nicht, daß der Code performanter wär. Im dümmsten Fall ist es dermaßen schlecht daß Du selbst nichts mehr rausholen kannst, gerade weil du auf diese High Level API Funktionen angewiesen bist.

Unperformant ist es nicht unbedingt. Nicht die Länge des Codes sagt was über die Geschwindigkeit aus, sondern die Art und Weise wie er arbeitet.
Bastel Dir doch Unterfunktionen die Du einfach aufrufen kannst.

> Zitat:Ich frage mich immer wieder, wie man das bei so Sachen wie SWIV und NAPALM hinbekommen hat?!

Eine Viewport erstellen, direkt in den Speicher malen (Du kannst auch Intuition Screens/Windows nehmen und systemkonform mit API Funktionen reinmalen), Doublebuffer. Das kannst du auch wenn Du das magst.

Das Prinzip ist dann im Wechsel: Auf Schirm 2 zeichnen, Schirm 2 auf sichtbaren Schirm kopieren. ggf musst du dann Schirm 2 leeren vor dem nächsten Zeichnen, je nachdem on Du alles vollmalst oder nur Bereiche.



[ Dieser Beitrag wurde von Thore am 05.07.2011 um 16:12 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]

2011-07-07, 22:04 h

Reth
Posts: 1858
User
@Thore:
Das mit dem DoubleBouffer muss ich mir mal im Hinterkopf behalten, wird aber ne Menge Speicher verbrauchen (habe gerade fixe 1024x768 eingestellt)!

Meinst Du das Thema Viewport im Zusammenhang mit Intuition und systemkonform+API oder als 2 unterschiedliche Alternativen (hätte hier eher Letzteres verstanden)?

@All:
So nun ist noch mehr Ärger da. Der Compile unter AOS4 läuft durch (mit -D__USE_INLINE__, da ich eigentlich 68k-kompatibel programmiere) und nach dem Start friert das System so ein, dass sich nicht einmal mehr der Mauszeiger bewegen lässt!
Meine Logausgaben zeigen mir, dass beim Aufbau des Spielfeldes für das erste Hintergrundobjekt noch Alles durchläuft, beim 2. jedoch der Freeze erfolgt!
(Nebenbei: Gibt es denn ein empfehlenswerte Loggingkonzept für Amiga und C++? Mache derzeit alles mit std:out, ohne Loglevels. Dazu noch mit verschachtelten Aufrufen, so dass innerhalb eines std:out eine Objektmethode gerufen wird, die selbst auch noch ein std:out macht! Weiss nicht, ob das gesund ist? Habe mir mal kurz Log4C++ angesehen, aber in Richtung Portierung noch nichts gemacht!)
Das wird wahrscheinlich ne anstrengende Suche, v.a., wenn ich an das nächste Manko denke: Ein fehlender graphischer Source Level Debugger (hier fand ich HiSoftC++ unübertroffen!!!)!

Also dann mal frisch ans Werk (Hände feste reib)!

[ Dieser Beitrag wurde von Reth am 07.07.2011 um 22:30 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]

2011-07-07, 22:35 h

Thore
Posts: 2266
User
> Meinst Du das Thema Viewport im Zusammenhang mit Intuition und systemkonform+API oder als 2 unterschiedliche Alternativen (hätte hier eher Letzteres verstanden)?

Unterschiedliche Alternativen. Viele Spiele benutzen die OS Funktionen nicht, und malen direkt in den Speicher des Viewports (z.B. NoDOS Spiele).
Wenn Du einen Intuition Screen verwendest, kannst Du aber ebenfalls einen Doublebuffer programmieren.
Mit DB brauchts nochmal so viel Speicher wie der Screen groß ist (also BxHxBits pro Farbe zusätzlich). Bei 1024x768 Pixel und 24 Bit Farbtiefe hast Du einen Zusatzverbrauch von 2,3MB
Aber dafür ohne Schlieren und ohne Ruckeln.

[ - Answer - Quote - Direct link - ]

2011-07-07, 22:41 h

Reth
Posts: 1858
User
@Thore:
Und nehme ich dazu einfach 2 BitMaps oder 2 RastPorts (wohl eher BitMaps)?
Wenn ich dann in Richtung 68k denke, dann wäre das wohl die bessere Alternative, da den Speicher die meisten höher getakteten Classics haben dürften, mit der Prozessorpower ist aber beim 68060 Schluss! Dann müsste ich aber immer eine BitMap im Hauptspeicher haben, nicht im Grafikkarten-RAM (denn das ist knapp bemessen)! Kann man das auch über MEMF_CHIP o.ä. steuern?

[ Dieser Beitrag wurde von Reth am 07.07.2011 um 22:44 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]

2011-07-08, 08:44 h

Thore
Posts: 2266
User
Benutzt Du eine Grafikkarte, kannst Du generell FastRAM benutzen. Der Grafikkartenspeicher wird lediglich (wie beim ChipRAM) für Anzeige und Hardwarebeschleunigte Grafikaktionen verwendet.

Benutzt Du Customchips, musst Du zur Anzeige der Grafik ChipRAM benutzen (da Agnus/Alice nur im ChipRAM arbeiten). Wenn die DB Bitmap nicht im ChipRAM liegt, kannst Du sie zwar nicht anzeigen aber wohl noch davon auf eine ChipRAM Bitmap kopieren. Dann funktioniert für den DB switch zwar der Blitter nicht, aber ich denk das ist verschmerzbar.

Es gibt zwei Ansätze für DB, die kopier-Methode ist hier möglich. Hier muss nur der Anzeige-Screen im ChipRAM sein

Die schnellere Methode ist das Screen-Switchen. Dabei wird im hinteren Screen gezeichnet, dann der Screen nach vorn geholt, dann wird auf den hinteren Screen (der vorher der vordere war) wieder gezeichnet, und dann nach vorn geholt. Für dieses müssen beide im ChipRAM liegen.


[ Dieser Beitrag wurde von Thore am 08.07.2011 um 08:46 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]

2011-07-08, 17:58 h

Reth
Posts: 1858
User
@Thore:
Danke für die Tips. Muss das Thema leider erst einmal nach hinten schieben, da sich meine Fehlersuche wie erwartet als "widerlich" erweist: Überlegen, Codestelle ändern, Logausgaben einfügen, compilieren, starten, Rechner kaltstarten, Logfile lesen und von vorn!

Habe wahrscheinlich ein grundsätzliches Problem mit dem Refresh-Handling. Vorher hatte ich immer NOCAREREFRESH und selbst einfach nur geblittet, ohne BeginRefresh/EndRefresh. Jetzt ja nicht mehr.
Beim Aufbau des Spielfeldes wird ein Hexagon nach dem anderen geblittet. Für das Erste läuft der ganze Zyklus auch durch, aber ohne, dass man was zu sehen bekommt. Beim 2. friert das System maximal ein, wenn es zu OrRectRegion kommt. RefreshMessages behandle ich derzeit noch nicht, sondern blitte wie zuvor alles immer selbst, wenn ich es brauche. Liegt es vielleicht daran?
Was ich unabhängig von RefreshMessages mache ist folgendes für jedes Hexagaon:
  • Bestimme aus allen existierenden grafischen Objekten, welches sich darstellen will, für dieses dann folgende Schritte durchführen
  • Rechteck ermitteln
  • Eigene Clipregion erweitern (OrRectRegion)
  • InstallClipRegion mit eigener ermittelten Region rufen, mir die alte Region merken
  • BeginRefresh rufen
  • EraseRect auf ganzen Spielfeldbereich ausführen
  • alle grafischen Objekte blitten
  • EndRefresh rufen
  • die alte gemerkte Region wieder installieren

Hier ist noch nicht die Verknüpfung mit der bereits bestehenden Region enthalten!
(Sorry Holger, dass mit den InstallClipRegion außerhalb von Begin-/EndRefresh hab ich in allen OS-Beispielen auf innoidea usw. so gesehen!)

Wie gesagt friert das System beim 2. Hexagon komplett ein, sobald OrRectRegion aufgerufen wird. Region hat dieselbe Adress wie beim ersten Aufruf, das Rechteck hat die erwarteten Dimensionen! Fehlt hier noch was? Irgendein Intuition-Aufruf? bin am Verzweifeln! V.a. ist die Art des Testens alles andere als effizient oder produktiv (eher stumpfsinnig). Mir ist aber noch nix Besseres eingefallen.
Was mich auch wundert ist, dass für die Region beim 2. Aufruf bei jedem Test dieselbe Adresse benutzt wird, wie beim ersten Aufruf, obwohl der Scope nur innerhalb der aufgerufenen Methode ist. Zufall?
So mich ärgerts gewaltig!
An die Hilfswilligen, wenn ihr mehr Details/Code was auch immer braucht, einfach hier melden!

Dank euch schon mal!

[ - Answer - Quote - Direct link - ]

2011-07-08, 20:35 h

Holger
Posts: 8116
User
Zitat:
Original von Reth:
Der Compile unter AOS4 läuft durch (mit -D__USE_INLINE__, da ich eigentlich 68k-kompatibel programmiere) und nach dem Start friert das System so ein, dass sich nicht einmal mehr der Mauszeiger bewegen lässt!

Und ein aus derselben Version gebautes 68k-Binary läuft unter AOS4 fehlerfrei?

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2011-07-08, 20:42 h

Reth
Posts: 1858
User
@Holger:
Hab ich leider noch nicht probiert (kann man denn aus dem AOS4-G++ cross-compilieren?)! Den letzten Compile-Versuch unter AOS3.9 hatte ich damals mit Abbruch aus Speichermangel. Seit dem hab ichs nie wieder probiert (wüsste auch nicht wie, zudem dauert es ewig!).

Meine erste Vermutung war, dass die erzeugten Rectangle-Objekte schuld sind, da ich die direkt in einer Schleife erstellt habe (ohne Zeiger oder Referenz) und das Objekt dann ja nach der Schleife eigentlich seinen Scope verliert (wenn ich mir das richtig gemerkt habe), so dass die darin gekapselten Rectangle-Strukturen auch futsch waren.
Hab das umgestellt und nun sollte es passen (Objekte werden zwar immer noch in der schleife erzeugt, aber direkt in einem Vector, der außerhalb der Schleife deklariert und definiert wurde)! Trotzdem erfolgt der Freeze immer noch an derselben Stelle. Ich hab bestimmt irgendwo nen dicken Hund bzgl. Reihenfolge und Abhängigkeiten der Intuition-relevanten Teile (Refresh-Funktionen etc.). Nur wo? Muss ich nach meinem Refreshzyklus noch irgendwas anstoßen oder irgendwelche Messages verarbeiten (wie gesagt, das ganze erfolgt außerhalb des Message-Handlings!)?

[ - Answer - Quote - Direct link - ]

2011-07-08, 21:12 h

Thore
Posts: 2266
User
Schwer zu sagen wo es crasht. Nachher ist es ein trivialer Fehler der eben zu diesem Zeitpunkt erst zum Tragen kommt (irgendwas nicht initialisiertes oder in einen nicht-reseriverten Speicher geschrieben oder so)
Ohne Blick auf die Sourcen kann man nur spekulieren. Falls es Closed Source sein soll, bitte doch einer "Vertrauensperson" mal über den Source zu schauen und dokumentier dann auch im Code wo genau es crasht.
Falls es sowieso mal Open Source werden soll, kannst Du den Source irgendwo hochladen und nen Link posten?

[ - Answer - Quote - Direct link - ]

2011-07-08, 22:23 h

Reth
Posts: 1858
User
Gibt es denn irgendwo ne gute Übersicht, was ich bei Intuition, Begin-/EndRefresh und Messages alles beachten muss (neben dem hier bereits gesagtem)?

Codeausschnitte kann ich immer gern posten, den ganzen Code (erst mal noch) nicht. Bis jetzt schon noch closed source.

[ - Answer - Quote - Direct link - ]

2011-07-08, 22:47 h

Thore
Posts: 2266
User
Ja möglich daß es gar nicht an den API Aufrufen liegt sondern z.B. einer Schleife wo du was freigibst und nicht wieder erstellst oder sowas in der Art. Da könnten wir sonst viele Nächte diskutieren... :)

[ - Answer - Quote - Direct link - ]

2011-07-08, 23:56 h

Holger
Posts: 8116
User
Zitat:
Original von Reth:
@Thore:
Das mit dem DoubleBouffer muss ich mir mal im Hinterkopf behalten,…

Das im Hinterkopf zu behalten bringt aber gar nichts, denn mit DoubleBuffer kannst Du alles das, was Du jetzt gerade versuchst, vergessen. Wenn Du mit Swap-Buffern arbeitest, muss natürlich jedes Update beim nächsten Zeichenvorgang in den anderen Buffer wiederholt werden (falls man nicht eh immer alles neu zeichnet), da man andernfalls beim Umschalten veraltete Inhalte wiederherstellen würde.

Mit dem systemeigenen Refresh-Mechanismus funktioniert das nicht, da der bei einem erfolgreichen Ende alle Damage-Bereiche verwirft und prinzipiell nicht dazu gebracht werden kann, diese für zwei Updates zu behalten, da nicht zwischen altem und neuem Damage unterschieden werden kann.

Was aber nicht so schlimm ist, da sich anwendungsfremde Fenster, deren Besitzer nichts von der Notwendigkeit, in zwei Buffer zu zeichnen, weiß, ja ohnehin verbieten. Damit braucht man auch von diesen verursachten Damage nicht zu berücksichtigen.

Zitat:
Dazu noch mit verschachtelten Aufrufen, so dass innerhalb eines std:out eine Objektmethode gerufen wird, die selbst auch noch ein std:out macht! Weiss nicht, ob das gesund ist? Habe mir mal kurz Log4C++ angesehen,…
Ob Du ein Framework benutzt oder nicht, ändert kaum etwas daran, dass Log-Aufrufe, egal wie sie umgesetzt sind, die ihrerseits neue Log-Aufrufe triggern, ziemlich gefährlich sind.

Zitat:
Original von Reth:
(Sorry Holger, dass mit den InstallClipRegion außerhalb von Begin-/EndRefresh hab ich in allen OS-Beispielen auf innoidea usw. so gesehen!)

Ähm, Du musst Dich nicht bei mir entschuldigen, mir ist es doch egal, ob Du es so oder so machst. Du solltest Dich nur fragen
Funktionieren eigentlich diese Beispiele unter AOS4?
Ist „es stand so in einem Beispiel“ als Erklärung ausreichend, was Dein Code macht?
Was macht es denn nun? Wird die Clip-Region überhaupt verwendet, wird sie mit der Damage-Region verknüpft, wenn ja, via AND oder OR, und wieso erklärt das Beispiel (bzw. dessen Autor) nicht, warum das so gemacht wurde und was passieren soll?

Zitat:
Original von Thore:
Benutzt Du eine Grafikkarte, kannst Du generell FastRAM benutzen.

Na ja, Du benutzt, was auch immer das Grafiksystem Dir gibt, wenn Du eine dazu kompatible BitMap anforderst. Auf den Typ des Speichers hast Du gar keinen direkten Einfluss,
Zitat:
Wenn die DB Bitmap nicht im ChipRAM liegt, kannst Du sie zwar nicht anzeigen aber wohl noch davon auf eine ChipRAM Bitmap kopieren. Dann funktioniert für den DB switch zwar der Blitter nicht, aber ich denk das ist verschmerzbar.
Ähem, wenn Du eine komplette BitMap via CPU in eine sichtbare BitMap kopierst, wozu dann überhaupt noch das Double-Buffering?
Zitat:
Die schnellere Methode ist das Screen-Switchen. Dabei wird im hinteren Screen gezeichnet, dann der Screen nach vorn geholt, dann wird auf den hinteren Screen (der vorher der vordere war) wieder gezeichnet, und dann nach vorn geholt.
Es gibt Methoden, um DoubleBuffering mit einem Screen durchzuführen. Das interferiert dann auch nicht mit dem manuellen Screen-Switching des Anwenders.

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2011-07-09, 00:23 h

Reth
Posts: 1858
User
Hi Holger,
Zitat:
Original von Holger:
Ähm, Du musst Dich nicht bei mir entschuldigen, mir ist es doch egal, ob Du es so oder so machst. Du solltest Dich nur fragen
Funktionieren eigentlich diese Beispiele unter AOS4?
Ist „es stand so in einem Beispiel“ als Erklärung ausreichend, was Dein Code macht?

Das Beispiel findet sich hier und auf allen anderen ähnlich gemachten Sites zur Beschreibung des "klassischen" Amiga-APIs.
Zitat:
Original von Holger:
Was macht es denn nun? Wird die Clip-Region überhaupt verwendet, wird sie mit der Damage-Region verknüpft, wenn ja, via AND oder OR, und wieso erklärt das Beispiel (bzw. dessen Autor) nicht, warum das so gemacht wurde und was passieren soll?

Ja, wird im Bsp. verwendet und als ClipRegion gesetzt. Das Erstellen der ClipRegion wird aber nicht einzeln gezeigt.
Wie oben gesagt erstelle ich meine Region so, dass ich alle Rechtecke der geänderten grafischen Objekte mit OrRectRegion hinzufüge, dann die so erzeugte Region als ClipRegion installiere, meine Blits durchführe und danach die alte ClipRegion wieder installiere. Eine Veroderung meiner ClipRegion mit der ggf. bereits vorhandenen erfolgt noch nicht.
Zitat:
Original von Holger:
Ähem, wenn Du eine komplette BitMap via CPU in eine sichtbare BitMap kopierst, wozu dann überhaupt noch das Double-Buffering?

Also wie gesagt, das Thema Doublebuffering schiebe ich erst mal in den Hintergrund. Das ich damit alles bisher diskutierte vergessen kann war mir klar. Um die Frage für mich zu beantworten hatte ich hier das Doublebuffering so verstanden, dass neben der BitMap des Fensters noch eine nicht sichtbare benutzt wird, die dann immer neu aufgebaut und ins Fenster geblittet wird. Deiner Frage entnehme ich mal, dass dies nicht die beste Lösung ist.

[ - Answer - Quote - Direct link - ]

2011-07-09, 10:45 h

Reth
Posts: 1858
User
Also hab letzte Nacht noch was rausgefunden. Habe mal systematisch die Neuerungen eliminiert. Zuerst das geänderte Regionhandling (das alte hatte funktioniert), so dass immer alles gelöscht und neu gezeichnet wird - immer noch Freeze. Dann Rückstellung auf NOCAREREFRESH - nun hat alles wieder funktioniert (ist aber unakzeptabel). D.h., GT_BeginRefresh/GT_EndRefresh führen bei mir zum Freeze!!!

Leider hatte diese "Lösung" immer noch ein Problem: Bei Beenden des Programms kam ein recoverable Alert, danach beendete sich das Programm und anschließend erfolgt ein kompletter Freeze. Also hab ich wohl noch ein anderes Problem (das zuvor noch nicht da war, kann aber u.U. auch nicht am Programm liegen!)!
Helfen hier eigentlich Zusatzprogramme (wie Mungwall oder was auch immer) und wenn ja, welche?

Da hab ich letzte Nacht wieder bedauert, dass es keinen funktionierenden SVN- oder CVS-Server für AOS gibt, sonst hätte ich mir den letzten, getaggten und funktionierenden Stand schnell mal auschecken können. Hmpf, sehr ärgerlich! Und nen 2. Rechner nebenher laufen zu lassen, nur für Repository seh ich nicht ein!

[ - Answer - Quote - Direct link - ]

2011-07-09, 13:07 h

Thore
Posts: 2266
User
> Na ja, Du benutzt, was auch immer das Grafiksystem Dir gibt, wenn Du eine dazu kompatible BitMap anforderst.

Ich wollte mit dem Satz lediglich ausdrücken, daß bei Grafikkarten kein ChipRAM für die Grafiken benötigt wird. Dann können die Grafiken im FastRAM liegen und von da aus in den Grafikkartenspeicher (sprich, sichtbaren Grafik-Bereich) kopiert werden. Bei Grafikkarten mit nur 4 MB Grafikspeicher macht das Sinn.

> Ähem, wenn Du eine komplette BitMap via CPU in eine sichtbare BitMap kopierst, wozu dann überhaupt noch das Double-Buffering?

Um Flackern bei Anims zu vermeiden oder bei Bewegungen den Hintergrund nicht zu zerstören. Du kannst das auch partiell machen und nicht über den ganzen Schirm.

Das DoubleBuffer Prinzip hab ich auch angesprochen, weil Reth fragte, wie das denn andere wie Napalm und so machen. Ich sehe nichts was dagegen spricht.
Und klar ist es eine Alternative und keine Zusatzoption. Und ich glaube auch daß das ClipRegion-Zeug bei Reth funktioniert, nur irgendwo eine Unachtsamkeit drin ist. Bevor er aber den Code wegwirft weil sein ClipRegion nicht tut, kann er sich das DB Prinzip als Backup Lösung merken. WIE er es dann implementiert, bleibt seine Sache.

> Es gibt Methoden, um DoubleBuffering mit einem Screen durchzuführen. Das interferiert dann auch nicht mit dem manuellen Screen-Switching des Anwenders.

Es gibt viele Wege, die Frage ist, was ist einfach und schnell zu implementieren. Du kannst auch eine weitere Bitmap erzeugen statt einem Screen. Es waren nur Beispiele um das Prinzip zu erläutern. Ob das schneller oder komplizierter ist als ClipRegion hängt von vielen Faktoren ab, und ich habe bisher nicht in den Code geschaut, um das abzuschätzen.



Was mich erstmal interessiert, ist die angesprochene Schleife. Dürfen wir hier mal Code sehen?


[ - Answer - Quote - Direct link - ]

2011-07-09, 20:31 h

Reth
Posts: 1858
User
@Thore:
Meinst Du die Refresh-Schleife? Hier isse (der Formatierer hier zerhaut mir leider die Einrückungen). Ich hoffe, ich muss nicht alles erklären, was (aus meiner Sicht) nichts mit dem Ganzen zu tun hat und in der früheren Version auch prima funktioniert hatte!
Wenn ich das Region-Erstellen und den Begin-/EndRefresh weglasse funktionierts wie gesagt mit dem Recoverable Alert und dem Freeze zu/nach Programmende.
Vernünftiges Logging hab ich wie gesagt auch noch nicht eingebaut, die Logausgaben sind aber mal mit drin (vielleicht machen die ja Probleme)! Wenn ich sie für die Übersichtlichkeit entfernen soll gebt Bescheid!
C++ code:
void AnimObjectManagerC::refreshAllObjects(WindowC& window)
{
    RegionC clipRegion;
    std::vector<RectangleC> rectangles;
    
    long start = time(NULL);
std::cout << "Beginne mit Refresh aller Objekte: " << start << std::endl;
    
    // TODO: Bei beweglichen Objekten auch vorherige Position mit berücksichtigen
     
    /************************************************************************************
     * 1. Durchgehen aller Objekte und Prüfen, welches sich geändert hat                *
     * 2. Für geänderte Objekte original ClippingRegion des Layers ergänzen             *
     * 3. Original ClippingRegion sichern und eigene ClippingRegion installieren        *
     * 4. EraseRect auf ganzes Spielfeld                                                *
     * 5. Alle Objekte entsprechend ihrer Layer von unten nach oben ablaufen und blitten*
     * 6. Alte ClippingRegion wieder herstellen                                         *
     ************************************************************************************/
    
    // 1. Durchgehen aller Objekte und Prüfen, welches sich geändert hat
    for (std::vector<AnimObjectC *>::iterator innerIterator = animObjects.begin(); innerIterator != animObjects.end(); innerIterator++)
    {
        AnimObjectC *animObject = (*innerIterator);
        // 2. Für geänderte Objekte ClippingRegion ergänzen
std::cout << "Prüfe, ob AnimObject: " << animObject << " dargestellt werden will." << std::endl;
        if (animObject->willAnimate())
        {
std::cout << "AnimObject: " << animObject << " will dargestellt." << std::endl;
            // umgebendes Rechteck für aktuelles AnimObjekt in aktueller Darstellung anlegen
            rectangles.push_back(RectangleC(animObject->getYPos(), animObject->getXPos(), animObject->getYPos() + animObject->getActiveAnimation()->getActHeight(),
                                               animObject->getXPos() + animObject->getActiveAnimation()->getActWidth()));
std::cout << "Rechteck " << rectangles.back().getRectangleStruct() << " mit X=" << rectangles.back().getLeft() << " Y=" << rectangles.back().getTop() << " WIDTH=" << rectangles.back().getRight() << " HEIGHT=" << rectangles.back().getBottom() << " für AnimObject: " << animObject << " erzeugt." << std::endl;
            clipRegion.orNewRectangle(rectangles.back());
std::cout << "ClipRegion für AnimObject: " << animObject << " erweitert." << std::endl;
        }
if (!rectangles.empty()) std::cout << "Rechteck in Schleife ist: " << rectangles.back().getRectangleStruct() << " mit X=" << rectangles.back().getLeft() << " Y=" << rectangles.back().getTop() << " WIDTH=" << rectangles.back().getRight() << " HEIGHT=" << rectangles.back().getBottom() << std::endl;
    }

    // wenn nix zu animieren ist => fertig
    if (!rectangles.empty())
    {
std::cout << "Letztes Rechteck nach Schleife ist: " << rectangles.back().getRectangleStruct() << " mit X=" << rectangles.back().getLeft() << " Y=" << rectangles.back().getTop() << " WIDTH=" << rectangles.back().getRight() << " HEIGHT=" << rectangles.back().getBottom() << std::endl;

        layers.unique();    // Duplikate entfernen
        layers.sort();
std::cout << "Layer sortiert und Duplikate eliminiert." << std::endl;
        // 3. Alte ClippingRegion sichern und eigene ClippingRegion installieren
        window.getRastPort().installClipRegion(clipRegion);
std::cout << "ClipRegion installiert." << std::endl;
        window.beginGadToolsRefresh();
std::cout << "GadToolsRefresh gestartet." << std::endl;
        // 4. EraseRect auf ganzes Spielfeld
        window.getRastPort().eraseRect(0, 0, 807, SCREENHEIGHT);
std::cout << "Spielbereich gelöscht." << std::endl;
    // 5. Alle Objekte entsprechend ihrer Layer von unten nach oben ablaufen und blitten
        for (std::list<int>::iterator layerIterator = layers.begin(); layerIterator != layers.end(); layerIterator++)
        {
            std::vector<AnimObjectC *> layerObjects = allObjects[*layerIterator];
               for (std::vector<AnimObjectC *>::iterator objectIterator = layerObjects.begin(); objectIterator != layerObjects.end(); objectIterator++)
               {
                    AnimObjectC *animObject = (*objectIterator);
std::cout << "AnimObject: " << animObject << std::endl;
                    if (animObject->isVisible())
                    {
                        window.getRastPort().blitFrameAt(animObject->getActiveFrame(), animObject->getXPos(), animObject->getYPos());
std::cout << "AnimObject geblittet. XPos=" << animObject->getXPos() << " YPos=" << animObject->getYPos() << " ActWidth=" << animObject->getActWidth() << " ActHeight=" << animObject->getActHeight() << std::endl;
                    }
            }
        }

        window.endGadToolsRefresh();
std::cout << "GadToolsRefresh beendet." << std::endl;
        // 6. Alte ClippingRegion wieder installieren
        window.getRastPort().restoreOldClipRegion();    
std::cout << "Alte ClipRegion wieder hergestellt." << std::endl;
std::cout << "Fertig mit Refresh aller Objekte: " << time(NULL) << " - Dauer: " << (time(NULL) - start) << std::endl;
    }
}


Was passier im Einzelnen:
In jedem Rectangle-Object wird eine struct rectangle mit den Werten befüllt. Die passen soweit überall auch. In der Klasse RegionC hat einen Zeiger auf struct region in sich, der wird im Default-Konstruktor mit NewRegion() initialisiert. Bei orNewRectangle() passiert Folgendes:
C++ code:
void RegionC::orNewRectangle(const RectangleC& newRectangle)
{
std::cout << "OrRectRegion für region: " << region << " und Rechteck: " << newRectangle.getRectangleStruct() << std::endl;
	if (region == NULL) region = NewRegion();
	BOOL result = OrRectRegion(region, newRectangle.getRectangleStruct());
std::cout << "OrRectRegion fertig, Ergebnis: "<< result << std::endl;
}

Bei den Animationen und AnimObjekten war ich noch auf Neubau und Highlevel-API unterwegs. Mittlerweile wrappe ich die nativen Sachen nur noch in Klassen! Die Prüfung der region auf NULL kann ich eigentlich überall weglassen, weil in beiden Konstruktoren immer dafür gesorgt wird, dass der region-Zeiger nicht NULL ist! Aber Vorsicht ist die Mutter...

Die Rastport-Klasse hat nen Zeiger auf strucht rastport in sich und ein Objekt vom Typ RegionC (sie ist als Friend deklariert). Bei installClipRegion passiert Folgendes:
C++ code:
void RastPortC::installClipRegion(const RegionC& clipRegion)
{
    if (rastPort)
    {
std::cout << "Installiere Region. MinX: " << clipRegion.region->bounds.MinX << " MinY: " << clipRegion.region->bounds.MinY << " MaxX: " << clipRegion.region->bounds.MaxX << " MaxY: " << clipRegion.region->bounds.MaxY << std::endl;
        regionBuffer.region = InstallClipRegion(rastPort->Layer, clipRegion.region);
    }
}

Hier der Vollständigkeit halber das Entfernen und der Restore der ClipRegion:
C++ code:
void RastPortC::uninstallClipRegion()
{
    if (rastPort)
    {
        RegionC oldRegion;
        // DisposeRegion für Zeiger auf region struct wird im Destruktor von RegionC gerufen
		oldRegion.region = InstallClipRegion(rastPort->Layer, NULL);
    }
}

void RastPortC::restoreOldClipRegion()
{
    if (rastPort)
    {
	    RegionC oldRegion;
        // DisposeRegion für Zeiger auf region struct wird im Destruktor von RegionC gerufen
		oldRegion.region = InstallClipRegion(rastPort->Layer, NULL);
        InstallClipRegion(rastPort->Layer, regionBuffer.region);
    }
}

EraseRect und das Blitten werden 1:1 durchgereicht.

So hier noch die beiden Refresh-Methoden, sind als inline im Header angelegt:
C++ code:
inline void beginGadToolsRefresh() { if (window) GT_BeginRefresh(window); }
inline void endGadToolsRefresh() { if (window) GT_EndRefresh(window, TRUE); }


So, hoffe das genügt fürs Erste!

[ - Answer - Quote - Direct link - ]

2011-07-09, 23:46 h

Thore
Posts: 2266
User
Sind WindowC und RastPortC von Window und RastPort abgeleitet?
Du kannst ja ein DEBUG_OUT definieren, und wenn Debug=True ist, ausgeben und wenn False dann ignorieren. So kannst du prüfen ob es an deinen Ausgaben liegt.
Bringt er beim Beenden den Fehler? Versuchst Du da irgendwas freizugeben was bereits frei ist oder NULL?

[ - Answer - Quote - Direct link - ]

2011-07-10, 00:01 h

Reth
Posts: 1858
User
Zitat:
Original von Thore:
Sind WindowC und RastPortC von Window und RastPort abgeleitet?

Nicht abgeleitet, beide kapseln mehr oder weniger die entsprechenden Intuition Strukturen und bieten die entsprechenden Funktionen als Methoden an. Ist wie gesagt nur ein Wrapping, keine neue API. In der Fensterklasse findet auch das Messagehandling statt (mir ist dazu noch nichts Besseres eingefallen).
Zitat:
Original von Thore:
Du kannst ja ein DEBUG_OUT definieren, und wenn Debug=True ist, ausgeben und wenn False dann ignorieren. So kannst du prüfen ob es an deinen Ausgaben liegt.

Ja, die Vorgehensweise kenn ich auch. Wollte aber wenn dann möglichst gleich ein "richtiges" Logging einbauen (mit Logleveln usw.), in der Art von Log4J.
Zitat:
Original von Thore:
Bringt er beim Beenden den Fehler? Versuchst Du da irgendwas freizugeben was bereits frei ist oder NULL?

Wie gesagt in der hier geposteten Version friert alles sofort ein, sobald versucht wird das 2. 6-Eck zu blitten (fürs erste läufts noch durch, es wird aber nicht angezeigt). Wenn ich das ganze Clipping mitsamt Regionbildung weglasse ändert sich auch nix. Erst wenn ich die Begin-/EndRefresh-Aufrufe weglasse, dann klappt das blitten (NOCAREREFRESH-Window) und während des Endens des Programms kommt ein recoverable alert, nach dem das Programm beendet ist friert das System komplett ein (vor meiner Umstellung hatte ich keines dieser Probleme, d.h., da hab ich wohl einige üble Sachen eingebaut).
Vielleicht sollte ich statt der Gadtools-Begin-/EndRefresh Aufrufe mal die "normalen" probieren? Habe allerdings Gadgets, die ganz normal mit struct Gadget arbeiten, kein Boopsi, Reaction o.ä.. Daher bin ich davon ausgegangen, dass ich auch die Gadtools-Refresh-Aufrufe benötige!

[ Dieser Beitrag wurde von Reth am 10.07.2011 um 00:13 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]

2011-07-10, 15:38 h

Reth
Posts: 1858
User
Nachtrag zu:

So hier noch die beiden Refresh-Methoden, sind als inline im Header angelegt:
C++ code:
inline void beginGadToolsRefresh() { if (window) GT_BeginRefresh(window); }
inline void endGadToolsRefresh() { if (window) GT_EndRefresh(window, TRUE); }

Gemeint ist der Header meiner Window-Klasse und window ist ein Zeiger vom Typ struct window.

[ - Answer - Quote - Direct link - ]

2011-07-11, 12:44 h

Holger
Posts: 8116
User
Zitat:
Original von Reth:
Das Beispiel findet sich hier und auf allen anderen ähnlich gemachten Sites zur Beschreibung des "klassischen" Amiga-APIs.

Du musst aber auch lesen, was da steht. Das Beispiel dient ausschließlich für den Fall, dass man EndRefresh mit dem Parameter FALSE aufruft, was, wie im darüberstehenden Text erklärt, äußerst problematisch ist. Da das Beispiel aber in keinster Weise erklärt, warum man das überhaupt tun sollte, außerdem, wie von Dir ebenfalls bemerkt, gar nicht gesagt wird, wo die Clip-Regionen denn herkommen, somit das Beispiel für die Lösung des Problems gar nicht ausreicht, gibt es nur eine mögliche Schlussfolgerung:

Rufe niemals EndRefresh mit FALSE auf und vergiss das Beispiel.

Zitat:
Eine Veroderung meiner ClipRegion mit der ggf. bereits vorhandenen erfolgt noch nicht.
Nur noch mal als Gedächtnisstütze: BeginRefresh dient einem primären Zweck: die Damage-Liste in eine aktive Clip-Region umzuwandeln. Wenn Du also Deine Clip-Region vor dem Aufruf setzt, gibt es nur zwei Möglichkeiten: a) die Regionen werden effektiv verknüpft oder b) Deine vorher gesetzt Region wird übergebügelt.

Was davon nun wirklich passiert, sollte man wissen, bevor man sich entscheidet, es so zu tun.

Zitat:
... hatte ich hier das Doublebuffering so verstanden, dass neben der BitMap des Fensters noch eine nicht sichtbare benutzt wird, die dann immer neu aufgebaut und ins Fenster geblittet wird.
Das ist eine mögliche Vorgehensweise, entspricht aber nicht der Art, wie die angesprochenen Spiele es umsetzen, bzw. wie Thore es beschrieben hat (v.a. mit Screen-Switching)
Zitat:
Deiner Frage entnehme ich mal, dass dies nicht die beste Lösung ist.
Das hast Du falsch verstanden. Ein Offscreen-Buffer ist nicht gleich Double-Buffering.

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2011-07-11, 12:58 h

Holger
Posts: 8116
User
Zitat:
Original von Reth:
Erst wenn ich die Begin-/EndRefresh-Aufrufe weglasse, dann klappt das blitten (NOCAREREFRESH-Window)...

NoCareRefresh und die Frage, ob Du Begin/EndRefresh benutzt, haben nichts miteinander zu tun. Das erste beeinflusst nur, ob Du Messages bekommst, das andere dient dem optimierten Zeichnen. Du solltest diese Dinge also auch unabhängig voneinander auf ihre Auswirkungen überprüfen.

Du solltest außerdem beachten, dass das Logging in eine Textkonsole problematisch werden kann, da diese unter Umständen die Meldung auf den Bildschirm bringen will und das mit den durch Deinen BeginRefresh gelockten Layern interferiert. Da die Ausgabe meist gepuffert ist, treten solche Problem möglicherweise nicht schon bei der ersten Meldung auf. Nur eine Möglichkeit...
Zitat:
Vielleicht sollte ich statt der Gadtools-Begin-/EndRefresh Aufrufe mal die "normalen" probieren? Habe allerdings Gadgets, die ganz normal mit struct Gadget arbeiten, kein Boopsi, Reaction o.ä.. Daher bin ich davon ausgegangen, dass ich auch die Gadtools-Refresh-Aufrufe benötige!
Die Gadtools-Refresh-Aufrufe dienen einzig und allein den über Gadtools angelegten Gadgets. Mit "ganz normal mit struct Gadget" hat das nichts zu tun.

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2011-07-11, 16:36 h

Reth
Posts: 1858
User
Zitat:
Original von Holger:
Nur noch mal als Gedächtnisstütze: BeginRefresh dient einem primären Zweck: die Damage-Liste in eine aktive Clip-Region umzuwandeln. Wenn Du also Deine Clip-Region vor dem Aufruf setzt, gibt es nur zwei Möglichkeiten: a) die Regionen werden effektiv verknüpft oder b) Deine vorher gesetzt Region wird übergebügelt.

Was davon nun wirklich passiert, sollte man wissen, bevor man sich entscheidet, es so zu tun.

Ups, Du hast recht. Ich weiss nicht genau, was hier passiert. Das war aber schon als nächste Änderung vorgesehen (Umstellung der Reihenfolge zw. BeginRefresh und ClipRegion-Erstellung)!

Zitat:
Original von Holger:
Du solltest außerdem beachten, dass das Logging in eine Textkonsole problematisch werden kann, da diese unter Umständen die Meldung auf den Bildschirm bringen will und das mit den durch Deinen BeginRefresh gelockten Layern interferiert. Da die Ausgabe meist gepuffert ist, treten solche Problem möglicherweise nicht schon bei der ersten Meldung auf. Nur eine Möglichkeit...

Die Textkonsole wird immer auf dem WB Bildschirm geöffnet. Hat für die hier beschriebenen Situationen aber keine Relevanz, da ich alle Ausgaben in eine Textdatei umleite, um die Infos für den Neustart nach dem Freeze parat zu haben.

Zitat:
Original von Holger:
Die Gadtools-Refresh-Aufrufe dienen einzig und allein den über Gadtools angelegten Gadgets. Mit "ganz normal mit struct Gadget" hat das nichts zu tun.

Mit ganz normal meinte ich lediglich BeginRefresh() und EndRefresh() anstelle von GT_BeginRefresh() bzw. GT_EndRefresh().

[ - Answer - Quote - Direct link - ]

2011-07-11, 19:24 h

Holger
Posts: 8116
User
Zitat:
Original von Reth:
Mit ganz normal meinte ich lediglich BeginRefresh() und EndRefresh() anstelle von GT_BeginRefresh() bzw. GT_EndRefresh().

Ich versuch's noch mal anders: Benutzt Du gadtools-Gadgets?
In diesem Fall musst Du die GT_… Funktionen benutzen, ansonsten auf keinen Fall.

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2011-07-12, 18:54 h

Thore
Posts: 2266
User
Ich tipp daß Du die Intuiton Gadgets verwendest. Mach mal ohne GT_, vll ist das das Problem.

[ - Answer - Quote - Direct link - ]

2011-07-12, 20:07 h

Reth
Posts: 1858
User
Tja, bin mir nicht 100% sicher. Öhm, wie kann ich das denn zuverlässig feststellen (peinliche Frage)?
Aus der gadtools.library nehme ich derzeit nur die GetVisualInfo- und die LayoutMenus-Funktion.
Für Gadgets nehme ich die AddGadget-Funktion. Allerdings verwende ich struct NewMenu für meine Menüs.
Heisst das nun, ich habe GadTools-Gadgets (in Form der Menüs) oder nicht?

[ - Answer - Quote - Direct link - ]

2011-07-12, 20:17 h

Thore
Posts: 2266
User
Spricht alles für GadTools, verwende mal die NewGadget Struktur.

[ - Answer - Quote - Direct link - ]

2011-07-12, 20:20 h

Holger
Posts: 8116
User
Zitat:
Original von Reth:
Heisst das nun, ich habe GadTools-Gadgets (in Form der Menüs) oder nicht?

Nein, Menüs sind keine Gadgets.
Gadgets sind die Dinger, bei denen Du, wenn Du gadtools benutzt, als allererstes CreateContext() aufrufen musst, das ein Pseudo-Gadget erzeugt, das immer als allererstes in der Liste vor allen anderen gadtools-Gadgets steht, die Du via CreateGadget[A]() erzeugt.

Wenn Du selbiges nicht machst, hast Du auch keine solchen Gadgets.

Wenn Du welche hättest, müsstest Du übrigens nicht nur GT_... Funktionen für den Refresh, sondern auch die GT_... Funktionen für die Verarbeitung von intuition-Messages verwenden.

Aber VisualInfo und Menüs betrifft das nicht.

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2011-07-12, 20:43 h

Thore
Posts: 2266
User
Ist NewMenu nicht in gadtools.h definiert? Wär entsprechend auch dann davon ausgegangen daß es die gadtools verwendet.

[ Dieser Beitrag wurde von Thore am 12.07.2011 um 20:59 Uhr geändert. ]

[ - Answer - Quote - Direct link - ]


1 2 -3- 4 5 6 [ - Post reply - ]


amiga-news.de Forum > Programmierung > Neue Frage zu Überdeckungen [ - Search - New posts - Register - Login - ]


.
Masthead | Privacy policy | Netiquette | Advertising | Contact
Copyright © 1998-2024 by amiga-news.de - all rights reserved.
.