OSGui v2 is an alpha release of an immediate-mode C++ UI library for native tools. It is usable for experimentation and internal tooling, but its API and serialized state may still change before a stable v2 release. It is not yet a drop-in replacement for Dear ImGui; see Current limits before choosing it for a project.
- CMake 3.20 or newer
- A C++11 compiler
- A graphics and platform integration supported by your application, or a custom backend
The core library is backend-neutral. The repository also contains Win32/OpenGL 2, Win32/DirectX 11, GLFW, and OpenGL 3 integration code. Backend coverage is not uniform; the README backend matrix records the current differences.
Clone the public repository and configure a build directory:
git clone https://github.com/qtWillyG/osGUI.git
cd osGUI
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DOSGUI_BUILD_TESTS=ON
cmake --build build --config Debug
ctest --test-dir build -C Debug --output-on-failureOn a multi-configuration generator such as Visual Studio, --config Debug selects the configuration at build and test time. On a single-configuration generator, CMAKE_BUILD_TYPE selects it during configuration.
To build the repository examples as well:
cmake -S . -B build -DOSGUI_BUILD_EXAMPLES=ON
cmake --build build --config ReleaseOnly enable the example and backend targets needed by your platform and toolchain. Consult cmake -LAH -N build after configuration for the options exposed by the current checkout.
Install OSGui to a prefix:
cmake --install build --config Release --prefix ./installThen request the core package from your own CMake project:
find_package(OSGui 2.0 CONFIG REQUIRED COMPONENTS Core)
add_executable(my_tool main.cpp)
target_link_libraries(my_tool PRIVATE OSGui::Core)Backend components are optional. Installed configurations can expose OpenGL3, Win32OpenGL2, DX11, and GLFW components when those targets were built and installed:
find_package(OSGui 2.0 CONFIG REQUIRED COMPONENTS Core OpenGL3 GLFW)
target_link_libraries(my_tool PRIVATE OSGui::Core OSGui::OpenGL3 OSGui::GLFW)Keep the requested components aligned with the backends you actually build. OSGui::Core alone is sufficient for a custom platform and renderer integration.
Create a context, verify the compile-time and runtime versions, initialize the selected backends, and make the context current before the first frame:
#include <osgui.h>
og::Context* context = og::CreateContext();
if (!OG_CHECKVERSION()) {
og::DestroyContext(context);
return false;
}
og::SetCurrentContext(context);
// Initialize the platform backend and renderer backend here.CreateContext() makes the new context current. Calling SetCurrentContext() explicitly is still useful when an application owns more than one context or hands UI work between modules.
A frame has four stages:
// 1. Let the platform and renderer backends prepare their frame data.
// PlatformBackend_NewFrame();
// RendererBackend_NewFrame();
// 2. Start the OSGui frame.
og::NewFrame();
// 3. Declare the interface.
if (og::Begin("Inspector")) {
og::Text("OSGui v2 alpha");
static float gain = 0.5f;
og::SliderFloat("Gain", &gain, 0.0f, 1.0f);
}
og::End();
// Optional during development: report unbalanced stacks or invalid state.
og::ValidateState();
// 4. Finalize and submit the draw data.
og::Render();
og::DrawData* draw_data = og::GetDrawData();
// RendererBackend_RenderDrawData(draw_data);The exact backend entry-point names depend on the selected osgui_impl_*.h integration. Follow its header and example rather than copying names from another backend.
At shutdown, release renderer and platform resources before destroying the context:
// RendererBackend_Shutdown();
// PlatformBackend_Shutdown();
og::DestroyContext(context);Do not destroy textures, font data, or graphics devices while a renderer backend can still reference them.
OSGui v2 records input events through IO helper methods. A backend should translate native events into this named-key and pointer API instead of writing OSGui's state arrays directly:
og::IO& io = og::GetIO();
io.AddMousePosEvent(mouse_x, mouse_y);
io.AddMouseButtonEvent(0, left_button_down);
io.AddMouseWheelEvent(wheel_x, wheel_y);
io.AddKeyEvent(og::Key_Enter, enter_down);
io.AddInputCharacter(static_cast<unsigned int>('A'));
io.AddFocusEvent(window_has_focus);Set the backend name and only the BackendFlags that the integration actually supports. Focus-loss handling matters: report it so OSGui can avoid leaving keys or pointer buttons stuck after the native window loses focus.
Applications using the Win32 backend must forward relevant window messages to its handler. Applications using the GLFW platform backend must also arrange a compatible font-atlas upload through their renderer integration; the platform layer does not invent renderer resources.
See Architecture: input contract for the event lifecycle and ownership rules.
Visible labels are not always unique. Use ID scopes around repeated controls so the same label produces distinct persistent state:
for (int row = 0; row < row_count; ++row) {
og::PushID(row);
og::Checkbox("Enabled", &rows[row].enabled);
og::PopID();
}Scoped style and disabled state use paired push/pop calls:
og::PushStyleColor(og::Col_Button, OG_COL32(51, 115, 204, 255));
og::PushItemWidth(180.0f);
og::SliderFloat("Exposure", &exposure, -4.0f, 4.0f);
og::PopItemWidth();
og::PopStyleColor();Every Begin/End, BeginChild/EndChild, and push/pop pair must balance in the same frame. ValidateState() and the built-in Metrics Studio are designed to expose mistakes while developing an integration.
Use a child region to create an independently scrollable area, and ListClipper to submit only rows that can be visible:
og::BeginChild("event_log", og::Vec2(0.0f, 260.0f), og::ChildFlags_Borders);
og::ListClipper clipper;
clipper.Begin(event_count);
while (clipper.Step()) {
for (int i = clipper.display_start; i < clipper.display_end; ++i) {
og::Text("Event %d", i);
}
}
clipper.End();
og::EndChild();The clipper reduces item submission work; it does not virtualize your application data. Keep item heights predictable for the best result.
OSGui can save and load v2 JSON state through files or memory. This is intended for OSGui-owned UI state, not as a general application data format.
og::SaveStateJSON("ui-state.json");
// Later, with a compatible current context:
if (!og::LoadStateJSON("ui-state.json")) {
const char* error = og::GetLastError();
// Log or display error.
}Treat state files as versioned input. The file loader enforces a 16 MiB limit, checks the supported schema range, clamps accepted numeric fields, and reports failures through GetLastError(). Re-save successfully imported older state to move it to the v2 schema; do not assume future alpha builds will preserve every serialized field.
GetDrawData() exposes data owned by the current context. It is normally consumed immediately after Render(). If another subsystem needs an owned copy - for capture, deferred inspection, or controlled handoff - use DrawDataSnapshot rather than retaining raw pointers into live frame storage.
Snapshots solve draw-data lifetime, not graphics-resource lifetime. The application still owns every texture represented by a TextureID, and the receiving renderer must understand callbacks, vertex offsets, clip rectangles, and effect fallbacks.
The built-in themes are Dark, Light, and High Contrast. Reduced-motion mode suppresses optional motion so an application can respect an accessibility preference. These features improve baseline usability, but they do not replace application-level accessibility testing, semantic navigation, or platform assistive-technology integration.
Headers and the linked OSGui library come from different builds. Remove stale artifacts, rebuild, and verify that the include path and linked package resolve to the same installation.
Create a context before calling frame or widget APIs, and call
SetCurrentContext() when switching between contexts owned by the current
thread. Keep each context on its creating thread for its entire lifetime,
including destruction; selecting a context is not a thread-migration mechanism.
Verify that the font atlas was built, uploaded by the renderer backend, and assigned a live texture for the duration of rendering. The Win32 GDI atlas path is deliberately bounded and does not provide full Unicode shaping, bidirectional layout, or exhaustive CJK coverage.
Forward focus events and both press and release transitions. For Win32, make sure the native message handler receives the messages documented by the backend. For GLFW, ensure callbacks are installed or chained as expected by the integration.
Effects are capability-dependent. Backends must provide a visible, documented fallback when an effect is unavailable. OpenGL 2 blur uses an expensive framebuffer-copy path, while OpenGL 3 and DirectX 11 currently fall back to tint for unsupported effects.
Audit every Begin/End and push/pop pair, then call ValidateState() and inspect Metrics Studio. Early-return paths are a common source of stack imbalance in immediate-mode code.
The v2 alpha does not yet provide:
- IME composition, grapheme-cluster-aware editing, bidirectional layout, and full native desktop text-control semantics;
- a complete docking system;
- multi-viewport platform windows;
- a Vulkan renderer;
- feature parity or performance parity with Dear ImGui across all workloads.
Start with the architecture guide when writing a backend, and read the v2 migration guide before porting a 0.x integration.