An immediate-mode, renderer agnostic, lightweight debug drawing API for C++

Overview

Debug Draw

Build Status

An immediate-mode, renderer agnostic, lightweight debug drawing API for C++.

Debug Draw

License

This software is in the public domain. Where that dedication is not recognized, you are granted a perpetual, irrevocable license to copy, distribute, and modify the source code as you see fit.

The source code is provided "as is", without warranty of any kind, express or implied. No attribution is required, but a mention about the author(s) is appreciated.

Using Debug Draw

Debug Draw is a single source file library, so the "header" forward declarations and the implementation are contained in the same file (debug_draw.hpp). This should facilitate deployment and integration with your own projects. All you have to do is #include the library file in one of your own source files and define DEBUG_DRAW_IMPLEMENTATION in that file to generate the implementation. You can also still include the library in other places. When DEBUG_DRAW_IMPLEMENTATION is not defined, it acts as a normal C++ header file. Example:

In my_program.cpp:

#define DEBUG_DRAW_IMPLEMENTATION
#include "debug_draw.hpp"

Now in my_program.hpp or any other header or source file, you can include it as a normal C++ header:

#include "debug_draw.hpp"

That's it, you should now be able to build Debug Draw into your own application.

Interfacing with your renderer

Debug Draw doesn't make assumptions about the underlaying renderer API, so it can be integrated very easily with Direct3D or OpenGL or any other rendering engine of your choice. All that is required is that you provide an implementation for the dd::RenderInterface abstract class, which provides Debug Draw with basic methods to draw points, lines and character glyphs. The following is what dd::RenderInterface looks like:

class RenderInterface
{
public:
    virtual void beginDraw();
    virtual void endDraw();

    virtual GlyphTextureHandle createGlyphTexture(int width, int height, const void * pixels);
    virtual void destroyGlyphTexture(GlyphTextureHandle glyphTex);

    virtual void drawPointList(const DrawVertex * points, int count, bool depthEnabled);
    virtual void drawLineList(const DrawVertex * lines, int count, bool depthEnabled);
    virtual void drawGlyphList(const DrawVertex * glyphs, int count, GlyphTextureHandle glyphTex);

    virtual ~RenderInterface() = 0;
};

Not all methods have to be implemented, you decide which features to support! Look into the source code for the declaration of RenderInterface. Each method is well commented and describes the expected behavior that you should implement. For reference implementations of the RenderInterface using standard APIs like OpenGL, refer to the samples/ directory in this project.

Once you implement a RenderInterface for your renderer, all you need to do before starting to use Debug Draw is to call dd::initialize() passing it a pointer to your custom RenderInterface:

MyRenderInterface renderIface;
dd::initialize(&renderIface);

Note however that Debug Draw batches all primitives to reduce the number of calls to RenderInterface, so drawing will only actually take place by the time you call dd::flush(), which is normally done at the end of a frame, before flipping the screen buffers:

// You only have to pass the current time if you have timed debug
// draws in the queues. Otherwise just omit the argument or pass 0.
dd::flush(getTimeMilliseconds());

So the overall setup should look something like the following:

class MyRenderInterface : public dd::RenderInterface
{
    // Cherrypick the methods you want to implement or implement them all
    ...
};

int main()
{
    MyRenderInterface renderIface;
    dd::initialize(&renderIface);

    while (!quitting)
    {
        // Any other drawing that you already do
        ...

        // Call any dd:: functions to add debug primitives to the draw queues
        ...

        dd::flush(getTimeMilliseconds());

        // Swap buffers to present the scene
        ...
    }

    dd::shutdown();
}

Configuration switches

Debug Draw provides several compiler switches for library configuration and customization. Check the documentation in debug_draw.hpp for a list of all switches plus detailed description of each.

Language/compiler requirements

The library has very few language requirements. One of its main goals is to be painless to integrate and portable. The only requirement is a fairly recent C++ compiler with minimal Standard Library support. Some C++11 features are assumed, such as nullptr and . The samples included make heavier use of the C++ Standard Library to demonstrate Debug Draw usage with threads.

RTTI and C++ Exceptions are not used, so you should have no problems integrating the library with projects that disable those features.

The memory footprint is also small and you can manage the amount of memory that gets committed to the internal queues via preprocessor directives. We currently only allocate a small amount of dynamic memory at library startup to decompress the font glyphs for the debug text drawing functions and for the draw queues and library context data.

Thread safety and explicit contexts

By default, Debug Draw will use a static global context internally, providing a procedural-style API that is not thread safe. This is the "classic" Debug Draw mode that is the easiest to use and set up, but the library also supports two other modes that are thread safe and configurable at compile time:

  • DEBUG_DRAW_PER_THREAD_CONTEXT: If this is defined before the implementation, the library will use a thread-local context instead of the global shared default. This allows calling the library from different threads since each will keep its private context and draw queues. This mode provides the same public library interface but requires TLS (Thread Local Storage) support from the compiler.

  • DEBUG_DRAW_EXPLICIT_CONTEXT: If this is defined before the implementation, the library expects the user to supply a handle to a context. This mode exposes the dd::ContextHandle type and changes each function in the library to take this handle as the first argument. This mode makes the library fully stateless, so that each rendering thread that calls into the library can create and maintain its own instance of Debug Draw.

The explicit context mode is a cleaner and more functional-style API and should be the preferred one for new users. The procedural mode is still kept as the default for compatibility with older library versions, but it is recommended that you use the explicit context mode by adding #define DEBUG_DRAW_EXPLICIT_CONTEXT together with DEBUG_DRAW_IMPLEMENTATION. In the future, the procedural stateful API will be deprecated in favor of the explicit one.

Samples

Drawing a box with a set of coordinate axes in its center:

const ddVec3 boxColor  = { 0.0f, 0.8f, 0.8f };
const ddVec3 boxCenter = { 0.0f, 0.0f, 3.0f };

dd::box(boxCenter, boxColor, 1.5f, 1.5f, 1.5f);
dd::cross(boxCenter, 1.0f);

box

To visualize a matrix transform, you can use dd::axisTriad() to draw the transform as three arrows:

const ddMat4x4 transform = { // The identity matrix
    1.0f, 0.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 0.0f, 1.0f
};
dd::axisTriad(transform, 0.3f, 2.0f);

arrows

More complex samples and examples on how to integrate Debug Draw with your own renderer can be found inside the samples/ directory. Each function provided in the public API is also well documented in the header file. You will find a descriptive header comment before the prototype of each public function exported by the library.

Comments
  • Added optional thread-safety without breaking the existing API.

    Added optional thread-safety without breaking the existing API.

    Hi, most of my use-cases for generating debug geometry occur within my gameplay code, which is running on different thread(s) to my rendering code (which produces the D3D/GL calls), so I needed to clean up the global data storage into a context object to make the library usable. I've tried to do it in a way that leaves the API exactly the same for users who don't need this feature, but also makes the library usable by people who need this feature.

    opened by hodgman 3
  • The usage of gl3winit() is incorrect

    The usage of gl3winit() is incorrect

    https://github.com/glampert/debug-draw/blob/master/samples/sample_gl_core.cpp#L764

    The function actually returns 0 on success, so the operator! should be removed.

    opened by YukinoHayakawa 1
  • `undefined reference` issues

    `undefined reference` issues

    Hey,

    I'm trying to integrate this header into my project. I've basically defined a .cpp and .hpp file which override the RenderInterface class. My setup is based off the sample_gl_core.cpp example. However I'm getting some linker errors when trying to compile, like these:

    undefined reference to `dd::xzSquareGrid(float, float, float, float, float const*, int, bool)'
    undefined reference to `dd::colors::Green'
    undefined reference to `dd::RenderInterface::~RenderInterface()'
    

    I have included the following

    #define DEBUG_DRAW
    #include <debug_draw.hpp>
    

    in my .cpp file. So I'm not sure where the error could be. Do you have any ideas on this?

    [edit] My bad, I mistakenly was using #define DEBUG_DRAW instead of #define DEBUG_DRAW_IMPLEMENTATION

    opened by frutas-fruit 0
  • Big library update

    Big library update

    I've just pushed a big update to Debug Draw: https://github.com/glampert/debug-draw/commit/286e1d7bb39d61af28efdc72314ee164686cf835

    This update includes several improvements and multi-threading support, with some minor API changes that could break existing users. Migration to this version should be straightforward.

    Hope everyone finds it useful. Thanks!

    enhancement 
    opened by glampert 0
  • Suggestions

    Suggestions

    Hey dude, good work.

    I've wondering if you plan to add eventually:

    • line thickness
    • line style { dotted ... , slashed _ _ _ , dotslashed . _ . _ . and/or others }
    • line alpha lerp { lerp between 0.0 at midpoint and 1.0 at every edge }

    keep up the good work

    enhancement 
    opened by r-lyeh-archived 4
Owner
Guilherme Lampert
Guilherme Lampert
Im3d is a small, self-contained library for immediate mode rendering of basic primitives

Im3d is a small, self-contained library for immediate mode rendering of basic primitives (points, lines, triangles), plus an immediate mode UI which provides 3d manipulation 'gizmos' and other tools. It is platform and graphics API agnostic and designed to be compatible with VR.

John Chapman 835 Jan 2, 2023
A real-time DirectX 11 renderer. The renderer is named by my girlfriend's english name.

sophia Sophia is a real-time DirectX 11 renderer. It is not quite a rich graphics engine, only packages some low-level DirectX functions and contains

BB 6 Dec 11, 2021
Cross-platform, graphics API agnostic, "Bring Your Own Engine/Framework" style rendering library.

bgfx - Cross-platform rendering library GitHub Discussions Discord Chat What is it? Cross-platform, graphics API agnostic, "Bring Your Own Engine/Fram

Бранимир Караџић 12.6k Jan 8, 2023
Legion Low Level Rendering Interface provides a graphics API agnostic rendering interface with minimal CPU overhead and low level access to verbose GPU operations.

Legion-LLRI Legion-LLRI, or “Legion Low Level Rendering Interface” is a rendering API that aims to provide a graphics API agnostic approach to graphic

Rythe Interactive 25 Dec 6, 2022
Antialiased 2D vector drawing library on top of OpenGL for UI and visualizations.

This project is not actively maintained. NanoVG NanoVG is small antialiased vector graphics rendering library for OpenGL. It has lean API modeled afte

Mikko Mononen 4.6k Jan 2, 2023
Pencil2D is an animation/drawing software for Windows, macOS, Linux, and FreeBSD.

Pencil2D is an animation/drawing software for Windows, macOS, Linux, and FreeBSD. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D is free and open source.

Pencil2D 1.2k Jan 7, 2023
A very simple and light-weight drawing app made with qt and C++.

Blackboard A very simple and light-weight drawing app made with qt and C++. It supports tablet and pen pressure with the help of QTabletEvents. So you

null 1 Nov 15, 2021
SPIRV-Reflect is a lightweight library that provides a C/C++ reflection API for SPIR-V shader bytecode in Vulkan applications.

SPIRV-Reflect SPIRV-Reflect is a lightweight library that provides a C/C++ reflection API for SPIR-V shader bytecode in Vulkan applications. SPIRV-Ref

The Khronos Group 457 Dec 26, 2022
A toy renderer written in C using Vulkan to perform real-time ray tracing research.

This is a toy renderer written in C using Vulkan. It is intentionally minimalist. It has been developed and used for the papers "BRDF Importance Sampl

Christoph Peters 290 Dec 19, 2022
physically based renderer written in DX12 with image-based lighting, classic deffered and tiled lighting approaches

Features Classical Deferred Renderer Physically Based shading Image Based Lighting BRDF Disney model (Burley + GGX) Tangent space normal mapping Reinh

Alena 35 Dec 13, 2022
2D GPU renderer for dynamic UIs

vger vger is a vector graphics renderer which renders a limited set of primitives, but does so almost entirely on the GPU. Works on iOS and macOS. API

Audulus LLC 172 Dec 30, 2022
PainterEngine is a application/game engine with software renderer,PainterEngine can be transplanted to any platform that supports C

PainterEngine is a application/game engine with software renderer,PainterEngine can be transplanted to any platform that supports C

DBinary 1.6k Jan 4, 2023
work in progress 3d renderer based on sdl2

work in progress 3d software renderer based on SDL. (Only supports wireframe view for now) Building On Linux, install libsdl2 and then run the folowin

null 4 Sep 12, 2021
work in progress 3d renderer based on sdl2

work in progress 3d software renderer based on SDL. (Only supports wireframe view for now) Building On Linux, install libsdl2 and then run the folowin

Jayachandra Kasarla 4 Sep 12, 2021
Ipsys Particle System Yey letS go, very cool particle system generator and fast renderer

ipsys - Ipsys Particle System Yey letS go About Ipsys is a piece of software that focuces on running and displaying cool randomly generated particule

Anima Libera 5 May 26, 2022
A modern C++ physically based renderer

The Dakku Renderer Warning: This project is currently under developing and does not guarantee any consistency. About Dakku is a physically based rende

xehoth 6 Apr 15, 2022
A Simple Spectral Renderer

Simple Spectral This is a simple multithreaded spectral pathtracer implementing the algorithm (linear combination of bases) described in our EGSR 2019

Ian Mallett 161 Dec 8, 2022
Source code for pbrt, the renderer described in the third edition of "Physically Based Rendering: From Theory To Implementation", by Matt Pharr, Wenzel Jakob, and Greg Humphreys.

pbrt, Version 3 This repository holds the source code to the version of pbrt that is described in the third edition of Physically Based Rendering: Fro

Matt Pharr 4.4k Jan 7, 2023
A dx12 river renderer using wave particles with interactive vortices.

Wave Particles with Interactive Vortices Final Result Overview In game industry water can be divided into two domains, ocean and river. This project f

ACskyline 221 Dec 26, 2022