0
\$\begingroup\$

I've been working through a few OpenGL tutorials, and decided to give myself the exercise of trying to draw a grid, with the added requirement of being able to press the - and + keys to change the dimensions of the grid. I've achieved what I set out to, however, it's left me with a few questions on how to go about separating some of the logic.

My biggest concern is to do with the input handling. Right now, I'm handling it like so:

Grid grid;

void key_callback(GLFWwindow* window, int key, int scanCode, int action, int mode)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);

    if (key == GLFW_KEY_MINUS && action == GLFW_PRESS)
        grid.DecrementGridSize();

    if (key == GLFW_KEY_EQUAL && action == GLFW_PRESS)
        grid.IncrementGridSize();

    grid.Build();
    glBufferData(GL_ARRAY_BUFFER, grid.Size() * sizeof(Vector3D), grid.Data(), GL_STATIC_DRAW);
}

There are several things I don't like about this:

  1. This is at the top of my main.cpp file, so grid is global, purely so it can be used in the input handler.
  2. I've coupled the glBufferData() call with the input handling.

I'm not sure how to go about solving point 1, as I'm inexperienced with C++, but, for 2, I've considered the idea of having a separate Update() method that would be called at the end of the handler, rather than calling glBufferData() directly. Update() would then take care of updating the contents of the buffer.

The problem I see with that is how you would pass the data from grid to it. In my simple program, passing one set of vertices is absolutely no problem, but I'm not sure how you'd handle doing that when you have a whole bunch of different objects with their own vertices. I assume there are different patterns that already exist for handling this, so I'm more looking for some phrases I can Google really.

What can I do to improve the situation?

| improve this question | | | | |
\$\endgroup\$
3
\$\begingroup\$

This is at the top of my main.cpp file, so grid is global, purely so it can be used in the input handler.

In general, the solution here is "don't make it global," and to pass instances needed to functions that need them. In this simple program you probably don't need to worry about it too much. Think of more as something you should think about for the future.

One way to refer to this concept is "dependency injection," which may give you something useful to search for (be wary though, as the phrase is also used to describe hideously over-complex "enterprise" engineering patterns as well; all I'm really talking about is the straightforward idea of passing instances of dependencies to objects or functions that require them).

In the case of GLFW you can't modify the input callback signature, so consider looking into attaching data to the user pointer of the window to remove the global variable reference.

I've coupled the glBufferData() call with the input handling.

Fundamentally, the input causes the action (the action in this case is regenerating the buffer). You'll never be able to decouple those unless you remove the functionality. You can place layers of abstraction in between them, sure, and in some cases that's desirable. Maybe not so much in this simple program; this key handling code is basically part of the "top level" game layer of abstraction, which is going to know about every other system in the game somehow already, or that system would never be instantiated/ticked/whatever.

You've already (apparently) got a start on the idea of keeping logical data (grid) and render data (the grid's buffer) distinct. This is a good direction, but I'd suggest that you focus on is continuing that separation rather than worrying so much that your input handling code is triggering a graphics rebuild.

For example, glBufferData operates on the currently bound buffer, and I don't see where you set that here. That means either you're setting it in grid.Build or you're setting it at the start of the program and expecting it to remain set. That is bad, as it will cause you no end of pain when you start adding more than one buffer to your program. Spending time getting OpenGL buffer management correct early can save you a lot of trouble in the long run. Consider building an abstraction around the renderable grid that makes it just as easy to update the render buffer data, but does it without making assumptions about which buffer is currently bound, et cetera.

| improve this answer | | | | |
\$\endgroup\$
  • \$\begingroup\$ Josh, your answer is spot on, thank you. My main problem is indeed to do with how buffer management works. I'm setting it at the start of the program, as I didn't want to tie it to the grid itself. It feels like what encapsulates a grid isn't the same concept as rendering the grid. Is this what you're getting at with your last sentence? \$\endgroup\$ – John H Mar 17 '16 at 17:04
  • \$\begingroup\$ Yes, that's it. \$\endgroup\$ – user1430 Mar 17 '16 at 17:04
  • \$\begingroup\$ Wonderful, that gives me something to start looking into. Thanks! \$\endgroup\$ – John H Mar 17 '16 at 17:06
1
\$\begingroup\$

I think simple layers of abstraction would do the trick. Create an InputModule that produces InputEvents that are handled by objects that have registered to the InputModule as event handlers, listeners or such.

| improve this answer | | | | |
\$\endgroup\$
  • \$\begingroup\$ Ah, interesting. That makes a lot of sense actually. I'll give this a try, thanks! \$\endgroup\$ – John H Mar 17 '16 at 17:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.