OpenGL GATEs

Ein großer Hemmschuh für das GATE Projekt war bisher die Fixierung auf Windows und Linux GTK Bereich in Sachen UI.

Viel interessanter sind da mobile Plattformen wie Android oder UWP, denn diese haben einen vollkommen anderen Aufbau und können mit klassischen Desktop-UIs nichts anfangen.

Die Idee: OpenGL öffnet die Tore zwischen diesen Welten.


Vorgeschichte

Exemplarische Tests von GATE Code in Android und UWP gibt es ja schon länger. Aber was bringt es den Inhalt eines Ordners aufzulisten, wenn man es nirgends anzeigen kann.

Genau das ist der essentielle Bruch zwischen Desktop und Phone-Apps. Die UIs sind nicht vereinbar und das gilt auch für deren Frameworks. So gesehen müsste ich mein Vorhaben, ein Framework für “alles” zu schaffen genau hier als Fehlschlag beenden.

Doch da gibt es ja noch OpenGL, die alte Grafik-API, die auf vielen Plattformen für Spiele benutzt wird und wurde.
Denn Spiele sind stets individuell aufgebaut und bauen selten auf einem Fenster UI Framework auf (schon gar nicht auf dem Desktop-Framework), sondern sie zeichnen sich ihre Welt selbst.

Ich möchte also einen neuen OpenGL-App-Typ einführen, mit dem der gleiche Logikcode auf Windows, Linux und Android kompilierbar ist und auf jeder Plattform eine korrekte Umsetzung davon gewährleistet ist.

OpenGL 1.1 und die WinAPI

Das größte Problem bei OpenGL sind seine Versionen und die dortigen Features, die sich leider extrem unterscheiden. Hatte man in OpenGL 1 noch die “Fixed-Function-Pipline” mit einem rein auf 3D-Grafik ausgelegten API-Set, so wurde dieses ab OpenGL 2 durch Shader ersetzt, wo wir Rechenvorgänge als Strings an den Shader-Compiler übergeben, der speziellen Code für die Grafikkarte erzeugt.

Damit gewinnt man natürlich enorm viel Flexibilität, weil man alles mögliche rechnen lassen kann, doch damit verschwinden auch die “Gemeinsamkeiten” zwischen 3D Renderfunktionen.
Doch für mich am schlimmsten ist, dass man jetzt von der Grafikkarte und deren Treiber abhängig ist. Passt da was nicht, lassen sich Shader-Routinen nicht ausführen.

Im Gegensatz dazu, war OpenGL 1.1 aber auch in Software implementiert und man konnte 3D Szenen von der gleichen API auch auf der CPU rechnen lassen. Das dauerte zwar viel viel länger, war aber somit stabil und immer verfügbar.

Die Erkenntnis: OpenGL 1.1 Programme laufen also von NT4 / Win95 angefangen bis hin zum neuesten Windows 10 oder dessen Server Varianten, weil sie stets auf die CPU umschalten können, wenn die entsprechende Grafikhardware oder deren Treiber fehlen.
OpenGL 2.0 und neuer tun das nicht und so kann ich nie sicher sein, auf welcher Hardware meine Software letztendlich läuft.

Kleinstes gemeinsames Vielfaches: Vertex-Arrays

Leider wird OpenGL 1.1 aber nicht von mobile Geräten wie Smartphones unterstützt, hier kommt Embedded GL (EGL) zum Einsatz, das auf OpenGL 2 aufsetzt. Hier wurde zwar eine Vielzahl on v1.1 APIs entfernt, doch es gibt eine Routine, mit der man auch recht viel machen kann, die in OpenGL 1.1 und 2+ enthalten ist: nämlich glDrawArrays().

Und diese Routine kann auch auf den neueren OpenGL Standards ohne den Einsatz von Shadern durch Vertexe definierte Objekte auf eine Oberfläche zeichnen.

Von daher ist meine Herausforderung die folgende:

Finde die Schnittpunkte zwischen den OpenGL Standards und schaffe eine gemeinsame Schnittstelle, die je nach Plattform das dortigen Toolset nutzt um Grafikoperationen durchführen zu können.

Und so beginnt die Aufgabe bei der WinAPI, die den gesamten OpenGL 1.1 Standard in sich abgebildet hat.

WinAPI OpenGL Setup

Hat man ein Fenster erstellt (CreateWindowEx()) und den Zeichenkontext davon (GetDC()) dann kann man recht schnell einen OpenGL Kontext dafür erzeugen.

 1PIXELFORMATDESCRIPTOR format;
 2format.nSize = sizeof(format);
 3format.nVersion = 1;
 4format.iPixelType = PFD_TYPE_RGBA;
 5format.dwFlags = (PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW 
 6               | PFD_DOUBLEBUFFER);
 7format.cColorBits = 12;
 8format.cDepthBits = 16;
 9format.dwLayerMask = PFD_MAIN_PLANE;
10format.iLayerType = PFD_MAIN_PLANE;
11
12int pixel_format = ChoosePixelFormat(hdc, &format);
13SetPixelFormat(hdc, pixel_format, &format);
14HGLRC context = wglCreateContext(hdc);
15wglMakeCurrent(hdc, context);

Danach kann man auch schon GL-Routinen nutzen und zeichnen.
Und mit der Funktion SwapBuffers() wird das Gezeichnete auf dem Fenster erscheinen, wenn beim Double-Buffering der Zeichenpuffer umgeschaltet wird.

Fazit

Mit der WinAPI Implementierung ist somit eine erste OpenGL Testbasis im GATE Projekt entstanden. Und nachdem die ersten Objekte auf dem Bildschirm halbwegs korrekt dargestellt wurden, habe ich nun einen Vergleichswert für andere Implementierungen.

Als nächstes steht eine EGL/GLES Variante auf dem Plan, mit die OpenGL Ansteuerung unter Linux befeuert werden soll.