
OpenGL ES 1.1 on Windows 8 and Windows Phone 8.1

I supported several projects made on this principle and a little insidious plan was lined up in my head: to make a cross-platform 2D game on mobile with OpenGL ES and C #, and on desktops with regular OpenGL. I did not achieve the goals the first time and there were a lot of problems with it, but as a result, the next project works for me without changing the business logic on iOS, Android, BlackBerry, Windows XP / 7, Mac OS X, Linux, ReactOS, Windows 8, Windows Phone 8.1. I gathered a lot of material on many articles, but this time I’ll talk about the support of Windows Runtime.
Opentk

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 are the same on both platforms. On desktops, I decided to use OpenTK.Graphics.OpenGL, i.e. regular desktop OpenGL with C # wrapper. There, in principle, there is no glDrawTexfOES, but without problems you can make a replacement for it and draw two triangles via GL_TRIANGLE_STIP / GL_TRIANGLES and glDrawElements - compared to mobile, performance is more than enough and VBO is not needed here.
Wrapper example with GL_TRIANGLES
Note that copying this code yourself is not worth it - 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 flip the viewport along the ordinate.
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();
}
Note that copying this code yourself is not worth it - 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 flip the viewport along the ordinate.
Xaml
A certain amount of magic was needed for the project to run on the current versions of Mono, .Net 2.0-4.5, Wine, and at the same time under ReactOS, but in general, there were no special problems besides the zoo with textures. But the problems started on Windows 8 and Windows Phone, where OpenGL is absent in principle. From the beginning, I tried to solve it with little blood, literally adding my version of glDrawTexfOES, which inside would call something specific for these systems. During the experiments, I used the XAML Canvas element, and in it I drew a Rectangle, which in Brush used the necessary transformation to display only part of the texture.
Transformation Code in XAML
clipRect - a rectangle with cropping parameters, an analog of s_textureCropOesTiv from the example above
texture - BitmapSource with the texture itself
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, an analog of s_textureCropOesTiv from the example above
texture - BitmapSource with the texture itself
This method seems strange, but keep in mind that XAML is often hardware accelerated and fairly fast. I have ported several OpenGL ES mobile games to Windows 8 with this approach and they work reasonably well, but there is no way to change the texture color, as in GL via glColor. Those. in principle, XAML allows you to change the transparency of an element, but you can’t change its Color Tint in any way. For example, if you use white fonts and then are painted in different colors, then with this approach they will remain white.
In general, the version with XAML is rather doubtful and did not quite correspond to the original plan, and even without the color
GL2DX
This library was uploaded by 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. There was an example in C ++ / CX 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 at least a little out of the prototype stage. Technically, only a few percent of OpenGL methods work in it, and the rest are assertions. On the other hand, it handles 2D texture output, transformation, and simple geometry. At this stage, I took on 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:
The code
PS The code is in the OpenTK call format, which is a little confusing for those who are used to writing glColor4f instead of GL.Color4.
This thing got the proud name of MetroGL from me. 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 The code is in the OpenTK call format, which is a little confusing for those who are used to writing glColor4f instead of GL.Color4.
Metrogl

Another unpleasant moment is that I have no mood and desire to bring the library to the level of 50-100% compatibility with OpenGL, which means that it will have to be sharpened on your own for your specific tasks. Fortunately, all the code has been posted on github, and so far I have not disappeared anywhere and will be happy to commit or generally want to shoulder this burden. 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 have 100% finished my project, and it was the combination of C # and OpenGL that made it possible to make high-level code completely unchangeable - it is a library without a single define that does not use any system calls. Then comes the mid-level code: 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 already different for each platform, this is creating a window, initializing the context, outputting sound. In any case, the nine platforms listed at the beginning of the article really work, and while C # in conjunction with OpenGL cannot yet be used on the web or on Firefox OS, but is it not a glimpse of a cross-platform future, gentlemen?
