Core
OGL3D Internals
ogl3d is a very small library with a narrow purpose: create an OpenGL context for a native view,
make that context current for drawing, swap the buffers, and report failures in a portable way. It does not
abstract OpenGL itself, and it does not sit inside draw2d.
Relevant Source Files
Library Boundary
The target is declared as nap_library(ogl3d "sewer" ...). That is an important architectural signal:
ogl3d does not depend on core, draw2d, gui, or osgui.
It only needs the low-level support layer plus the platform OpenGL libraries wired in through the build system.
Because of that, the public API takes a raw native view pointer as void *. The higher GUI layer is responsible
for producing that handle, which is why the demos call view_native(view) before creating an OpenGL context.
Lifecycle And Leak Checks
ogl3d_start() and ogl3d_finish() are much lighter than the equivalent functions in
core or draw2d. They only maintain a user count. On the last ogl3d_finish(),
the library asserts if the number of context allocations and deallocations does not match.
That means ogl3d actively checks for leaked OGLCtx objects but does not own a wider runtime stack.
It is a thin portability layer, not a subsystem bootstrapper.
Public Contract
The portable API surface is small and stable:
ogl3d_context(...): create a platform context fromOGLPropsand a native view handle.ogl3d_begin_draw(...)/ogl3d_end_draw(...): make the context current, then flush or swap the back buffer.ogl3d_set_size(...): notify the backend about size changes when it cares.ogl3d_destroy(...): tear the context down and update the allocation counters.ogl3d_err_str(...): map portable error codes to user-facing strings.
The error enum is intentionally coarse: API version missing, fullscreen unsupported, view binding failure, pixel format failure, context creation failure, or GLEW initialization failure.
What OGLProps Controls
OGLProps exposes the requested OpenGL API level, accelerated versus fallback rendering, color/depth/stencil sizes,
auxiliary buffer count, transparency, and an optional shared context. The platform backends all consume the same structure,
but each interprets it through native APIs.
The shared-context field is real and wired through on every desktop backend in this checkout. On Windows it uses
wglShareLists, on macOS it passes the existing NSOpenGLContext into shareContext:,
and on GTK/EGL it forwards the existing EGL context pointer when creating the new one.
Version Validation Uses GLEW
Context creation does not stop at the native API call. After the backend creates and binds a context, ogl3d
runs glewInit() and then checks the requested version against the relevant GLEW_VERSION_x_y flag.
That is how the portable oglapi_t enum becomes enforceable. A backend may succeed in creating some context,
but the wrapper still rejects it if the requested API level is not actually available through GLEW.
Platform Backend Behavior
| Platform | Context Type | Backend-Specific Notes |
|---|---|---|
| Windows | HGLRC |
Uses an HWND plus HDC, chooses a pixel format, creates a WGL context, and swaps with SwapBuffers. |
| macOS | NSOpenGLContext |
Builds a profile-aware NSOpenGLPixelFormat, binds the context to the target NSView, and flushes with flushBuffer. |
| GTK | EGLContext |
Uses EGL on top of X11-backed GTK widgets, disables GTK double buffering, and swaps with eglSwapBuffers. |
Binding To NAppGUI Views
All three backends adapt the native widget state so the OpenGL context can coexist with NAppGUI's normal 2D drawing path.
Windows marks NAppGUI view windows as non-GDI when an OpenGL context is attached. macOS calls Objective-C category hooks
on NSView to switch the view into an OpenGL-aware mode. GTK renames the widget from the Cairo path to an OpenGL path
and turns GTK double buffering off while the context is alive.
That is why ogl3d works best when paired with a View widget: the native view object is the seam where
the backend swaps from normal GUI drawing to OpenGL ownership.
Resize Handling Is Backend-Specific
ogl3d_set_size(...) is not a generic viewport helper. The demos still call it from the view size callback,
but the backend behavior differs by platform. On macOS it calls [NSOpenGLContext update], while the Windows
and GTK implementations are effectively no-ops and leave size handling to the caller's GL viewport logic.
What glhello Shows About Real Usage
demo/glhello is the canonical integration pattern. The app starts ogl3d once, creates a normal NAppGUI
View, converts it to a native handle with view_native(...), and then builds small wrappers around
OGLCtx for OpenGL 1.1, 2.1, and 3.3.
Those wrappers own the real GPU objects: textures, VBOs, IBOs, VAOs, and shader programs. ogl3d itself never tries
to manage that state. Its job ends at context management and buffer swapping.
ogl3d is OpenGL-only.
Reading Order
Start with ogl3d.h and ogl3d.hxx for the public contract, then read ogl3d.c for
lifecycle and version checks. After that, read the platform backend that matches your target OS, and finish with the
three glhello renderer wrappers to see how an application layers its own GPU resource management on top.