A glfw application with C++11:
class glfw_app { public: glfw_app(const std::string& window_title, int window_width, int window_height); virtual ~glfw_app(); void start(); virtual void on_keydown(GLFWwindow* window, int key, int scancode, int action, int mods); virtual void on_error(int error, const char* desc); virtual void on_resize(GLFWwindow* window, int width, int height); virtual void glloop() = 0; GLFWwindow* window() const; };
This base class is simple: It manages a glfw window and their OpenGL context for us, wraps (and currently hides) the event and rendering loop, finally and provides us some polymorphic functions to say what to do when a key is pressed, when the window is resized, etc.
class ball : public glfw_app { public: template<typename... ARGS> ball(ARGS&&... args) : glfw_app{ std::forward<ARGS>(args)... } , x_ball{ 0.0f }, y_ball{ 0.8f }, vx_ball{ 0.0f }, vy_ball{ 0.0f } {} virtual void on_keydown(GLFWwindow* window, int key, int scancode, int action, int mods) override; virtual void glloop() override; private: float x_ball, y_ball; float vx_ball, vy_ball; const float gravity = 0.01; const float radius = 0.05f; void draw_ball(); };
We have ball coordinates, ball speed, and its radius. There is also a `gravity` constant, since we want our ball to bounce.
The
on_keydon()
callback is not complex: Just closes the window when the user presses ESC:void ball::on_keydown(GLFWwindow* window, int key, int scancode, int action, int mods) { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); }
Now this is the body of our rendering loop:
void ball::glloop() { float ratio = framebuffer_width() / (float)framebuffer_height(); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f); glMatrixMode(GL_MODELVIEW); //Bounce on window bottom if (y_ball + radious <= radious) vy_ball = std::abs(vy_ball); else vy_ball -= gravity; //Apply gravity //Update ball coordinates x_ball += vx_ball; y_ball += vy_ball; //Lets draw the ball! draw_ball(); }
Note how the ball is projected. The visible area of our OpenGL scene (The area which matches the viewport) goes from -1 to 1 in both axes, where -1 is the bottom-left corner of our window, and 1 is its top-left.
//Bounce on window bottom if (y_ball - radious <= - 1) vy_ball = std::abs(vy_ball); else vy_ball -= gravity; //Apply gravity //Update ball coordinates x_ball += vx_ball; y_ball += vy_ball; //Lets draw the ball! draw_ball();
The ball’s position and speed are updated following the equations v’ = v + a*t and p’ = p + v * t, where v is velocity (speed), a is acceleration (The gravity constant), and t is time.
Time is measured in frames, so in all the equations t is one. That’s why there’s no t in our code. If you want a stable simulation (independent of frame rate) you should use a more complex technique, like those described in this article.
If the ball goes out of the window bounds, that is, y_ball – radious is less than -1, we should make the ball go upwards: Set its vertical speed as positive:
if (y_ball - radious <= - 1) vy_ball = std::abs(vy_ball);
Also apply gravity. Don’t apply acceleration when the ball bounces.
The final step is to draw the ball: Draw a white “circle” (a regular polygon) using GL_POLYGON:
void ball::draw_ball() { const float full_angle = 2.0f*3.141592654f; float x, y; glBegin(GL_POLYGON); glColor3f(1.0f, 1.0f, 1.0f); for (std::size_t i = 0; i < 20; ++i) { x = x_ball + radious*(std::cos(i*full_angle / 20.0f)); y = y_ball + radious*(std::sin(i*full_angle / 20.0f)); glVertex2f(x, y); } glEnd(); }
Now here the main() function
#include "glfw_app.hpp" #include "ball.hpp" int main() { auto app = make_app<ball>("bouncing ball!" , 800 , 600); app->start(); }
glfw is a great library to write OpenGL applications. Its C API is clear and simple, and making it work in the C++ way can be done with just a little effort. We learnt here how to make a little framework to write simple OpenGL applications in a OO way. Encapsulating the most common tasks in a base class reduces noise in our simple OpenGL examples.
Nice Article