1 / 27

V03 Laden und Initialisieren der Grafiken

V03 Laden und Initialisieren der Grafiken. Grafiken des Spiels laden und testweise auf dem Bildschirm anzeigen eine Klasse anlegen, die alle erforderlichen Grafikoperationen enthält: class display unter Rückgriff auf definierte Klassen CDisplay und CSurface in Ddutil.h und Ddutil.cpp

wang-hodges
Télécharger la présentation

V03 Laden und Initialisieren der Grafiken

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. V03 Laden und Initialisieren der Grafiken Grafiken des Spiels laden und testweise auf dem Bildschirm anzeigen eine Klasse anlegen, die alle erforderlichen Grafikoperationen enthält: class display unter Rückgriff auf definierte Klassen CDisplay und CSurface in Ddutil.h und Ddutil.cpp CDisplay: allgemeine Schnittstelle zum Grafiksystem stellt übergreifende Dienste bereit CSurface: Instanzen nehmen einzelne darzustellende Bitmaps auf Elemente der Oberfläche werden aus Bitmap - Datei in Klasse CSurface eingelesen

  2. CDisplay: Funktionen von Interesse class CDisplay { public: HRESULT CreateWindowedDisplay; // erzeugt ein Display in einem Fenster HRESULT CreateSurfaceFromBitmap(...); // erzeugt eine Surface aus einer Bitmapdatei HRESULT Blt(...); // kopiert eine Surface in das Display HRESULT Present(); // aktualisiert Display im Fenster LPDIRECTDRAW7 GetDirectDraw(); // gibt Zeiger auf das mit Display verbundene DirectDraw - Objekt zurück HRESULT UpdateBounds(); // aktualisiert Display bei Größenänderung des Fensters };

  3. CSurface: Funktionen von Interesse class CSurface { HRESULT DrawBitmap(); }; - Funktion überträgt eine Bitmap aus einer Datei in eine Surface bzw. Oberfläche

  4. 1. Schritt • Klasse display wird mit dem CDisplay versehen und mit erforderlichen Oberflächen bzw. Csurfaces • hinzu kommen Konstruktor display und Destruktor ~display und eine Freigabefunktion namens free_all class display { private: CDisplay dsply; CSurface *hgrnd;// Zeiger auf ein CSurface CSurface *fldst; CSurface *fllst; CSurface *prvst; CSurface *deckel; CSurface *ziff [10]; public: display ();// Initialisierung der Zeiger mit 0 void free_all();// gibt Speicher frei ~display() { free_all(); }// Aufruf von Freigabefunktion };

  5. Konstruktor: alle Zeiger werden mit 0 initialisiert display::display () { int i; hgrnd = 0; fldst = 0; fllst = 0; prvst = 0; deckel = 0; for ( i = 0; i < 10; i++) ziff [i] = 0; }

  6. free_all wird vom Destruktor aufgerufen und beseitigt alle dynamisch angelegten Objekte, d.h. gibt Speicher frei void display :: free_all () { int i; if (hgrnd) delete hgrnd; if (fldst) delete fldst; if (fllst) delete fllst; if (prvst) delete prvst; if (deckel) delete deckel; for (i = 0; i < 10; i++) { if ( ziff [i] ) delete ziff [i];} }

  7. 2. Schritt • Hinzufügen einer Initialisierungsmethode • erzeugt Display und Surfaces • Initialisierung des Displays durch die Funktion CreateWindowedDisplay • diese übernimmt den Handle des umschließenden Fensters (wnd) und die gewünschten Abmessungen des Displays (ultris_nettobreite, ultris_nettohoehe) • Zur Erinnerung: HWND ultris_window • Handle; Zeiger, der Zugriff auf Hauptfenster ermöglicht; in WinMain Funktion class display { private: ... public: .. HRESULT init (HWND wnd); };

  8. HRESULT display :: init (HWND wnd) { HRESULT hr; //Fehlercode hr,erfolgt Rücksprung in aufrufendes Programm int i; char fname[20]; hr = dsply.CreateWindowedDisplay (wnd, ultris_nettobreite, ultris_nettohoehe); if (hr < 0) return hr; hr = dsply.CreateSurfaceFromBitmap (&hgrnd, “ul_hgrnd.bmp”, ultris_nettobreite, ultris_nettohoehe); if (hr < 0) return hr; hr = dsply.CreateSurfaceFromBitmap (&fldst, “ul_feld.bmp”, 20, 20); if (hr < 0) return hr; hr = dsply.CreateSurfaceFromBitmap(&fllst, “ul_stein.bmp”, 20, 20);

  9. if (hr < 0) return hr; hr = dsply.CreateSurfaceFromBitmap (&prvst, “ul_prev.bmp”, 15, 15); if (hr < 0) return hr; hr = dsply.CreateSurfaceFromBitmap (&deckel, “ul_adeck.bmp”, 240, 100); if (hr < 0) // überprüft ob bei Erzeugung Fehler aufgetreten return hr; // Rücksprung in aufrufendes Programm for (i=0; i < 10; i++) { sprintf (fname, “ul_z%d.bmp”, i); hr = dsply.CreateSurfaceFromBitmap ( &ziff[i], fname, 20, 40); if (hr < 0) return hr; } return S_OK; }

  10. hr = dsply.CreateSurfaceFromBitmap (&fldst, “ul_feld.bmp”, 20, 20); if (hr < 0) return hr; • einzelne Surfaces werden durch Aufruf der Funktion CreateSurfaceFromBitmap dynamisch aus jeweiliger Bitmap - Datei erzeugt • als Parameter übergeben: • Adresse eines Zeigers, in dem Referenz auf Surface abgelegt wird • Name der Bitmap - Datei • Abmessung (Breite, Höhe) der Bitmap • tritt bei Erzeugung eines Elements ein Fehler auf • Fehlercode hr - erfolgt Rücksprung in aufrufendes Programm • ein Surface entspricht einer Bitmap

  11. Kontinuierlich wirkende Animation für das menschliche Auge - Kinofilm besteht aus Folge von Standbildern • in der Abfolge der Standbilder eine Frequenz von mehr als 20 Bildern bzw. Frames pro Sekunde = Eindruck einer kontinuierlichen Bewegung - unser Display hat Front- und Backbuffer - im Frontbuffer: befindet sich Bild, das gerade angezeigt wird - im Backbuffer: neues Bild, das heißt den nächsten Frame aufbauen • zur Darstellung des nächsten Frames - umschalten zwischen Front- und Backbuffer - zwei benötigte Funktionen: - Funktion um Surfaces in den Backbuffer des Displays zu laden ( Blt) - Funktion um zwischen Front- und Backbuffer umzuschalten (Present)

  12. Funktion Blt = Abkürzung für Blocktransfer • Bitmap einer Surface (Quellsurface) an bestimmte Position des Displays (Zielbereich) transferieren oder “blitten” HRESULT CDisplay::Blt (DWORD x, DWORD y, CSurface * pSurface, RECT* prc) HRESULT CDisplay::Blt (x - Koordinate des Zielbereichs, y-Koordinate des Zielbereichs, Quell - Surface, ausgewähltes Rechteck der Quell Surface (kann fehlen)) • wenn kein Teilrechteck (prc) angegeben wird,so wird die gesamte Bitmap geblittet 2. Funktion zum Umschalten zwischen Front- und Backbuffer HRESULT CDisplay::Present()

  13. Blt - Methoden class display { private:... public: ... void hintergrund () {dsply.Blt (0, 0, hgrnd);} // hintergrund beginnt an Position (0,0), füllt gesamten // Fensterinhalt, Csurface ist hgrnd void abdeckung () {dsply.Blt (60, 0, deckel); } // abdeckung beginnt an stelle (60,0), void ziffer (int pos, int val) {dsply.Blt (120+pos*20, 50, ziff [val] );} // Zifferndarstellung beginnt bei 120, deshalb 120+ // eine Ziffernabbildung ist 20 Pixel breit // int pos ist Index der Ziffer // int val entscheidet über Art der Bitmap void feldstein (int z, int s) {dsply.Blt (80+s*20, 100+z*20, fldst);} // Segment eines gefallenen Steins liegt in einer Zeile z und Spalte s // Feld beginnt bei x = 80 und y = 100 // Zeilen- und Spaltenbreite beträgt jeweils 20 Pixel // Koordinaten berechnen sich daher x = 80+s*20 und y = 100+z*20

  14. void fallstein (int z, int s, int offset){ dsply.Blt (80+s*20, 100+z*20+offset, fllst);} // fallendes Steinsegment in Spalte s, jedoch nicht in Zeile, // da es Pixel für Pixel fällt // zu der letzten Zeile z kommt Zugabe offset, um die das // Segment weiter gerückt ist // Offset = Anzahl von Pixeln, die sich Stein n.u. bewegt hat void prevstein (int p, int z, int s, int b, int h) { dsply.Blt (290+s*15+(4-b)*15/2, 410-p*70+z*15+(4-h)*15/2, prvst);} // Berechnung der Position der Vorschausteine // Steine sollen in Ausgabe zentriert dargestellt werden // es gibt bis zu fünf Vorschausteine p = 0,1,2,3,4 // linke obere Ecke: x = 290 und y = 410-p*70 /* bei Segmentgröße von 15 x 15 Pixeln liegt die linke obere Ecke eines Segments in Spalte s und Zeile z bei x = 290+s*15 und y = 410-p*70 + z*15 */ /* wenn Anzahl der Segmente des Steins in Höhe h und Breite b bekannt ist, kann man den Randausgleich berechnen, wenn Stein in 4 x 4 Segmente großen Vorschaubereich */ /* man erhält Koordinaten: x = 290+s * 15 + (4-b)*15/2 und y = 410 - p*70+z*15+(4-h) * 15/2 */ };

  15. Ziffernbereich Deckel Fallfläche Hintergrund Spieloberfläche Vorschau

  16. Funktion HRESULT present (); • Grafiken aus dem Backbuffer auf den Bildschirm bringen • Phänomen der “Lost Devices”: Zugriff auf Devices wie die Grafikkarte kann “verloren gehen” -> Device befindet sich dann im “lost state” • Grafikoperationen, die nur auf internen Speicher zurück greifen, wie etwa das Blitten, werden fehlerfrei durchgeführt • jedoch wird bei Umschalten von Front- und Backbuffer der lost state kritisch, da jetzt auf Grafikkarte zugegriffen werden muss • Returncode für Fehlermeldung: DDERR_SURFACELOST • verlorene Daten auf Grafikkarte müssen restauriert werden: dies macht Funktion restore

  17. Funktion HRESULT present () • zunächst Ausführen der Present Funktion von CDisplay • sollte das misslingen, weil der Fehlercode übergeben wird, so werden die Surfaces restauriert HRESULT display::present() { HRESULT hr; hr = dsply.Present(); if ( hr == DDERR_SURFACELOST )//fehlercode return restore(); return hr; }

  18. Funktion HRESULT restore(); • restaurieren aller Surfaces des Displays • neuzeichnen aller Bitmaps in Surfaces HRESULT display::restore() {HRESULT hr; int i; char fname[20]; hr = dsply.GetDirectDraw() -> RestoreAllSurfaces(); if (hr < 0) return hr; hr = hgrnd->DrawBitmap (“ul_hgrnd.bmp”, ultris_nettobreite, ultris_nettohoehe); if (hr < 0) return hr; hr = fldst -> DrawBitmap (“ul_feld.bmp”, 20,20); if...fllst, prvst, deckel ... for ( i = 0; i < 10 ; i++) {sprintf (fname, “ul_z%d.bmp”, i); hr = ziff [i] -> DrawBitmap (fname, 20, 40); if ( hr < 0) return hr;} return S_OK;}

  19. zum Abschluss zwei weitere Member - Funktionen... class display { private: ... public:.. void update () { dsply.UpdateBounds();} HRESULT cooperative (){ return dsply.GetDirectDraw() -> TestCooperativeLevel ();} }; • Memberfunktion update:Aufruf, wenn die Lage unseres Hauptfensters auf Bildschirm verändert ist • es geschieht Aufruf der Methode UpdateBounds, die Display an die neue Lage anpasst • Memberfunktion cooperative: stellt „Kooperativität“ des Displays fest

  20. Klasse display ist jetzt vollständig implementiert, wir legen Instanz dieser Klasse mit dem Namen ultris_display an display ultris_display; - Objekt muss zum Schluss in Windows Applikation integriert werden • innerhalb WinMain Funktion Display initialisieren bevor Fenster mit ShowWindow dargestellt wird int APIENTRY WinMain (...) {... if (ultris_display.init (ultris_window) < 0) { // wenn Initialisierung fehl schlägt, Abbruch // der Anwendung mit Fehlerdialog MessageBox (ultris_window, “Fehler beim Initialisieren der Grafik”, “Ultris - Fehlermeldung”, MB_OK | MB_ICONERROR | MB_SETFOREGROUND); return 0; } // sonst geht es mit Anzeige des Fensters // und Main Event Loop weiter ShowWindow (ultris_window, nCmdShow); while (TRUE){...} }

  21. Callback - Handler unseres Hauptfensters ultris_windowhandler • immer wenn Fenster bewegt oder in seiner Größe verändert wurde, erhalten wir eine Benachrichtigung durch die Nachricht WM_MOVE • als Reaktion rufen wir die update Funktion unseres Display auf LRESULT CALLBACK ultris_windowhandler ( ... ) { switch (msg) { ... case WM_MOVE: ultris_display.update(); return 0; case WM_PAINT: int i; ultris_display.hintergrund(); ultris_display.abdeckung();

  22. for (i = 0; i< 6; i++) ultris_display.ziffer (i, i+1); for (i = 0; i < 10; i++) ultris_display.feldstein (19-i, i); for (i = 0; i < 10;i++) ultris_display.fallstein ( 1, i, 2*i); for ( i = 0; i < 4; i++) ultris_display.prevstein ( 3, 0, i, 4, 1); ultris_display.present (); break; } ... } • hier wird message - orientierte Architektur des Windows - Systems deutlich • Fensterausgaben dürfen nicht spontan gemacht werden • System fordert zum Neuzeichnen des Hauptfensters mit Message WM_PAINT auf • wenn diese Message erkannt wird, werden einige Testausgaben gemacht: Hintergrund, Abdeckung, einige Ziffern und Steine

  23. Funktion WinMain • an die Stelle, in der regelmäßig wiederkehrende, das Spiel betreffende Aktivitäten eingebaut werden können, gelangt man immer dann, wenn keine Windows - Message vorliegt • hier kann also der Spielverlauf programmiert werden • zudem: regelmäßiges Prüfen der Devices und der Kooperativität int APIENTRY WinMain (...) { while (TRUE) { if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {...} else { HRESULT hr; hr = ultris_display.cooperative(); // Prüfen der Kooperativität // wenn der Aufruf der Funktion ein negatives Ergebnis // liefert, so liegt ein Problem vor if (hr < 0) {

  24. switch (hr) { case DDERR_EXCLUSIVEMODEALREADYSET: // eine andere Anwendung hat sich Grafik Device exklusiv // gesichert Sleep (10);//warten bis es frei gegeben wird break; case DDERR_WRONGMODE: // jemand hat Grafikmodus (etwa die Auflösung) geändert // in dieser Situation muss alles noch einmal neu // initialisiert werden // zuvor belegte Ressourcen frei geben ultris_display.free_all(); ultris_display.init (ultris_window); PostMessage (ultris_window, WM_PAINT, 0, 0); // hier Message WM PAINT schicken zum Neuzeichnen des Fensters break; } } else{// hier kann Spiel stehen} } } }

  25. Es gibt weitere Meldungen im Zusammenhang mit Grafikkarte, auf die man reagieren kann • Wenn das System im 8 -Bit -Grafikmodus ist (256 Farben), arbeitet die Grafikkarte mit Farbpalette • Das heißt, auch die Farbpalette muss neu initialisiert werden, wenn sie durch andere Anwendung überschrieben wurde • Entsprechende Message: WM_QUERYNEWPALETTE • Wir verwenden jedoch für Ultris Bitmaps mit mehr als 256 Farben

  26. Kurz zurück zum Blitten - • es ist auch möglich statt rechteckiger Objekte andersformige Objekte zu blitten • Dies geschieht unter Verwendung des Color Keying • Eine in der darzustellenden Bitmap nicht vorkommende Farbe wird als Color Key für die Surface ausgewählt • Alles, was in Color Key Farbe in der Bitmap vorkommt, wird nicht transferiert • Equivalent: „Blue Box“ im Fernsehen • Beispiel: Bitmap liegt in einer Datei vor, alles, was nicht gezeichnet werden soll, ist schwarz • Anlegen einer Surface: CSurface *s • Initialisieren der Surface mit CreateSurfaceFromBitmap • Color Key wird duch Funktionsaufruf gesetzt: s -> SetColorKey (RGB (0, 0, 0)); - schwarze Bildpunkte werden nicht transferiert

  27. ... Vielen Dank!!

More Related