First off, thank you for creating this incredible Go library! I've recently discovered it and I'm a huge fan! I really like the approach of using OpenGL for platform-independent, high performance UI rendering, since it allows one to stay general and not to be constrained by each platform's UI toolkits. I've experimented with OpenGL UIs here.
Now, the description of this project says:
GXUI - A Go cross platform UI library.
Currently, it is cross platform in that it will run and look/behave the same on OS X, Linux and Windows. However, with relatively little work, it seems it could be expanded to support more platforms: mobile and perhaps even web.
First, let me be a little imprecise and describe OpenGL APIs in this way:
- OpenGL 3.2 Core - "Largest" OpenGL API available. Available on most desktop platforms (OS X, Linux, Windows).
- OpenGL ES 2.0 - Roughly speaking, a subset of OpenGL API (with minor deviations). Available on most mobile platforms (iOS, Android).
- WebGL 1.0 - Roughly speaking, a subset of OpenGL ES 2.0 (with minor deviations). Available in all major browsers (Chrome, Safari, Firefox, Opera, IE).
OpenGL 3.2 Core API is currently used in
gxui . But with a few changes (outlined in considerations section), it's possible to reduce what it used so that it can mapped to WebGL API.
I wanted to see what it would take to get
gxui to run in browsers (and see how it'd perform), so I made a quick little prototype tonight in just a few hours. Some screenshots:
Here's a demo you can try in your browser (no gzip compression on served assets, sorry):
There are two different approaches to supporting additional platforms that I can see.
First approach is to create additional drivers, similar to the existing
gl one. This seems to be suggested in related issue #45.
Another approach, which is the one I've used so far, is a little different.
Since the three OpenGL APIs are similar enough, it's possible to create a Go package that has a single OpenGL-like API, but using build tags, it can have three different backend implementations depending on what is available on the given platform:
- OpenGL 2.1 or 3.2 Core, etc., backend on desktops.
- OpenGL ES backend on mobile devices.
- WebGL backend in browser.
github.com/shurcooL/gogl package used in my quick prototype is an example of that. It only has OpenGL 2.1 and WebGL backend implementations (incomplete), but adding OpenGL ES one would be trivial since it's a superset of WebGL. It's a WIP package with unpolished API, but I think the general approach is solid and can be turned into a production ready package.
Here are some implementation details of the changes I needed to do to make
gxui samples run in the browser.
glPolygonMode is not available in WebGL (since its implementation is very inefficient; a shame because it's useful for debugging). I commented it out since it was just a debugging feature.
Index buffers with
uint32 types were used. It seems my WebGL implementation (latest stable Chrome on OS X) did not support that type, so I dropped it down to
uint16 which worked well.
My WebGL implementation seemed not to support
gl.UniformMatrix3fv calls with transpose equal to
true, so I had to transpose the matrix before calling the gl func. I'm guessing the WebGL implementation opts to support fewer choices for performance reasons. It'd be better to avoid needless conversions between one format to the other when rendering.
WebGL fragment shaders require precision to be set, so I added this to all fragment shaders to allow them to compile under all OpenGL/WebGL versions:
precision lowp float;
Previous commits read the font directly from disk via
ioutil.ReadFile. This can't work on all other platforms, so it's better to read from a virtual filesystem and each platform can provide that. It's no longer a problem since latest version embeds the font in code.
gogl package happens to use a higher level-style API (similar to
x/mobile/gl) with types like
*Texture instead of
uint32, and it favors using
uint32 the way the low-level C-style
github.com/go-gl/gl/... packages do. This is a design decision that is orthogonal to all other API changes, but it required me to make some changes like:
-f.framebuffer = 0
-f.texture = 0
+f.framebuffer = nil
+f.texture = nil
-gl.Viewport(0, 0, int32(fw), int32(fh))
-gl.Scissor(0, 0, int32(fw), int32(fh))
+gl.Viewport(0, 0, fw, fh)
+gl.Scissor(0, 0, fw, fh)
gl.TRIANGLE_STRIP are not const on all platforms. For example, to get that value in a browser, you either need to create a WebGLContext first (which can't be done at const-time), or just hardcode the const value from spec. I went with the latter for now.
You can see the entire code change I made at https://github.com/google/gxui/commit/469940010c8be6abd4feb535ba14a8b4e707720d. Keep in mind it's a quick prototype to test what it would take, and not a fully finished and polished version.
With just a few changes (do not use transpose
uint16 type for index buffers, etc.) it is possible to avoid using OpenGL-only features that are not available in OpenGL ES and WebGL. Doing that seems like a good idea as it enables
gxui to be more cross platform.
This issue is to demonstrate what I've created. I'd love to hear feedback and thoughts. If you are interested, I'd love to help out with adding support for mobile and/or web and taking this prototype further.
 The imported package is
v3.2-core/gl, so that's the API used, but since context version glfw hints are not set, it creates an OpenGL 2.1 context. Add this snippet after
gl.Init() call to confirm:
var samples int32
fmt.Printf("OpenGL %s %s %s; %s; %v samples.\n", gl.GoStr(gl.GetString(gl.VENDOR)), gl.GoStr(gl.GetString(gl.RENDERER)), gl.GoStr(gl.GetString(gl.VERSION)),
On my Mac, I got
OpenGL ATI Technologies Inc. AMD Radeon HD 6770M OpenGL Engine 2.1 ATI-1.30.5; 1.20; 4 samples.. OpenGL 2.1.