📜 ⬆️ ⬇️

OpenGL ES 1.1 on Windows 8 and Windows Phone 8.1

Back in 1998, I tried to make my game with OpenGL. The development hardly reached the alpha and was abandoned, but what was especially remembered was how convenient it was to do the GL interfaces — the orthogonal projection, the pair of transformations, the binding of several vertices with GL_TRIANGLE_STRIP, and we already have a button. And now, sixteen years later, while working on a mobile game developer, I encountered the same approach in OpenGL ES 1. *, except that 2D textures without rotations can now be drawn through glDrawTexfOES.
I supported several projects made according to this principle and a cunning plan lined up in my head: make a cross-platform 2D game on mobile with OpenGL ES and C #, and on desktops with regular OpenGL. I did not achieve the goal the first time and there were many problems with this, but as a result, another project works for me without any changes in business logic on iOS, Android, BlackBerry, Windows XP / 7, Mac OS X, Linux, ReactOS, Windows 8, Windows Phone 8.1. The material has accumulated a lot of articles, but this time I will talk about the support for the Windows Runtime.

Opentk


You can argue a lot about the convenience of OpenGL for 2D, to hoarseness in your throat to convince yourself that shaders and multi-pass rendering are necessary for a full game, and at the same time to find confirmation that the outdated OpenGL ES 1.1 is often implemented at the emulation level through shaders. This I will leave for Don Quixote and the theorists. I was worried that this is the easiest way to write a 2D drawing code once and run it on different platforms, and not using Unity, MonoGame and other engines.
On iOS and Android under Xamarin, everything went smoothly, working with GL is done through the OpenTK library with the OpenGL.Graphics.GL11 namespace, the constants and methods on both platforms are the same. On desktops, I decided to use OpenTK.Graphics.OpenGL, i.e. plain desktop opengl with c # wrapper. There, in principle, there is no glDrawTexfOES, but you can easily make a replacement for it and draw two triangles via GL_TRIANGLE_STIP / GL_TRIANGLES and glDrawElements - compared to mobile ones, the performance is more than enough and VBO is not needed here.
An example wrapper with 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(); } 

Please note that you should not copy this code to yourself - it will not work where there are no GL_TEXTURE_WIDTH / GL_TEXTURE_HEIGHT constants. At the same time, the s_textureCropOesTiv variable must be filled before the call, and the code itself does not perform a viewport flip along the vertical axis.


XAML


It took a certain amount of magic to run the project on current versions of Mono, .Net 2.0-4.5, Wine, and at the same time under ReactOS, but in general, apart from the zoo with textures, there were no special problems. But the problems started on Windows 8 and Windows Phone, where OpenGL is missing in principle. From the beginning, I tried to solve it with a little blood, literally adding my version of glDrawTexfOES, which would cause something specific to these systems inside. In the course of the experiments, I used the XAML element Canvas, and in it I drew a Rectangle, which in Brush used the necessary transformation to display only a part of the texture.
Transformation code 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 - a rectangle with cropping parameters, analogous to s_textureCropOesTiv from the example above
texture - BitmapSource with the texture itself.

This method seems strange, but we must remember that XAML is often hardware accelerated and quite fast. I ported with this approach several mobile OpenGL ES games on Windows 8 and they work acceptable, but there is no possibility to change the color of the textures, as in GL through glColor. Those. in principle, in XAML it is allowed to change the transparency of an element, but it is not possible to change its Color Tint at all. For example, if you use white fonts and then paint in different colors, then with this approach they will remain white.

In general, the XAML version is rather dubious and did not quite correspond to the original plan, and even without color differentiation of modulation pants , because when the game was 80% ready and already worked on mobile and stationary .Net / Mono, I started looking for more acceptable options for Windows 8. There were a lot of rumors and enthusiasm around the port of the Angle library, but at that time it was very raw and without the support of C #. Directly from C #, working with DirectX also turned out to be impossible, and Microsoft itself offers the developer several “easy” ways: to redo all C # code in C ++, use the third-party SharpDX library (C # binding over DirectX), or switch to MonoGame. The MonoGame library is a XNA heir that uses the same SharpDX for displaying graphics on Windows 8, it is pretty good, but rather specific, and it was too late to switch to it in my project. SharpDX looked no less monstrous, because it draws all the existing capabilities of DirectX , although it is pretty close to what I needed. I have already started to have serious conversations with him with a soldering iron and a manual when I came across a gl2dx project.
')

GL2DX


This library was laid out by the user average on CodePlex several years ago and was no longer updated. This is a C ++ library that declares the same functions as in OpenGL, and internally translates them into D3D11 calls. An example of C ++ / CX went to the library, which created a XAML page with SwapChainBackgroundPanel and initialized it through D3D11CreateDevice to work with the C ++ part. The project would be good if it were at least a bit out of the prototype stage. Technically, only a few percent of the OpenGL methods work in it, and the rest are asserted. On the other hand, it copes with the output of 2D textures, transformation and the simplest geometry. At this stage, I took the library and brought it to the state of the product, which connects to the C # project as a Visual Studio Extension and allows you to write similar code:
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 Code in the OpenTK call format, which is a bit confusing for those who are used to writing glColor4f instead of GL.Color4.
This share has received from me the proud name MetroGL.

MetroGL


The C ++ / CX example was transformed into a library in the same avian modern language, acquired a large number of additional functions, and C ++ received the implementation of many OpenGL methods, blending, internal VertexBuilder optimization, loading of arbitrary images and DDS textures, and most importantly - an exact imitation of glDrawTexfOES, giving 1in1 the same picture as on OpenGL ES, and at the same time connecting successive operations with one texture into a single DrawCall. Something had to be done with a file, the code itself is rather dirty in places (both before and after me), and to create VSIX extensions, you need to rebuild the project manually for each architecture (x86, x64, ARM) and only then build the VSIX project. The main thing is that if you have OpenGL ES 1. * code with a 2D interface or not complicated 3D, then with this library you can use it directly from C #, without thinking about the internals, C ++ code, D3D11 contexts and other nasty things . At the same time made an example with the fish on the right and the code from under kata. Of course, if you have code on OpenGL 2.0+ with shaders and extensions, then there will be no porting of speech.
Another unpleasant moment is that I do not have the mood and desire to bring the library to the level of 50-100% compatibility with OpenGL, which means it will have to be sharpened for yourself with your specific tasks. Fortunately, all the code is laid out on github and I still do not disappear anywhere, and I will be happy with commits or even those who want to take on this load. The library is built under Windows 8.0 and Windows Phone 8.1, for VSIX you may need a non-Express version of Visual Studio.

Epilogue


Well, in the end, a little about games. I finished my project 100% and it was the combination of C # and OpenGL that made it possible to make the high-level code not changeable at all - it is a library without a single define that does not use any system calls. Then there is the code of the middle level: drawing through OpenGL in 2D, with rotation, transformation and color modulation, here the code is slightly different on different platforms - different textures, data is stored differently. The low-level part is different for each platform, this is the creation of a window, the initialization of the context, the output of sound. In any case, the nine platforms listed at the beginning of the article really work, and let C # in conjunction with OpenGL cannot be used on the web or on Firefox OS yet, but isn't it all a reflection of the cross-platform future, gentlemen?


Source: https://habr.com/ru/post/246911/


All Articles