OpenGL ES 1.1 unter Windows 8 und Windows Phone 8.1

    1998 habe ich versucht, mein Spiel mit OpenGL zu machen. Die Entwicklung erreichte kaum Alpha und wurde abgebrochen, aber ich erinnerte mich besonders daran, wie bequem es war, GL-Schnittstellen zu erstellen - orthogonale Projektion, einige Transformationen, mehrere Vertex-Binder mit GL_TRIANGLE_STRIP und wir haben bereits einen Button. Und jetzt, nach sechzehn Jahren und beim Entwickeln mobiler Spiele, bin ich in OpenGL ES 1 auf denselben Ansatz gestoßen. * Es sei denn, 2D-Texturen ohne Rotationen können jetzt über glDrawTexfOES gezeichnet werden.
    Ich habe mehrere Projekte unterstützt, die nach diesem Prinzip erstellt wurden, und ein kleiner Plan war in meinem Kopf aufgereiht: ein plattformübergreifendes 2D-Spiel auf Mobilgeräten mit OpenGL ES und C # sowie auf Desktops mit regulärem OpenGL zu erstellen. Ich habe die Ziele beim ersten Mal nicht erreicht und es gab viele Probleme damit, aber als Ergebnis funktioniert das nächste Projekt für mich, ohne die Geschäftslogik unter iOS, Android, BlackBerry, Windows XP / 7, Mac OS X, Linux, ReactOS, Windows 8 zu ändern. Windows Phone 8.1. Ich habe viel Material zu vielen Artikeln gesammelt, aber dieses Mal werde ich über die Unterstützung von Windows Runtime sprechen.

    Opentk


    Sie können sich viel über die Bequemlichkeit von OpenGL speziell für 2D streiten, um sich selbst davon zu überzeugen, dass Shader und Multi-Pass-Rendering für ein vollständiges Spiel erforderlich sind, und gleichzeitig eine Bestätigung dafür finden, dass das veraltete OpenGL ES 1.1 häufig genau auf der Ebene der Emulation durch Shader implementiert wird. Dies werde ich für Don Quijote und Theoretiker verlassen. Ich war jedoch besorgt, dass dies der einfachste Weg ist, 2D-Rendering-Code einmal zu schreiben und auf verschiedenen Plattformen auszuführen, ohne die monströsen Unity-, MonoGame- und anderen Engines zu verwenden.
    Unter iOS und Android lief unter Xamarin alles reibungslos. Die Arbeit mit GL erfolgt über die OpenTK-Bibliothek mit dem OpenGL.Graphics.GL11-Namespace. Die Konstanten und Methoden sind auf beiden Plattformen gleich. Auf Desktops habe ich mich für OpenTK.Graphics.OpenGL entschieden, d.h. reguläres Desktop OpenGL mit C # Wrapper. Es gibt im Prinzip kein glDrawTexfOES, aber Sie können es problemlos ersetzen und über GL_TRIANGLE_STIP / GL_TRIANGLES und glDrawElements zwei Dreiecke zeichnen - im Vergleich zu Mobile ist die Leistung mehr als ausreichend und VBO wird hier nicht benötigt.
    Ein Beispiel für einen Wrapper mit GL_TRIANGLES
            private static readonly int[] s_textureCropOesTiv = new int[4];
            private static readonly short[] s_indexValues = new short[] { 0, 1, 2, 1, 2, 3 };
            private static readonly float[] s_vertexValues = new float[] { -0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f };
            public void glDrawTexfOES(float x, float y, float z, float w, float h)
            {
                glPushMatrix();
                glLoadIdentity();
                glTranslatef(w / 2.0f + x, h / 2.0f + y, 0.0f);
                glScalef(w, -h, 1.0f);
                int[] tiv = s_textureCropOesTiv; // NOTE: clip rectangle, should be set before call
                int[] texW = new int[1];
                glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, texW);
                int[] texH = new int[1];
                glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, texH);
                float[] texCoordValues = new float[8];
                float left = 1.0f - (tiv[0] + tiv[2]) / (float)texW[0];
                float bottom = 1.0f - tiv[1] / (float)texH[0];
                float right = 1.0f - tiv[0] / (float)texW[0];
                float top = 1.0f - (tiv[1] + tiv[3]) / (float)texH[0];
                texCoordValues[0] = right;
                texCoordValues[2] = left;
                texCoordValues[4] = right;
                texCoordValues[6] = left;
                texCoordValues[1] = bottom;
                texCoordValues[3] = bottom;
                texCoordValues[5] = top;
                texCoordValues[7] = top;
                glEnableClientState(GL_VERTEX_ARRAY);
                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                glVertexPointer(2, GL_FLOAT, 0, s_vertexValues);
                glTexCoordPointer(2, GL_FLOAT, 0, texCoordValues);
                glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, s_indexValues);
                glPopMatrix();
            }
    

    Beachten Sie, dass sich das Kopieren dieses Codes nicht lohnt - es funktioniert nicht, wenn keine GL_TEXTURE_WIDTH / GL_TEXTURE_HEIGHT-Konstanten vorhanden sind. Gleichzeitig muss die Variable s_textureCropOesTiv vor dem Aufruf gefüllt werden, und der Code selbst kippt das Ansichtsfenster entlang der Ordinate nicht.


    Xaml


    Ein gewisses Maß an Magie war erforderlich, damit das Projekt auf den aktuellen Versionen von Mono, .Net 2.0-4.5, Wine und gleichzeitig unter ReactOS ausgeführt werden konnte. Im Allgemeinen gab es jedoch neben dem Zoo keine besonderen Probleme mit Texturen. Die Probleme begannen aber unter Windows 8 und Windows Phone, wo OpenGL prinzipiell fehlt. Von Anfang an habe ich versucht, es mit ein wenig Blut zu lösen, indem ich buchstäblich meine Version von glDrawTexfOES hinzugefügt habe, die im Inneren etwas Spezielles für diese Systeme nennt. Während der Experimente habe ich das XAML-Canvas-Element verwendet und darin ein Rechteck gezeichnet, das in Brush die erforderliche Transformation verwendet hat, um nur einen Teil der Textur anzuzeigen.
    Transformationscode in XAML
                    TransformGroup group = new TransformGroup();
                    ScaleTransform scale = new ScaleTransform();
                    scale.ScaleX = (double)texture.PixelWidth / (double)clipRect.Width;
                    scale.ScaleY = (double)texture.PixelHeight / (double)clipRect.Height;
                    group.Children.Add(scale);
                    TranslateTransform translate = new TranslateTransform();
                    translate.X = -scale.ScaleX * (double)clipRect.X / (double)texture.PixelWidth;
                    translate.Y = -scale.ScaleY * (double)clipRect.Y / (double)texture.PixelHeight;
                    group.Children.Add(translate);
                    imageBrush.RelativeTransform = group;
    

    clipRect - ein Rechteck mit Beschneidungsparametern, ein Analogon von s_textureCropOesTiv aus dem obigen Beispiel
    texture - BitmapSource mit der Textur selbst

    Diese Methode scheint seltsam, aber denken Sie daran, dass XAML häufig hardwarebeschleunigt und relativ schnell ist. Ich habe mehrere OpenGL ES-Handyspiele mit Windows 8 auf diesen Ansatz portiert und sie funktionieren recht gut, aber es gibt keine Möglichkeit, die Texturfarbe wie in GL über glColor zu ändern. Das heißt Im Prinzip können Sie in XAML die Transparenz eines Elements ändern, aber den Farbton in keiner Weise. Wenn Sie beispielsweise weiße Schriftarten verwenden und dann in verschiedenen Farben bemalt werden, bleiben diese bei dieser Vorgehensweise weiß.

    Generell ist die Version mit XAML eher zweifelhaft und entsprach nicht ganz dem ursprünglichen Plan, und das auch ohne die farbliche Differenzierung der HoseModulation, denn als das Spiel zu 80% fertig war und bereits auf mobilen und stationären .Net / Mono-Systemen lief, suchte ich nach akzeptableren Optionen für Windows 8. Es gab viele Gerüchte und Enthusiasmus rund um den Port der Angle- Bibliothek , aber zu dieser Zeit war es sehr roh und ohne C # -Unterstützung. Direkt war es auch nicht möglich, direkt in C # mit DirectX zu arbeiten, und Microsoft bietet dem Entwickler mehrere „einfache“ Möglichkeiten: Erstellen Sie den gesamten C # -Code in C ++ neu, und verwenden Sie eine SharpDX- Bibliothek eines Drittanbieters(C # -Bindung über DirectX), oder wechseln Sie zu MonoGame. Die MonoGame-Bibliothek ist ein XNA-Nachkomme, der dasselbe SharpDX-Format für die Anzeige von Grafiken unter Windows 8 verwendet. Sie ist ziemlich gut, aber recht spezifisch, und es war etwas spät, in meinem Projekt darauf umzusteigen. SharpDX sah nicht weniger ungeheuerlich aus, da es alle vorhandenen DirectX- Funktionen nutzt , obwohl es ziemlich genau dem entspricht, was ich brauchte. Ich begann bereits ernsthafte Gespräche mit ihm mit einem Lötkolben und einem Handbuch zu führen, als ich auf das gl2dx-Projekt stieß.

    GL2DX


    Diese Bibliothek wurde durchschnittlich auf CodePlex veröffentlicht.vor einigen Jahren und wurde nicht mehr aktualisiert. Dies ist eine C ++ - Bibliothek, die dieselben Funktionen wie in OpenGL deklariert und intern in D3D11-Aufrufe übersetzt. In C ++ / CX gab es ein Beispiel für die Bibliothek, die eine XAML-Seite mit SwapChainBackgroundPanel erstellte und über D3D11CreateDevice für die Arbeit mit dem C ++ - Teil initialisierte. Das Projekt wäre gut, wenn es zumindest ein wenig außerhalb des Prototypenstadiums liegen würde. Technisch funktionieren nur ein paar Prozent der OpenGL-Methoden, der Rest sind Behauptungen. Auf der anderen Seite werden 2D-Texturausgaben, Transformationen und einfache Geometrien verarbeitet. In dieser Phase habe ich die Bibliothek übernommen und auf den Produktstatus gebracht, der eine Verbindung zum C # -Projekt als Visual Studio-Erweiterung herstellt und das Schreiben ähnlichen Codes ermöglicht:
    Code
     GL.Enable(All.ColorMaterial);
                GL.Enable(All.Texture2D);
                GL.Color4(1.0f, 1.0f, 1.0f, 1.0f);
                GL.TexParameter(All.Texture2D, All.TextureCropRectOes, new int[] { 0, 0, 1024, 1024 });
                GL.BindTexture(All.Texture2D, m_textureId1);
                GL.DrawTex(0, - (m_width - m_height) / 2, 0, m_width, m_width);
                for (int i = 0; i < 10; i++)
                {
                    if (i % 2 == 0)
                    {
                        GL.BindTexture(All.Texture2D, m_textureId2);
                        GL.TexParameter(All.Texture2D, All.TextureCropRectOes, new int[] { 0, 0, 256, 256 });
                    }
                    else
                    {
                        GL.BindTexture(All.Texture2D, m_textureId2);
                        GL.TexParameter(All.Texture2D, All.TextureCropRectOes, new int[] { 256, 0, 256, 256 });
                    }
                    int aqPadding = 20;
                    int fishSize = 128;
                    int aqWidth = (int)m_width - aqPadding * 2 - fishSize;
                    float x = (Environment.TickCount / (i + 10)) % aqWidth;
                    float alpha = 1.0f;
                    if (x < fishSize)
                        alpha = x / fishSize;
                    else
                        if (x > aqWidth - fishSize)
                            alpha = (aqWidth - x - fishSize) / 128.0f;
                    GL.Color4(1.0f, 1.0f, 1.0f, alpha);
                    GL.DrawTex(x + aqPadding, m_height / 20 * (i + 5), 0, fishSize, fishSize);
                }
    

    PS Der Code ist im OpenTK-Aufrufformat, was für diejenigen, die es gewohnt sind, glColor4f anstelle von GL.Color4 zu schreiben, etwas verwirrend ist.
    Diese Sachen erhielten von mir den stolzen Namen MetroGL.

    Metrogl


    Ein Beispiel in C ++ / CX wurde in eine Bibliothek für denselben Vogel umgewandeltDie moderne Sprache, die mit einer Vielzahl von zusätzlichen Funktionen überwachsen ist, und C ++ haben die Implementierung vieler OpenGL-Methoden erhalten, die Überblendung, die Optimierung des internen VertexBuilder, das Laden beliebiger Bilder und DDS-Texturen und vor allem - eine exakte Simulation von glDrawTexfOES, die 1v1 das gleiche Bild wie auf OpenGL ES verleiht, aber gleichzeitig Verbinden von sequentiellen Operationen mit einer Textur zu einem einzigen DrawCall. Es musste eine Datei erstellt werden, der Code selbst ist stellenweise (vor und nach mir) fehlerhaft. Um eine VSIX-Erweiterung zu erstellen, müssen Sie das Projekt für jede Architektur (x86, x64, ARM) manuell neu erstellen und erst dann das VSIX-Projekt erstellen. Die Hauptsache ist, dass Sie OpenGL ES 1. * -Code mit einer 2D-Schnittstelle oder nicht komplexem 3D mit dieser Bibliothek direkt in C # verwenden können, ohne sich Gedanken über die Interna, C ++ - Code, D3D11-Kontexte und andere unangenehme Dinge zu machenFreuden. Gleichzeitig wurde ein Beispiel mit dem Fisch auf der rechten Seite und dem Code unter der Kata angefertigt. Wenn Sie OpenGL 2.0+ Code mit Shadern und Erweiterungen haben, wird natürlich nicht über Portierung gesprochen.
    Ein anderer unangenehmer Moment ist, dass ich keine Lust und Laune habe, die Bibliothek auf ein Niveau von 50-100% Kompatibilität mit OpenGL zu bringen, was bedeutet, dass sie für Ihre spezifischen Aufgaben selbst geschärft werden muss. Glücklicherweise wurde der gesamte Code auf Github gepostet , und bis jetzt bin ich nirgendwo verschwunden und werde froh sein, Verpflichtungen einzugehen oder sogar diejenigen, die diese Belastung übernehmen wollen. Die Bibliothek wurde unter Windows 8.0 und Windows Phone 8.1 erstellt. Für VSIX benötigen Sie möglicherweise eine Nicht-Express-Version von Visual Studio.

    Nachwort


    Nun, am Ende ein wenig über die Spiele. Ich habe mein Projekt zu 100% abgeschlossen, und es war die Kombination von C # und OpenGL, die es ermöglichte, Code auf hoher Ebene vollständig unveränderlich zu machen - es ist eine Bibliothek ohne eine einzige Definition, die keine Systemaufrufe verwendet. Dann kommt der Code der mittleren Ebene: Zeichnen durch OpenGL in 2D mit Drehung, Transformation und Farbmodulation, hier ist der Code auf verschiedenen Plattformen leicht unterschiedlich - verschiedene Texturen, Daten werden unterschiedlich gespeichert. Der Low-Level-Teil ist für jede Plattform bereits unterschiedlich. Dadurch wird ein Fenster erstellt, der Kontext initialisiert und der Sound ausgegeben. Auf jeden Fall funktionieren die neun am Anfang des Artikels aufgelisteten Plattformen wirklich, und während C # in Verbindung mit OpenGL noch nicht im Web oder unter Firefox OS verwendet werden kann, ist es nicht ein Spiegelbild der plattformübergreifenden Zukunft, meine Herren?



    Jetzt auch beliebt: