deech / fltkhs

Haskell bindings to FLTK GUI toolkit.
MIT License
190 stars 24 forks source link

How to enable modern OpenGL? #157

Closed ericu closed 5 years ago

ericu commented 5 years ago

The OpenGL context of a GLWindow doesn't support modern OpenGL. When I try to request GLSL 3.3.0 in a shader [by saying #version 330] I get this error:

Vertex Shader Error:0:1(10): error: GLSL 3.30 is not supported. Supported versions are: 1.10, 1.20, 1.30, 1.00 ES, 3.00 ES, 3.10 ES, and 3.20 ES

In GLFW one could do this: glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

I see that other FLTK users have hit the same problem: https://stackoverflow.com/questions/11557186/how-to-create-opengl-3-x-or-4-x-context-with-fltk-1-3?rq=1 https://groups.google.com/forum/#!topic/fltkcoredev/ogdzbBSBZmI

Apparently one can create the GL context separately, then pass it into FLTK somehow. Is this possible in FLTKHS?

deech commented 5 years ago

There are two functions on GlWindow:

 setContext :: 'Ref' 'GlWindowBase' -> 'Ref' 'FlGlContext' -> 'IO' ()
 setContextWithDestroyFlag :: 'Ref' 'GlWindowBase' -> 'Ref' 'FlGlContext' -> 'Bool' -> 'IO' ()

The Bool flag in the latter, if True, destroys the FlGlContext passed in when the window's destructor is called.

I've honestly never done this as I'm not too familiar with OpenGL. If you successfully get this working on your platform do you mind posting to this issue? I'll make it part of the official documentation.

ericu commented 5 years ago

Hmm...it's a problem that what we need to pass in is an OpenGL context, and the API takes an FlGlContext. And the ways of creating OpenGL contexts in Haskell generally create e.g. GLFWWindow or SDLWindow or their particular wrapped versions of OpenGL contexts. I don't see a way to extract the actual underlying C context object and pass it around between APIs. They don't export it and you can't accept it anyway.

The most likely to succeed suggestion I've seen so far in the C world is to somehow create a hidden or offscreen core context window in a different API and then blit the bitmap across each frame. That might be doable in Haskell, depending on the other API chosen, but it'll be quite cumbersome.

The Google Groups thread above manages to get something working, but that's by hacking a new enum value into the FLTK source. I don't know how you feel about doing something so invasive in a wrapper library. We could add a new function to do that instead of altering the existing API, but it would still be functionality not published by the wrapped library. Of course, that's the whole point of this issue: that FLTK doesn't publish this functionality. But in C there are potentially reasonable ways to work around that, and in Haskell there don't seem to be.

deech commented 5 years ago

Broadly speaking I'm ok adding functionality that FLTK doesn't provide but don't really want to patch the library. But perhaps the FLTK folks would be amenable to a PR? That would be the best solution because I have no problem bundling the FLTK master branch into this project if it is merged, that's what I do now anyway and this in particular seems like really useful functionality.

ericu commented 5 years ago

Never mind! There's already an API that does it [with a small hack], that I hadn't previously found.

See https://www.fltk.org/doc-1.3/opengl.html#opengl3 In Haskell: setMode glwin $ Modes [ModeDouble, ModeDepth, ModeOpenGL3]

There's a small problem in that getMode returns a Mode that's a bunch of bits orred together, which we can't take apart safely without blowing up on toEnum. But the error message told me the raw bits, so I went though the FLTK headers to see what they were [18 == ModeDouble | ModeDepth] and I just overwrote with that and the bit for ModeOpenGL3. getMode should really take the bits apart and return a Modes instead so that we could just or in a single bit, and then we'd have a clean solution.

deech commented 5 years ago

Ooh great find! Can you confirm that you're able to are indeed able to render using newer versions of OpenGL? I'll change getMode as you suggest.

ericu commented 5 years ago

I've got a square rendering with #version 330 in my shaders, so I believe that indicates I'm using newer OpenGL. I don't know how to get the actual version out, but I believe it should default to the full range of whatever I've got installed.

ericu commented 5 years ago

Taking out that one setMode line gives me back the old error: Vertex Shader Error:0:1(10): error: GLSL 3.30 is not supported. Supported versions are: 1.10, 1.20, 1.30, 1.00 ES, 3.00 ES, 3.10 ES, and 3.20 ES That seems like proof.

ericu commented 5 years ago

Incidentally, if you do update the OpenGL docs section, you might want to point out that you have to do all the GL setup stuff lazily in the first draw call, not where you create the GlWindow. Until the draw call, there doesn't seem to be an OpenGL context, or at least I couldn't make one current.

ericu commented 5 years ago

I get it now: the lazy init of the context is why this works at all. You create the GlWindow and call setMode on it before the context is created, because afterward it would be too late. At some point between then and the first draw call, FLTK creates the context. Then you can create your VAO etc. and start rendering.

deech commented 5 years ago

getMode now extracts the different Modes out of the bits.

ericu commented 5 years ago

Works great--thanks!