|
wx_BGI_Graphics
Classic BGI-compatible graphics API with modern OpenGL extension API
|
This tutorial explains how double (and layered) buffering works in wx_bgi_graphics and how to write smooth, flicker-free animation using the real API.
Note on older references: An earlier draft of this document used function names such as
setVisualBuffer(),setActiveBuffer(),createBuffer(), anddestroyBuffer(). None of these functions exist in the library. The correct API is described below.
The library implements two independent layers of buffering:
initwindow() / initgraph() automatically allocates exactly two software pixel buffers in CPU memory: page 0 and page 1. Each buffer stores one colour-index byte per pixel (the BGI palette index or an extended RGB slot).
| Variable | Meaning |
|---|---|
activePage | The page all BGI drawing commands write to (0 or 1). |
visualPage | The page that is read and sent to OpenGL when a frame is presented (0 or 1). |
You control these with three BGI API calls:
| Function | Effect |
|---|---|
setactivepage(int page) | Redirect all drawing to page 0 or page 1. |
setvisualpage(int page) | Make page 0 or page 1 the displayed page, and immediately present it to the screen. |
swapbuffers() | Atomically exchange activePage and visualPage, then present – the canonical double-buffer flip. |
GLFW opens the window with a hardware double-buffered OpenGL context (a standard front and back OpenGL render buffer managed by the GPU driver).
Every time a BGI page is to be shown, the internal flushToScreen() function:
glVertex2i point.glFlush() then glfwSwapBuffers() – this atomically swaps the GPU front/back buffers, displaying the new frame.The programmer never calls glfwSwapBuffers() directly; flushToScreen() is an internal function invoked by setvisualpage(), swapbuffers(), and wxbgi_swap_window_buffers().
For programmers mixing raw OpenGL with BGI, the extension API exposes:
| Function | Effect |
|---|---|
wxbgi_poll_events() | Process OS/window events without swapping buffers. |
wxbgi_swap_window_buffers() | Call glfwSwapBuffers() directly (skips BGI pixel upload). |
wxbgi_begin_advanced_frame() | Begin a manual OpenGL draw frame. |
wxbgi_end_advanced_frame(int swap) | End a frame; optionally swap the OpenGL buffers. |
Call initwindow() or initgraph(). Two BGI software page buffers (page 0 and page 1) are created automatically. The GLFW window opens with a hardware double-buffered OpenGL context.
Call setactivepage(1) to send all drawing commands to page 1 while page 0 remains visible. In Double-Buffering you deliberately avoid drawing on the visible page.
Use normal BGI drawing commands (line, circle, outtextxy, etc.). Nothing appears on screen yet – all output goes into the page 1 CPU buffer.
Call swapbuffers(). This exchanges which page is active and which is visual, then calls flushToScreen() to upload the new visual page to OpenGL and call glfwSwapBuffers() on the GPU.
Call cleardevice() (which clears the new active page) and draw the next frame.
Call closegraph(). Both software page buffers are freed and the GLFW window is destroyed.
The library provides exactly two BGI software page buffers (page 0 and page 1). It does not support creating additional buffers with a createBuffer() call – that function does not exist.
Classic triple-buffering at the BGI level is therefore not available. However, the underlying GLFW/OpenGL context is always hardware double-buffered, so the complete system pipeline is:
The GPU front/back buffer swap (glfwSwapBuffers) is triggered automatically inside flushToScreen() every time setvisualpage() or swapbuffers() is called. This gives tear-free presentation without any additional programmer effort.
The library protects all BGI state with a single internal mutex (gMutex). Every public API function acquires this mutex before reading or writing state, so concurrent calls from multiple threads will not corrupt internal state.
However, there are still design-level considerations:
flushToScreen() (called by swapbuffers()) must run on the thread that owns the OpenGL context. By default this is the thread that called initwindow().setactivepage(1) and present from the main thread using swapbuffers(), the mutex serialises the two, but you must ensure the background thread has finished its frame before calling swapbuffers().Safe single-producer / single-display pattern:
Use a std::atomic<bool> or std::condition_variable to coordinate; do not call swapbuffers() from both threads simultaneously.
| BGI Classic API | Effect |
|---|---|
initwindow(w, h, title) | Open window; allocate page 0 and page 1. |
setactivepage(page) | Direct drawing to page 0 or page 1 (0 = default). |
setvisualpage(page) | Display page 0 or page 1; triggers flushToScreen(). |
swapbuffers() | Atomic flip of active/visual pages + flushToScreen(). |
cleardevice() | Clear the active page to the background colour. |
closegraph() | Free page buffers, destroy GLFW window. |
Extension API (wxbgi_*) | Effect |
|---|---|
wxbgi_poll_events() | Process OS events (no buffer swap). |
wxbgi_swap_window_buffers() | Swap the OpenGL front/back buffers directly. |
wxbgi_begin_advanced_frame() | Begin a manual OpenGL frame (clears GL buffers). |
wxbgi_end_advanced_frame(swap) | End a frame; swap GL buffers if swap != 0. |
wxbgi_should_close() | Returns non-zero when the user closes the window. |
The canonical animation loop is: