Fenstergrößen mit XLIB und GLES
« | 04 Jul 2021 | »EGL und die XLIB bereiteten mir schon vor einigen Jahren Schwierigkeiten und ich bin offenbar nicht der einzige. Selbst die Raspberry-PI Edition von Minecraft kam beim Verändern der Fenstergröße durcheinander.
Nun treffe ich erneut auf diese Umgebung im Zuge der OpenGL
Implementierung im GATE Projekt.
In diesem Sinne fasse ich mal meinen aktuellen Stand zusammen.
Viele Spiele machen es sich leicht. Sie funktionieren nur im Vollbildmodus und nicht selten stürzt eines ab, wenn sich die Auflösung ändert oder man z.B. einen zweiten Monitor an oder absteckt und die Fenster damit den Bildschirm wechseln.
Das läuft also nach dem Schema: Screen einmal initialisieren und der bleibt für immer so. Heute reagieren die meisten Apps zum Glück korrekt, aber Fehler passieren und früher war das noch viel schlimmer.
Deshalb möchte ich, dass in meinen Anwendungen Fenstergrößen immer vom
Nutzer frei bestimmbar sein sollen.
Und im Fall der XLIB
bedeutet das bei meinen OpenGL-Experimenten natürlich
ein bisschen mehr Aufwand.
ConfigureNotify Event
Wenn man in seiner X11
Event-Mask per XSelectInput
die Flags StructureNotifyMask
und SubstructureNotifyMask
gesetzt hat,
dann liefert XNextEvent
auch ConfigureNotify
Ereignisse und dort drinnen steht, wo und wie groß
der Benutzer sein Fenster haben möchte.
Das ist also ein guter Ort um Größenveränderungen zu erkennen und entsprechende Callbacks auszulösen.
Ich hatte anfangs den Fehler gemacht, das Ereignis ConfigureRequest
abzufangen aber dieses Unterfangen bereitete mir nur Probleme und
Crashes.
Doch die Dimensionen des Fensters beziehen sich vor allem auf die äußeren Größen und müssen nicht zwingend mit dem Anzeigebereich übereinstimmen.
Und deshalb nutze ich im Event-Callback XGetWindowAttributes()
um die tatsächliche aktuelle Größe des Fenster-Clientbereiches auszulesen.
glViewport macht den Rest
Die vorhin abgeholten Fenstergrößen werden dann in der Render-Routine
in den ersten Zeilen an glViewport()
übergeben, also glViewport(0, 0, width, height)
.
Das Verhältnis von Höhe und Breite braucht zusätzlich noch beim Setzen des
AspectRatio
Wertes beim Definieren der Perspektive in der Projektionsmatrix.
Das erledigt oft auch die Hilfsfunktion gluPerspective()
, doch leider fehlt
die in EGL/GLES Implementierungen.
Dank des weltweiten Netzes konnte ich eine alternative gluPerspective
Implementierung finden, dich ich hier nicht vorenthalten möchte:
1void glPerspective(GLfloat fovy, GLfloat aspect, 2 GLfloat znear, GLfloat zfar) 3{ 4 GLfloat f = (GLfloat)(1.0f / tan((fovy * PI / 180.0f) / 2.0f)); 5 GLfloat m[16] = { 6 f / aspect, 0, 0, 0, 7 0, f, 0, 0, 8 0, 0, (zfar + znear) / (znear - zfar), -1.0f, 9 0, 0, (2.0f * zfar * znear) / (znear - zfar), 0 10 }; 11 glMultMatrixf(m); 12}
Und eigentlich war es das auch schon, denn nun wird die nächste Szene korrekt an die neue Fenstergröße angepasst gezeichnet.
Fazit
Am Ende des Tages läuft also auch unter X11 eine EGL Anwendung, die sich
genau so verhält wie eine OpenGL Anwendung unter Windows.
Denn unter Windows konnte ich den entsprechenden WM_SIZE
Code quasi
auswendig niederschreiben … doch XLIB
Event Details habe ich leider
nicht mehr so genau im Hinterkopf.
Schließlich liegen meine X11 Experimente auch schon 10 Jahre zurück und in der Praxis schreibt man nur selten Code auf dieser Ebene.
Und was die GL-Matrizen anbelangt, da muss auch unter
Android
rechnen, dass sie sich ändern können.
Denn wenn man das Smartphone kippt und keine Rotationssperre gesetzt ist,
dann ändert sich auch dort der Aspect-Ratio des Anzeigebereichs.