The SGL's object-oriented API is relatively simple and straightforward for developers familiar with the concepts of inheritance, polymorphism, virtual functions, and method overriding, but these concepts can be a significant barrier to novice programmers. To address this, the SGL provides a simplified procedural interface that opens up graphics programming in C++ to those less familiar with OO development concepts.
The procedural API limits an application to just one graphical window. The developer calls functions to register callbacks that respond to major events. Example 3.4 uses the procedural API within an application that allows a user to place or move a box within its window by selecting a position with the mouse.
Example 3.4. Using the Procedural Interface
#include <GL/sgl.hpp> // Box initially is out of the window double box_x = -10; double box_y = -10; void draw() { sgl::set_color(sgl::BLUE); sgl::fill_rectangle(box_x - 10, box_y - 10, 20, 20); } void mouse_pressed(double x, double y, sgl::MouseButton) { box_x = x; box_y = y; sgl::update_window(); } int main() { sgl::create_window("BoxWindow", 0, 300, 0, 300); sgl::set_paint_function(draw); sgl::set_mouse_pressed_function(mouse_pressed); sgl::run_window(); }
Note that Example 3.4 uses no explicit
objects. The sgl::create_window
function
behind the scenes allocates a single global graphical window
object. The sgl::set_paint_function
and
sgl::set_mouse_pressed_function
functions allow the
programmer to register the appropriate event handler callback
functions.
The procedural API provides simmilar functions to track mouse
movement and dragging and key presses.
The run_window
function calls the
run
method of the hidden global graphical window
object.
Example 3.4 used global variables to
maintain the state of the system (that is, the location of the box
within the window).
The OO approach would have avoided the use of global variables,
making them instance variables within a graphical window
object. Even though the global variables may be appropriate for the
simple Example 3.4, good
programming practice discourages the use of global
variables. Fortunately, it is possible to use the procedural
interface along with simple OO techniques that avoid inheritance
and polymorphism.
Example 3.5 uses C++ lambda
functions to serve as callbacks to methods within an object. Note
that the object b
is local to
the main
function,
and the application declares no global variables. It is safe for
the lambda functions to
capture local variable b
by reference because
the sgl::run_window
function does not return
until the graphical program is finished.
Example 3.5. The Procedural Interface without Global Variables
#include <GL/sgl.hpp> class GraphicalBox { int x; int y; public: GraphicalBox(int x, int y): x(x), y(y) {} void draw() { sgl::set_color(sgl::BLUE); sgl::fill_rectangle(x - 10, y - 10, 20, 20); } void mouse_pressed(double mx, double my, sgl::MouseButton) { x = static_cast<int>(mx); y = static_cast<int>(my); sgl::update_window(); } }; int main() { GraphicalBox b{-10, -10}; // Initially out of the window sgl::create_window("BoxWindow", 0, 300, 0, 300); sgl::set_paint_function([&b]() { b.draw(); }); sgl::set_mouse_pressed_function([&b](double x, double y, sgl::MouseButton mb) { b.mouse_pressed(x, y, mb); }); sgl::run_window(); }
Copyright ©2019 Richard L. Halterman | Version 0.9.5 | February 17, 2019 |