www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Messing with OpenGL in D

reply Nadir Chowdhury <chowdhurynadir0 outlook.com> writes:
I'm fairly new to Dlang, but have learnt the basics. I wondered 
how I would be able to make an OpenGL-based Engine in D, what 
libraries would I need? Your help will be much appreciated!

- NCPlayz
Dec 05 2018
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Dec 05, 2018 at 07:12:34PM +0000, Nadir Chowdhury via
Digitalmars-d-learn wrote:
 I'm fairly new to Dlang, but have learnt the basics. I wondered how I
 would be able to make an OpenGL-based Engine in D, what libraries
 would I need?  Your help will be much appreciated!
[...] All you need is some bindings to your OS's OpenGL libraries and GUI libraries, and you should be able to just call OpenGL functions directly. You could use dstep to translate the system headers into D then import them. The main tricky part is setting up your GL context so that it plays nicely with your OS's GUI system. I don't know what OS you're on, but I have a Linux project that does just this: - Install required libraries: X11 libraries (+ header files), MESA (which contains an implementation of GL and GLX needed to make X11 and GL work together). - First, I translated /usr/include/X11/{X,Xlib,Xutil,keysymdef}.h into D (I did it by hand -- not the entire header file but just enough to call the most basic functions to create an X11 window). - Then I translated /usr/include/GL/{gl,glx,glext,glxext}.h into D -- again, not the entire thing but just those OpenGL calls that I need to work with. You could probably just use dstep to translate the whole thing and not have to worry about it after that. - Write code to connect to the X server and create a window: - XOpenDisplay - glXChooseGBConfig - glXGetVisualFromFBConfig - XCreateColormap - XCreateWindow - XMapWindow - If you need any GL extensions: - glXQueryExtensionsString - glXCreateContextAttribsARB or glXCreateContext - Once the window is created and mapped, you need an event loop to process X11 / GLX events. This may be quite delicate, depending on whether you're planning to have a mainly passive GUI (i.e., respond to user actions only) or you want to have animation / program-driven changes (like game engines). - For passive GUIs, all you need is a loop that calls XNextEvent to retrieve the next event, and when you get an Expose event, call XGetWindowAttributes to get the window dimensions, then use that to setup your GL viewport, projection matrices, render the scene, etc.. - For active GUIs (like games), you'll need to handle X events asynchronously. You can either use a different timing thread and send yourself custom events when you need to redraw a frame, or if you need to make it work in a single thread: /* Very rough sketch on what needs to be done -- if you want to * see actual code, ask. */ // This function handles all X11 events -- the bare minimum is // Expose, so that you know when to draw the first frame. You // probably also want KeyPress if you need keyboard input, // ButtonPress / ButtonRelease for mouse buttons, MotionNotify // for mouse motion, etc.. void handleEvent() { XEvent ev; XNextEvent(display, &ev); switch (ev.type) { case Expose: ... // draw first frame break; ... // handle other events here } } // This is needed for processing initial events triggered by // window creation and mapping, in order to clear Xlib's queue, // otherwise the main loop will have sync problems or stall for // the first couple of frames. XFlush(display); while (XEventsQueued(display, QueuedAlready) > 0) handleEvent(); // File descriptor of X11 socket immutable x11fd = ConnectionNumber(display); // Main loop for (;;) { // Use select() or epoll() on x11fd to check when you // need to process X11 events. // Use the timeout argument on select() or epoll() to // schedule your animation. if ( /* select or epoll indicates read-ready on x11fd */) { // Note: be sure to write it exactly this way in // order to prevent your main loop from stalling // due to Xlib misbehaviour. while (XPending(display)) handleEvent(); } if ( /* timeout expired / time to draw a frame */ ) { // call GL functions to render frame } } - When compiling, make sure to pass `-lX11 -lGL` to your linker so that it will link the X11 and GL libraries. Otherwise you'll get a bunch of undefined symbol errors. P.S., Yes, this is the manual way, low-down of doing things. There are probably libraries out there that abstract these ugly dirty details away for you. But I'm putting this out here so that people know how to make things work when the easy way fails. P.S.S. I can share the X11/GL headers I translated to D if you're curious. Be warned, however, that they are highly incomplete, because I only translated what I actually use, not the entire header files. Using dstep for translating your local header files is highly recommended instead. But looking at my translated headers may give you a good idea of how to mechanically translate C headers to D. It's pretty straightforward once you know how. P.S.S.S. The stuff about managing the event loop can probably be avoided by using XCB instead, or using a dedicated GUI thread separate from your application logic just to work nicely with Xlib. But since GLX is built on Xlib, you cannot avoid using Xlib at least for setting up the GL context. After that, you might be able to get away with switching to XCB as long as you let XCB know that the X11 connection is "owned" by Xlib (google for the dirty details). P.S.S.S.S. I highly recommend defining an abstract API for your program logic, so that the above dirty stuff can be kept in its own module and just make calls to the real program logic via the abstract API. You really do not want to be debugging code that has application logic mixed with Xlib handling. For my project, since it's Android based (the X11 driver is just for testing app logic on host PC), I use an API closely modelled after Android's: interface Application { void initialize(); void onChange(int width, int height); void onDrawFrame(); void onTouch(float x, float y); void onPause(); void onResume(); void onStop(); } You can add other methods as needed, of course. And you can use D's compile-time features to eliminate those nasty virtual calls, if need be. But the point is to keep the application logic completely separate from the dirty low-level details of X11 handling. It will help maintain your sanity when it comes time for debugging. T -- Do not reason with the unreasonable; you lose by definition.
Dec 05 2018
parent reply Nadir Chowdhury <chowdhurynadir0 outlook.com> writes:
On Wednesday, 5 December 2018 at 20:06:09 UTC, H. S. Teoh wrote:
 I don't know what OS you're on, but I have a Linux project [...]
I'm on Windows 10, so which parts would differ? Sorry, should've mentioned it in my original post. Thanks for the reply!
Dec 05 2018
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 5 December 2018 at 20:36:43 UTC, Nadir Chowdhury 
wrote:
 I'm on Windows 10, so which parts would differ? Sorry, 
 should've mentioned it in my original post. Thanks for the 
 reply!
Basically all of it lol. The principals are the same, but the specific functions are all different. What version of opengl do you wanna play with? my lib simpledisplay.d https://github.com/adamdruppe/arsd/blob/master/simpledisplay.d depends on color.d https://github.com/adamdruppe/arsd/blob/master/color.d but otherwise might help get started. lemme know a few deets and i can get you a sample
Dec 05 2018
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Dec 05, 2018 at 08:44:13PM +0000, Adam D. Ruppe via Digitalmars-d-learn
wrote:
 On Wednesday, 5 December 2018 at 20:36:43 UTC, Nadir Chowdhury wrote:
 I'm on Windows 10, so which parts would differ? Sorry, should've
 mentioned it in my original post. Thanks for the reply!
Basically all of it lol. The principals are the same, but the specific functions are all different.
Haha yeah. Pretty much everything I said would be completely different on Windows. But yeah, the principles are the same: 1) Somehow create a window / screen using your OS's GUI API. 2) Create a GL context for that window / screen (probably can be done as part of (1)). 3) Create a main loop to handle OS GUI events (mainly forwarding to application logic). 4) Use GL for rendering whenever it's time to draw a frame. T -- If Java had true garbage collection, most programs would delete themselves upon execution. -- Robert Sewell
Dec 05 2018
prev sibling next sibling parent Gheorghe Gabriel <knoppy273 live.com> writes:
On Wednesday, 5 December 2018 at 19:12:34 UTC, Nadir Chowdhury 
wrote:
 I'm fairly new to Dlang, but have learnt the basics. I wondered 
 how I would be able to make an OpenGL-based Engine in D, what 
 libraries would I need? Your help will be much appreciated!

 - NCPlayz
I use BindBC-OpenGL for my game engine. To handle windows and input you can either use BindBC-GLFW (like me) or BindBC-SDL2. It's very nice and easy. I hope it helped. Good luck!
Dec 05 2018
prev sibling parent JN <666total wp.pl> writes:
On Wednesday, 5 December 2018 at 19:12:34 UTC, Nadir Chowdhury 
wrote:
 I'm fairly new to Dlang, but have learnt the basics. I wondered 
 how I would be able to make an OpenGL-based Engine in D, what 
 libraries would I need? Your help will be much appreciated!

 - NCPlayz
I use Derelict's GLFW bindings - https://github.com/DerelictOrg/DerelictGLFW3 to create the OpenGL context and stuff. If you need a math library, dlib math from https://code.dlang.org/packages/dlib is probably the best place to start. gl3n is also nice, but it uses row-major matrices, so you have to remember to always transpose them when uploading to OpenGL.
Dec 05 2018