diff --git a/demo/data/debug_frag.glsl b/demo/data/debug_frag.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..2eb3d7dd24a5436602d83acbe5ac14203e0049c1
--- /dev/null
+++ b/demo/data/debug_frag.glsl
@@ -0,0 +1,9 @@
+#version 150
+
+in  vec4 v_Color;
+out vec4 out_FragColor;
+
+void main()
+{
+    out_FragColor = v_Color;
+}
\ No newline at end of file
diff --git a/demo/data/debug_vert.glsl b/demo/data/debug_vert.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..b02778e76af3d77553028b2f36d515f07c547408
--- /dev/null
+++ b/demo/data/debug_vert.glsl
@@ -0,0 +1,14 @@
+#version 150
+
+in vec3 in_Position;
+in vec4 in_ColorPointSize;
+
+out vec4 v_Color;
+uniform mat4 u_MvpMatrix;
+
+void main()
+{
+    gl_Position  = u_MvpMatrix * vec4(in_Position, 1.0);
+    gl_PointSize = in_ColorPointSize.w;
+    v_Color      = vec4(in_ColorPointSize.xyz, 1.0);
+}
\ No newline at end of file
diff --git a/demo/demo/rollball.cpp b/demo/demo/rollball.cpp
index 640b801d99b1d697c0cc4889927b80a21bbf61eb..4b7c8b70dcb0caca4e63b676f0d89308371251a0 100644
--- a/demo/demo/rollball.cpp
+++ b/demo/demo/rollball.cpp
@@ -94,7 +94,9 @@ static void setupPrefabs(fggl::ecs3::World& world, Prefabs& prefabs) {
 		prefabs.player = world.create(true);
 		world.add<fggl::math::Transform>(prefabs.player);
 		world.add<fggl::phys::Dynamics>(prefabs.player);
-		world.add<fggl::phys::RigidBody>(prefabs.player);
+
+		auto rb = world.add<fggl::phys::RigidBody>(prefabs.player);
+		rb->shape = new fggl::phys::Sphere(1.0f);
 
 		fggl::data::StaticMesh meshComponent;
 		meshComponent.pipeline = "phong";
diff --git a/fggl/data/model.cpp b/fggl/data/model.cpp
index 157c2a5067123fd7075748853b32d4ac5282c02b..f1bb7733140d657ad949cbb9f25e25bc9c835d7e 100644
--- a/fggl/data/model.cpp
+++ b/fggl/data/model.cpp
@@ -26,7 +26,6 @@ Mesh::IndexType Mesh::indexOf(Vertex term) {
 		return INVALID_IDX;
 	}
 	return itr - m_verts.begin();
-
 }
 
 void Mesh::removeDups() {
diff --git a/fggl/data/procedural.cpp b/fggl/data/procedural.cpp
index 2598f7220631dd8ce4bc4850d954f10fab6ac06a..e98dce6b20b6482d7cbcbd7c0aea035fd359688b 100644
--- a/fggl/data/procedural.cpp
+++ b/fggl/data/procedural.cpp
@@ -120,20 +120,21 @@ namespace fggl::data {
 
 	static void quads2Tris(std::vector<Mesh::IndexType>& indexList, int stacks, int slices) {
 		const auto HORZ_SIZE = slices + 1;
+
 		for (int vertical = 0; vertical < stacks; vertical++) {
 			for (int horz = 0; horz < slices; horz++) {
-				int lt = vertical * HORZ_SIZE + horz;
-				int rt = vertical * HORZ_SIZE + (horz + 1);
-				int lb = (vertical + 1) * HORZ_SIZE + horz;
-				int rb = (vertical + 1) * HORZ_SIZE + (horz + 1);
-
-				indexList.push_back(lt);
-				indexList.push_back(lb);
-				indexList.push_back(rt);
-
-				indexList.push_back(rt);
-				indexList.push_back(lb);
-				indexList.push_back(rb);
+				const int topLeft = vertical * HORZ_SIZE + horz;
+				const int topRight = vertical * HORZ_SIZE + (horz + 1);
+				const int bottomLeft = (vertical + 1) * HORZ_SIZE + horz;
+				const int bottomRight = (vertical + 1) * HORZ_SIZE + (horz + 1);
+
+				indexList.push_back(topLeft);
+				indexList.push_back(bottomLeft);
+				indexList.push_back(topRight);
+
+				indexList.push_back(topRight);
+				indexList.push_back(bottomLeft);
+				indexList.push_back(bottomRight);
 			}
 		}
 	}
@@ -204,7 +205,7 @@ fggl::data::Mesh fggl::data::make_quad_xy() {
 	};
 
 	fggl::data::Mesh mesh;
-	std::array<int,4> colIdx;
+	std::array<int,4> colIdx{};
 	for (int i = 0; i < 4; ++i){
 		colIdx[ i ] = mesh.pushVertex( Vertex::from_pos(pos[i]));
 	}
@@ -217,25 +218,25 @@ fggl::data::Mesh fggl::data::make_quad_xy() {
 }
 
 fggl::data::Mesh fggl::data::make_quad_xz() {
-	constexpr fggl::math::vec3 pos[] {
-		{-0.5F, 0.0F, -0.5F},
-		{ 0.5F, 0.0F, -0.5F},
-		{ 0.5F, 0.0F,  0.5F},
-		{-0.5F, 0.0F,  0.5F}
-	};
-	constexpr int idx[] {
-		0, 1, 3,
-		3, 1, 2
-	};
+	constexpr std::array<fggl::math::vec3, 4> pos {{
+													   {-0.5F, 0.0F, -0.5F},
+													   {0.5F, 0.0F, -0.5F},
+													   {0.5F, 0.0F, 0.5F},
+													   {-0.5F, 0.0F, 0.5F}
+												   }};
+	constexpr std::array<int, 6> idx {{
+										  0, 1, 3,
+										  3, 1, 2
+									  }};
 
 	fggl::data::Mesh mesh;
-	int colIdx[4];
+	std::array<int, 4> colIdx{};
 	for (int i = 0; i < 4; ++i){
 		colIdx[ i ] = mesh.pushVertex( Vertex::from_pos(pos[i]) );
 	}
 
 	for( auto i : idx ) {
-		mesh.pushIndex( colIdx[ i ] );
+		mesh.pushIndex(colIdx.at( i ));
 	}
 
 	return mesh;
diff --git a/fggl/debug/CMakeLists.txt b/fggl/debug/CMakeLists.txt
index 85b947df5b1abd1cc81234954d2aca22aab8b80b..09ac442d3f89228ef3919e9969172f3b165e4b38 100644
--- a/fggl/debug/CMakeLists.txt
+++ b/fggl/debug/CMakeLists.txt
@@ -1,6 +1,7 @@
 target_sources(fggl
     PRIVATE
-	debug.cpp
+		debug.cpp
+		debug_draw.cpp
 	
 	# imgui
 	imgui/imgui.cpp
diff --git a/fggl/debug/debug_draw.cpp b/fggl/debug/debug_draw.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b34718c4f6edf95095ee19ba6c628d790a3ea3f1
--- /dev/null
+++ b/fggl/debug/debug_draw.cpp
@@ -0,0 +1,26 @@
+/*
+ * ${license.title}
+ * Copyright (C) 2022 ${license.owner}
+ * ${license.mailto}
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+//
+// Created by webpigeon on 30/05/22.
+//
+
+#define DEBUG_DRAW_IMPLEMENTATION
+#include "fggl/debug/draw.hpp"
\ No newline at end of file
diff --git a/fggl/gfx/ogl/renderer.cpp b/fggl/gfx/ogl/renderer.cpp
index 2f0de497c9290b3976577622258fcd4c36ee6307..c51a07058920489710f22cf8ff58c9fde11d05a7 100644
--- a/fggl/gfx/ogl/renderer.cpp
+++ b/fggl/gfx/ogl/renderer.cpp
@@ -4,11 +4,10 @@
 #include "fggl/gfx/ogl/common.hpp"
 #include "fggl/gfx/window.hpp"
 
-#include <fggl/data/model.hpp>
 #include <fggl/gfx/camera.hpp>
 #include <fggl/gfx/ogl/renderer.hpp>
 #include <fggl/gfx/paint.hpp>
-#include <fggl/math/triangulation.hpp>
+#include "fggl/data/model.hpp"
 
 #include <glm/ext/matrix_clip_space.hpp>
 #include <glm/ext/matrix_transform.hpp>
@@ -160,6 +159,11 @@ namespace fggl::gfx {
 		// rendering helpers
 		m_canvasRenderer = std::make_unique<ogl4::CanvasRenderer>();
 		m_modelRenderer = std::make_unique<ogl4::StaticModelRenderer>(m_cache.get());
+
+		m_debugRenderer = std::make_unique<ogl4::DebugRenderer>(m_cache->getOrLoad(ShaderFromName("debug")));
+		if ( m_debugRenderer ) {
+			dd::initialize(m_debugRenderer.get());
+		}
 	};
 
 	void OpenGL4Backend::clear() {
@@ -180,6 +184,20 @@ namespace fggl::gfx {
 		if ( m_modelRenderer ) {
 			m_modelRenderer->render(world);
 		}
+
+		if ( m_debugRenderer ) {
+			auto cameras = world.findMatching<gfx::Camera>();
+			auto cameraEnt = cameras[0];
+
+			auto* const camTransform = world.get<math::Transform>(cameraEnt);
+			auto* const camComp = world.get<gfx::Camera>(cameraEnt);
+
+			const math::mat4 projectionMatrix = glm::perspective(camComp->fov, camComp->aspectRatio, camComp->nearPlane, camComp->farPlane);
+			const math::mat4 viewMatrix = glm::lookAt( camTransform->origin(), camComp->target, camTransform->up() );
+			m_debugRenderer->mvpMatrix = projectionMatrix * viewMatrix;
+
+			dd::flush();
+		}
 	}
 
 	void OpenGL4Backend::resize(int width, int height) {
diff --git a/fggl/gfx/ogl4/CMakeLists.txt b/fggl/gfx/ogl4/CMakeLists.txt
index 0b9e81784f74f840f0b28ac7a9c609bc346aba38..3b0954f68c4e5684f794b4842b8e6cdac7efbd59 100644
--- a/fggl/gfx/ogl4/CMakeLists.txt
+++ b/fggl/gfx/ogl4/CMakeLists.txt
@@ -4,4 +4,5 @@ target_sources(fggl
     PRIVATE
 		canvas.cpp
 		models.cpp
+		debug.cpp
 )
diff --git a/fggl/gfx/ogl4/debug.cpp b/fggl/gfx/ogl4/debug.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6f40f1dbecb16428aa951484130265865f74d57a
--- /dev/null
+++ b/fggl/gfx/ogl4/debug.cpp
@@ -0,0 +1,75 @@
+/*
+ * ${license.title}
+ * Copyright (C) 2022 ${license.owner}
+ * ${license.mailto}
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+//
+// Created by webpigeon on 30/05/22.
+//
+
+#include "fggl/debug/draw.hpp"
+#include "fggl/gfx/ogl/types.hpp"
+#include "fggl/gfx/ogl4/debug.hpp"
+
+#include <cassert>
+
+namespace fggl::gfx::ogl4 {
+
+
+	DebugRenderer::DebugRenderer(GLuint shader) :
+		mvpMatrix(1.0f),
+		m_lineShader(shader),
+		m_lineShaderMVP( m_lineShader.uniform("u_MvpMatrix")) {
+		// define our attributes
+		auto posAttr = ogl::attribute<dd::DrawVertex, math::vec3>( 0 );
+		auto colAttr = ogl::attribute<dd::DrawVertex, math::vec3>( sizeof(float) * 3 );
+
+		// bind the attributes to the vao
+		m_lineVao.setAttribute(m_lineVbo, 0, posAttr);
+		m_lineVao.setAttribute(m_lineVbo, 1, colAttr);
+	}
+
+	void DebugRenderer::drawLineList(const dd::DrawVertex * lines, int count, bool depthEnabled)
+	{
+		assert(lines != nullptr);
+		assert(count > 0 && count <= DEBUG_DRAW_VERTEX_BUFFER_SIZE);
+
+		m_lineVao.bind();
+		m_lineShader.use();
+		m_lineShader.setUniformMtx(m_lineShaderMVP, mvpMatrix);
+
+		if (depthEnabled)
+		{
+			glEnable(GL_DEPTH_TEST);
+		}
+		else
+		{
+			glDisable(GL_DEPTH_TEST);
+		}
+
+		m_lineVbo.bind();
+		m_lineVbo.replace<dd::DrawVertex>(count, lines);
+
+		m_lineVao.draw(ogl::Primative::LINE, 0, count);
+
+		glUseProgram(0);
+		glBindVertexArray(0);
+		glBindBuffer(GL_ARRAY_BUFFER, 0);
+	}
+
+} // namespace fggl::gfx::ogl4
\ No newline at end of file
diff --git a/fggl/phys/bullet/CMakeLists.txt b/fggl/phys/bullet/CMakeLists.txt
index 54d35e509bfac7bcc27633afad4d22c2e8317f14..1a6d67e47406c2d5ed9760bd6039769b095ddb1f 100644
--- a/fggl/phys/bullet/CMakeLists.txt
+++ b/fggl/phys/bullet/CMakeLists.txt
@@ -7,5 +7,6 @@ target_link_libraries(fggl PUBLIC Bullet::Bullet )
 target_sources(fggl
         PRIVATE
             simulation.cpp
+            phys_draw.cpp
 )
 
diff --git a/fggl/phys/bullet/phys_draw.cpp b/fggl/phys/bullet/phys_draw.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4cd4475f893580a5924871a8dcddb660177bf11f
--- /dev/null
+++ b/fggl/phys/bullet/phys_draw.cpp
@@ -0,0 +1,79 @@
+/*
+ * ${license.title}
+ * Copyright (C) 2022 ${license.owner}
+ * ${license.mailto}
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+//
+// Created by webpigeon on 30/05/22.
+//
+
+#include "fggl/phys/bullet/phys_draw.hpp"
+#include "fggl/debug/draw.hpp"
+
+#include <iostream>
+
+namespace fggl::debug {
+
+	using btdd = debug::BulletDebugDrawList;
+
+	void btdd::drawLine(const btVector3 &from,
+				  const btVector3 &to,
+				  const btVector3 &fromColour,
+				  const btVector3 &toColour) {
+		dd::line(from, to, fromColour);
+	}
+
+	void btdd::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &colour)  {
+		dd::line(from, to, colour);
+	}
+
+	void btdd::drawSphere(const btVector3 &p, btScalar radius, const btVector3 &color) {
+		dd::sphere(p, color, radius);
+	}
+
+	void btdd::drawTriangle(const btVector3 &a,
+					  const btVector3 &b,
+					  const btVector3 &c,
+					  const btVector3 &color,
+					  btScalar alpha) {
+		dd::line(a, b, color);
+		dd::line(b, c, color);
+		dd::line(c, a, color);
+	}
+
+	void btdd::drawContactPoint(const btVector3 &PointOnB,
+						  const btVector3 &normalOnB,
+						  btScalar distance,
+						  int lifeTime,
+						  const btVector3 &color) {
+
+	}
+
+	void btdd::reportErrorWarning(const char *warningString)  {
+		std::cerr << warningString << std::endl;
+	}
+
+	void btdd::draw3dText(const btVector3 &location, const char *textString) {
+		dd::screenText(textString, location, dd::colors::Wheat);
+	}
+
+	BulletDebugDrawList::BulletDebugDrawList() : m_mode( DBG_DrawAabb ) {
+
+	}
+
+}
\ No newline at end of file
diff --git a/fggl/phys/bullet/simulation.cpp b/fggl/phys/bullet/simulation.cpp
index 9e028e0b36fd033cdbe0d7bf63c08cd878d2b2cb..5524cf55640c8afcd4b61d6d269d5079d5cf875e 100644
--- a/fggl/phys/bullet/simulation.cpp
+++ b/fggl/phys/bullet/simulation.cpp
@@ -33,6 +33,10 @@ namespace fggl::phys::bullet {
 			m_config.broadphase,
 			m_config.solver,
 			m_config.collisionConfiguration);
+
+		m_debug = std::make_unique<debug::BulletDebugDrawList>();
+		m_world->setDebugDrawer( m_debug.get() );
+		m_debug->setDebugMode(1);
 	}
 
 	void BulletPhysicsEngine::step() {
@@ -48,13 +52,18 @@ namespace fggl::phys::bullet {
 			}
 
 			const auto forceVec = dynamicComp->force;
-			bulletProxy->body->applyCentralForce( {forceVec.x, forceVec.y, forceVec.z} );
-			dynamicComp->force = math::VEC3_ZERO;
+			if ( glm::length(forceVec) != 0.F ) {
+				bulletProxy->body->applyCentralForce({forceVec.x, forceVec.y, forceVec.z});
+				bulletProxy->body->activate();
+				dynamicComp->force = math::VEC3_ZERO;
+			}
 		}
 
 		m_world->stepSimulation(60.0f);
 		syncToECS();
 		dealWithCollisions();
+
+		m_world->debugDrawWorld();
 	}
 
 	static void build_motation_state(math::Transform* myState, BulletBody* btState) {
diff --git a/include/fggl/debug/draw.hpp b/include/fggl/debug/draw.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..66c56aecb65773bfc2b4d53f00782257e97a9695
--- /dev/null
+++ b/include/fggl/debug/draw.hpp
@@ -0,0 +1,3299 @@
+
+// ================================================================================================
+// -*- C++ -*-
+// File:   debug_draw.hpp
+// Author: Guilherme R. Lampert
+// Brief:  Debug Draw - an immediate-mode, renderer agnostic, lightweight debug drawing API.
+// ================================================================================================
+
+#ifndef DEBUG_DRAW_HPP
+#define DEBUG_DRAW_HPP
+
+// ========================================================
+// Library Overview:
+// ========================================================
+//
+// ---------
+//  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
+// this file 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.
+//
+// -------------
+//  QUICK SETUP
+// -------------
+// In *one* C++ source file, *before* including this file, do this:
+//
+//   #define DEBUG_DRAW_IMPLEMENTATION
+//
+// To enable the implementation. Further includes of this
+// file *should not* redefine DEBUG_DRAW_IMPLEMENTATION.
+// Example:
+//
+// In my_program.cpp:
+//
+//   #define DEBUG_DRAW_IMPLEMENTATION
+//   #include "debug_draw.hpp"
+//
+// In my_program.hpp:
+//
+//   #include "debug_draw.hpp"
+//
+// ----------------------
+//  COMPILATION SWITCHES
+// ----------------------
+//
+// DEBUG_DRAW_CXX11_SUPPORTED
+//  Enables the use of some C++11 features. If your compiler supports C++11
+//  or better, you should define this switch globally or before every inclusion
+//  of this file. If it is not defined, we try to guess it from the value of the
+//  '__cplusplus' built-in macro constant.
+//
+// DEBUG_DRAW_MAX_*
+//  Sizes of internal intermediate buffers, which are allocated on initialization
+//  by the implementation. If you need to draw more primitives than the sizes of
+//  these buffers, you need to redefine the macros and recompile.
+//
+// DEBUG_DRAW_VERTEX_BUFFER_SIZE
+//  Size in dd::DrawVertex elements of the intermediate vertex buffer used
+//  to batch primitives before sending them to dd::RenderInterface. A bigger
+//  buffer will reduce the number of calls to dd::RenderInterface when drawing
+//  large sets of debug primitives.
+//
+// DEBUG_DRAW_OVERFLOWED(message)
+//  An error handler called if any of the DEBUG_DRAW_MAX_* sizes overflow.
+//  By default it just prints a message to stderr.
+//
+// DEBUG_DRAW_USE_STD_MATH
+//  If defined to nonzero, uses cmath/math.h. If you redefine it to zero before
+//  the library implementation, it will force the use of local replacements
+//  for the Standard Library. This might be useful if you want to avoid the
+//  dependency. It is defined to zero by default (i.e. we use cmath by default).
+//
+// DEBUG_DRAW_*_TYPE_DEFINED
+//  The compound types used by Debug Draw can also be customized.
+//  By default, ddVec3 and ddMat4x4 are plain C-arrays, but you can
+//  redefine them to use your own classes or structures (see below).
+//  ddStr is by default a std::string, but you can redefine it to
+//  a custom string type if necessary. The only requirements are that
+//  it provides a 'c_str()' method returning a null terminated
+//  const char* string and an assignment operator (=).
+//
+// DEBUG_DRAW_STR_DEALLOC_FUNC(str)
+//  If you define a custom string type for ddStr and it requires some
+//  extra cleanup besides the class destructor, you might define this
+//  function macro to perform said cleanup. It is called by dd::clear()
+//  and dd::shutdown() on every instance of the internal DebugString buffer.
+//
+// DEBUG_DRAW_NO_DEFAULT_COLORS
+//  If defined, doesn't add the set of predefined color constants inside
+//  dd::colors:: namespace. Each color is a ddVec3, so you can define this
+//  to prevent adding more global data to the binary if you don't need them.
+//
+// DEBUG_DRAW_PER_THREAD_CONTEXT
+//  If defined, a per-thread global context will be created for Debug Draw.
+//  This allows having an instance of the library for each thread in
+//  your application. You must then call initialize/shutdown/flush/etc
+//  for each thread that wishes to use the library. If this is not
+//  defined it defaults to a single threaded global context.
+//
+// DEBUG_DRAW_EXPLICIT_CONTEXT
+//  If defined, each Debug Draw function will expect and additional argument
+//  (the first one) which is the library context instance. This is an alternative
+//  to DEBUG_DRAW_PER_THREAD_CONTEXT to allow having multiple instances of the
+//  library in the same application. This flag is mutually exclusive with
+//  DEBUG_DRAW_PER_THREAD_CONTEXT.
+//
+// -------------------
+//  MEMORY ALLOCATION
+// -------------------
+// Debug Draw will only perform a couple of memory allocations during startup to decompress
+// the built-in glyph bitmap used for debug text rendering and to allocate the vertex buffers
+// and intermediate draw/batch buffers and context data used internally.
+//
+// Memory allocation and deallocation for Debug Draw will be done via:
+//
+//   DD_MALLOC(size)
+//   DD_MFREE(ptr)
+//
+// These two macros can be redefined if you'd like to supply you own memory allocator.
+// By default, they are defined to use std::malloc and std::free, respectively.
+// Note: If you redefine one, you must also provide the other.
+//
+// --------------------------------
+//  INTERFACING WITH YOUR RENDERER
+// --------------------------------
+// Debug Draw doesn't touch on any renderer-specific aspects or APIs, instead you provide
+// the library with all of it's rendering needs via the dd::RenderInterface abstract class.
+//
+// See the declaration of dd::RenderInterface for details. Not all methods are
+// required. In fact, you could also implement a full no-op RenderInterface that
+// disables debug drawing by simply inheriting from dd::RenderInterface and not overriding
+// any of the methods (or even easier, call dd::initialize(nullptr) to make everything a no-op).
+//
+// For examples on how to implement your own dd::RenderInterface, see the accompanying samples.
+// You can also find them in the source code repository for this project:
+// https://github.com/glampert/debug-draw
+//
+// ------------------
+//  CONVENTIONS USED
+// ------------------
+// Points and lines are always specified in world-space positions. This also
+// applies to shapes drawn from lines, like boxes, spheres, cones, etc.
+//
+// 2D screen-text is in screen-space pixels (from 0,0 in the upper-left
+// corner of the screen to screen_width-1 and screen_height-1).
+// RenderInterface::drawGlyphList() also receives vertexes in screen-space.
+//
+// We make some usage of matrices for things like the projected text labels.
+// Matrix layout used is column-major and vectors multiply as columns.
+// This is the convention normally used by standard OpenGL.
+//
+// C++ Exceptions are not used. Little error checking is provided or
+// done inside the library. We favor simpler, faster and easier to maintain
+// code over more sophisticated error handling. The rationale is that a
+// debug drawing API doesn't have to be very robust, since it won't make
+// into the final release executable in most cases.
+//
+
+// ========================================================
+// Configurable compilation switches:
+// ========================================================
+
+//
+// If the user didn't specify if C++11 or above are supported, try to guess
+// from the value of '__cplusplus'. It should be 199711L for pre-C++11 compilers
+// and 201103L in those supporting C++11, but this is not a guarantee that all
+// C++11 features will be available and stable, so again, we are making a guess.
+// It is recommended to instead supply the DEBUG_DRAW_CXX11_SUPPORTED switch
+// yourself before including this file.
+//
+#ifndef DEBUG_DRAW_CXX11_SUPPORTED
+	#if (__cplusplus > 199711L)
+		#define DEBUG_DRAW_CXX11_SUPPORTED 1
+	#endif // __cplusplus
+#endif // DEBUG_DRAW_CXX11_SUPPORTED
+
+//
+// Max elements of each type at any given time.
+// We supply these reasonable defaults, but you can provide your
+// own tunned values to save memory or fit all of your debug data.
+// These are hard constraints. If not enough, change and recompile.
+//
+#ifndef DEBUG_DRAW_MAX_STRINGS
+	#define DEBUG_DRAW_MAX_STRINGS 512
+#endif // DEBUG_DRAW_MAX_STRINGS
+
+#ifndef DEBUG_DRAW_MAX_POINTS
+	#define DEBUG_DRAW_MAX_POINTS 8192
+#endif // DEBUG_DRAW_MAX_POINTS
+
+#ifndef DEBUG_DRAW_MAX_LINES
+	#define DEBUG_DRAW_MAX_LINES 32768
+#endif // DEBUG_DRAW_MAX_LINES
+
+//
+// Size in vertexes of a local buffer we use to sort elements
+// drawn with and without depth testing before submitting them to
+// the dd::RenderInterface. A larger buffer will require less flushes
+// (e.g. dd::RenderInterface calls) when drawing large amounts of
+// primitives. Less will obviously save more memory. Each DrawVertex
+// is about 32 bytes in size, we keep a context-specific array
+// with this many entries.
+//
+#ifndef DEBUG_DRAW_VERTEX_BUFFER_SIZE
+	#define DEBUG_DRAW_VERTEX_BUFFER_SIZE 4096
+#endif // DEBUG_DRAW_VERTEX_BUFFER_SIZE
+
+//
+// This macro is called with an error message if any of the above
+// sizes is overflowed during runtime. In a debug build, you might
+// keep this enabled to be able to log and find out if more space
+// is needed for the debug data arrays. Default output is stderr.
+//
+#ifndef DEBUG_DRAW_OVERFLOWED
+	#include <cstdio>
+	#define DEBUG_DRAW_OVERFLOWED(message) std::fprintf(stderr, "%s\n", message)
+#endif // DEBUG_DRAW_OVERFLOWED
+
+//
+// Use <math.h> and <float.h> for trigonometry functions by default.
+// If you wish to avoid those dependencies, DD provides local approximations
+// of the required functions as a portable replacement. Just define
+// DEBUG_DRAW_USE_STD_MATH to zero before including this file.
+//
+#ifndef DEBUG_DRAW_USE_STD_MATH
+	#define DEBUG_DRAW_USE_STD_MATH 1
+#endif // DEBUG_DRAW_USE_STD_MATH
+
+// ========================================================
+// Overridable Debug Draw types:
+// ========================================================
+
+#include <cstddef>
+#include <cstdint>
+
+//
+// Following typedefs are not members of the dd:: namespace to allow easy redefinition by the user.
+// If you provide a custom implementation for them before including this file, be sure to
+// also define the proper DEBUG_DRAW_*_TYPE_DEFINED switch to disable the default typedefs.
+//
+// The only requirement placed on the vector/matrix types is that they provide
+// an array subscript operator [] and have the expected number of elements. Apart
+// from that, they could be structs, classes, what-have-you. POD types are recommended
+// but not mandatory.
+//
+
+#ifndef DEBUG_DRAW_VEC3_TYPE_DEFINED
+// ddVec3:
+//  A small array of floats with at least three elements, but
+//  it could have more for alignment purposes, extra slots are ignored.
+//  A custom ddVec3 type must provide the array subscript operator.
+typedef float ddVec3[3];
+
+// ddVec3_In/ddVec3_Out:
+//  Since our default ddVec3 is a plain C-array, it decays to a pointer
+//  when passed as an input parameter to a function, so we can use it directly.
+//  If you change it to some structured type, it might be more efficient
+//  passing by const reference instead, however, some platforms have optimized
+//  hardware registers for vec3s/vec4s, so passing by value might also be efficient.
+typedef const ddVec3 ddVec3_In;
+typedef       ddVec3 ddVec3_Out;
+
+	#define DEBUG_DRAW_VEC3_TYPE_DEFINED 1
+#endif // DEBUG_DRAW_VEC3_TYPE_DEFINED
+
+#ifndef DEBUG_DRAW_MAT4X4_TYPE_DEFINED
+// ddMat4x4:
+//  Homogeneous matrix of 16 floats, representing rotations as well as
+//  translation/scaling and projections. The internal matrix layout used by this
+//  library is COLUMN-MAJOR, vectors multiplying as columns (usual OpenGL convention).
+//  Column-major matrix layout:
+//          c.0   c.1   c.2    c.3
+//    r.0 | 0.x   4.x   8.x    12.x |
+//    r.1 | 1.y   5.y   9.y    13.y |
+//    r.2 | 2.z   6.z   10.z   14.z |
+//    r.3 | 3.w   7.w   11.w   15.w |
+//  If your custom matrix type uses row-major format internally, you'll
+//  have to transpose them before passing your matrices to the DD functions.
+//  We use the array subscript operator internally, so it must also be provided.
+typedef float ddMat4x4[4 * 4];
+
+// ddMat4x4_In/ddMat4x4_Out:
+//  Since our default ddMat4x4 is a plain C-array, it decays to a pointer
+//  when passed as an input parameter to a function, so we can use it directly.
+//  If you change it to some structured type, it might be more efficient
+//  passing by const reference instead.
+typedef const ddMat4x4 ddMat4x4_In;
+typedef       ddMat4x4 ddMat4x4_Out;
+
+	#define DEBUG_DRAW_MAT4X4_TYPE_DEFINED 1
+#endif // DEBUG_DRAW_MAT4X4_TYPE_DEFINED
+
+#ifndef DEBUG_DRAW_STRING_TYPE_DEFINED
+// ddStr:
+//  String type used internally to store the debug text strings.
+//  A custom string type must provide at least an assignment
+//  operator (=) and a 'c_str()' method that returns a
+//  null-terminated const char* string pointer. That's it.
+//  An array subscript operator [] is not required for ddStr.
+	#include <string>
+typedef std::string   ddStr;
+typedef const ddStr & ddStr_In;
+typedef       ddStr & ddStr_Out;
+
+	#define DEBUG_DRAW_STRING_TYPE_DEFINED 1
+#endif // DEBUG_DRAW_STRING_TYPE_DEFINED
+
+namespace dd
+{
+
+// ========================================================
+// Optional built-in colors in RGB float format:
+// ========================================================
+
+#ifndef DEBUG_DRAW_NO_DEFAULT_COLORS
+	namespace colors
+	{
+		extern const ddVec3 AliceBlue;
+		extern const ddVec3 AntiqueWhite;
+		extern const ddVec3 Aquamarine;
+		extern const ddVec3 Azure;
+		extern const ddVec3 Beige;
+		extern const ddVec3 Bisque;
+		extern const ddVec3 Black;
+		extern const ddVec3 BlanchedAlmond;
+		extern const ddVec3 Blue;
+		extern const ddVec3 BlueViolet;
+		extern const ddVec3 Brown;
+		extern const ddVec3 BurlyWood;
+		extern const ddVec3 CadetBlue;
+		extern const ddVec3 Chartreuse;
+		extern const ddVec3 Chocolate;
+		extern const ddVec3 Coral;
+		extern const ddVec3 CornflowerBlue;
+		extern const ddVec3 Cornsilk;
+		extern const ddVec3 Crimson;
+		extern const ddVec3 Cyan;
+		extern const ddVec3 DarkBlue;
+		extern const ddVec3 DarkCyan;
+		extern const ddVec3 DarkGoldenRod;
+		extern const ddVec3 DarkGray;
+		extern const ddVec3 DarkGreen;
+		extern const ddVec3 DarkKhaki;
+		extern const ddVec3 DarkMagenta;
+		extern const ddVec3 DarkOliveGreen;
+		extern const ddVec3 DarkOrange;
+		extern const ddVec3 DarkOrchid;
+		extern const ddVec3 DarkRed;
+		extern const ddVec3 DarkSalmon;
+		extern const ddVec3 DarkSeaGreen;
+		extern const ddVec3 DarkSlateBlue;
+		extern const ddVec3 DarkSlateGray;
+		extern const ddVec3 DarkTurquoise;
+		extern const ddVec3 DarkViolet;
+		extern const ddVec3 DeepPink;
+		extern const ddVec3 DeepSkyBlue;
+		extern const ddVec3 DimGray;
+		extern const ddVec3 DodgerBlue;
+		extern const ddVec3 FireBrick;
+		extern const ddVec3 FloralWhite;
+		extern const ddVec3 ForestGreen;
+		extern const ddVec3 Gainsboro;
+		extern const ddVec3 GhostWhite;
+		extern const ddVec3 Gold;
+		extern const ddVec3 GoldenRod;
+		extern const ddVec3 Gray;
+		extern const ddVec3 Green;
+		extern const ddVec3 GreenYellow;
+		extern const ddVec3 HoneyDew;
+		extern const ddVec3 HotPink;
+		extern const ddVec3 IndianRed;
+		extern const ddVec3 Indigo;
+		extern const ddVec3 Ivory;
+		extern const ddVec3 Khaki;
+		extern const ddVec3 Lavender;
+		extern const ddVec3 LavenderBlush;
+		extern const ddVec3 LawnGreen;
+		extern const ddVec3 LemonChiffon;
+		extern const ddVec3 LightBlue;
+		extern const ddVec3 LightCoral;
+		extern const ddVec3 LightCyan;
+		extern const ddVec3 LightGoldenYellow;
+		extern const ddVec3 LightGray;
+		extern const ddVec3 LightGreen;
+		extern const ddVec3 LightPink;
+		extern const ddVec3 LightSalmon;
+		extern const ddVec3 LightSeaGreen;
+		extern const ddVec3 LightSkyBlue;
+		extern const ddVec3 LightSlateGray;
+		extern const ddVec3 LightSteelBlue;
+		extern const ddVec3 LightYellow;
+		extern const ddVec3 Lime;
+		extern const ddVec3 LimeGreen;
+		extern const ddVec3 Linen;
+		extern const ddVec3 Magenta;
+		extern const ddVec3 Maroon;
+		extern const ddVec3 MediumAquaMarine;
+		extern const ddVec3 MediumBlue;
+		extern const ddVec3 MediumOrchid;
+		extern const ddVec3 MediumPurple;
+		extern const ddVec3 MediumSeaGreen;
+		extern const ddVec3 MediumSlateBlue;
+		extern const ddVec3 MediumSpringGreen;
+		extern const ddVec3 MediumTurquoise;
+		extern const ddVec3 MediumVioletRed;
+		extern const ddVec3 MidnightBlue;
+		extern const ddVec3 MintCream;
+		extern const ddVec3 MistyRose;
+		extern const ddVec3 Moccasin;
+		extern const ddVec3 NavajoWhite;
+		extern const ddVec3 Navy;
+		extern const ddVec3 OldLace;
+		extern const ddVec3 Olive;
+		extern const ddVec3 OliveDrab;
+		extern const ddVec3 Orange;
+		extern const ddVec3 OrangeRed;
+		extern const ddVec3 Orchid;
+		extern const ddVec3 PaleGoldenRod;
+		extern const ddVec3 PaleGreen;
+		extern const ddVec3 PaleTurquoise;
+		extern const ddVec3 PaleVioletRed;
+		extern const ddVec3 PapayaWhip;
+		extern const ddVec3 PeachPuff;
+		extern const ddVec3 Peru;
+		extern const ddVec3 Pink;
+		extern const ddVec3 Plum;
+		extern const ddVec3 PowderBlue;
+		extern const ddVec3 Purple;
+		extern const ddVec3 RebeccaPurple;
+		extern const ddVec3 Red;
+		extern const ddVec3 RosyBrown;
+		extern const ddVec3 RoyalBlue;
+		extern const ddVec3 SaddleBrown;
+		extern const ddVec3 Salmon;
+		extern const ddVec3 SandyBrown;
+		extern const ddVec3 SeaGreen;
+		extern const ddVec3 SeaShell;
+		extern const ddVec3 Sienna;
+		extern const ddVec3 Silver;
+		extern const ddVec3 SkyBlue;
+		extern const ddVec3 SlateBlue;
+		extern const ddVec3 SlateGray;
+		extern const ddVec3 Snow;
+		extern const ddVec3 SpringGreen;
+		extern const ddVec3 SteelBlue;
+		extern const ddVec3 Tan;
+		extern const ddVec3 Teal;
+		extern const ddVec3 Thistle;
+		extern const ddVec3 Tomato;
+		extern const ddVec3 Turquoise;
+		extern const ddVec3 Violet;
+		extern const ddVec3 Wheat;
+		extern const ddVec3 White;
+		extern const ddVec3 WhiteSmoke;
+		extern const ddVec3 Yellow;
+		extern const ddVec3 YellowGreen;
+	} // namespace colors
+#endif // DEBUG_DRAW_NO_DEFAULT_COLORS
+
+// ========================================================
+// Optional explicit context mode:
+// ========================================================
+
+#ifdef DEBUG_DRAW_EXPLICIT_CONTEXT
+	struct OpaqueContextType { };
+    typedef OpaqueContextType * ContextHandle;
+    #define DD_EXPLICIT_CONTEXT_ONLY(...) __VA_ARGS__
+#else // !DEBUG_DRAW_EXPLICIT_CONTEXT
+	#define DD_EXPLICIT_CONTEXT_ONLY(...) /* nothing */
+#endif // DEBUG_DRAW_EXPLICIT_CONTEXT
+
+// ========================================================
+// Debug Draw functions:
+// - Durations are always in milliseconds.
+// - Colors are RGB floats in the [0,1] range.
+// - Positions are in world-space, unless stated otherwise.
+// ========================================================
+
+// Add a point in 3D space to the debug draw queue.
+// Point is expressed in world-space coordinates.
+// Note that not all renderer support configurable point
+// size, so take the 'size' parameter as a hint only
+	void point(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+			   ddVec3_In pos,
+			   ddVec3_In color,
+			   float size = 1.0f,
+			   int durationMillis = 0,
+			   bool depthEnabled = true);
+
+// Add a 3D line to the debug draw queue. Note that
+// lines are expressed in world coordinates, and so are
+// all wireframe primitives which are built from lines.
+	void line(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+			  ddVec3_In from,
+			  ddVec3_In to,
+			  ddVec3_In color,
+			  int durationMillis = 0,
+			  bool depthEnabled = true);
+
+// Add a 2D text string as an overlay to the current view, using a built-in font.
+// Position is in screen-space pixels, origin at the top-left corner of the screen.
+// The third element (Z) of the position vector is ignored.
+// Note: Newlines and tabs are handled (1 tab = 4 spaces).
+	void screenText(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+					const char * str,
+					ddVec3_In pos,
+					ddVec3_In color,
+					float scaling = 1.0f,
+					int durationMillis = 0);
+
+// Add a 3D text label centered at the given world position that
+// gets projected to screen-space. The label always faces the viewer.
+// sx/sy, sw/sh are the viewport coordinates/size, in pixels.
+// 'vpMatrix' is the view * projection transform to map the text from 3D to 2D.
+	void projectedText(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+					   const char * str,
+					   ddVec3_In pos,
+					   ddVec3_In color,
+					   ddMat4x4_In vpMatrix,
+					   int sx, int sy,
+					   int sw, int sh,
+					   float scaling = 1.0f,
+					   int durationMillis = 0);
+
+// Add a set of three coordinate axis depicting the position and orientation of the given transform.
+// 'size' defines the size of the arrow heads. 'length' defines the length of the arrow's base line.
+	void axisTriad(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+				   ddMat4x4_In transform,
+				   float size,
+				   float length,
+				   int durationMillis = 0,
+				   bool depthEnabled = true);
+
+// Add a 3D line with an arrow-like end to the debug draw queue.
+// 'size' defines the arrow head size. 'from' and 'to' the length of the arrow's base line.
+	void arrow(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+			   ddVec3_In from,
+			   ddVec3_In to,
+			   ddVec3_In color,
+			   float size,
+			   int durationMillis = 0,
+			   bool depthEnabled = true);
+
+// Add an axis-aligned cross (3 lines converging at a point) to the debug draw queue.
+// 'length' defines the length of the crossing lines.
+// 'center' is the world-space point where the lines meet.
+	void cross(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+			   ddVec3_In center,
+			   float length,
+			   int durationMillis = 0,
+			   bool depthEnabled = true);
+
+// Add a wireframe circle to the debug draw queue.
+	void circle(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+				ddVec3_In center,
+				ddVec3_In planeNormal,
+				ddVec3_In color,
+				float radius,
+				float numSteps,
+				int durationMillis = 0,
+				bool depthEnabled = true);
+
+// Add a wireframe plane in 3D space to the debug draw queue.
+// If 'normalVecScale' is not zero, a line depicting the plane normal is also draw.
+	void plane(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+			   ddVec3_In center,
+			   ddVec3_In planeNormal,
+			   ddVec3_In planeColor,
+			   ddVec3_In normalVecColor,
+			   float planeScale,
+			   float normalVecScale,
+			   int durationMillis = 0,
+			   bool depthEnabled = true);
+
+// Add a wireframe sphere to the debug draw queue.
+	void sphere(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+				ddVec3_In center,
+				ddVec3_In color,
+				float radius,
+				int durationMillis = 0,
+				bool depthEnabled = true);
+
+// Add a wireframe cone to the debug draw queue.
+// The cone 'apex' is the point where all lines meet.
+// The length of the 'dir' vector determines the thickness.
+// 'baseRadius' & 'apexRadius' are in degrees.
+	void cone(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+			  ddVec3_In apex,
+			  ddVec3_In dir,
+			  ddVec3_In color,
+			  float baseRadius,
+			  float apexRadius,
+			  int durationMillis = 0,
+			  bool depthEnabled = true);
+
+// Wireframe box from the eight points that define it.
+	void box(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+			 const ddVec3 points[8],
+			 ddVec3_In color,
+			 int durationMillis = 0,
+			 bool depthEnabled = true);
+
+// Add a wireframe box to the debug draw queue.
+	void box(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+			 ddVec3_In center,
+			 ddVec3_In color,
+			 float width,
+			 float height,
+			 float depth,
+			 int durationMillis = 0,
+			 bool depthEnabled = true);
+
+// Add a wireframe Axis Aligned Bounding Box (AABB) to the debug draw queue.
+	void aabb(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+			  ddVec3_In mins,
+			  ddVec3_In maxs,
+			  ddVec3_In color,
+			  int durationMillis = 0,
+			  bool depthEnabled = true);
+
+// Add a wireframe frustum pyramid to the debug draw queue.
+// 'invClipMatrix' is the inverse of the matrix defining the frustum
+// (AKA clip) volume, which normally consists of the projection * view matrix.
+// E.g.: inverse(projMatrix * viewMatrix)
+	void frustum(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+				 ddMat4x4_In invClipMatrix,
+				 ddVec3_In color,
+				 int durationMillis = 0,
+				 bool depthEnabled = true);
+
+// Add a vertex normal for debug visualization.
+// The normal vector 'normal' is assumed to be already normalized.
+	void vertexNormal(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+					  ddVec3_In origin,
+					  ddVec3_In normal,
+					  float length,
+					  int durationMillis = 0,
+					  bool depthEnabled = true);
+
+// Add a "tangent basis" at a given point in world space.
+// Color scheme used is: normal=WHITE, tangent=YELLOW, bi-tangent=MAGENTA.
+// The normal vector, tangent and bi-tangent vectors are assumed to be already normalized.
+	void tangentBasis(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+					  ddVec3_In origin,
+					  ddVec3_In normal,
+					  ddVec3_In tangent,
+					  ddVec3_In bitangent,
+					  float lengths,
+					  int durationMillis = 0,
+					  bool depthEnabled = true);
+
+// Makes a 3D square grid of lines along the X and Z planes.
+// 'y' defines the height in the Y axis where the grid is placed.
+// The grid will go from 'mins' to 'maxs' units in both the X and Z.
+// 'step' defines the gap between each line of the grid.
+	void xzSquareGrid(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+					  float mins,
+					  float maxs,
+					  float y,
+					  float step,
+					  ddVec3_In color,
+					  int durationMillis = 0,
+					  bool depthEnabled = true);
+
+// ========================================================
+// Debug Draw vertex type:
+// The only drawing type the user has to interface with.
+// ========================================================
+
+	union DrawVertex
+	{
+		struct
+		{
+			float x, y, z;
+			float r, g, b;
+			float size;
+		} point;
+
+		struct
+		{
+			float x, y, z;
+			float r, g, b;
+		} line;
+
+		struct
+		{
+			float x, y;
+			float u, v;
+			float r, g, b;
+		} glyph;
+	};
+
+//
+// Opaque handle to a texture object.
+// Used by the debug text drawing functions.
+//
+	struct OpaqueTextureType { };
+	typedef OpaqueTextureType * GlyphTextureHandle;
+
+// ========================================================
+// Debug Draw rendering callbacks:
+// Implementation is provided by the user so we don't
+// tie this code directly to a specific rendering API.
+// ========================================================
+
+	class RenderInterface
+	{
+		public:
+
+			//
+			// These are called by dd::flush() before any drawing and after drawing is finished.
+			// User can override these to perform any common setup for subsequent draws and to
+			// cleanup afterwards. By default, no-ops stubs are provided.
+			//
+			virtual void beginDraw();
+			virtual void endDraw();
+
+			//
+			// Create/free the glyph bitmap texture used by the debug text drawing functions.
+			// The debug renderer currently only creates one of those on startup.
+			//
+			// You're not required to implement these two if you don't care about debug text drawing.
+			// Default no-op stubs are provided by default, which disable debug text rendering.
+			//
+			// Texture dimensions are in pixels, data format is always 8-bits per pixel (Grayscale/GL_RED).
+			// The pixel values range from 255 for a pixel within a glyph to 0 for a transparent pixel.
+			// If createGlyphTexture() returns null, the renderer will disable all text drawing functions.
+			//
+			virtual GlyphTextureHandle createGlyphTexture(int width, int height, const void * pixels);
+			virtual void destroyGlyphTexture(GlyphTextureHandle glyphTex);
+
+			//
+			// Batch drawing methods for the primitives used by the debug renderer.
+			// If you don't wish to support a given primitive type, don't override the method.
+			//
+			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);
+
+			// User defined cleanup. Nothing by default.
+			virtual ~RenderInterface() = 0;
+	};
+
+// ========================================================
+// Housekeeping functions:
+// ========================================================
+
+// Flags for dd::flush()
+	enum FlushFlags
+	{
+		FlushPoints = 1 << 1,
+		FlushLines  = 1 << 2,
+		FlushText   = 1 << 3,
+		FlushAll    = (FlushPoints | FlushLines | FlushText)
+	};
+
+// Initialize with the user-supplied renderer interface.
+// Given object must remain valid until after dd::shutdown() is called!
+// If 'renderer' is null, the Debug Draw functions become no-ops, but
+// can still be safely called.
+	bool initialize(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle * outCtx,) RenderInterface * renderer);
+
+// After this is called, it is safe to dispose the dd::RenderInterface instance
+// you passed to dd::initialize(). Shutdown will also attempt to free the glyph texture.
+	void shutdown(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx));
+
+// Test if the Debug Draw library is currently initialized and has a render interface.
+	bool isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx));
+
+// Test if there's data in the debug draw queue and dd::flush() should be called.
+	bool hasPendingDraws(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx));
+
+// Manually removes all queued debug render data without drawing.
+// This is not normally called. To draw stuff, call dd::flush() instead.
+	void clear(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx));
+
+// Actually calls the dd::RenderInterface to consume the debug draw queues.
+// Objects that have expired their lifetimes get removed. Pass the current
+// application time in milliseconds to remove timed objects that have expired.
+// Passing zero removes all objects after they get drawn, regardless of lifetime.
+	void flush(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,)
+			   std::int64_t currTimeMillis = 0,
+			   std::uint32_t flags = FlushAll);
+
+} // namespace dd
+
+// ================== End of header file ==================
+#endif // DEBUG_DRAW_HPP
+// ================== End of header file ==================
+
+// ================================================================================================
+//
+//                                  Debug Draw Implementation
+//
+// ================================================================================================
+
+#ifdef DEBUG_DRAW_IMPLEMENTATION
+
+#ifndef DD_MALLOC
+    #include <cstdlib>
+    #define DD_MALLOC std::malloc
+    #define DD_MFREE  std::free
+#endif // DD_MALLOC
+
+#if DEBUG_DRAW_USE_STD_MATH
+    #include <math.h>
+    #include <float.h>
+#endif // DEBUG_DRAW_USE_STD_MATH
+
+namespace dd
+{
+
+#if defined(FLT_EPSILON) && DEBUG_DRAW_USE_STD_MATH
+    static const float FloatEpsilon = FLT_EPSILON;
+#else // !FLT_EPSILON || !DEBUG_DRAW_USE_STD_MATH
+    static const float FloatEpsilon = 1e-14;
+#endif // FLT_EPSILON && DEBUG_DRAW_USE_STD_MATH
+
+#if defined(M_PI) && DEBUG_DRAW_USE_STD_MATH
+    static const float PI = static_cast<float>(M_PI);
+#else // !M_PI || !DEBUG_DRAW_USE_STD_MATH
+    static const float PI = 3.1415926535897931f;
+#endif // M_PI && DEBUG_DRAW_USE_STD_MATH
+
+static const float HalfPI = PI * 0.5f;
+static const float TAU    = PI * 2.0f;
+
+template<typename T>
+static inline float degreesToRadians(const T degrees)
+{
+    return (static_cast<float>(degrees) * PI / 180.0f);
+}
+
+template<typename T, int Size>
+static inline int arrayLength(const T (&)[Size])
+{
+    return Size;
+}
+
+// ========================================================
+// Built-in color constants:
+// ========================================================
+
+#ifndef DEBUG_DRAW_NO_DEFAULT_COLORS
+namespace colors
+{
+const ddVec3 AliceBlue         = {0.941176f, 0.972549f, 1.000000f};
+const ddVec3 AntiqueWhite      = {0.980392f, 0.921569f, 0.843137f};
+const ddVec3 Aquamarine        = {0.498039f, 1.000000f, 0.831373f};
+const ddVec3 Azure             = {0.941176f, 1.000000f, 1.000000f};
+const ddVec3 Beige             = {0.960784f, 0.960784f, 0.862745f};
+const ddVec3 Bisque            = {1.000000f, 0.894118f, 0.768627f};
+const ddVec3 Black             = {0.000000f, 0.000000f, 0.000000f};
+const ddVec3 BlanchedAlmond    = {1.000000f, 0.921569f, 0.803922f};
+const ddVec3 Blue              = {0.000000f, 0.000000f, 1.000000f};
+const ddVec3 BlueViolet        = {0.541176f, 0.168627f, 0.886275f};
+const ddVec3 Brown             = {0.647059f, 0.164706f, 0.164706f};
+const ddVec3 BurlyWood         = {0.870588f, 0.721569f, 0.529412f};
+const ddVec3 CadetBlue         = {0.372549f, 0.619608f, 0.627451f};
+const ddVec3 Chartreuse        = {0.498039f, 1.000000f, 0.000000f};
+const ddVec3 Chocolate         = {0.823529f, 0.411765f, 0.117647f};
+const ddVec3 Coral             = {1.000000f, 0.498039f, 0.313726f};
+const ddVec3 CornflowerBlue    = {0.392157f, 0.584314f, 0.929412f};
+const ddVec3 Cornsilk          = {1.000000f, 0.972549f, 0.862745f};
+const ddVec3 Crimson           = {0.862745f, 0.078431f, 0.235294f};
+const ddVec3 Cyan              = {0.000000f, 1.000000f, 1.000000f};
+const ddVec3 DarkBlue          = {0.000000f, 0.000000f, 0.545098f};
+const ddVec3 DarkCyan          = {0.000000f, 0.545098f, 0.545098f};
+const ddVec3 DarkGoldenRod     = {0.721569f, 0.525490f, 0.043137f};
+const ddVec3 DarkGray          = {0.662745f, 0.662745f, 0.662745f};
+const ddVec3 DarkGreen         = {0.000000f, 0.392157f, 0.000000f};
+const ddVec3 DarkKhaki         = {0.741176f, 0.717647f, 0.419608f};
+const ddVec3 DarkMagenta       = {0.545098f, 0.000000f, 0.545098f};
+const ddVec3 DarkOliveGreen    = {0.333333f, 0.419608f, 0.184314f};
+const ddVec3 DarkOrange        = {1.000000f, 0.549020f, 0.000000f};
+const ddVec3 DarkOrchid        = {0.600000f, 0.196078f, 0.800000f};
+const ddVec3 DarkRed           = {0.545098f, 0.000000f, 0.000000f};
+const ddVec3 DarkSalmon        = {0.913725f, 0.588235f, 0.478431f};
+const ddVec3 DarkSeaGreen      = {0.560784f, 0.737255f, 0.560784f};
+const ddVec3 DarkSlateBlue     = {0.282353f, 0.239216f, 0.545098f};
+const ddVec3 DarkSlateGray     = {0.184314f, 0.309804f, 0.309804f};
+const ddVec3 DarkTurquoise     = {0.000000f, 0.807843f, 0.819608f};
+const ddVec3 DarkViolet        = {0.580392f, 0.000000f, 0.827451f};
+const ddVec3 DeepPink          = {1.000000f, 0.078431f, 0.576471f};
+const ddVec3 DeepSkyBlue       = {0.000000f, 0.749020f, 1.000000f};
+const ddVec3 DimGray           = {0.411765f, 0.411765f, 0.411765f};
+const ddVec3 DodgerBlue        = {0.117647f, 0.564706f, 1.000000f};
+const ddVec3 FireBrick         = {0.698039f, 0.133333f, 0.133333f};
+const ddVec3 FloralWhite       = {1.000000f, 0.980392f, 0.941176f};
+const ddVec3 ForestGreen       = {0.133333f, 0.545098f, 0.133333f};
+const ddVec3 Gainsboro         = {0.862745f, 0.862745f, 0.862745f};
+const ddVec3 GhostWhite        = {0.972549f, 0.972549f, 1.000000f};
+const ddVec3 Gold              = {1.000000f, 0.843137f, 0.000000f};
+const ddVec3 GoldenRod         = {0.854902f, 0.647059f, 0.125490f};
+const ddVec3 Gray              = {0.501961f, 0.501961f, 0.501961f};
+const ddVec3 Green             = {0.000000f, 0.501961f, 0.000000f};
+const ddVec3 GreenYellow       = {0.678431f, 1.000000f, 0.184314f};
+const ddVec3 HoneyDew          = {0.941176f, 1.000000f, 0.941176f};
+const ddVec3 HotPink           = {1.000000f, 0.411765f, 0.705882f};
+const ddVec3 IndianRed         = {0.803922f, 0.360784f, 0.360784f};
+const ddVec3 Indigo            = {0.294118f, 0.000000f, 0.509804f};
+const ddVec3 Ivory             = {1.000000f, 1.000000f, 0.941176f};
+const ddVec3 Khaki             = {0.941176f, 0.901961f, 0.549020f};
+const ddVec3 Lavender          = {0.901961f, 0.901961f, 0.980392f};
+const ddVec3 LavenderBlush     = {1.000000f, 0.941176f, 0.960784f};
+const ddVec3 LawnGreen         = {0.486275f, 0.988235f, 0.000000f};
+const ddVec3 LemonChiffon      = {1.000000f, 0.980392f, 0.803922f};
+const ddVec3 LightBlue         = {0.678431f, 0.847059f, 0.901961f};
+const ddVec3 LightCoral        = {0.941176f, 0.501961f, 0.501961f};
+const ddVec3 LightCyan         = {0.878431f, 1.000000f, 1.000000f};
+const ddVec3 LightGoldenYellow = {0.980392f, 0.980392f, 0.823529f};
+const ddVec3 LightGray         = {0.827451f, 0.827451f, 0.827451f};
+const ddVec3 LightGreen        = {0.564706f, 0.933333f, 0.564706f};
+const ddVec3 LightPink         = {1.000000f, 0.713726f, 0.756863f};
+const ddVec3 LightSalmon       = {1.000000f, 0.627451f, 0.478431f};
+const ddVec3 LightSeaGreen     = {0.125490f, 0.698039f, 0.666667f};
+const ddVec3 LightSkyBlue      = {0.529412f, 0.807843f, 0.980392f};
+const ddVec3 LightSlateGray    = {0.466667f, 0.533333f, 0.600000f};
+const ddVec3 LightSteelBlue    = {0.690196f, 0.768627f, 0.870588f};
+const ddVec3 LightYellow       = {1.000000f, 1.000000f, 0.878431f};
+const ddVec3 Lime              = {0.000000f, 1.000000f, 0.000000f};
+const ddVec3 LimeGreen         = {0.196078f, 0.803922f, 0.196078f};
+const ddVec3 Linen             = {0.980392f, 0.941176f, 0.901961f};
+const ddVec3 Magenta           = {1.000000f, 0.000000f, 1.000000f};
+const ddVec3 Maroon            = {0.501961f, 0.000000f, 0.000000f};
+const ddVec3 MediumAquaMarine  = {0.400000f, 0.803922f, 0.666667f};
+const ddVec3 MediumBlue        = {0.000000f, 0.000000f, 0.803922f};
+const ddVec3 MediumOrchid      = {0.729412f, 0.333333f, 0.827451f};
+const ddVec3 MediumPurple      = {0.576471f, 0.439216f, 0.858824f};
+const ddVec3 MediumSeaGreen    = {0.235294f, 0.701961f, 0.443137f};
+const ddVec3 MediumSlateBlue   = {0.482353f, 0.407843f, 0.933333f};
+const ddVec3 MediumSpringGreen = {0.000000f, 0.980392f, 0.603922f};
+const ddVec3 MediumTurquoise   = {0.282353f, 0.819608f, 0.800000f};
+const ddVec3 MediumVioletRed   = {0.780392f, 0.082353f, 0.521569f};
+const ddVec3 MidnightBlue      = {0.098039f, 0.098039f, 0.439216f};
+const ddVec3 MintCream         = {0.960784f, 1.000000f, 0.980392f};
+const ddVec3 MistyRose         = {1.000000f, 0.894118f, 0.882353f};
+const ddVec3 Moccasin          = {1.000000f, 0.894118f, 0.709804f};
+const ddVec3 NavajoWhite       = {1.000000f, 0.870588f, 0.678431f};
+const ddVec3 Navy              = {0.000000f, 0.000000f, 0.501961f};
+const ddVec3 OldLace           = {0.992157f, 0.960784f, 0.901961f};
+const ddVec3 Olive             = {0.501961f, 0.501961f, 0.000000f};
+const ddVec3 OliveDrab         = {0.419608f, 0.556863f, 0.137255f};
+const ddVec3 Orange            = {1.000000f, 0.647059f, 0.000000f};
+const ddVec3 OrangeRed         = {1.000000f, 0.270588f, 0.000000f};
+const ddVec3 Orchid            = {0.854902f, 0.439216f, 0.839216f};
+const ddVec3 PaleGoldenRod     = {0.933333f, 0.909804f, 0.666667f};
+const ddVec3 PaleGreen         = {0.596078f, 0.984314f, 0.596078f};
+const ddVec3 PaleTurquoise     = {0.686275f, 0.933333f, 0.933333f};
+const ddVec3 PaleVioletRed     = {0.858824f, 0.439216f, 0.576471f};
+const ddVec3 PapayaWhip        = {1.000000f, 0.937255f, 0.835294f};
+const ddVec3 PeachPuff         = {1.000000f, 0.854902f, 0.725490f};
+const ddVec3 Peru              = {0.803922f, 0.521569f, 0.247059f};
+const ddVec3 Pink              = {1.000000f, 0.752941f, 0.796078f};
+const ddVec3 Plum              = {0.866667f, 0.627451f, 0.866667f};
+const ddVec3 PowderBlue        = {0.690196f, 0.878431f, 0.901961f};
+const ddVec3 Purple            = {0.501961f, 0.000000f, 0.501961f};
+const ddVec3 RebeccaPurple     = {0.400000f, 0.200000f, 0.600000f};
+const ddVec3 Red               = {1.000000f, 0.000000f, 0.000000f};
+const ddVec3 RosyBrown         = {0.737255f, 0.560784f, 0.560784f};
+const ddVec3 RoyalBlue         = {0.254902f, 0.411765f, 0.882353f};
+const ddVec3 SaddleBrown       = {0.545098f, 0.270588f, 0.074510f};
+const ddVec3 Salmon            = {0.980392f, 0.501961f, 0.447059f};
+const ddVec3 SandyBrown        = {0.956863f, 0.643137f, 0.376471f};
+const ddVec3 SeaGreen          = {0.180392f, 0.545098f, 0.341176f};
+const ddVec3 SeaShell          = {1.000000f, 0.960784f, 0.933333f};
+const ddVec3 Sienna            = {0.627451f, 0.321569f, 0.176471f};
+const ddVec3 Silver            = {0.752941f, 0.752941f, 0.752941f};
+const ddVec3 SkyBlue           = {0.529412f, 0.807843f, 0.921569f};
+const ddVec3 SlateBlue         = {0.415686f, 0.352941f, 0.803922f};
+const ddVec3 SlateGray         = {0.439216f, 0.501961f, 0.564706f};
+const ddVec3 Snow              = {1.000000f, 0.980392f, 0.980392f};
+const ddVec3 SpringGreen       = {0.000000f, 1.000000f, 0.498039f};
+const ddVec3 SteelBlue         = {0.274510f, 0.509804f, 0.705882f};
+const ddVec3 Tan               = {0.823529f, 0.705882f, 0.549020f};
+const ddVec3 Teal              = {0.000000f, 0.501961f, 0.501961f};
+const ddVec3 Thistle           = {0.847059f, 0.749020f, 0.847059f};
+const ddVec3 Tomato            = {1.000000f, 0.388235f, 0.278431f};
+const ddVec3 Turquoise         = {0.250980f, 0.878431f, 0.815686f};
+const ddVec3 Violet            = {0.933333f, 0.509804f, 0.933333f};
+const ddVec3 Wheat             = {0.960784f, 0.870588f, 0.701961f};
+const ddVec3 White             = {1.000000f, 1.000000f, 1.000000f};
+const ddVec3 WhiteSmoke        = {0.960784f, 0.960784f, 0.960784f};
+const ddVec3 Yellow            = {1.000000f, 1.000000f, 0.000000f};
+const ddVec3 YellowGreen       = {0.603922f, 0.803922f, 0.196078f};
+} // namespace colors
+#endif // DEBUG_DRAW_NO_DEFAULT_COLORS
+
+// ========================================================
+// Embedded bitmap font for debug text rendering:
+// ========================================================
+
+struct FontChar
+{
+    std::uint16_t x;
+    std::uint16_t y;
+};
+
+struct FontCharSet
+{
+    enum { MaxChars = 256 };
+    const std::uint8_t * bitmap;
+    int bitmapWidth;
+    int bitmapHeight;
+    int bitmapColorChannels;
+    int bitmapDecompressSize;
+    int charBaseHeight;
+    int charWidth;
+    int charHeight;
+    int charCount;
+    FontChar chars[MaxChars];
+};
+
+#if DEBUG_DRAW_CXX11_SUPPORTED
+    #define DD_ALIGNED_BUFFER(name) alignas(16) static const std::uint8_t name[]
+#else // !C++11
+    #if defined(__GNUC__) // Clang & GCC
+        #define DD_ALIGNED_BUFFER(name) static const std::uint8_t name[] __attribute__((aligned(16)))
+    #elif defined(_MSC_VER) // Visual Studio
+        #define DD_ALIGNED_BUFFER(name) __declspec(align(16)) static const std::uint8_t name[]
+    #else // Unknown compiler
+        #define DD_ALIGNED_BUFFER(name) static const std::uint8_t name[] /* hope for the best! */
+    #endif // Compiler id
+#endif // DEBUG_DRAW_CXX11_SUPPORTED
+
+//
+// Data generated from font 'Monoid18' by font-tool.
+// Command line: monoid-18.fnt monoid-18.png monoid-18.h Monoid18 --static --compress --structs --hex --encoding=lzw
+//
+// The Monoid font, copyright (c) 2015 Andreas Larsen and contributors,
+// is released under the MIT license. See: https://github.com/larsenwork/monoid
+//
+// The following glyph bitmap is an LZW compressed graymap.
+// ~7.55 KB of data.
+//
+// It is better to ensure it is aligned to a, say 16 bytes boundary,
+// because we cast the first few bytes to uint32s.
+//
+// font-tool: https://github.com/glampert/font-tool
+// LZW compression: https://github.com/glampert/compression-algorithms
+//
+DD_ALIGNED_BUFFER(s_fontMonoid18Bitmap) =
+"\x2F\x1E\x00\x00\x78\xF1\x00\x00\x00\x00\x06\x14\x38\x90\x60\x41\x83\x07\x11\x26\x54\xB8"
+"\x90\x61\x43\x87\x0F\x21\x46\x94\x38\x91\x62\x45\x8B\x17\x31\x66\xD4\x88\x70\x43\x13\x8C"
+"\x15\x80\x0D\xD8\x98\x10\x0D\x98\x84\x4D\x36\x8C\x8C\x28\x40\xC1\x01\x95\x2F\x1F\x06\x10"
+"\x10\x00\x26\xC0\x44\xFE\x5C\x5A\xA4\xF4\x8F\x4E\xCD\x81\x01\xF8\xFD\x4B\x70\x30\x40\x3F"
+"\x3F\x3E\x17\x32\xFA\xB7\xB4\x5F\xCA\x8C\x67\xFC\xD1\x04\xB0\x2F\x0D\x52\x82\x74\x96\xF2"
+"\x54\xD9\xC4\x5D\xD6\xA5\xBF\x10\x36\x5B\xBA\xE3\x60\x81\x7E\xFD\xA4\x2E\x3C\xC0\xE8\xDB"
+"\xD2\x77\xC1\x2A\x34\xF4\xF2\xEF\x52\x42\x7E\x3D\xAD\x1E\x74\xB5\x34\x13\xB4\xA5\x11\x9E"
+"\x46\x05\x78\x37\x6F\xC0\x25\x4B\xDB\xFE\xAB\xB2\x51\x0E\xE2\x7E\xFF\xDE\xF9\x73\xA6\xF7"
+"\x9F\xBF\xA5\x14\x0E\xEE\xFC\xC2\xD0\x44\x56\x7F\xEF\xB2\xB2\x60\xA8\xCF\xDF\x50\x84\x84"
+"\x0B\x13\x8C\xF0\xAF\x5F\xCE\x2F\xFF\xC0\x62\x84\x4A\x13\x28\xDE\xC2\xD8\xFC\xC5\xA5\xE0"
+"\xAF\x5B\x40\x1A\x16\x0F\xF8\xF3\x67\x02\x40\x17\x7F\x09\x4B\xB0\x06\x30\xE4\x5F\x6F\x83"
+"\xC1\xFB\x31\xDC\xF7\x4F\x4D\x5A\x2B\xFF\xD8\x2D\x9C\xF2\x8F\x94\x42\xD4\xA9\x05\x7E\xF8"
+"\x57\x35\xE0\x3E\x6E\x19\x8D\x07\xE4\x47\xBE\xF0\xB2\xE3\x83\x9D\x2B\x1A\x5F\x91\xF9\x66"
+"\x00\xB3\x11\x66\xFB\x07\x02\xA0\xB2\x7F\xA2\x0D\x12\xE5\x1F\x26\x14\x3A\xAC\xBB\x81\x70"
+"\x4B\xEB\xA0\x7C\xFE\x01\xCC\x2E\xDB\x16\x6A\x86\xC0\x8C\xC4\x3B\x10\x80\x01\xFA\x71\xCE"
+"\xA2\x59\xDA\x9A\xC5\xC3\x7F\xBE\x01\x46\x23\x09\x11\x4A\xE4\x1F\x6F\x9A\xE8\x86\x2E\x00"
+"\xE4\x6B\xAD\xA2\xC6\x34\x00\x08\x3F\x83\x34\xF8\x67\x32\x80\x6A\xBC\xB1\x20\x08\xFE\xE1"
+"\x47\x21\x34\xFE\xF9\x00\xA0\x06\xAC\x00\xC3\x0A\x67\x04\x43\x88\xB9\xD8\x1E\x74\xE8\x3B"
+"\x8C\xA6\xC3\x0C\x00\x66\xB4\xB2\x28\x00\xCB\xBC\x5A\x2A\xC9\x81\x5A\x3A\xC0\xCB\x03\x14"
+"\x10\xC0\x3B\x08\x0B\xDA\x26\xAB\x76\x00\x30\xB1\x1F\x91\x2A\x92\x61\xC5\xFB\xB6\x24\x48"
+"\x97\x7F\x66\x10\xE8\x9E\x06\x0F\xDA\xE5\x1F\xB2\x10\x82\xCA\x00\x00\xD2\xC8\x32\xCE\x82"
+"\xD2\xF9\x27\xC6\x31\x9D\x24\xD3\xA2\xC3\xFC\x51\xE3\xB1\xE8\x30\x12\xC0\x0F\x7F\x1A\x20"
+"\xA0\x01\x7E\xFE\x10\x93\xA0\x2B\xB3\xFC\xE7\xA8\x26\x13\x32\x81\x08\xE2\xD4\xFC\xD3\x22"
+"\x0C\xFF\xA9\x03\x00\x34\xDE\x7B\xCE\xC1\x80\x0E\x78\xB5\xA0\x0C\xFE\x41\xB3\xCF\xE3\x3C"
+"\xA8\xAC\x89\x06\x14\xF8\x63\xD0\x81\xDC\xD4\x11\xD4\x83\x36\x88\x6B\x30\xF2\x04\xF8\x8D"
+"\xA0\x06\x32\x99\x45\xD5\x80\x76\x90\xC5\xA0\x40\xB3\x7A\x46\x41\x8B\x66\x7C\x72\x20\x60"
+"\x3C\xEC\x36\x98\x09\x4F\x53\xF4\x20\x4B\x58\x33\xF5\xA2\x1D\xBC\xF2\xC7\x8A\x8D\x96\xF9"
+"\xEF\x56\x00\xCC\xD8\x33\x20\x57\x7E\x15\x48\x3F\xFE\x16\xD2\x96\x20\x7B\x2A\xAB\x03\x84"
+"\x7E\x30\x31\x21\x98\xA5\x00\x0C\x08\xA8\xAC\x20\x05\xA0\x92\x5F\x47\xF1\x0A\x2F\x01\x08"
+"\x90\x2D\x49\x7D\x21\x92\x49\x00\x01\x0E\xC0\x14\x80\x8B\x35\x35\x88\x5C\x17\x0D\xB2\x98"
+"\xE3\x91\x3B\x26\x08\x24\xAF\xFA\x31\xED\xA2\xE4\x34\x2C\x08\x2A\x78\xF7\x0B\x28\x9B\x7A"
+"\x01\x62\xB9\x21\x8A\x05\x02\x23\xB1\x4E\x4D\x71\x2A\xA0\x19\xFE\x29\x25\x02\x75\x60\x03"
+"\x68\xE6\x6B\x19\xAD\x80\x07\xD6\x44\x92\x83\xE6\x87\xD2\x3B\xD6\xA2\xC6\x3A\xD5\xF2\xDA"
+"\x80\x1A\x5E\x13\x21\xAA\xAB\x7E\x7A\xAA\x45\x2A\x50\xD1\xC7\x8C\xB4\x89\xD9\xA0\x97\xE3"
+"\xAD\x13\x00\x1E\x9F\x6E\xB7\x60\x44\x15\x52\x00\x0C\x84\xF1\x25\xA8\x31\x21\x03\x98\x6E"
+"\x16\x40\xB0\x23\xA8\xEC\x12\x00\x12\x70\xB2\x19\x29\x6A\x62\x16\x7F\xC0\x68\x02\x0C\x7F"
+"\x80\xF1\x88\x22\x2A\xBE\x81\x46\x72\xC8\x24\x87\xC6\x9B\xAB\x01\xC8\x5A\x01\xC3\x67\x31"
+"\x89\x20\xC8\x2B\x0F\xDD\x72\xCC\xD5\x23\xAF\x6C\x21\x31\x0A\xF6\xA0\x97\x55\xA8\x8C\x07"
+"\x1E\x82\xA2\x99\x56\x5B\x19\xC2\x99\xA0\xE4\x96\x6A\x79\x20\xA7\xD9\x8C\x00\x4B\x79\x05"
+"\x02\x2A\xBB\x80\xF4\xF9\x87\x08\x2A\xBC\x5E\x28\x80\xAA\x97\x22\x3D\xA2\xF5\x12\x6A\x18"
+"\xA7\x4A\xBC\x8A\x45\x23\xD4\x56\x98\x2F\xA3\x42\x8D\x25\xE8\x8C\x7F\x20\x00\x60\xAF\xA5"
+"\xDC\x09\x86\x66\x3D\xF9\xAC\x5D\x5C\x82\x50\x25\x42\x2C\x45\x0C\x8A\xA0\x85\xE0\x79\x20"
+"\xA2\x81\x4D\xF9\x39\x2F\xA0\x1A\xAD\xB6\xA8\x85\x52\xFC\xC1\x83\x16\xF0\xA0\x1F\xA5\x98"
+"\x5F\x41\x82\x92\xA5\xF5\x19\xCC\x76\x99\xAB\x4C\x02\x14\xC0\x9A\x0A\x54\x80\x1D\x86\xCA"
+"\x08\x6A\x68\xB5\xC0\x88\xA0\xCB\x17\x06\x69\x0C\xE0\x00\xC0\x03\x40\xA8\x01\x00\x0D\x50"
+"\x16\x41\x78\x34\xB6\x9B\x69\x30\x20\xED\xEA\x4E\x70\xFE\x41\x9C\x8A\xE8\xE7\x50\x00\x01"
+"\x12\x6B\x9C\xE7\x90\xA8\x01\x00\x7A\x06\xD1\xC7\x3B\x80\x08\x44\x7F\xB0\xE7\x20\x0D\xDC"
+"\x07\xA5\x00\x50\x23\x34\x00\xA4\x0B\x66\xB3\x12\x6A\x4C\xF4\xB6\x8B\x30\x48\x56\xD0\xE2"
+"\x8E\x43\x04\x04\x2E\xF5\x29\x84\x02\xCA\x01\x08\x73\x84\x25\x11\x2A\x54\x46\x86\x00\x28"
+"\x40\xEE\x24\x26\x95\x06\x56\xCC\x28\x08\x69\x80\x83\xC4\x53\x8A\xC0\xFD\x03\x84\x14\x51"
+"\x63\x55\xAE\xE3\x0F\x73\x61\x64\x3B\x16\x1A\xC8\x74\x00\x51\xB2\x92\x09\x04\x3A\x10\x59"
+"\x23\x40\x22\x20\xAB\x13\x56\xE4\x15\xE4\x6B\x96\x57\x0E\x58\x91\x6C\xB1\x10\x22\x28\x69"
+"\x48\xF1\x26\x97\xB0\x89\xD4\xC8\x1F\x6D\xF9\xCC\x52\x86\xA0\x12\xD2\xA8\x4C\x20\x2D\xF0"
+"\x0C\x68\x96\x82\xBA\x81\x68\xC6\x90\x94\xF4\x09\x0F\xBA\x92\x15\x40\x5C\x47\x93\x00\x00"
+"\x81\x15\x9A\x90\x4B\x5D\xE6\x72\x5D\x67\x4B\x12\x55\xC0\x33\x90\x06\x54\xF0\x1F\xEE\xA8"
+"\x62\x44\x28\xF0\x18\xAF\x78\xC3\x67\x1B\x99\xCB\x22\x0C\xA2\x80\x4C\x24\xE6\x33\xDF\xE8"
+"\x5E\x40\xCC\x82\x96\x56\x06\xB3\x20\x04\xF0\x12\x42\xF6\xC0\xBC\xE6\x71\x53\x22\xDF\xD4"
+"\x88\x02\xFC\x51\x97\x9A\x1C\x8C\x94\x10\xD9\x89\x2B\x09\x72\x48\x72\xAA\xA6\x05\x26\xB0"
+"\xE7\x3D\xED\x19\xC9\x79\xEE\x13\x20\x96\xF4\xC9\x17\x3C\x37\x91\x0A\xCC\x82\x4D\x0F\x91"
+"\x27\x3F\x11\x9A\x50\x85\xF2\x13\x98\x0B\x75\xE8\x43\x21\x1A\x51\x89\x4E\x94\xA2\x15\xB5"
+"\xE8\x45\x31\x9A\x51\x8D\x6E\x94\xA3\x1D\xF5\xE8\x47\x41\x1A\x52\x91\x8E\x94\xA4\x25\x35"
+"\xE9\x49\x51\x9A\x52\x95\xAE\x14\xA1\x8C\x00\xC3\xFD\x20\x42\x03\x46\xE8\x73\x20\x44\xB0"
+"\xE9\x4D\x15\xB2\x81\x9B\xDA\xB4\x99\x03\xA1\x41\xDD\x20\x12\x50\x96\xA2\x94\x53\xFF\x80"
+"\x66\x43\x2A\xA0\x4C\xF8\x15\x64\x79\xE9\xCA\x21\x00\xB8\xB6\x94\xA5\x16\x64\x3A\x47\x75"
+"\x48\x04\x82\x42\xC4\xA1\x1E\x04\x62\x83\xAC\x68\x04\x16\x07\xBC\x85\x60\xE3\x1F\xC0\x30"
+"\x41\x4E\x0A\x42\x03\xB5\xFE\x2F\x79\x50\x21\x82\x5A\x69\x70\xCD\x81\xF0\xC0\x32\x98\x70"
+"\x08\x03\x1E\x03\x0C\xB4\x9E\xB4\xA1\x08\x69\x58\xB5\x8E\x39\x10\xF7\x30\x40\xA1\x6E\x82"
+"\x27\x50\x54\xB8\x10\xE3\x3C\xF5\x65\x0C\x61\x40\x50\x16\xC3\x10\x06\x59\x35\xA5\x87\xC4"
+"\x0D\x34\x4C\xA1\x4C\x98\x1A\x64\x8C\xEA\x44\x28\x86\xE0\xC9\xC3\xA9\x2E\x84\x70\xBE\x7C"
+"\xAA\x40\xBA\xE8\x0F\xC2\x2A\x84\x7A\xD6\x63\xE9\x21\x4B\xA6\x86\x37\x1D\xE4\x88\x7B\x3C"
+"\xC8\x25\x42\x3B\x90\x04\xB0\x03\xA8\x06\x39\x28\x0F\xB5\x9A\x90\xD2\xBA\x2C\x79\x03\xE9"
+"\xAC\x42\x0A\xE0\x8F\x5A\x56\x36\xB7\x00\x00\x8A\xEE\xEC\xF6\x8F\xD1\x1A\x64\x00\xD3\xB1"
+"\xEB\x43\x22\xF0\x98\xE0\xC6\x73\xBB\x06\xD9\x47\x6E\x87\xEB\xBD\xE2\xFE\x71\xB9\x9F\xD3"
+"\x9E\x42\x86\x10\x8C\x6F\x2D\x24\xBD\xEB\x45\xE8\x6F\x01\x62\x16\xE8\x0E\x64\x00\xB3\x60"
+"\x84\xF2\xD6\xF1\x0F\x69\x35\x04\x04\x96\x89\xAC\x5D\x98\x94\x10\x1E\x81\xB7\xAD\xE3\x15"
+"\x88\x80\x7A\x4B\x90\x76\x05\xD6\x65\x4B\x71\xE5\xF7\xAA\xC4\x4F\xF8\x02\x60\x27\xDD\x9D"
+"\x48\xA1\xC2\x78\x10\x53\x0E\x48\x79\xFC\xF0\x07\x83\x07\x22\x9F\x4F\x31\x24\xBC\x03\x29"
+"\x71\x9F\x9C\x68\x10\x65\x18\x98\x6A\xAE\x6C\x71\x42\xE1\x8B\x2E\x7F\x14\x94\x6C\xB5\x7A"
+"\x2A\x11\xC6\xD2\x10\x13\xFD\x23\x18\x8B\x1C\x08\x23\xBA\x82\xC4\x86\x9C\x38\x20\x44\x36"
+"\x88\x0E\x52\x5C\x10\x65\x24\x36\x21\x2D\xA8\x43\x1D\x7C\x6C\x10\x27\x43\x39\xA1\xDC\xF8"
+"\xAF\x42\xC4\x23\xD6\x8D\x50\x09\x64\x05\x79\x0D\x9D\x1C\x32\x80\xAC\x4C\xD7\x60\x58\xF2"
+"\x23\x69\x0B\x7C\xDA\x81\xD0\x2A\xC1\x03\x51\x86\xFE\xB6\xEA\x10\x74\x44\x58\x25\xBD\xF0"
+"\x54\xC8\x1E\xD3\x66\x84\x14\xCA\x1B\x34\xD8\xEB\x40\x36\x50\x87\x1C\x0F\x39\xCD\x0F\x19"
+"\xA3\x9E\x03\xA2\x8C\xF2\xC6\x99\x28\xFC\x60\xF2\x46\x0A\x50\xC1\x05\x06\x85\x84\x0D\x41"
+"\x2C\x43\x82\x40\x67\x85\x18\x19\x4E\x6A\x16\xC8\xF7\x10\x0D\x10\xF7\x78\x9A\xD1\x00\xD0"
+"\x87\x85\x2D\xF2\xD8\xA2\x1D\x04\x04\x4B\xA1\xAC\x77\x3C\x9B\x90\xE4\x12\x98\xB1\x06\x4E"
+"\xF4\x3F\xE4\x4A\x10\x3D\xA9\xB2\xD4\xF3\xCC\xEE\x3F\x5C\x8B\x10\x0D\xD4\xF5\x66\xA8\x1E"
+"\x08\x7C\x39\xCD\x69\xFA\xF6\xE3\xD1\x04\x41\x32\x99\x2F\xE2\x05\x20\xDA\x27\x21\xD2\x7E"
+"\x07\xB5\x53\x3A\xEC\x7F\x5C\x57\x21\xBF\x0E\xF6\xB0\xBC\x63\x6C\x13\x17\xBA\x21\x8D\x81"
+"\xF6\xB2\x67\xBC\x10\x05\x80\x00\x04\x9B\x45\xB1\xA6\xCF\xE6\x60\x75\xB3\xDB\xDD\x19\x31"
+"\x01\x23\x00\x31\x92\x56\x1B\xF5\xAE\x8F\x09\x30\x75\xFB\x11\x5A\x7E\x9C\xDB\xB4\xC2\xB5"
+"\x75\x6A\x57\x9B\x10\xEA\xFD\xDB\x83\x4B\x19\xF1\xD6\xE4\xAD\x90\x17\x4B\xDC\xE1\x2A\x99"
+"\xCE\x79\x2F\xC2\x80\xA5\xFC\x01\x22\x09\x08\x4A\x07\x11\x62\x58\x86\x00\x85\x76\x8A\x2D"
+"\x70\x43\x32\xF6\x0F\x6C\x27\xA4\x78\x1C\x17\x6E\xC4\x13\xB2\x01\x2B\xF8\xC3\x95\x32\xA7"
+"\x39\x69\x61\x9E\x91\x83\xDD\x59\x23\x7D\x68\x2E\x36\xD9\x51\x6F\x81\x34\xA0\x09\x8F\xA9"
+"\xA3\x42\x0A\x35\x0B\x10\x44\xCC\x20\x34\x68\x41\x3D\x01\x58\x6B\x01\xB6\x20\xAE\x1A\x7E"
+"\x8C\x1C\x1B\xE2\xBB\xA0\x31\x3D\xDE\x18\x07\xF7\xD7\xBB\x2E\xEE\x88\x34\x32\xC9\x13\x2D"
+"\x2A\xD6\x19\xF2\x6B\xE9\x86\x4C\x50\x4F\x8D\xEA\xDA\x7D\xBB\x6D\x88\x24\xD5\xEB\x15\x01"
+"\x1A\x3C\xEF\x9E\xD0\x03\x90\x3A\xA1\x8C\x50\x03\x88\x11\xC2\x83\x4C\x44\x39\x20\x3B\xB5"
+"\x69\x4E\x0D\xDF\x53\x81\xF0\xA0\x8C\x10\xA9\x4E\x46\x98\xE3\x2E\xF4\x12\xAC\xD7\x95\xA7"
+"\x68\x63\x2A\x4D\xF1\xCC\x5B\x9E\xF3\x0F\xF5\x2A\x42\x3E\xDF\x79\xD1\x8F\x9E\xF4\xA5\x37"
+"\xFD\xE9\x51\x9F\x7A\xD5\xAF\x9E\xF5\xAD\x77\xFD\xEB\x61\x1F\x7B\xD9\xCF\x9E\xF6\xB5\x8F"
+"\x08\x01\xB8\x9E\x10\x8E\x35\x04\xF7\x2F\xC9\xFD\x45\x03\x80\xFB\xD0\x97\xD4\x77\xDF\x5E"
+"\xDD\x2F\x51\x8D\xE3\xA5\x3C\x83\xC6\x05\x29\x45\x56\xF4\x9A\x90\xB9\x2D\xC5\x1B\x42\xBF"
+"\x75\xD5\x78\x5D\x10\xDC\x00\x7E\x2A\x9D\x42\x35\xAB\x4C\xD3\x57\x82\x5C\xDC\x2D\x75\x27"
+"\xDE\x32\x73\x5D\x90\x06\x74\x43\x9B\x19\x15\x0F\x9C\x6F\xA5\xC6\x05\xF2\x2F\x32\xFF\x80"
+"\x3F\x41\xFC\xE3\x0F\x68\x58\xA6\xD9\x01\xB9\x21\x34\x40\x83\x66\x7A\xE1\x33\x82\x08\x95"
+"\x42\x8D\x05\x6A\xC5\x3B\x20\x23\x88\xCC\xAF\x85\x26\x66\x81\x7E\x08\x88\x12\xE3\xE1\x8E"
+"\xED\x1B\x82\x61\x16\x02\xB0\x9D\x08\xE2\x3A\x2A\x83\xEF\x10\xAA\x46\xEE\xAF\xE0\x78\x68"
+"\x81\xF4\x64\x31\x02\x80\x68\xD2\x0F\x00\xBA\xA8\xFD\xF4\x43\x6D\xA8\x2A\x37\x00\x62\x11"
+"\x1A\x50\xFB\xD2\xED\x20\x0A\x25\xFB\x10\x28\xB7\xD0\x41\x85\xE4\x89\x01\x84\x83\xFB\x02"
+"\x42\x3E\x62\xED\x27\x7E\xA1\x32\xBE\xC1\xD6\x12\x0A\x04\xD1\x4C\xFE\x68\x4B\x85\xF4\xA4"
+"\xBB\x80\xE6\xBF\x92\x63\x7D\x6A\xC4\xB3\x92\x2B\x04\x0D\x22\x01\x80\x2D\xE4\x56\x0D\xEC"
+"\x4E\x03\xCE\xE4\x49\x3F\xB4\xC8\x3B\xE6\x0B\x20\xA6\x43\x5A\x16\x4B\xA3\x94\x70\xD3\x1E"
+"\xB0\x88\xD4\xA9\x8B\xE0\x0D\x20\x60\x24\x20\x40\xCB\x20\xC4\x83\x88\xCC\x83\xC4\x24\xCF"
+"\x20\xE6\x4C\x4A\xBC\x30\x7E\x78\x6E\x04\x15\x62\x8C\x18\x0E\x21\x82\x03\x0B\x01\x42\x0D"
+"\x94\xC5\xC8\x16\xA1\x5B\x3C\x04\x1A\x52\x50\x0D\x98\x4F\x20\xAA\xE0\x19\x34\x10\x00\x62"
+"\x21\x18\xF4\xA9\x14\xA0\xC1\x05\x69\xC4\xFE\x96\x70\x30\x26\x8D\x3C\xC8\x6E\x7D\x40\x4D"
+"\x20\xBE\xCB\x20\x7C\x90\x49\x78\xA4\x10\x09\x65\xD1\x70\x84\x35\x4C\x80\x06\xB8\x8F\x1F"
+"\x36\x63\x80\x14\x6F\x20\x6A\x84\x3D\xD6\x28\x01\x94\xEB\x21\xFA\x20\x0E\xC5\x2B\x87\xCE"
+"\xA1\x53\x8E\x4E\x20\xF8\x00\xCC\x02\x02\x1D\x6A\x70\x20\x80\x24\x61\x98\x43\x6B\x84\xCD"
+"\x46\x42\x51\x10\x7D\xAB\x27\x78\x04\x10\xC4\x4F\x20\x80\xA4\x6E\x56\x63\x81\x8E\xE8\x80"
+"\x60\xE1\x1F\x42\x89\x8B\x66\xAB\x20\xDE\x6E\xBF\xBC\xEB\x1B\x94\x89\xDF\x0E\x62\x2E\xEA"
+"\x66\x8D\xF4\xA3\x1D\x88\xE0\xF7\x0E\x22\x38\xF4\xA8\x1A\x0D\xC2\x9B\x0E\xC0\x52\xCE\x82"
+"\x74\x92\x63\xAA\x30\xA4\x0C\x01\xA0\x6C\xC8\x63\x3A\x3C\xF1\x13\x11\x71\x20\x98\xE0\x72"
+"\x00\xC2\xCA\x0C\xA2\x8B\x7A\x42\x14\xFA\x41\x01\xF4\x21\xC3\x00\xE2\x30\x6C\x43\xE4\x0C"
+"\x02\x01\xFF\x61\x16\xBA\x82\x20\x07\x02\x11\x82\x04\x21\xDA\xA5\x51\x04\x4D\x31\xF0\xAC"
+"\x32\xAC\x80\x6F\xB4\x6C\x20\x92\xF1\x55\xD6\x08\x1F\x3C\xC3\xB6\x0C\x62\x2F\x28\xF0\xF8"
+"\x3C\xAD\x31\xC6\x30\x78\xF8\x81\x76\x02\xF2\x20\x34\x2E\x2A\x1A\xC3\xF8\x42\x66\xC2\x12"
+"\x42\x3C\xD0\xE0\x8C\x8E\x62\x1F\xCA\x90\x47\xFA\xE1\x7E\x08\x80\x68\xAE\x6C\x20\x78\xA4"
+"\x7A\x46\x03\x16\xCD\xF0\xC3\x6A\xA6\x39\x0E\xA2\x0E\x80\x41\x2A\x96\xE4\x20\x46\x4D\x3D"
+"\x58\x08\x63\x1A\x80\x1B\xE0\x6E\x1A\xB5\x72\xDC\xD4\x2C\x38\x86\x87\x2C\x4B\x03\x20\x92"
+"\x51\x8A\x4C\x0C\x32\x70\x68\x8B\x32\xC2\x07\xC1\x60\x52\xFE\x84\x1F\xCE\x4C\x20\xEC\x0C"
+"\x44\xB2\xC2\x0F\x09\x82\x41\x00\xE1\x00\x36\x60\x3A\x56\xAE\x20\xB2\x27\x27\xFF\xA8\x65"
+"\xF2\xC1\xC0\xF6\xA1\xFF\x00\x00\x1F\x5A\xA6\x87\x90\x8B\x37\x14\x42\x0C\x09\x4D\xCD\xF6"
+"\x22\xD4\x00\x60\x2E\x22\x4B\x1B\xF2\x11\x21\xA8\x44\x19\x17\x42\x1F\x1A\xB3\x22\xF6\x21"
+"\x18\xFA\xA1\x3B\x80\x02\xD5\x32\x01\x65\x0E\x42\x3C\x58\xD1\x2B\x13\x62\x2F\x6A\x31\xD6"
+"\x56\xCC\xD3\x7E\x93\xA9\x28\x0D\x0C\xC0\xA0\x0E\xFC\x21\x18\x84\xCA\x24\xBD\x06\x68\x4A"
+"\x8E\x0D\x4F\x4B\x3C\x8C\x92\x20\x34\x6E\x32\xCC\x22\x2E\x0F\xA2\x31\x9A\x91\x9B\xA6\x83"
+"\x2B\xAD\x31\x21\x98\x63\x08\x3F\x8D\x8E\xEC\xA5\x2D\x85\x27\xDC\x04\xA2\x2C\x17\x22\x38"
+"\x37\xA5\x1D\xB3\x44\xCD\xEE\xC1\x6B\x18\xA4\xF1\x9C\x13\xE9\xE6\x52\x21\x98\x71\x00\x62"
+"\x20\x10\x55\xD1\xCC\xF6\x29\x28\x62\x43\x22\x17\x62\xCE\x52\xF0\x3E\x2C\x28\xD1\xBC\xA6"
+"\x3E\xBC\xC3\x8F\xD4\x53\x21\xD0\x93\x20\x4C\x00\x04\xEC\x09\x04\x5A\xA0\x80\x44\xD3\x01"
+"\x9D\xA7\x89\x30\x32\xFE\x12\x42\x23\x19\x62\x3B\xC0\x40\x06\x71\x50\xB0\x8C\xE7\x6F\x16"
+"\xE2\xDE\xF2\x4D\x23\xA2\x04\x20\x90\x4C\xDC\x6C\xE6\x20\x0E\xE3\xCA\xF2\xA1\x2D\xDD\xE3"
+"\x12\x7D\xD2\x3A\x9D\x72\xE4\xF8\xC1\x3A\xED\x42\xEC\x06\xA3\x39\x7D\x12\x4F\x1C\xC2\xC8"
+"\xF2\xA6\x2D\x7F\xD4\x8B\x0E\x82\x39\xB2\x23\x7B\x2C\x13\x15\x97\x82\x47\x19\x42\x4F\xEC"
+"\x83\x41\x06\x54\x66\xF6\xB0\x20\x34\x2E\x65\x00\x02\x2B\xA2\x13\x56\x24\x63\x21\xF4\xE3"
+"\x80\x98\x00\x14\x43\x46\x20\xFC\xE0\x1C\xFF\xD0\xB9\x04\x02\x2B\x02\x33\x20\x48\x12\x3C"
+"\xE7\xF3\x20\x4C\x24\x7D\x16\x22\x18\xAF\x88\x28\xA6\x03\x84\xDA\x85\x85\x76\x0E\x32\x27"
+"\x22\xCB\x66\xE1\x31\x16\x32\x20\x90\x4C\x47\x0B\x42\x40\xFE\xC1\x14\x54\x04\x48\xE3\xAD"
+"\x27\x0B\x02\x5D\x78\xCC\x2F\xCA\x4E\x3D\xDE\xC2\x14\x62\xC9\xFA\xAE\xB1\x88\x26\x35\x96"
+"\x0C\xF3\xD8\x10\x23\x88\xFC\xA1\x86\x74\xF2\x34\x2A\xC3\x53\xC5\x6D\x3A\xEC\x52\x20\xA8"
+"\x47\x47\x38\xC9\x52\x03\x82\xEC\x2A\xF4\x21\x9A\xA0\x5A\x9A\xAF\x20\xC8\xE5\x18\x0D\xC2"
+"\x25\x8B\x29\x17\xCF\x33\x3B\x11\xA2\x09\xB0\x24\x80\x10\xA2\x78\xB2\xC2\x1D\xA6\x74\xFC"
+"\x2C\x4C\x58\xC9\x47\x57\xCD\xB0\x6A\x40\x55\x04\xBD\xAB\x53\x28\x49\x1F\xB4\xD2\x07\xFF"
+"\xC1\x30\xF7\x62\x4D\x07\x62\xEF\x5E\xA2\x25\x1A\x82\x55\x09\x02\x63\xFE\x2C\x23\xCC\x29"
+"\x21\x82\x6F\x5C\x75\x8E\x1F\x37\xAA\x4C\xDD\xD4\xF6\xD8\xF5\x21\x64\xE1\x31\xEA\xB3\x5D"
+"\xE5\x15\x22\x1E\xE3\x19\x8A\x75\x5E\xF1\x95\x20\x0E\x60\xF8\xF2\xB5\x5F\xFD\xF5\x5F\x01"
+"\x36\x60\x05\x76\x60\x09\xB6\x60\x0D\xF6\x60\x11\x36\x61\x15\x76\x61\x19\xB6\x61\x01\x62"
+"\x26\x18\x82\x5F\x1D\x76\xA2\xB6\x91\xAA\x9C\x54\x50\x2B\xC3\x5B\x01\xA2\x50\xD6\x75\xA2"
+"\x74\xAA\x61\x0F\x09\x29\xA9\xC6\x56\x7F\xE2\x31\x08\xB5\xA2\x9C\xC6\x03\xF1\x35\x64\x7F"
+"\xAE\xBF\xDA\x61\x56\x09\x82\x14\x54\x6E\xA3\x76\x48\x61\x59\x16\xA1\x14\x41\x1D\x05\x82"
+"\x06\xAC\x89\x20\x24\x91\xC6\x2A\x91\x46\x49\x24\x20\x86\x76\x20\xD2\x8B\x43\x3E\xD2\x43"
+"\xDC\xCB\x20\xD4\xE0\x1B\xDE\xE1\x1B\x22\x87\x51\x01\xA2\x19\x42\x09\x10\x9C\xF6\x1D\xAA"
+"\xB2\xA6\x9C\x56\x16\x0E\xE0\x17\xA4\x16\x00\x9A\x81\xF1\xDC\xE1\x1D\xB8\x36\x54\x9E\x01"
+"\x1A\xBE\xE1\x44\x0F\xA2\x19\x6C\x0A\x6A\x4D\x01\x66\x97\x03\x39\xA1\x36\xAE\xBA\xE1\x1D"
+"\xC2\xF2\x4C\xCD\x32\x20\x12\x20\x18\xA0\x01\xC4\x8E\x76\x16\x44\x04\x21\xB8\x65\x16\x96"
+"\xD6\x20\x1A\x34\x20\x1A\x23\xC1\x82\xF1\xE8\x70\xC3\x26\x45\x51\x20\x28\x26\x9C\xAA\x86"
+"\x4F\x01\xA0\x50\xB2\x84\x72\xF9\x01\x51\x1D\x66\x75\xA0\xB5\x88\xDA\xEE\x48\xB3\x64\x49"
+"\x13\x08\x61\xBA\xAE\x6A\x32\x34\x6F\x41\xA5\xBA\xDC\xB1\xE1\xFA\x67\x25\x73\x4E\xC9\x7E"
+"\xE5\x14\x07\x02\x68\xF0\xD0\x47\x51\xF7\x71\x09\xC2\x52\x0E\x40\x11\xFC\x61\x03\x1A\xE0"
+"\x77\xED\x11\x20\xBA\xA8\xFA\x00\x22\x00\xB4\xF5\x59\xA9\x83\x36\x1A\xCD\x78\x00\xA0\x33"
+"\x84\xB1\xFB\xC0\x82\x00\xCC\x04\x1C\xFF\xC1\x23\x08\x40\x2D\x2D\x6C\x3A\xD6\xE5\x00\xD4"
+"\xB2\x1C\xEF\xB2\x27\x02\xA5\x35\x0A\xE0\x88\x72\xE8\x66\x03\x80\x41\xB0\x35\x20\x30\x46"
+"\x52\xBC\xA6\x1F\x2F\x85\x85\x82\xF3\x00\x4C\xC1\x73\x64\x57\x20\x7C\x50\x47\xBA\x28\x7D"
+"\x9F\xA4\x81\x1A\x2B\x21\x6A\x64\x0E\x1A\x62\x3A\xC4\x0E\x3A\xFD\xEF\x79\xC9\x17\x20\x34"
+"\x0E\x11\x6B\xC4\x42\x0E\x91\xB6\x34\x44\x3C\xC4\xC5\x4F\xCC\xA8\x1F\x8E\x0A\x11\xBC\x26"
+"\x64\x97\x88\x68\x5C\x91\xB8\xD4\x6C\x8D\x82\x13\xC9\x20\xE5\x7B\x42\x34\x46\x03\x62\x3B"
+"\xBE\x76\x7F\x35\x48\xD9\x6A\xC4\x1D\x36\x40\xCD\xF6\x81\x48\x01\x62\x2E\x0A\x06\x40\xBD"
+"\x4B\x58\xB2\xA1\xFD\xEE\x52\x4E\xD3\x81\x66\xBE\xA3\x36\x38\x58\x6A\x3A\x2D\x5C\xBC\x83"
+"\x11\x8A\xF0\x74\x7F\x18\x6E\x8E\xEF\x4F\x42\xA1\x32\x08\xAB\x0F\xEA\x65\x2F\xA4\x84\x37"
+"\x8B\x08\x42\xF8\x77\xBC\xDA\x45\x4B\x66\x01\xF0\xF2\x10\xE7\x54\x09\x82\x1D\x58\x20\x16"
+"\x34\x3C\x79\x2D\x8C\x21\x97\x8A\x23\xB8\x0D\x83\x78\x8A\x15\x82\xFC\x68\x2D\x5F\x58\x48"
+"\x84\x2F\x13\x94\x00\x60\x19\x70\x58\x20\x94\x60\x66\x4D\x4D\x2B\x51\x58\x43\x17\xC2\x0A"
+"\x82\x01\x95\x70\x4D\x8D\x71\xAE\x6E\x7C\xD8\xB7\x1E\x8E\x8C\x65\x24\xC5\x10\x19\x77\x19"
+"\xF9\xD3\xD0\xD8\xC8\x42\xD6\x33\x12\xEE\x4D\xF1\x16\x00\xC4\x83\x0A\xCE\xA8\x09\xD2\xA1"
+"\x3B\xF2\xA1\x0C\x83\x63\x32\x68\x25\x7D\xBB\x73\x94\x87\xF1\x21\x04\x40\x06\x17\xF2\xA0"
+"\xEA\x37\x83\x68\x4B\x58\x16\x19\x8E\x0D\x94\x74\xF6\xB8\x94\xAD\x11\x92\x29\xE9\x27\x01"
+"\xE0\x8E\x8D\xD8\x2D\xDD\x38\x21\x82\x23\x0D\x68\xE0\x1F\x0E\x60\x12\xF8\x21\x63\x3A\xD6"
+"\x34\x01\x20\x0E\x54\x13\x81\x88\xA8\x8A\x55\x16\x00\xD0\x01\x16\x0F\xEA\x6E\x02\x82\x95"
+"\x6B\x18\x8C\xEB\xE5\x83\xEC\x85\x87\xCD\xF8\x88\x51\xC3\x96\xCD\xB3\x72\x5F\x32\x54\x91"
+"\xF8\x20\xF4\x01\x18\x32\xC1\x47\x64\x00\x71\x54\xD2\x20\xE6\xC2\x0A\xB6\x41\x2B\x81\x82"
+"\x49\x68\x38\xDE\x9A\x95\x21\x8E\xE6\x52\x17\x22\x39\x5C\x0E\x00\x90\x0C\x1C\x55\x08\x43"
+"\x4E\x16\x00\x10\x70\xC4\x8A\x62\xA0\x47\x99\x62\x26\x49\x46\x2E\xF8\x96\xF1\x42\x3C\xEA"
+"\x98\x9C\x2B\x19\x00\xF4\x64\x45\xCC\x62\x29\xEE\x99\x4B\x97\x42\x94\xA7\x02\x06\x01\x80"
+"\x5C\x34\x68\x2E\xD0\xAE\x21\xC2\x14\xA1\x0F\x0A\x1F\x01\x43\x75\xA9\x97\x3C\xA8\x67\x5D"
+"\x93\xCB\xA3\xC9\xA5\x63\x67\x99\x97\x6B\xF9\x69\x48\x0E\x89\x5B\xC1\x4C\xDD\x79\xBC\x0E"
+"\x09\xC2\xD4\x66\xCE\x22\x7A\x20\x2A\x3A\xA3\x91\x71\x29\x66\xA1\x1D\x5E\x77\x20\x2E\xDA"
+"\x1D\x4C\xE1\x1B\xB2\x96\x78\xA0\x61\x16\x9A\x7A\x29\x12\xB2\x8C\x1B\x62\x89\xFF\x61\xFF"
+"\x92\xBA\x3C\x3A\x75\x29\x26\x79\x20\xE8\x34\x13\x54\x24\x5E\xE3\xA9\x9B\x69\xF9\x9B\xBD"
+"\x66\xCE\xBE\x61\x16\xBC\xB7\xAC\xB1\x29\xCF\x14\x82\x5E\x3A\x98\x92\x52\x8B\x4D\x1A\x63"
+"\x83\x01\x42\x3C\x76\x39\x06\xB5\x84\x07\x2A\x76\x20\x28\x28\x2B\xA8\x77\x58\x09\xAF\x3C"
+"\x2E\x16\x13\x98\x02\x04\x52\xD1\xB7\xD4\x40\xB6\xC8\x28\x21\x1C\xFB\x44\xB4\x18\x0F\xB7"
+"\x6B\x46\x1A\xCA\xC8\x1A\xE0\xE2\x28\x57\xFC\xE6\x62\xAF\x99\xD1\x85\x2F\x16\x26\x64\xE2"
+"\x21\xBC\x49\x62\x83\x0F\x62\x54\xE2\x62\x1A\xF9\xD8\x00\x98\x00\x24\x96\x90\x82\x97\x9C"
+"\xBC\xE4\x99\x11\xE2\x35\x02\x95\x60\x6D\x07\x29\x57\xAA\x1B\x82\xA1\x2F\x96\x42\x59\x0B"
+"\x36\xB7\x7F\x6E\xA5\x46\xD7\x1F\x5E\x35\x60\x8B\x82\x4F\x93\x3B\xF5\x20\x46\x01\x26\xB6"
+"\x9F\x94\xD5\x9F\x9E\x7B\xBA\xA9\xBB\xBA\xAD\xFB\xBA\xB1\x3B\xBB\xB5\x7B\xBB\xB9\xBB\xBB"
+"\xBD\x1B\xA5\x84\xEF\xBB\x33\xEA\xAF\x33\x62\xFA\xB6\xFA\x22\xC8\x1B\x22\xD2\xDB\xBA\x75"
+"\x9B\x21\xF6\xCD\x43\xDC\xA1\x35\x2F\xA2\xBD\xDD\xDA\xBB\xE9\x9B\xE2\xE4\xF4\x25\xEE\xDB"
+"\xAA\xED\x7B\xB8\x49\x0C\x27\x90\x62\xBF\x6F\x97\xBB\xF9\x41\x0D\x88\xC0\x6D\xE1\x36\x20"
+"\xB8\x82\x6C\xBB\xF6\x6B\xE1\xA4\x21\x78\x40\x72\xBE\x21\x13\xC2\x55\x6B\x43\xA4\x02\xF4"
+"\x41\x83\x36\xC0\x14\x24\xB0\x67\x7D\xEB\x0B\x4C\xC0\x1D\xBE\xA1\x6C\x0F\x22\x02\xA0\x16"
+"\x6A\xA1\xA1\xB0\xFF\x95\xFC\x98\x02\xE2\x14\xA8\x9B\x1A\x60\x77\x7B\xF7\x77\x2B\xE5\x20"
+"\x6E\xC8\x33\x12\x1C\xC2\x36\xD7\x20\x80\x26\x4B\x48\x76\x59\x9D\xEA\x36\x3B\xE5\xB8\xDB"
+"\x55\x7B\x01\x80\x7B\xC9\xF1\x28\xFF\xE1\x37\x36\xE0\x31\xC4\x45\x72\x3B\x85\x4F\x07\xC0"
+"\xC3\xE6\x47\x00\x62\x41\x3F\x7F\x94\x08\x9A\xF7\xBC\x4D\xED\x1F\x02\x2A\xB6\x97\xF5\x17"
+"\x82\x6F\x7A\x0D\x51\x2A\x02\x85\x72\xFB\xF5\x46\xF3\x5A\x18\x17\xB8\xC8\xE2\x70\x08\x4C"
+"\x61\x9A\x0E\x35\x13\x32\xC1\x14\xDA\x3A\x3C\xD6\x12\x43\x10\x91\x80\x6D\x88\xCD\xBB\x70"
+"\x8D\x93\x24\x81\x1D\xEB\x79\xFB\xB5\x87\x71\xA6\x89\xEA\xA6\x46\x34\xA8\x66\xDF\x11\xCC"
+"\x02\x80\x26\xA2\x19\x73\x64\x38\x20\xEA\x79\x20\xE6\xA2\xAA\x5B\x79\x3C\x3D\x6D\xB1\x71"
+"\xDB\xAC\xBD\x67\x0F\x7D\x30\x85\x8B\x4B\xC7\x83\xFC\xD3\xBB\x58\x18\x81\x24\x44\xBD\xAB"
+"\x65\x16\x39\x11\x77\x86\xD0\xF3\x75\xA6\x9D\xD1\x89\x2A\x9D\x96\xDF\xED\xC4\xA1\xB6\x0C"
+"\xEB\xB7\x90\x09\x82\x39\x88\x9C\x1F\x0E\x59\x00\xDD\x02\x6A\x61\x7D\x65\x3D\xDD\x68\x55"
+"\xD3\x8B\x25\x9A\x73\x55\xFD\xD3\xEB\xC6\x9A\x4D\x3D\x80\x5D\xB9\x5E\x6A\xC4\x1B\x9C\xDB"
+"\xB9\x04\xDC\xF5\x64\x1D\xB5\xC4\x54\x61\x08\x5D\xD9\xB4\x79\x21\xA8\x19\x20\xA0\x7D\xD6"
+"\x7F\x9C\xAA\xA6\x1D\x73\xBE\xC7\x7B\x15\xDD\x60\xB7\x5D\x20\x18\x04\x13\x1A\xC0\xB1\x45"
+"\xFD\xB4\x82\x72\x9F\xFF\xA1\x9F\xFF\xD9\x20\xEE\x7D\x21\x2A\x93\x0E\xFB\x61\xA0\xC3\x3D"
+"\x97\x8B\x7D\x5E\xDF\x3D\x20\x36\xCC\xA8\x6F\x6E\xD9\x9F\xC3\x32\x5E\x15\xA5\x2F\x64\x3A"
+"\xD6\xC7\x2C\x7A\x57\x3A\xB4\xA7\xA5\x8F\x6C\xD5\x0E\x40\xE2\xDD\xFD\xD8\x97\x05\x10\x32"
+"\x81\x07\x1A\xE0\xDB\xC7\x2B\x19\x0F\xD5\x14\xFE\xD8\xC2\xB0\xFA\x70\xB8\xFC\x86\x2E\xD0"
+"\x7C\xB2\x77\x29\xD0\xD6\xAB\xCD\xB9\x98\x66\x41\xB0\x0D\x56\xFC\xD6\x5B\x20\xF2\xB3\xDE"
+"\x19\x42\x0D\x7E\x67\x06\x01\x00\xB1\x5D\x67\xBD\xC3\x2A\x2B\xB2\xB7\xB1\xB5\x44\x3E\x85"
+"\x89\x98\xDA\x01\xC3\x43\x5B\x61\x07\xA0\x78\x88\x9C\x21\xFA\x11\x62\x75\xAF\xC2\xEF\xD1"
+"\xB5\x19\xC2\x9B\xAC\x5E\xEB\xAB\x1B\x72\xA4\xDA\x32\xF0\x5A\xBC\x19\x8D\xD4\xB9\xCD\xEC"
+"\x47\xAF\x5C\xC1\x5C\xED\xDD\xFE\xED\xE1\x3E\xEE\xE5\x7E\xEE\xE9\xBE\xEE\xED\xFE\xEE\xF1"
+"\x3E\xEF\xF5\x7E\xEF\xF9\xBE\xEF\xFD\xFE\xEF\x01\x3F\xF0\x05\x7F\xF0\x09\xBF\xF0\x0D\xFF"
+"\xF0\x11\x3F\xF1\x15\x7F\xF1\x19\xBF\xF1\x1D\xFF\xF1\x21\x3F\xF2\x25\x7F\xF2\x29\xBF\xF2"
+"\x2D\xFF\xF2\x31\x3F\xF3\x35\x7F\xF3\x39\xBF\xF3\x3D\xFF\xF3\x41\x3F\xF4\x45\x7F\xF4\x37"
+"\x4A\xF8\x68\x9B\xAB\x7A\x6F\x24\x20\xA6\xED\x1D\x8A\x7F\x4C\xD7\x6F\x4E\x53\x20\x1A\x23"
+"\x21\x83\x51\xAB\x02\x80\x34\x6C\x8B\x22\xAF\x06\x2A\xAA\x48\xD1\x0A\xE2\xD0\x68\xDA\x91"
+"\xAF\x85\xD4\xB3\x24\xA8\x01\x02\x76\xB2\xC4\x15\xC9\xEF\x2D\x78\xC0\x10\x65\xC1\x33\xB4"
+"\x9C\xB6\xB2\x82\xF9\x9D\x1F\xFA\xE3\x2D\xBF\xD3\xD8\xCD\xAB\x5A\x1B\x8C\x7F\xE7\xF7\x67"
+"\x01\x0B\x70\x29\x42\xB0\x31\x82\xEB\x88\x9A\x6F\x28\x69\xAC\x28\x15\x2C\x76\x93\x6C\x17"
+"\x84\x0C\x55\x03\x59\xF8\x6D\x3D\x86\xC1\xDF\x2D\x80\xC8\xF8\x6F\xE8\x1B\x50\xFE\x08\x33"
+"\x34\x28\x80\x28\x2B\x9C\x01\x08\x28\x30\x60\x03\x7F\xFF\xFC\x99\x82\xF6\xEF\x1F\xA6\x81"
+"\x0E\xF9\xFD\x7B\xF7\x6E\xE1\x3F\x80\x0E\x09\x1A\x44\xA8\xF0\x1F\xA9\x8B\x00\xCE\xFC\xEB"
+"\x77\xF1\x8C\xBF\x00\x0E\x41\xF2\x73\xA8\xE3\xA0\xC9\x8B\xFC\xE8\x78\x8C\xE9\x31\xDD\xBF"
+"\x19\x17\x0B\xF8\x13\x39\x50\xC9\xBF\x4B\x1E\x13\xFD\x5B\x24\xB0\x40\x3F\x7F\x09\x2E\x2E"
+"\x2B\x39\xF2\x1F\x08\x87\x5E\x6A\x5E\xD4\xA6\x73\x20\xC9\x96\x54\x95\xCA\x7C\x29\x33\x60"
+"\x82\x83\x2D\xB6\x0E\xD4\x1A\x10\xC4\xBE\x9E\x1E\xB5\x31\x14\x08\xA2\xDF\x3F\x16\x31\xC5"
+"\x02\x20\x6B\x36\xEA\xBF\x52\x6A\xD9\xBA\x3D\xB9\xF0\xCB\x49\xAC\x02\x41\xFE\x1B\x32\x10"
+"\x1F\x4B\x8F\x70\xC1\x7A\xA4\x52\x31\xA6\xA8\xC0\x83\xFF\x31\xF0\x38\x80\x9F\xD1\x80\x94"
+"\xFE\xFD\xF1\x28\xC7\xEF\x5F\x7F\x03\x1C\x7E\xC0\xEC\x30\x00\xBF\x6E\x23\x39\x07\xAC\xBA"
+"\xF5\xB0\x47\x9E\x55\x10\x0B\x3C\x1C\x40\x9F\x3F\x03\x0E\x4B\x2C\x1E\x18\xDA\xB4\x61\x98"
+"\x02\x67\xD7\x76\x08\xE2\x1F\x37\xD0\xFF\x78\x53\x5D\xD8\xCF\xEA\x47\xD4\x80\xA7\x0E\x59"
+"\x88\x3A\x20\x6B\xD8\x01\x27\xFB\x8B\xEC\x91\xC1\xBF\x94\x01\x57\xC6\x92\xF9\x34\x3C\xF7"
+"\xE5\x1E\x55\xF7\x65\x0E\x60\x40\x3F\xE4\x01\x35\x88\x4E\x7F\x5A\xFD\x43\xDF\x32\xE5\xFC"
+"\xFB\x60\x1D\x00\xEB\x38\x4C\x1D\x22\xF2\x9F\x43\xBD\x54\xE6\x92\x7D\x01\xF9\xD7\xD4\x40"
+"\x40\x29\x38\x10\x81\x47\x51\xD5\x0F\x18\xF1\xA5\xE6\x5C\x3F\x80\xFC\xF3\x1A\x00\xF9\xB8"
+"\xC3\xC8\x74\xFC\x1D\xB8\x1F\x00\x8D\x85\xE8\x50\x25\xFF\x30\x11\x50\x3E\xD9\x6D\x95\xCF"
+"\x3F\x11\x34\xA6\xE1\x69\x02\x45\x70\x40\x40\x5E\x4C\x87\x0E\x67\x5D\x40\x25\x9F\x8F\x6F"
+"\x95\xE8\xD0\x0C\x73\xC1\xC6\xDA\x24\x02\x0A\xB4\xCC\x54\x03\xF1\x58\x42\x6F\x0E\x1D\xD9"
+"\x60\x40\x4A\x7A\xD4\xE4\x49\xFD\x08\x90\x4D\x81\xCD\xA9\x77\x46\x3F\x07\xE4\x23\x12\x4F"
+"\x43\x50\xF1\x61\x75\xB0\xC1\xB7\xA4\x47\x38\xF9\x03\x80\x19\x44\xC6\xB4\xD2\x42\xDE\x9D"
+"\xF7\x4F\x05\x00\x84\xC6\x4E\x40\xAE\x4C\x07\x94\x06\x03\xED\xB2\x65\x67\xF4\xA1\x07\x24"
+"\x58\xEC\xFD\x03\x06\x7D\x4F\x0E\x74\xE2\x9F\x03\x29\x33\x1D\x48\x52\xC6\x16\xA2\xA3\x0E"
+"\x45\x4A\x28\x92\x15\xE2\xC9\xD1\xA0\x7D\x01\xC0\x13\x20\xEC\x88\x64\x86\x99\x41\x22\x46"
+"\x93\x4D\x60\xE1\xF7\x8D\x3F\x9E\x21\x86\x56\x8F\x9A\xFD\x87\x46\x61\x49\xD1\x37\x64\x1A"
+"\x03\xE9\x43\xE7\x55\x84\x7E\x58\x29\x62\x3B\x50\xF4\x4D\x26\x3C\xAC\x76\xE0\x70\x6A\x02"
+"\x90\xE9\x52\x94\x52\xA7\x6C\x48\x17\x39\xAB\x17\xA5\xAA\x29\xF3\x0F\x05\x15\x76\xA9\x94"
+"\x3E\x0B\xBD\x56\x68\x58\xA8\x6E\xA5\x98\x45\x88\xB9\x88\x22\x6C\xAD\x2C\xA4\x9D\x47\x2C"
+"\xFC\xF3\x67\xB6\xF9\x35\xAB\xE7\x4D\xFD\x9C\x0B\x9F\x4F\xF3\xF1\x9B\x15\xB9\x03\x6D\x10"
+"\x0C\x45\x21\x7D\x66\xD8\x1F\x01\x10\xD0\x80\x1A\x0B\xA5\xE8\xD0\x2B\xFF\xD8\x66\xAD\xC1"
+"\x08\x2B\xCC\xF0\x45\x0F\x47\x9C\xDC\xB5\x4A\x51\x90\x9B\xB8\x5C\x02\xB0\xC4\xB4\x20\x1B"
+"\x28\xE2\x7A\x45\xB9\x0B\x56\xC7\xBF\xC0\x06\x01\x45\xE1\xC5\x04\xDF\x6B\xFC\xD4\xA1\xCF"
+"\x1C\x1B\x16\x77\x16\x56\xB6\xE6\xF5\xE3\xA7\xFE\x8A\x48\x80\x09\xDD\xFC\xD3\x4E\x4C\x65"
+"\x0D\xFC\x4F\x90\x4A\x6A\x0A\x2D\x00\x48\x0F\xBC\xB4\x79\x12\xFF\x1A\x50\x63\x4E\x7E\x8C"
+"\x1E\x08\x0D\x70\xCB\xE8\x7E\x24\x8A\xB8\xCF\xAE\x88\x65\x6B\xC5\x36\xF4\x7A\x44\x1A\x1A"
+"\x11\xBC\xD8\x4A\x71\x67\x02\xC0\x73\x40\xDA\x7C\x48\x92\x47\x38\x2E\x2A\xAC\xC9\x00\xD0"
+"\xF4\xE8\x43\xEE\xCC\x12\xCC\x2C\x07\xC5\x54\xAD\xC6\x86\x01\x2E\x78\x1D\x11\x14\x2E\xE9"
+"\xA6\x24\x1F\xE0\x8F\xD1\xA6\x76\x0B\xEC\xA2\x70\xC7\x14\x1A\xB3\x60\x61\x2E\x10\x6E\x46"
+"\xC7\x70\x5C\x4C\xA4\xA5\x51\x85\x48\x53\xF4\xD3\xC0\x3E\xA8\xB2\xED\x53\xE4\x2C\xD7\xC9"
+"\xB8\x43\xA2\x04\x1B\xED\xDE\x00\xAC\xD4\xF0\x43\x63\x03\x70\xA2\x8C\x90\x62\x65\x15\x48"
+"\xFA\xB9\xC4\xFB\x56\x86\xFF\xF5\x78\xA1\x01\xCE\x50\x66\xE5\xFD\xD6\x27\xA2\xAA\x26\x77"
+"\x1E\x10\x4D\x79\x65\xF3\xCF\x0E\x31\x61\xF3\x0C\x30\x00\x75\x5C\xC7\x3F\x4E\xC6\x94\xCE"
+"\xE9\x8E\x79\x64\x2B\xF9\x03\x61\x53\x3B\x88\xB7\x77\xEC\x87\xD7\x2E\xFB\x2A\x90\xAD\x82"
+"\x05\xD0\x8F\x6F\xEA\x9C\x0A\xDB\xFD\x17\xE1\xC3\x39\x7E\x21\x4D\x3B\x00\x21\x40\xCB\x79"
+"\x0D\x31\x8A\x81\x9D\x88\xAA\x17\x9D\x9C\x75\x6A\x73\x00\xE8\xC5\x5E\x02\xF2\xAD\x78\xC9"
+"\xC4\x56\x2D\x60\x46\xB0\xA2\xD3\x91\x81\x44\x4E\x82\x7A\x33\x19\x50\x7A\x36\x2E\x48\xB5"
+"\xE5\x22\x1D\x33\xDA\xFB\xE0\x75\xAE\xE8\x21\x66\x85\x0E\x71\x21\xF4\x3E\x22\x9D\xE7\xF9"
+"\x6C\x84\x60\x21\x8A\xA0\xAC\x53\xBD\x6F\xF9\x0D\x00\xBB\xF8\x07\x5F\x96\x62\xA7\x80\x0C"
+"\xB1\x76\x09\x30\x88\xA7\x64\x52\x16\x30\x08\x44\x01\xDC\x20\x22\xE7\xFE\x15\x10\xF5\x34"
+"\xE1\x20\x19\x3B\xA1\x40\x56\x90\x1B\x87\x64\xAF\x14\x04\x10\x5B\x04\xF0\x62\x28\xD8\x64"
+"\xAF\x21\x01\xD9\x80\x19\x73\xF8\xAD\x03\xD6\x50\x87\x5B\x01\xCC\x37\x24\x62\xC7\x77\x4C"
+"\xED\x8C\x31\xC1\x0F\x03\x03\xE2\x32\x58\x09\x69\x64\x00\x50\x0C\x0B\x65\x42\x41\x0C\xCA"
+"\x84\x58\x07\x31\x85\xC0\x8A\x86\x98\xEA\xC1\xE7\x1D\xD0\x98\x85\x29\xDC\xB1\x10\xC1\x24"
+"\x10\x00\x84\x91\xDD\x40\x0A\x92\xB4\xB4\xE8\x11\x2C\x11\xC8\x48\x42\x16\x62\x97\x38\xF2"
+"\x04\x8E\x39\x0C\xC8\x3E\xFC\x71\x47\x89\xE4\x31\x79\x9F\x54\x4E\xDE\x58\x69\xBC\x8B\xD0"
+"\x26\x65\x01\x39\x51\x11\x07\xC2\x36\x06\xB2\x0D\x66\x32\x09\xCD\x0B\x63\x52\x01\x60\x50"
+"\xC4\x1F\x50\x44\x8C\xD8\x54\xC6\x96\x81\x79\x63\x03\x4E\xBC\xA5\xC8\x6E\x19\x90\x03\x0C"
+"\x6E\x21\xEF\x68\xC2\x56\x9A\x69\x1D\x6C\x26\x93\x9B\xE7\x99\x8E\xF9\x70\x58\xB5\x8B\x40"
+"\x6D\x60\xB1\xBC\x1D\x3B\xDB\xE9\x4E\x99\x08\xE0\x00\x04\x78\x67\x4C\x04\x40\x80\x7B\xD2"
+"\xD3\x23\x14\xB4\x26\x3D\xE3\x69\xA3\x7C\x02\x34\xA0\x02\x1D\x28\x41\x0B\xFA\xCE\x8E\xFD"
+"\xE3\x1B\xA6\x78\x86\x41\x1B\xEA\xD0\x87\x42\x34\xA2\x12\xBD\x88\x09\xDA\x71\xC3\x89\x62"
+"\x34\xA3\x1A\xDD\x28\x47\x05\x42\x80\x03\x08\xA0\xA3\x22\x1D\x29\x49\x4B\x6A\xD2\x93\xA2"
+"\x34\xA5\x2A\x5D\x29\x4B\x5B\xEA\xD2\x97\xC2\x34\xA6\x32\x9D\x29\x4D\x6B\x6A\xD3\x9B\xE2"
+"\x34\xA7\x3A\xDD\x29\x4F\x7B\xEA\xD3\x9F\x02\x35\xA8\x42\x1D\xEA\x46\xED\x49\x80\x90\xCE"
+"\xF4\x9E\x47\x25\x6A\x41\x3F\x46\xC1\x55\xA1\x73\x96\xEB\x64\xE5\x27\xF9\xF9\x31\x92\x5D"
+"\x84\x07\xDF\x48\x1A\x3F\x9F\x26\xD5\x45\xA5\x93\x22\xEB\x04\x8C\x74\x82\x21\xCE\xAD\x58"
+"\xE1\x99\x2F\x33\xA2\x74\xA0\x71\xD6\xAD\x44\xA7\x90\x40\x15\x97\x25\x9A\xE8\x11\x7D\xBC"
+"\x72\x22\x1F\xC2\xEB\x44\x22\xF2\x0F\xAB\x4A\xEA\x43\x67\xFB\x87\x3B\x4C\x31\x0B\x68\xF8"
+"\xA3\x97\x0F\x89\xC8\x2B\xA7\xCA\x1F\xC6\xDE\x71\xAC\x90\x65\x62\x3F\x20\x74\x91\x00\xAC"
+"\x63\x21\x0A\x3D\xAC\x3F\x20\x98\x3C\x3B\xAE\x15\x2C\x17\x54\xAC\x4F\x0B\x65\x2B\xF7\xC0"
+"\xE6\xAA\x5C\x8C\xC9\x55\xAF\xDA\x18\x77\x48\xB3\x48\x56\x5C\xED\x1C\xFD\x12\x81\x66\x08"
+"\xD2\x21\xAE\xF8\xC7\x33\xB8\x06\x96\x42\x55\xA0\x2C\xBA\xF3\x88\xC8\x66\xC1\x0F\x11\xE6"
+"\x14\x3D\x2B\x41\x2E\x6B\xDD\xD7\xB9\xD6\xA2\x86\x6D\xCC\x85\xA1\x6C\x53\x8B\x1A\x45\xC0"
+"\x29\x20\x1D\x9B\x6E\xD7\x04\xC2\x80\xCE\x6E\x25\x1D\x6D\xF2\xCF\xF6\xE6\xAA\x94\x0A\x1C"
+"\xC4\xB2\xFB\x51\xAD\x1C\x57\xF9\xB1\xFF\xED\xA7\x7A\xB4\x95\xC9\x55\xF5\xC1\x2C\xF8\x22"
+"\xE6\x63\xFB\xF0\xAC\x43\x32\xE0\xA9\xC8\x15\x93\xA7\x76\x2B\x00\x44\x9C\x96\x5F\xE7\xFE"
+"\x0B\xBA\xEA\x41\xDE\x23\x67\xDB\xDE\x71\xD2\xE7\x52\xC0\xAB\xA5\xCF\x00\x2C\x93\x00\x11"
+"\x2F\x52\x5B\x14\xF0\x97\xEE\x81\xBE\xBD\xB1\xD7\x76\xF4\x6D\xD3\x45\xBA\x80\x1A\x06\x73"
+"\xAE\xAB\x86\x51\xF1\x39\x07\xF2\x14\x4A\xA1\xB8\xB9\x03\x09\x00\x6E\x49\x3B\x90\x30\x09"
+"\x44\x64\xBF\x13\xF0\xC0\x0C\x7C\x60\x0A\x3F\xF7\x1F\x80\xA8\x03\x91\x89\xAC\x86\x60\x9C"
+"\xD8\x2F\x3C\x30\x45\x26\x32\x61\x8A\xB7\x3C\x43\x0D\x45\xAE\x03\x0D\xB2\xF2\x0D\x46\x34"
+"\xD9\xC9\x98\x74\xEF\xE3\x62\x5C\x27\x26\x67\x62\x16\x06\x09\xB0\x40\xE0\x23\x4C\xEE\x90"
+"\x39\xB9\xEA\x64\x67\x88\xDF\x47\xDF\x59\x5E\x74\xC2\x02\xD9\x43\x32\xC1\xFA\x49\x45\x38"
+"\xF1\xCE\x10\xBE\x08\x28\xBA\xEC\xBE\xE4\x7C\xD2\x1F\x06\xC6\xCF\x96\x35\x09\xC8\x9E\x82"
+"\xC4\x34\xEC\x12\xA6\x88\xDA\xFC\x5C\x7F\xB4\x60\x03\x92\x96\x74\x05\x2E\x91\x64\xAB\x24"
+"\xEC\x00\x8A\x30\x13\x26\x2A\x30\xE9\xAD\x65\x65\x11\x07\x68\x00\xA9\x1B\x30\xCF\x38\x02"
+"\xE0\xC5\x98\xFA\x73\x67\x36\x50\xEA\x0A\x4C\xE8\x1F\xBE\x75\x48\x52\x0A\x16\x90\x00\xF9"
+"\xD8\xA6\x24\xB1\x4D\x00\xCA\x52\x68\xEB\x38\x3A\xC1\x24\x76\x08\xE5\x68\x1D\xD8\xCB\xB1"
+"\x78\x77\xD6\x6D\x9A\xB1\x29\x7C\x95\x8B\x10\x8B\xD1\x02\x29\x4B\x1D\xC0\x60\x6D\x2B\x64"
+"\x36\xD9\x34\x45\x0F\x6E\x82\x23\xA2\x3E\x20\xB8\xB6\x08\x1C\x08\xED\x36\x8C\xD5\xF9\x26"
+"\x6B\xD9\xD4\xF2\xC7\xAC\xAD\xE6\xED\x1F\xBB\x84\xBF\x00\x60\x1B\x9C\xA5\xAD\xD3\x42\x01"
+"\x25\xCD\x32\xD1\x12\x90\x85\x3D\x6E\x81\xF0\xA8\x44\xAA\x95\xEF\x83\xE3\xC8\x9E\xFA\x0D"
+"\x52\x69\xC0\x46\xCD\x00\xBE\xE8\xB9\xBA\x6C\xC0\x04\x12\x07\x01\x0D\xDA\xF3\x53\x71\xB9"
+"\xC8\xC6\x01\xE1\xA4\x40\x5C\x26\xD7\x4C\xBA\x17\x35\x21\x44\xB5\x9B\xAB\x0B\xEF\x81\x2C"
+"\xE3\x1F\xF2\x73\x48\x08\x9D\xDD\xDD\x8E\x83\x57\x2F\x50\x15\x08\xBF\x4B\xCB\x19\xF8\xBC"
+"\xE8\x22\x5D\xF1\x06\x27\x23\x50\x16\x8D\xA3\xBB\xC5\x3F\x1B\x08\xBB\xBC\xD1\x6E\x34\xF4"
+"\xCF\x87\x0E\x2E\x54\x04\x32\x2B\xC1\x50\xFC\x83\xE7\x27\x27\xC8\xB7\x86\xBB\x4B\x44\x02"
+"\x8A\x45\x88\x46\x0D\x7E\x10\x7E\x80\x0B\xBE\x63\x16\x5B\x75\xB8\x43\xF8\x7A\x90\x77\xF8"
+"\x03\xB0\xFF\x16\xC8\x00\x2E\x08\x8D\x30\x6F\x35\xE9\xB0\x69\x65\x5E\x25\x2B\x91\x3A\x4A"
+"\x47\xBD\x33\x4E\xD7\x66\x83\x81\xC7\xA5\xDC\x91\x22\x64\xC6\xD5\xB3\x6C\x4E\x1F\xB4\xEC"
+"\x38\x20\x4D\x18\x3B\x61\xAD\xD0\xCD\x4F\x06\x49\xC1\x31\x01\x83\x5A\x23\x22\x8B\xA3\x69"
+"\x7B\xDA\x5F\xD5\x4B\x32\xDD\x8A\x98\x26\x58\x52\x9D\x5D\x4A\x9A\x3F\xBE\xB1\x4C\xA4\x4C"
+"\x15\x24\x26\x60\xAA\x75\x02\x20\x00\xA4\x8E\xF4\xA3\x04\x70\x39\x4A\x65\x0F\x7B\xD6\xE3"
+"\x3E\xF7\xBA\xDF\x3D\xEF\x7B\xEF\xFB\xDF\x03\x3F\xF8\xC2\x1F\x3E\xF1\x8B\x6F\xFC\xE3\x23"
+"\x3F\xF9\xCA\x5F\x3E\xF3\x9B\xEF\xFC\xE7\x43\x3F\xFA\xD2\x9F\x3E\xF5\xAB\x6F\xFD\xEB\x63"
+"\x3F\xFB\xDA\xDF\x3E\xF7\xBB\xEF\xFD\xEF\x83\x3F\xFC\xE2\x1F\x3F\xF9\xCB\x6F\xFE\xF3\xA3"
+"\x3F\xFD\xEA\x5F\x3F\xFB\xDB\xEF\xFE\xF7\xC3\xFF\xF8";
+#undef DD_ALIGNED_BUFFER
+
+static const FontCharSet s_fontMonoid18CharSet = {
+  /* bitmap               = */ s_fontMonoid18Bitmap,
+  /* bitmapWidth          = */ 256,
+  /* bitmapHeight         = */ 256,
+  /* bitmapColorChannels  = */ 1,
+  /* bitmapDecompressSize = */ 65536,
+  /* charBaseHeight       = */ 20,
+  /* charWidth            = */ 17,
+  /* charHeight           = */ 30,
+  /* charCount            = */ 96,
+  {
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0, 150 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,  60 }, {  17,  60 }, {  68,   0 },
+   { 153,   0 }, { 119,   0 }, {  34,   0 }, { 204,  30 },
+   { 119,  30 }, { 102,  30 }, {   0,   0 }, { 102,   0 },
+   { 170,  30 }, { 136,   0 }, { 187,  30 }, { 221,   0 },
+   {  34,  60 }, { 187,  60 }, { 170,  60 }, { 153,  60 },
+   { 136,  60 }, { 119,  60 }, { 102,  60 }, {  85,  60 },
+   {  68,  60 }, {  51,  60 }, { 136,  30 }, { 153,  30 },
+   {  17,  30 }, {  85,   0 }, {   0,  30 }, { 221,  30 },
+   { 204,   0 }, { 170, 210 }, { 153, 210 }, { 136, 210 },
+   { 119, 210 }, { 102, 210 }, {  85, 210 }, {  68, 210 },
+   {  51, 210 }, {  34, 210 }, {  17, 210 }, {   0, 210 },
+   { 238, 180 }, { 221, 180 }, { 204, 180 }, { 187, 180 },
+   { 170, 180 }, { 153, 180 }, { 136, 180 }, { 119, 180 },
+   { 102, 180 }, {  85, 180 }, {  68, 180 }, {  51, 180 },
+   {  34, 180 }, {  17, 180 }, {   0, 180 }, {  85,  30 },
+   { 187,   0 }, {  68,  30 }, { 170,   0 }, {  51,   0 },
+   { 238,  30 }, { 119, 120 }, { 102, 120 }, {  85, 120 },
+   {  68, 120 }, {  51, 120 }, {  34, 120 }, {  17, 120 },
+   {   0, 120 }, { 238,  90 }, { 221,  90 }, { 204,  90 },
+   { 187,  90 }, { 170,  90 }, { 153,  90 }, { 136,  90 },
+   { 119,  90 }, { 102,  90 }, {  85,  90 }, {  68,  90 },
+   {  51,  90 }, {  34,  90 }, {  17,  90 }, {   0,  90 },
+   { 238,  60 }, { 221,  60 }, { 204,  60 }, {  51,  30 },
+   { 238,   0 }, {  34,  30 }, {  17,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
+   {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 }
+  }
+};
+
+// ========================================================
+// LZW decompression helpers for the font bitmap:
+// ========================================================
+
+// These must match the font-tool encoder!
+static const int LzwNil            = -1;
+static const int LzwMaxDictBits    = 12;
+static const int LzwStartBits      = 9;
+static const int LzwFirstCode      = (1 << (LzwStartBits - 1)); // 256
+static const int LzwMaxDictEntries = (1 << LzwMaxDictBits);     // 4096
+
+struct LzwDictionary
+{
+    // Dictionary entries 0-255 are always reserved to the byte/ASCII range.
+    struct Entry
+    {
+        int code;
+        int value;
+    };
+
+    int size;
+    Entry entries[LzwMaxDictEntries];
+
+    LzwDictionary();
+    int findIndex(int code, int value) const;
+    bool add(int code, int value);
+    bool flush(int & codeBitsWidth);
+};
+
+struct LzwBitStreamReader
+{
+    const std::uint8_t * stream; // Pointer to the external bit stream. Not owned by the reader.
+    int sizeInBytes;             // Size of the stream in bytes. Might include padding.
+    int sizeInBits;              // Size of the stream in bits, padding not include.
+    int currBytePos;             // Current byte being read in the stream.
+    int nextBitPos;              // Bit position within the current byte to access next. 0 to 7.
+    int numBitsRead;             // Total bits read from the stream so far. Never includes byte-rounding.
+
+    LzwBitStreamReader(const std::uint8_t * bitStream, int byteCount, int bitCount);
+    bool readNextBit(int & outBit);
+    int readBits(int bitCount);
+};
+
+// ========================================================
+// LzwDictionary:
+// ========================================================
+
+LzwDictionary::LzwDictionary()
+{
+    // First 256 dictionary entries are reserved to the byte/ASCII
+    // range. Additional entries follow for the character sequences
+    // found in the input. Up to 4096 - 256 (LzwMaxDictEntries - LzwFirstCode).
+    size = LzwFirstCode;
+    for (int i = 0; i < size; ++i)
+    {
+        entries[i].code  = LzwNil;
+        entries[i].value = i;
+    }
+}
+
+int LzwDictionary::findIndex(const int code, const int value) const
+{
+    if (code == LzwNil)
+    {
+        return value;
+    }
+    for (int i = 0; i < size; ++i)
+    {
+        if (entries[i].code == code && entries[i].value == value)
+        {
+            return i;
+        }
+    }
+    return LzwNil;
+}
+
+bool LzwDictionary::add(const int code, const int value)
+{
+    if (size == LzwMaxDictEntries)
+    {
+        return false;
+    }
+    entries[size].code  = code;
+    entries[size].value = value;
+    ++size;
+    return true;
+}
+
+bool LzwDictionary::flush(int & codeBitsWidth)
+{
+    if (size == (1 << codeBitsWidth))
+    {
+        ++codeBitsWidth;
+        if (codeBitsWidth > LzwMaxDictBits)
+        {
+            // Clear the dictionary (except the first 256 byte entries).
+            codeBitsWidth = LzwStartBits;
+            size = LzwFirstCode;
+            return true;
+        }
+    }
+    return false;
+}
+
+// ========================================================
+// LzwBitStreamReader:
+// ========================================================
+
+LzwBitStreamReader::LzwBitStreamReader(const std::uint8_t * bitStream, const int byteCount, const int bitCount)
+    : stream(bitStream)
+    , sizeInBytes(byteCount)
+    , sizeInBits(bitCount)
+    , currBytePos(0)
+    , nextBitPos(0)
+    , numBitsRead(0)
+{ }
+
+bool LzwBitStreamReader::readNextBit(int & outBit)
+{
+    if (numBitsRead >= sizeInBits)
+    {
+        return false; // We are done.
+    }
+
+    const int mask = 1 << nextBitPos;
+    outBit = !!(stream[currBytePos] & mask);
+    ++numBitsRead;
+
+    if (++nextBitPos == 8)
+    {
+        nextBitPos = 0;
+        ++currBytePos;
+    }
+    return true;
+}
+
+int LzwBitStreamReader::readBits(const int bitCount)
+{
+    int num = 0;
+    for (int b = 0; b < bitCount; ++b)
+    {
+        int bit;
+        if (!readNextBit(bit))
+        {
+            break;
+        }
+        const int mask = 1 << b;
+        num = (num & ~mask) | (-bit & mask);
+    }
+    return num;
+}
+
+// ========================================================
+// lzwDecompress() and helpers:
+// ========================================================
+
+static bool lzwOutputByte(int code, std::uint8_t *& output, int outputSizeBytes, int & bytesDecodedSoFar)
+{
+    if (code < 0 || code >= 256)
+    {
+        return false;
+    }
+    if (bytesDecodedSoFar >= outputSizeBytes)
+    {
+        return false;
+    }
+    *output++ = static_cast<std::uint8_t>(code);
+    ++bytesDecodedSoFar;
+    return true;
+}
+
+static bool lzwOutputSequence(const LzwDictionary & dict, int code,
+                              std::uint8_t *& output, int outputSizeBytes,
+                              int & bytesDecodedSoFar, int & firstByte)
+{
+    // A sequence is stored backwards, so we have to write
+    // it to a temp then output the buffer in reverse.
+    int i = 0;
+    std::uint8_t sequence[LzwMaxDictEntries];
+    do
+    {
+        sequence[i++] = dict.entries[code].value & 0xFF;
+        code = dict.entries[code].code;
+    } while (code >= 0);
+
+    firstByte = sequence[--i];
+    for (; i >= 0; --i)
+    {
+        if (!lzwOutputByte(sequence[i], output, outputSizeBytes, bytesDecodedSoFar))
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+static int lzwDecompress(const void * compressedData, int compressedSizeBytes,
+                         int compressedSizeBits, void * uncompressedData,
+                         int uncompressedSizeBytes)
+{
+    if (compressedData == nullptr || uncompressedData == nullptr)
+    {
+        return 0;
+    }
+    if (compressedSizeBytes <= 0 || compressedSizeBits <= 0 || uncompressedSizeBytes <= 0)
+    {
+        return 0;
+    }
+
+    int code          = LzwNil;
+    int prevCode      = LzwNil;
+    int codeBitsWidth = LzwStartBits;
+    int firstByte     = 0;
+    int bytesDecoded  = 0;
+
+    const std::uint8_t * compressedPtr = reinterpret_cast<const std::uint8_t *>(compressedData);
+    std::uint8_t * uncompressedPtr = reinterpret_cast<std::uint8_t *>(uncompressedData);
+
+    // We'll reconstruct the dictionary based on the bit stream codes.
+    LzwBitStreamReader bitStream(compressedPtr, compressedSizeBytes, compressedSizeBits);
+    LzwDictionary dictionary;
+
+    // We check to avoid an overflow of the user buffer.
+    // If the buffer is smaller than the decompressed size, we
+    // break the loop and return the current decompression count.
+    while (bitStream.numBitsRead < bitStream.sizeInBits)
+    {
+        if (codeBitsWidth > LzwMaxDictBits)
+        {
+            break;
+        }
+        code = bitStream.readBits(codeBitsWidth);
+
+        if (prevCode == LzwNil)
+        {
+            if (!lzwOutputByte(code, uncompressedPtr, uncompressedSizeBytes, bytesDecoded))
+            {
+                break;
+            }
+            firstByte = code;
+            prevCode  = code;
+            continue;
+        }
+
+        if (code >= dictionary.size)
+        {
+            if (!lzwOutputSequence(dictionary, prevCode, uncompressedPtr,
+                 uncompressedSizeBytes, bytesDecoded, firstByte))
+            {
+                break;
+            }
+            if (!lzwOutputByte(firstByte, uncompressedPtr, uncompressedSizeBytes, bytesDecoded))
+            {
+                break;
+            }
+        }
+        else
+        {
+            if (!lzwOutputSequence(dictionary, code, uncompressedPtr,
+                 uncompressedSizeBytes, bytesDecoded, firstByte))
+            {
+                break;
+            }
+        }
+
+        if (!dictionary.add(prevCode, firstByte))
+        {
+            break;
+        }
+
+        if (dictionary.flush(codeBitsWidth))
+        {
+            prevCode = LzwNil;
+        }
+        else
+        {
+            prevCode = code;
+        }
+    }
+
+    return bytesDecoded;
+}
+
+// ========================================================
+// Built-in font glyph bitmap decompression:
+// ========================================================
+
+// If you decide to change the font, these are the only things that
+// need to be updated. The s_font* variables are never referenced
+// directly in the code, these functions are used instead.
+static inline const std::uint8_t * getRawFontBitmapData() { return s_fontMonoid18Bitmap;  }
+static inline const FontCharSet  & getFontCharSet()       { return s_fontMonoid18CharSet; }
+
+static std::uint8_t * decompressFontBitmap()
+{
+    const std::uint32_t * compressedData = reinterpret_cast<const std::uint32_t *>(getRawFontBitmapData());
+
+    // First two uint32s are the compressed size in
+    // bytes followed by the compressed size in bits.
+    const int compressedSizeBytes = *compressedData++;
+    const int compressedSizeBits  = *compressedData++;
+
+    // Allocate the decompression buffer:
+    const int uncompressedSizeBytes = getFontCharSet().bitmapDecompressSize;
+    std::uint8_t * uncompressedData = static_cast<std::uint8_t *>(DD_MALLOC(uncompressedSizeBytes));
+
+    // Out of memory? Font rendering will be disable.
+    if (uncompressedData == nullptr)
+    {
+        return nullptr;
+    }
+
+    // Decode the bitmap pixels (stored with an LZW-flavor of compression):
+    const int bytesDecoded = lzwDecompress(compressedData,
+                                           compressedSizeBytes,
+                                           compressedSizeBits,
+                                           uncompressedData,
+                                           uncompressedSizeBytes);
+
+    // Unexpected decompression size? Probably a data mismatch in the font-tool.
+    if (bytesDecoded != uncompressedSizeBytes)
+    {
+        DD_MFREE(uncompressedData);
+        return nullptr;
+    }
+
+    // Must later free with DD_MFREE().
+    return uncompressedData;
+}
+
+// ========================================================
+// Internal Debug Draw queues and helper types/functions:
+// ========================================================
+
+struct DebugString
+{
+    std::int64_t expiryDateMillis;
+    ddVec3       color;
+    float        posX;
+    float        posY;
+    float        scaling;
+    ddStr        text;
+    bool         centered;
+};
+
+struct DebugPoint
+{
+    std::int64_t expiryDateMillis;
+    ddVec3       position;
+    ddVec3       color;
+    float        size;
+    bool         depthEnabled;
+};
+
+struct DebugLine
+{
+    std::int64_t expiryDateMillis;
+    ddVec3       posFrom;
+    ddVec3       posTo;
+    ddVec3       color;
+    bool         depthEnabled;
+};
+
+struct InternalContext DD_EXPLICIT_CONTEXT_ONLY(: public OpaqueContextType)
+{
+    int                vertexBufferUsed;
+    int                debugStringsCount;
+    int                debugPointsCount;
+    int                debugLinesCount;
+    std::int64_t       currentTimeMillis;                           // Latest time value (in milliseconds) from dd::flush().
+    GlyphTextureHandle glyphTexHandle;                              // Our built-in glyph bitmap. If kept null, no text is rendered.
+    RenderInterface *  renderInterface;                             // Ref to the external renderer. Can be null for a no-op debug draw.
+    DrawVertex         vertexBuffer[DEBUG_DRAW_VERTEX_BUFFER_SIZE]; // Vertex buffer we use to expand the lines/points before calling on RenderInterface.
+    DebugString        debugStrings[DEBUG_DRAW_MAX_STRINGS];        // Debug strings queue (2D screen-space strings + 3D projected labels).
+    DebugPoint         debugPoints[DEBUG_DRAW_MAX_POINTS];          // 3D debug points queue.
+    DebugLine          debugLines[DEBUG_DRAW_MAX_LINES];            // 3D debug lines queue.
+
+    InternalContext(RenderInterface * renderer)
+        : vertexBufferUsed(0)
+        , debugStringsCount(0)
+        , debugPointsCount(0)
+        , debugLinesCount(0)
+        , currentTimeMillis(0)
+        , glyphTexHandle(nullptr)
+        , renderInterface(renderer)
+    { }
+};
+
+// ========================================================
+// Library context mode selection:
+// ========================================================
+
+#if (defined(DEBUG_DRAW_PER_THREAD_CONTEXT) && defined(DEBUG_DRAW_EXPLICIT_CONTEXT))
+    #error "DEBUG_DRAW_PER_THREAD_CONTEXT and DEBUG_DRAW_EXPLICIT_CONTEXT are mutually exclusive!"
+#endif // DEBUG_DRAW_PER_THREAD_CONTEXT && DEBUG_DRAW_EXPLICIT_CONTEXT
+
+#if defined(DEBUG_DRAW_EXPLICIT_CONTEXT)
+    //
+    // Explicit context passed as argument
+    //
+    #define DD_CONTEXT static_cast<InternalContext *>(ctx)
+#elif defined(DEBUG_DRAW_PER_THREAD_CONTEXT)
+    //
+    // Per-thread global context (MT safe)
+    //
+    #if defined(__GNUC__) || defined(__clang__) // GCC/Clang
+        #define DD_THREAD_LOCAL static __thread
+    #elif defined(_MSC_VER) // Visual Studio
+        #define DD_THREAD_LOCAL static __declspec(thread)
+    #else // Try C++11 thread_local
+        #if DEBUG_DRAW_CXX11_SUPPORTED
+            #define DD_THREAD_LOCAL static thread_local
+        #else // !DEBUG_DRAW_CXX11_SUPPORTED
+            #error "Unsupported compiler - unknown TLS model"
+        #endif // DEBUG_DRAW_CXX11_SUPPORTED
+    #endif // TLS model
+    DD_THREAD_LOCAL InternalContext * s_threadContext = nullptr;
+    #define DD_CONTEXT s_threadContext
+    #undef DD_THREAD_LOCAL
+#else // Debug Draw context selection
+    //
+    // Global static context (single threaded operation)
+    //
+    static InternalContext * s_globalContext = nullptr;
+    #define DD_CONTEXT s_globalContext
+#endif // Debug Draw context selection
+
+// ========================================================
+
+#if DEBUG_DRAW_USE_STD_MATH
+
+static inline float floatAbs(float x)       { return fabsf(x); }
+static inline float floatSin(float radians) { return sinf(radians); }
+static inline float floatCos(float radians) { return cosf(radians); }
+static inline float floatInvSqrt(float x)   { return (1.0f / sqrtf(x)); }
+
+#else // !DEBUG_DRAW_USE_STD_MATH
+
+// ========================================================
+// Fast approximations of math functions used by Debug Draw
+// ========================================================
+
+union Float2UInt
+{
+    float asFloat;
+    std::uint32_t asUInt;
+};
+
+static inline float floatRound(float x)
+{
+    // Probably slower than std::floor(), also depends of FPU settings,
+    // but we only need this for that special sin/cos() case anyways...
+    const int i = static_cast<int>(x);
+    return (x >= 0.0f) ? static_cast<float>(i) : static_cast<float>(i - 1);
+}
+
+static inline float floatAbs(float x)
+{
+    // Mask-off the sign bit
+    Float2UInt i;
+    i.asFloat = x;
+    i.asUInt &= 0x7FFFFFFF;
+    return i.asFloat;
+}
+
+static inline float floatInvSqrt(float x)
+{
+    // Modified version of the emblematic Q_rsqrt() from Quake 3.
+    // See: http://en.wikipedia.org/wiki/Fast_inverse_square_root
+    Float2UInt i;
+    float y, r;
+    y = x * 0.5f;
+    i.asFloat = x;
+    i.asUInt = 0x5F3759DF - (i.asUInt >> 1);
+    r = i.asFloat;
+    r = r * (1.5f - (r * r * y));
+    return r;
+}
+
+static inline float floatSin(float radians)
+{
+    static const float A = -2.39e-08;
+    static const float B = 2.7526e-06;
+    static const float C = 1.98409e-04;
+    static const float D = 8.3333315e-03;
+    static const float E = 1.666666664e-01;
+
+    if (radians < 0.0f || radians >= TAU)
+    {
+        radians -= floatRound(radians / TAU) * TAU;
+    }
+
+    if (radians < PI)
+    {
+        if (radians > HalfPI)
+        {
+            radians = PI - radians;
+        }
+    }
+    else
+    {
+        radians = (radians > (PI + HalfPI)) ? (radians - TAU) : (PI - radians);
+    }
+
+    const float s = radians * radians;
+    return radians * (((((A * s + B) * s - C) * s + D) * s - E) * s + 1.0f);
+}
+
+static inline float floatCos(float radians)
+{
+    static const float A = -2.605e-07;
+    static const float B = 2.47609e-05;
+    static const float C = 1.3888397e-03;
+    static const float D = 4.16666418e-02;
+    static const float E = 4.999999963e-01;
+
+    if (radians < 0.0f || radians >= TAU)
+    {
+        radians -= floatRound(radians / TAU) * TAU;
+    }
+
+    float d;
+    if (radians < PI)
+    {
+        if (radians > HalfPI)
+        {
+            radians = PI - radians;
+            d = -1.0f;
+        }
+        else
+        {
+            d = 1.0f;
+        }
+    }
+    else
+    {
+        if (radians > (PI + HalfPI))
+        {
+            radians = radians - TAU;
+            d = 1.0f;
+        }
+        else
+        {
+            radians = PI - radians;
+            d = -1.0f;
+        }
+    }
+
+    const float s = radians * radians;
+    return d * (((((A * s + B) * s - C) * s + D) * s - E) * s + 1.0f);
+}
+
+#endif // DEBUG_DRAW_USE_STD_MATH
+
+// ========================================================
+// ddVec3 helpers:
+// ========================================================
+
+enum VecElements { X, Y, Z, W };
+
+static inline void vecSet(ddVec3_Out dest, const float x, const float y, const float z)
+{
+    dest[X] = x;
+    dest[Y] = y;
+    dest[Z] = z;
+}
+
+static inline void vecCopy(ddVec3_Out dest, ddVec3_In src)
+{
+    dest[X] = src[X];
+    dest[Y] = src[Y];
+    dest[Z] = src[Z];
+}
+
+static inline void vecAdd(ddVec3_Out result, ddVec3_In a, ddVec3_In b)
+{
+    result[X] = a[X] + b[X];
+    result[Y] = a[Y] + b[Y];
+    result[Z] = a[Z] + b[Z];
+}
+
+static inline void vecSub(ddVec3_Out result, ddVec3_In a, ddVec3_In b)
+{
+    result[X] = a[X] - b[X];
+    result[Y] = a[Y] - b[Y];
+    result[Z] = a[Z] - b[Z];
+}
+
+static inline void vecScale(ddVec3_Out result, ddVec3_In v, const float s)
+{
+    result[X] = v[X] * s;
+    result[Y] = v[Y] * s;
+    result[Z] = v[Z] * s;
+}
+
+static inline void vecNormalize(ddVec3_Out result, ddVec3_In v)
+{
+    const float lenSqr = v[X] * v[X] + v[Y] * v[Y] + v[Z] * v[Z];
+    const float invLen = floatInvSqrt(lenSqr);
+    result[X] = v[X] * invLen;
+    result[Y] = v[Y] * invLen;
+    result[Z] = v[Z] * invLen;
+}
+
+static inline void vecOrthogonalBasis(ddVec3_Out left, ddVec3_Out up, ddVec3_In v)
+{
+    // Produces two orthogonal vectors for normalized vector v.
+    float lenSqr, invLen;
+    if (floatAbs(v[Z]) > 0.7f)
+    {
+        lenSqr  = v[Y] * v[Y] + v[Z] * v[Z];
+        invLen  = floatInvSqrt(lenSqr);
+        up[X]   = 0.0f;
+        up[Y]   =  v[Z] * invLen;
+        up[Z]   = -v[Y] * invLen;
+        left[X] = lenSqr * invLen;
+        left[Y] = -v[X] * up[Z];
+        left[Z] =  v[X] * up[Y];
+    }
+    else
+    {
+        lenSqr  = v[X] * v[X] + v[Y] * v[Y];
+        invLen  = floatInvSqrt(lenSqr);
+        left[X] = -v[Y] * invLen;
+        left[Y] =  v[X] * invLen;
+        left[Z] = 0.0f;
+        up[X]   = -v[Z] * left[Y];
+        up[Y]   =  v[Z] * left[X];
+        up[Z]   = lenSqr * invLen;
+    }
+}
+
+// ========================================================
+// ddMat4x4 helpers:
+// ========================================================
+
+static inline void matTransformPointXYZ(ddVec3_Out result, ddVec3_In p, ddMat4x4_In m)
+{
+    result[X] = (m[0] * p[X]) + (m[4] * p[Y]) + (m[8]  * p[Z]) + m[12]; // p[W] assumed to be 1
+    result[Y] = (m[1] * p[X]) + (m[5] * p[Y]) + (m[9]  * p[Z]) + m[13];
+    result[Z] = (m[2] * p[X]) + (m[6] * p[Y]) + (m[10] * p[Z]) + m[14];
+}
+
+static inline void matTransformPointXYZW(float result[4], ddVec3_In p, ddMat4x4_In m)
+{
+    result[X] = (m[0] * p[X]) + (m[4] * p[Y]) + (m[8]  * p[Z]) + m[12]; // p[W] assumed to be 1
+    result[Y] = (m[1] * p[X]) + (m[5] * p[Y]) + (m[9]  * p[Z]) + m[13];
+    result[Z] = (m[2] * p[X]) + (m[6] * p[Y]) + (m[10] * p[Z]) + m[14];
+    result[W] = (m[3] * p[X]) + (m[7] * p[Y]) + (m[11] * p[Z]) + m[15];
+}
+
+static inline float matTransformPointXYZW2(ddVec3_Out result, const float p[3], ddMat4x4_In m)
+{
+    result[X] = (m[0] * p[X]) + (m[4] * p[Y]) + (m[8]  * p[Z]) + m[12]; // p[W] assumed to be 1
+    result[Y] = (m[1] * p[X]) + (m[5] * p[Y]) + (m[9]  * p[Z]) + m[13];
+    result[Z] = (m[2] * p[X]) + (m[6] * p[Y]) + (m[10] * p[Z]) + m[14];
+    float rw  = (m[3] * p[X]) + (m[7] * p[Y]) + (m[11] * p[Z]) + m[15];
+    return rw;
+}
+
+// ========================================================
+// Misc local functions for draw queue management:
+// ========================================================
+
+enum DrawMode
+{
+    DrawModePoints,
+    DrawModeLines,
+    DrawModeText
+};
+
+static void flushDebugVerts(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) const DrawMode mode, const bool depthEnabled)
+{
+    if (DD_CONTEXT->vertexBufferUsed == 0)
+    {
+        return;
+    }
+
+    switch (mode)
+    {
+    case DrawModePoints :
+        DD_CONTEXT->renderInterface->drawPointList(DD_CONTEXT->vertexBuffer,
+                                                   DD_CONTEXT->vertexBufferUsed,
+                                                   depthEnabled);
+        break;
+    case DrawModeLines :
+        DD_CONTEXT->renderInterface->drawLineList(DD_CONTEXT->vertexBuffer,
+                                                  DD_CONTEXT->vertexBufferUsed,
+                                                  depthEnabled);
+        break;
+    case DrawModeText :
+        DD_CONTEXT->renderInterface->drawGlyphList(DD_CONTEXT->vertexBuffer,
+                                                   DD_CONTEXT->vertexBufferUsed,
+                                                   DD_CONTEXT->glyphTexHandle);
+        break;
+    } // switch (mode)
+
+    DD_CONTEXT->vertexBufferUsed = 0;
+}
+
+static void pushPointVert(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) const DebugPoint & point)
+{
+    // Make room for one more vert:
+    if ((DD_CONTEXT->vertexBufferUsed + 1) >= DEBUG_DRAW_VERTEX_BUFFER_SIZE)
+    {
+        flushDebugVerts(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DrawModePoints, point.depthEnabled);
+    }
+
+    DrawVertex & v = DD_CONTEXT->vertexBuffer[DD_CONTEXT->vertexBufferUsed++];
+    v.point.x      = point.position[X];
+    v.point.y      = point.position[Y];
+    v.point.z      = point.position[Z];
+    v.point.r      = point.color[X];
+    v.point.g      = point.color[Y];
+    v.point.b      = point.color[Z];
+    v.point.size   = point.size;
+}
+
+static void pushLineVert(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) const DebugLine & line)
+{
+    // Make room for two more verts:
+    if ((DD_CONTEXT->vertexBufferUsed + 2) >= DEBUG_DRAW_VERTEX_BUFFER_SIZE)
+    {
+        flushDebugVerts(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DrawModeLines, line.depthEnabled);
+    }
+
+    DrawVertex & v0 = DD_CONTEXT->vertexBuffer[DD_CONTEXT->vertexBufferUsed++];
+    DrawVertex & v1 = DD_CONTEXT->vertexBuffer[DD_CONTEXT->vertexBufferUsed++];
+
+    v0.line.x = line.posFrom[X];
+    v0.line.y = line.posFrom[Y];
+    v0.line.z = line.posFrom[Z];
+    v0.line.r = line.color[X];
+    v0.line.g = line.color[Y];
+    v0.line.b = line.color[Z];
+
+    v1.line.x = line.posTo[X];
+    v1.line.y = line.posTo[Y];
+    v1.line.z = line.posTo[Z];
+    v1.line.r = line.color[X];
+    v1.line.g = line.color[Y];
+    v1.line.b = line.color[Z];
+}
+
+static void pushGlyphVerts(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) const DrawVertex verts[4])
+{
+    static const int indexes[6] = { 0, 1, 2, 2, 1, 3 };
+
+    // Make room for one more glyph (2 tris):
+    if ((DD_CONTEXT->vertexBufferUsed + 6) >= DEBUG_DRAW_VERTEX_BUFFER_SIZE)
+    {
+        flushDebugVerts(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DrawModeText, false);
+    }
+
+    for (int i = 0; i < 6; ++i)
+    {
+        DD_CONTEXT->vertexBuffer[DD_CONTEXT->vertexBufferUsed++].glyph = verts[indexes[i]].glyph;
+    }
+}
+
+static void pushStringGlyphs(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) float x, float y,
+                             const char * text, ddVec3_In color, const float scaling)
+{
+    // Invariants for all characters:
+    const float initialX    = x;
+    const float scaleU      = static_cast<float>(getFontCharSet().bitmapWidth);
+    const float scaleV      = static_cast<float>(getFontCharSet().bitmapHeight);
+    const float fixedWidth  = static_cast<float>(getFontCharSet().charWidth);
+    const float fixedHeight = static_cast<float>(getFontCharSet().charHeight);
+    const float tabW        = fixedWidth  * 4.0f * scaling; // TAB = 4 spaces.
+    const float chrW        = fixedWidth  * scaling;
+    const float chrH        = fixedHeight * scaling;
+
+    for (; *text != '\0'; ++text)
+    {
+        const int charVal = *text;
+        if (charVal >= FontCharSet::MaxChars)
+        {
+            continue;
+        }
+        if (charVal == ' ')
+        {
+            x += chrW;
+            continue;
+        }
+        if (charVal == '\t')
+        {
+            x += tabW;
+            continue;
+        }
+        if (charVal == '\n')
+        {
+            y += chrH;
+            x  = initialX;
+            continue;
+        }
+
+        const FontChar fontChar = getFontCharSet().chars[charVal];
+        const float u0 = (fontChar.x + 0.5f) / scaleU;
+        const float v0 = (fontChar.y + 0.5f) / scaleV;
+        const float u1 = u0 + (fixedWidth  / scaleU);
+        const float v1 = v0 + (fixedHeight / scaleV);
+
+        DrawVertex verts[4];
+        verts[0].glyph.x = x;
+        verts[0].glyph.y = y;
+        verts[0].glyph.u = u0;
+        verts[0].glyph.v = v0;
+        verts[0].glyph.r = color[X];
+        verts[0].glyph.g = color[Y];
+        verts[0].glyph.b = color[Z];
+        verts[1].glyph.x = x;
+        verts[1].glyph.y = y + chrH;
+        verts[1].glyph.u = u0;
+        verts[1].glyph.v = v1;
+        verts[1].glyph.r = color[X];
+        verts[1].glyph.g = color[Y];
+        verts[1].glyph.b = color[Z];
+        verts[2].glyph.x = x + chrW;
+        verts[2].glyph.y = y;
+        verts[2].glyph.u = u1;
+        verts[2].glyph.v = v0;
+        verts[2].glyph.r = color[X];
+        verts[2].glyph.g = color[Y];
+        verts[2].glyph.b = color[Z];
+        verts[3].glyph.x = x + chrW;
+        verts[3].glyph.y = y + chrH;
+        verts[3].glyph.u = u1;
+        verts[3].glyph.v = v1;
+        verts[3].glyph.r = color[X];
+        verts[3].glyph.g = color[Y];
+        verts[3].glyph.b = color[Z];
+
+        pushGlyphVerts(DD_EXPLICIT_CONTEXT_ONLY(ctx,) verts);
+        x += chrW;
+    }
+}
+
+static float calcTextWidth(const char * text, const float scaling)
+{
+    const float fixedWidth = static_cast<float>(getFontCharSet().charWidth);
+    const float tabW = fixedWidth * 4.0f * scaling; // TAB = 4 spaces.
+    const float chrW = fixedWidth * scaling;
+
+    float x = 0.0f;
+    for (; *text != '\0'; ++text)
+    {
+        // Tabs are handled differently (4 spaces)
+        if (*text == '\t')
+        {
+            x += tabW;
+        }
+        else // Non-tab char (including whitespace)
+        {
+            x += chrW;
+        }
+    }
+
+    return x;
+}
+
+static void drawDebugStrings(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx))
+{
+    const int count = DD_CONTEXT->debugStringsCount;
+    if (count == 0)
+    {
+        return;
+    }
+
+    const DebugString * const debugStrings = DD_CONTEXT->debugStrings;
+
+    for (int i = 0; i < count; ++i)
+    {
+        const DebugString & dstr = debugStrings[i];
+        if (dstr.centered)
+        {
+            // 3D Labels are centered at the point of origin, e.g. center-aligned.
+            const float offset = calcTextWidth(dstr.text.c_str(), dstr.scaling) * 0.5f;
+            pushStringGlyphs(DD_EXPLICIT_CONTEXT_ONLY(ctx,) dstr.posX - offset, dstr.posY, dstr.text.c_str(), dstr.color, dstr.scaling);
+        }
+        else
+        {
+            // Left-aligned
+            pushStringGlyphs(DD_EXPLICIT_CONTEXT_ONLY(ctx,) dstr.posX, dstr.posY, dstr.text.c_str(), dstr.color, dstr.scaling);
+        }
+    }
+
+    flushDebugVerts(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DrawModeText, false);
+}
+
+static void drawDebugPoints(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx))
+{
+    const int count = DD_CONTEXT->debugPointsCount;
+    if (count == 0)
+    {
+        return;
+    }
+
+    const DebugPoint * const debugPoints = DD_CONTEXT->debugPoints;
+
+    //
+    // First pass, points with depth test ENABLED:
+    //
+    int numDepthlessPoints = 0;
+    for (int i = 0; i < count; ++i)
+    {
+        const DebugPoint & point = debugPoints[i];
+        if (point.depthEnabled)
+        {
+            pushPointVert(DD_EXPLICIT_CONTEXT_ONLY(ctx,) point);
+        }
+        numDepthlessPoints += !point.depthEnabled;
+    }
+    flushDebugVerts(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DrawModePoints, true);
+
+    //
+    // Second pass draws points with depth DISABLED:
+    //
+    if (numDepthlessPoints > 0)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            const DebugPoint & point = debugPoints[i];
+            if (!point.depthEnabled)
+            {
+                pushPointVert(DD_EXPLICIT_CONTEXT_ONLY(ctx,) point);
+            }
+        }
+        flushDebugVerts(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DrawModePoints, false);
+    }
+}
+
+static void drawDebugLines(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx))
+{
+    const int count = DD_CONTEXT->debugLinesCount;
+    if (count == 0)
+    {
+        return;
+    }
+
+    const DebugLine * const debugLines = DD_CONTEXT->debugLines;
+
+    //
+    // First pass, lines with depth test ENABLED:
+    //
+    int numDepthlessLines = 0;
+    for (int i = 0; i < count; ++i)
+    {
+        const DebugLine & line = debugLines[i];
+        if (line.depthEnabled)
+        {
+            pushLineVert(DD_EXPLICIT_CONTEXT_ONLY(ctx,) line);
+        }
+        numDepthlessLines += !line.depthEnabled;
+    }
+    flushDebugVerts(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DrawModeLines, true);
+
+    //
+    // Second pass draws lines with depth DISABLED:
+    //
+    if (numDepthlessLines > 0)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            const DebugLine & line = debugLines[i];
+            if (!line.depthEnabled)
+            {
+                pushLineVert(DD_EXPLICIT_CONTEXT_ONLY(ctx,) line);
+            }
+        }
+        flushDebugVerts(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DrawModeLines, false);
+    }
+}
+
+template<typename T>
+static void clearDebugQueue(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) T * queue, int & queueCount)
+{
+    const std::int64_t time = DD_CONTEXT->currentTimeMillis;
+    if (time == 0)
+    {
+        queueCount = 0;
+        return;
+    }
+
+    int index = 0;
+    T * pElem = queue;
+
+    // Concatenate elements that still need to be draw on future frames:
+    for (int i = 0; i < queueCount; ++i, ++pElem)
+    {
+        if (pElem->expiryDateMillis > time)
+        {
+            if (index != i)
+            {
+                queue[index] = *pElem;
+            }
+            ++index;
+        }
+    }
+
+    queueCount = index;
+}
+
+static void setupGlyphTexture(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx))
+{
+    if (DD_CONTEXT->renderInterface == nullptr)
+    {
+        return;
+    }
+
+    if (DD_CONTEXT->glyphTexHandle != nullptr)
+    {
+        DD_CONTEXT->renderInterface->destroyGlyphTexture(DD_CONTEXT->glyphTexHandle);
+        DD_CONTEXT->glyphTexHandle = nullptr;
+    }
+
+    std::uint8_t * decompressedBitmap = decompressFontBitmap();
+    if (decompressedBitmap == nullptr)
+    {
+        return; // Failed to decompressed. No font rendering available.
+    }
+
+    DD_CONTEXT->glyphTexHandle = DD_CONTEXT->renderInterface->createGlyphTexture(
+                                        getFontCharSet().bitmapWidth,
+                                        getFontCharSet().bitmapHeight,
+                                        decompressedBitmap);
+
+    // No longer needed.
+    DD_MFREE(decompressedBitmap);
+}
+
+// ========================================================
+// Public Debug Draw interface:
+// ========================================================
+
+bool initialize(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle * outCtx,) RenderInterface * renderer)
+{
+    if (renderer == nullptr)
+    {
+        return false;
+    }
+
+    void * buffer = DD_MALLOC(sizeof(InternalContext));
+    if (buffer == nullptr)
+    {
+        return false;
+    }
+
+    InternalContext * newCtx = ::new(buffer) InternalContext(renderer);
+
+    #ifdef DEBUG_DRAW_EXPLICIT_CONTEXT
+    if ((*outCtx) != nullptr) { shutdown(*outCtx); }
+    (*outCtx) = newCtx;
+    #else // !DEBUG_DRAW_EXPLICIT_CONTEXT
+    if (DD_CONTEXT != nullptr) { shutdown(); }
+    DD_CONTEXT = newCtx;
+    #endif // DEBUG_DRAW_EXPLICIT_CONTEXT
+
+    setupGlyphTexture(DD_EXPLICIT_CONTEXT_ONLY(*outCtx));
+    return true;
+}
+
+void shutdown(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx))
+{
+    if (DD_CONTEXT != nullptr)
+    {
+        // If this macro is defined, the user-provided ddStr type
+        // needs some extra cleanup before shutdown, so we run for
+        // all entries in the debugStrings[] array.
+        //
+        // We could call std::string::clear() here, but clear()
+        // doesn't deallocate memory in std string, so we might
+        // as well let the default destructor do the cleanup,
+        // when using the default (AKA std::string) ddStr.
+        #ifdef DEBUG_DRAW_STR_DEALLOC_FUNC
+        for (int i = 0; i < DEBUG_DRAW_MAX_STRINGS; ++i)
+        {
+            DEBUG_DRAW_STR_DEALLOC_FUNC(DD_CONTEXT->debugStrings[i].text);
+        }
+        #endif // DEBUG_DRAW_STR_DEALLOC_FUNC
+
+        if (DD_CONTEXT->renderInterface != nullptr && DD_CONTEXT->glyphTexHandle != nullptr)
+        {
+            DD_CONTEXT->renderInterface->destroyGlyphTexture(DD_CONTEXT->glyphTexHandle);
+        }
+
+        DD_CONTEXT->~InternalContext(); // Destroy first
+        DD_MFREE(DD_CONTEXT);
+
+        #ifndef DEBUG_DRAW_EXPLICIT_CONTEXT
+        DD_CONTEXT = nullptr;
+        #endif // DEBUG_DRAW_EXPLICIT_CONTEXT
+    }
+}
+
+bool isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx))
+{
+    return (DD_CONTEXT != nullptr && DD_CONTEXT->renderInterface != nullptr);
+}
+
+bool hasPendingDraws(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx))
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return false;
+    }
+    return (DD_CONTEXT->debugStringsCount + DD_CONTEXT->debugPointsCount + DD_CONTEXT->debugLinesCount) > 0;
+}
+
+void flush(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) const std::int64_t currTimeMillis, const std::uint32_t flags)
+{
+    if (!hasPendingDraws(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    // Save the last know time value for next dd::line/dd::point calls.
+    DD_CONTEXT->currentTimeMillis = currTimeMillis;
+
+    // Let the user set common render states.
+    DD_CONTEXT->renderInterface->beginDraw();
+
+    // Issue the render calls:
+    if (flags & FlushLines)  { drawDebugLines(DD_EXPLICIT_CONTEXT_ONLY(ctx));   }
+    if (flags & FlushPoints) { drawDebugPoints(DD_EXPLICIT_CONTEXT_ONLY(ctx));  }
+    if (flags & FlushText)   { drawDebugStrings(DD_EXPLICIT_CONTEXT_ONLY(ctx)); }
+
+    // And cleanup if needed.
+    DD_CONTEXT->renderInterface->endDraw();
+
+    // Remove all expired objects, regardless of draw flags:
+    clearDebugQueue(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DD_CONTEXT->debugStrings, DD_CONTEXT->debugStringsCount);
+    clearDebugQueue(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DD_CONTEXT->debugPoints,  DD_CONTEXT->debugPointsCount);
+    clearDebugQueue(DD_EXPLICIT_CONTEXT_ONLY(ctx,) DD_CONTEXT->debugLines,   DD_CONTEXT->debugLinesCount);
+}
+
+void clear(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx))
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    // Let the user cleanup the debug strings:
+    #ifdef DEBUG_DRAW_STR_DEALLOC_FUNC
+    for (int i = 0; i < DEBUG_DRAW_MAX_STRINGS; ++i)
+    {
+        DEBUG_DRAW_STR_DEALLOC_FUNC(DD_CONTEXT->debugStrings[i].text);
+    }
+    #endif // DEBUG_DRAW_STR_DEALLOC_FUNC
+
+    DD_CONTEXT->vertexBufferUsed  = 0;
+    DD_CONTEXT->debugStringsCount = 0;
+    DD_CONTEXT->debugPointsCount  = 0;
+    DD_CONTEXT->debugLinesCount   = 0;
+}
+
+void point(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In pos, ddVec3_In color,
+           const float size, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    if (DD_CONTEXT->debugPointsCount == DEBUG_DRAW_MAX_POINTS)
+    {
+        DEBUG_DRAW_OVERFLOWED("DEBUG_DRAW_MAX_POINTS limit reached! Dropping further debug point draws.");
+        return;
+    }
+
+    DebugPoint & point     = DD_CONTEXT->debugPoints[DD_CONTEXT->debugPointsCount++];
+    point.expiryDateMillis = DD_CONTEXT->currentTimeMillis + durationMillis;
+    point.depthEnabled     = depthEnabled;
+    point.size             = size;
+
+    vecCopy(point.position, pos);
+    vecCopy(point.color, color);
+}
+
+void line(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In from, ddVec3_In to,
+          ddVec3_In color, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    if (DD_CONTEXT->debugLinesCount == DEBUG_DRAW_MAX_LINES)
+    {
+        DEBUG_DRAW_OVERFLOWED("DEBUG_DRAW_MAX_LINES limit reached! Dropping further debug line draws.");
+        return;
+    }
+
+    DebugLine & line      = DD_CONTEXT->debugLines[DD_CONTEXT->debugLinesCount++];
+    line.expiryDateMillis = DD_CONTEXT->currentTimeMillis + durationMillis;
+    line.depthEnabled     = depthEnabled;
+
+    vecCopy(line.posFrom, from);
+    vecCopy(line.posTo, to);
+    vecCopy(line.color, color);
+}
+
+void screenText(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) const char * const str, ddVec3_In pos,
+                ddVec3_In color, const float scaling, const int durationMillis)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    if (DD_CONTEXT->glyphTexHandle == nullptr)
+    {
+        return;
+    }
+
+    if (DD_CONTEXT->debugStringsCount == DEBUG_DRAW_MAX_STRINGS)
+    {
+        DEBUG_DRAW_OVERFLOWED("DEBUG_DRAW_MAX_STRINGS limit reached! Dropping further debug string draws.");
+        return;
+    }
+
+    DebugString & dstr    = DD_CONTEXT->debugStrings[DD_CONTEXT->debugStringsCount++];
+    dstr.expiryDateMillis = DD_CONTEXT->currentTimeMillis + durationMillis;
+    dstr.posX             = pos[X];
+    dstr.posY             = pos[Y];
+    dstr.scaling          = scaling;
+    dstr.text             = str;
+    dstr.centered         = false;
+    vecCopy(dstr.color, color);
+}
+
+void projectedText(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) const char * const str, ddVec3_In pos, ddVec3_In color,
+                   ddMat4x4_In vpMatrix, const int sx, const int sy, const int sw, const int sh, const float scaling,
+                   const int durationMillis)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    if (DD_CONTEXT->glyphTexHandle == nullptr)
+    {
+        return;
+    }
+
+    if (DD_CONTEXT->debugStringsCount == DEBUG_DRAW_MAX_STRINGS)
+    {
+        DEBUG_DRAW_OVERFLOWED("DEBUG_DRAW_MAX_STRINGS limit reached! Dropping further debug string draws.");
+        return;
+    }
+
+    float tempPoint[4];
+    matTransformPointXYZW(tempPoint, pos, vpMatrix);
+
+    // Bail if W ended up as zero.
+    if (floatAbs(tempPoint[W]) < FloatEpsilon)
+    {
+        return;
+    }
+
+    // Bail if point is behind camera.
+    if (tempPoint[Z] < -tempPoint[W] || tempPoint[Z] > tempPoint[W])
+    {
+        return;
+    }
+
+    // Perspective divide (we only care about the 2D part now):
+    tempPoint[X] /= tempPoint[W];
+    tempPoint[Y] /= tempPoint[W];
+
+    // Map to window coordinates:
+    float scrX = ((tempPoint[X] * 0.5f) + 0.5f) * sw + sx;
+    float scrY = ((tempPoint[Y] * 0.5f) + 0.5f) * sh + sy;
+
+    // Need to invert the direction because on OGL the screen origin is the bottom-left corner.
+    // NOTE: This is not renderer agnostic, I think... Should add a #define or something!
+    scrY = static_cast<float>(sh) - scrY;
+
+    DebugString & dstr    = DD_CONTEXT->debugStrings[DD_CONTEXT->debugStringsCount++];
+    dstr.expiryDateMillis = DD_CONTEXT->currentTimeMillis + durationMillis;
+    dstr.posX             = scrX;
+    dstr.posY             = scrY;
+    dstr.scaling          = scaling;
+    dstr.text             = str;
+    dstr.centered         = true;
+    vecCopy(dstr.color, color);
+}
+
+void axisTriad(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddMat4x4_In transform, const float size,
+               const float length, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    ddVec3 p0, p1, p2, p3;
+    ddVec3 xEnd, yEnd, zEnd;
+    ddVec3 origin, cR, cG, cB;
+
+    vecSet(cR, 1.0f, 0.0f, 0.0f);
+    vecSet(cG, 0.0f, 1.0f, 0.0f);
+    vecSet(cB, 0.0f, 0.0f, 1.0f);
+
+    vecSet(origin, 0.0f, 0.0f, 0.0f);
+    vecSet(xEnd, length, 0.0f, 0.0f);
+    vecSet(yEnd, 0.0f, length, 0.0f);
+    vecSet(zEnd, 0.0f, 0.0f, length);
+
+    matTransformPointXYZ(p0, origin, transform);
+    matTransformPointXYZ(p1, xEnd, transform);
+    matTransformPointXYZ(p2, yEnd, transform);
+    matTransformPointXYZ(p3, zEnd, transform);
+
+    arrow(DD_EXPLICIT_CONTEXT_ONLY(ctx,) p0, p1, cR, size, durationMillis, depthEnabled); // X: red axis
+    arrow(DD_EXPLICIT_CONTEXT_ONLY(ctx,) p0, p2, cG, size, durationMillis, depthEnabled); // Y: green axis
+    arrow(DD_EXPLICIT_CONTEXT_ONLY(ctx,) p0, p3, cB, size, durationMillis, depthEnabled); // Z: blue axis
+}
+
+void arrow(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In from, ddVec3_In to, ddVec3_In color,
+           const float size, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    static const float arrowStep = 30.0f; // In degrees
+    static const float arrowSin[45] = {
+        0.0f, 0.5f, 0.866025f, 1.0f, 0.866025f, 0.5f, -0.0f, -0.5f, -0.866025f,
+        -1.0f, -0.866025f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
+    };
+    static const float arrowCos[45] = {
+        1.0f, 0.866025f, 0.5f, -0.0f, -0.5f, -0.866026f, -1.0f, -0.866025f, -0.5f, 0.0f,
+        0.5f, 0.866026f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
+    };
+
+    // Body line:
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) from, to, color, durationMillis, depthEnabled);
+
+    // Aux vectors to compute the arrowhead:
+    ddVec3 up, right, forward;
+    vecSub(forward, to, from);
+    vecNormalize(forward, forward);
+    vecOrthogonalBasis(right, up, forward);
+    vecScale(forward, forward, size);
+
+    // Arrowhead is a cone (sin/cos tables used here):
+    float degrees = 0.0f;
+    for (int i = 0; degrees < 360.0f; degrees += arrowStep, ++i)
+    {
+        float scale;
+        ddVec3 v1, v2, temp;
+
+        scale = 0.5f * size * arrowCos[i];
+        vecScale(temp, right, scale);
+        vecSub(v1, to, forward);
+        vecAdd(v1, v1, temp);
+
+        scale = 0.5f * size * arrowSin[i];
+        vecScale(temp, up, scale);
+        vecAdd(v1, v1, temp);
+
+        scale = 0.5f * size * arrowCos[i + 1];
+        vecScale(temp, right, scale);
+        vecSub(v2, to, forward);
+        vecAdd(v2, v2, temp);
+
+        scale = 0.5f * size * arrowSin[i + 1];
+        vecScale(temp, up, scale);
+        vecAdd(v2, v2, temp);
+
+        line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) v1, to, color, durationMillis, depthEnabled);
+        line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) v1, v2, color, durationMillis, depthEnabled);
+    }
+}
+
+void cross(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In center, const float length,
+           const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    ddVec3 from, to;
+    ddVec3 cR, cG, cB;
+
+    vecSet(cR, 1.0f, 0.0f, 0.0f);
+    vecSet(cG, 0.0f, 1.0f, 0.0f);
+    vecSet(cB, 0.0f, 0.0f, 1.0f);
+
+    const float cx = center[X];
+    const float cy = center[Y];
+    const float cz = center[Z];
+    const float hl = length * 0.5f; // Half on each side.
+
+    // Red line: X - length/2 to X + length/2
+    vecSet(from, cx - hl, cy, cz);
+    vecSet(to,   cx + hl, cy, cz);
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) from, to, cR, durationMillis, depthEnabled);
+
+    // Green line: Y - length/2 to Y + length/2
+    vecSet(from, cx, cy - hl, cz);
+    vecSet(to,   cx, cy + hl, cz);
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) from, to, cG, durationMillis, depthEnabled);
+
+    // Blue line: Z - length/2 to Z + length/2
+    vecSet(from, cx, cy, cz - hl);
+    vecSet(to,   cx, cy, cz + hl);
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) from, to, cB, durationMillis, depthEnabled);
+}
+
+void circle(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In center, ddVec3_In planeNormal, ddVec3_In color,
+            const float radius, const float numSteps, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    ddVec3 left, up;
+    ddVec3 point, lastPoint;
+
+    vecOrthogonalBasis(left, up, planeNormal);
+
+    vecScale(up, up, radius);
+    vecScale(left, left, radius);
+    vecAdd(lastPoint, center, up);
+
+    for (int i = 1; i <= numSteps; ++i)
+    {
+        const float radians = TAU * i / numSteps;
+
+        ddVec3 vs, vc;
+        vecScale(vs, left, floatSin(radians));
+        vecScale(vc, up,   floatCos(radians));
+
+        vecAdd(point, center, vs);
+        vecAdd(point, point,  vc);
+
+        line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) lastPoint, point, color, durationMillis, depthEnabled);
+        vecCopy(lastPoint, point);
+    }
+}
+
+void plane(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In center, ddVec3_In planeNormal, ddVec3_In planeColor,
+           ddVec3_In normalVecColor, const float planeScale, const float normalVecScale, const int durationMillis,
+           const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    ddVec3 v1, v2, v3, v4;
+    ddVec3 tangent, bitangent;
+    vecOrthogonalBasis(tangent, bitangent, planeNormal);
+
+    // A little bit of preprocessor voodoo to make things more interesting :P
+    #define DD_PLANE_V(v, op1, op2) \
+    v[X] = (center[X] op1 (tangent[X] * planeScale) op2 (bitangent[X] * planeScale)); \
+    v[Y] = (center[Y] op1 (tangent[Y] * planeScale) op2 (bitangent[Y] * planeScale)); \
+    v[Z] = (center[Z] op1 (tangent[Z] * planeScale) op2 (bitangent[Z] * planeScale))
+    DD_PLANE_V(v1, -, -);
+    DD_PLANE_V(v2, +, -);
+    DD_PLANE_V(v3, +, +);
+    DD_PLANE_V(v4, -, +);
+    #undef DD_PLANE_V
+
+    // Draw the wireframe plane quadrilateral:
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) v1, v2, planeColor, durationMillis, depthEnabled);
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) v2, v3, planeColor, durationMillis, depthEnabled);
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) v3, v4, planeColor, durationMillis, depthEnabled);
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) v4, v1, planeColor, durationMillis, depthEnabled);
+
+    // Optionally add a line depicting the plane normal:
+    if (normalVecScale != 0.0f)
+    {
+        ddVec3 normalVec;
+        normalVec[X] = (planeNormal[X] * normalVecScale) + center[X];
+        normalVec[Y] = (planeNormal[Y] * normalVecScale) + center[Y];
+        normalVec[Z] = (planeNormal[Z] * normalVecScale) + center[Z];
+        line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) center, normalVec, normalVecColor, durationMillis, depthEnabled);
+    }
+}
+
+void sphere(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In center, ddVec3_In color,
+            const float radius, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    static const int stepSize = 15;
+    ddVec3 cache[360 / stepSize];
+    ddVec3 radiusVec;
+
+    vecSet(radiusVec, 0.0f, 0.0f, radius);
+    vecAdd(cache[0], center, radiusVec);
+
+    for (int n = 1; n < arrayLength(cache); ++n)
+    {
+        vecCopy(cache[n], cache[0]);
+    }
+
+    ddVec3 lastPoint, temp;
+    for (int i = stepSize; i <= 360; i += stepSize)
+    {
+        const float s = floatSin(degreesToRadians(i));
+        const float c = floatCos(degreesToRadians(i));
+
+        lastPoint[X] = center[X];
+        lastPoint[Y] = center[Y] + radius * s;
+        lastPoint[Z] = center[Z] + radius * c;
+
+        for (int n = 0, j = stepSize; j <= 360; j += stepSize, ++n)
+        {
+            temp[X] = center[X] + floatSin(degreesToRadians(j)) * radius * s;
+            temp[Y] = center[Y] + floatCos(degreesToRadians(j)) * radius * s;
+            temp[Z] = lastPoint[Z];
+
+            line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) lastPoint, temp, color, durationMillis, depthEnabled);
+            line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) lastPoint, cache[n], color, durationMillis, depthEnabled);
+
+            vecCopy(cache[n], lastPoint);
+            vecCopy(lastPoint, temp);
+        }
+    }
+}
+
+void cone(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In apex, ddVec3_In dir, ddVec3_In color,
+          const float baseRadius, const float apexRadius, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    static const int stepSize = 20;
+    ddVec3 axis[3];
+    ddVec3 top, temp0, temp1, temp2;
+    ddVec3 p1, p2, lastP1, lastP2;
+
+    vecCopy(axis[2], dir);
+    vecNormalize(axis[2], axis[2]);
+    vecOrthogonalBasis(axis[0], axis[1], axis[2]);
+
+    axis[1][X] = -axis[1][X];
+    axis[1][Y] = -axis[1][Y];
+    axis[1][Z] = -axis[1][Z];
+
+    vecAdd(top, apex, dir);
+    vecScale(temp1, axis[1], baseRadius);
+    vecAdd(lastP2, top, temp1);
+
+    if (apexRadius == 0.0f)
+    {
+        for (int i = stepSize; i <= 360; i += stepSize)
+        {
+            vecScale(temp1, axis[0], floatSin(degreesToRadians(i)));
+            vecScale(temp2, axis[1], floatCos(degreesToRadians(i)));
+            vecAdd(temp0, temp1, temp2);
+
+            vecScale(temp0, temp0, baseRadius);
+            vecAdd(p2, top, temp0);
+
+            line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) lastP2, p2, color, durationMillis, depthEnabled);
+            line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) p2, apex, color, durationMillis, depthEnabled);
+
+            vecCopy(lastP2, p2);
+        }
+    }
+    else // A degenerate cone with open apex:
+    {
+        vecScale(temp1, axis[1], apexRadius);
+        vecAdd(lastP1, apex, temp1);
+
+        for (int i = stepSize; i <= 360; i += stepSize)
+        {
+            vecScale(temp1, axis[0], floatSin(degreesToRadians(i)));
+            vecScale(temp2, axis[1], floatCos(degreesToRadians(i)));
+            vecAdd(temp0, temp1, temp2);
+
+            vecScale(temp1, temp0, apexRadius);
+            vecScale(temp2, temp0, baseRadius);
+
+            vecAdd(p1, apex, temp1);
+            vecAdd(p2, top,  temp2);
+
+            line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) lastP1, p1, color, durationMillis, depthEnabled);
+            line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) lastP2, p2, color, durationMillis, depthEnabled);
+            line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) p1, p2, color, durationMillis, depthEnabled);
+
+            vecCopy(lastP1, p1);
+            vecCopy(lastP2, p2);
+        }
+    }
+}
+
+void box(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) const ddVec3 points[8], ddVec3_In color,
+         const int durationMillis, const bool depthEnabled)
+{
+    // Build the lines from points using clever indexing tricks:
+    // (& 3 is a fancy way of doing % 4, but avoids the expensive modulo operation)
+    for (int i = 0; i < 4; ++i)
+    {
+        line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) points[i], points[(i + 1) & 3], color, durationMillis, depthEnabled);
+        line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) points[4 + i], points[4 + ((i + 1) & 3)], color, durationMillis, depthEnabled);
+        line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) points[i], points[4 + i], color, durationMillis, depthEnabled);
+    }
+}
+
+void box(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In center, ddVec3_In color, const float width,
+         const float height, const float depth, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    const float cx = center[X];
+    const float cy = center[Y];
+    const float cz = center[Z];
+    const float w  = width  * 0.5f;
+    const float h  = height * 0.5f;
+    const float d  = depth  * 0.5f;
+
+    // Create all the 8 points:
+    ddVec3 points[8];
+    #define DD_BOX_V(v, op1, op2, op3) \
+    v[X] = cx op1 w; \
+    v[Y] = cy op2 h; \
+    v[Z] = cz op3 d
+    DD_BOX_V(points[0], -, +, +);
+    DD_BOX_V(points[1], -, +, -);
+    DD_BOX_V(points[2], +, +, -);
+    DD_BOX_V(points[3], +, +, +);
+    DD_BOX_V(points[4], -, -, +);
+    DD_BOX_V(points[5], -, -, -);
+    DD_BOX_V(points[6], +, -, -);
+    DD_BOX_V(points[7], +, -, +);
+    #undef DD_BOX_V
+
+    box(DD_EXPLICIT_CONTEXT_ONLY(ctx,) points, color, durationMillis, depthEnabled);
+}
+
+void aabb(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In mins, ddVec3_In maxs,
+          ddVec3_In color, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    ddVec3 bb[2];
+    ddVec3 points[8];
+
+    vecCopy(bb[0], mins);
+    vecCopy(bb[1], maxs);
+
+    // Expand min/max bounds:
+    for (int i = 0; i < arrayLength(points); ++i)
+    {
+        points[i][X] = bb[(i ^ (i >> 1)) & 1][X];
+        points[i][Y] = bb[(i >> 1) & 1][Y];
+        points[i][Z] = bb[(i >> 2) & 1][Z];
+    }
+
+    // Build the lines:
+    box(DD_EXPLICIT_CONTEXT_ONLY(ctx,) points, color, durationMillis, depthEnabled);
+}
+
+void frustum(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddMat4x4_In invClipMatrix,
+             ddVec3_In color, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    // Start with the standard clip volume, then bring it back to world space.
+    static const float planes[8][3] = {
+        // near plane
+        { -1.0f, -1.0f, -1.0f }, {  1.0f, -1.0f, -1.0f },
+        {  1.0f,  1.0f, -1.0f }, { -1.0f,  1.0f, -1.0f },
+        // far plane
+        { -1.0f, -1.0f,  1.0f }, {  1.0f, -1.0f,  1.0f },
+        {  1.0f,  1.0f,  1.0f }, { -1.0f,  1.0f,  1.0f }
+    };
+
+    ddVec3 points[8];
+    float wCoords[8];
+
+    // Transform the planes by the inverse clip matrix:
+    for (int i = 0; i < arrayLength(planes); ++i)
+    {
+        wCoords[i] = matTransformPointXYZW2(points[i], planes[i], invClipMatrix);
+    }
+
+    // Divide by the W component of each:
+    for (int i = 0; i < arrayLength(planes); ++i)
+    {
+        // But bail if any W ended up as zero.
+        if (floatAbs(wCoords[W]) < FloatEpsilon)
+        {
+            return;
+        }
+
+        points[i][X] /= wCoords[i];
+        points[i][Y] /= wCoords[i];
+        points[i][Z] /= wCoords[i];
+    }
+
+    // Connect the dots:
+    box(DD_EXPLICIT_CONTEXT_ONLY(ctx,) points, color, durationMillis, depthEnabled);
+}
+
+void vertexNormal(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In origin, ddVec3_In normal,
+                  const float length, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    ddVec3 normalVec;
+    ddVec3 normalColor;
+
+    vecSet(normalColor, 1.0f, 1.0f, 1.0f);
+
+    normalVec[X] = (normal[X] * length) + origin[X];
+    normalVec[Y] = (normal[Y] * length) + origin[Y];
+    normalVec[Z] = (normal[Z] * length) + origin[Z];
+
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) origin, normalVec, normalColor, durationMillis, depthEnabled);
+}
+
+void tangentBasis(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) ddVec3_In origin, ddVec3_In normal, ddVec3_In tangent,
+                  ddVec3_In bitangent, const float lengths, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    ddVec3 cN, cT, cB;
+    ddVec3 vN, vT, vB;
+
+    vecSet(cN, 1.0f, 1.0f, 1.0f); // Vertex normals are WHITE
+    vecSet(cT, 1.0f, 1.0f, 0.0f); // Tangents are YELLOW
+    vecSet(cB, 1.0f, 0.0f, 1.0f); // Bi-tangents are MAGENTA
+
+    vN[X] = (normal[X] * lengths) + origin[X];
+    vN[Y] = (normal[Y] * lengths) + origin[Y];
+    vN[Z] = (normal[Z] * lengths) + origin[Z];
+
+    vT[X] = (tangent[X] * lengths) + origin[X];
+    vT[Y] = (tangent[Y] * lengths) + origin[Y];
+    vT[Z] = (tangent[Z] * lengths) + origin[Z];
+
+    vB[X] = (bitangent[X] * lengths) + origin[X];
+    vB[Y] = (bitangent[Y] * lengths) + origin[Y];
+    vB[Z] = (bitangent[Z] * lengths) + origin[Z];
+
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) origin, vN, cN, durationMillis, depthEnabled);
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) origin, vT, cT, durationMillis, depthEnabled);
+    line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) origin, vB, cB, durationMillis, depthEnabled);
+}
+
+void xzSquareGrid(DD_EXPLICIT_CONTEXT_ONLY(ContextHandle ctx,) const float mins, const float maxs, const float y,
+                  const float step, ddVec3_In color, const int durationMillis, const bool depthEnabled)
+{
+    if (!isInitialized(DD_EXPLICIT_CONTEXT_ONLY(ctx)))
+    {
+        return;
+    }
+
+    ddVec3 from, to;
+    for (float i = mins; i <= maxs; i += step)
+    {
+        // Horizontal line (along the X)
+        vecSet(from, mins, y, i);
+        vecSet(to,   maxs, y, i);
+        line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) from, to, color, durationMillis, depthEnabled);
+
+        // Vertical line (along the Z)
+        vecSet(from, i, y, mins);
+        vecSet(to,   i, y, maxs);
+        line(DD_EXPLICIT_CONTEXT_ONLY(ctx,) from, to, color, durationMillis, depthEnabled);
+    }
+}
+
+// ========================================================
+// RenderInterface stubs:
+// ========================================================
+
+RenderInterface::~RenderInterface()                                              { }
+void RenderInterface::beginDraw()                                                { }
+void RenderInterface::endDraw()                                                  { }
+void RenderInterface::drawPointList(const DrawVertex *, int, bool)               { }
+void RenderInterface::drawLineList(const DrawVertex *, int, bool)                { }
+void RenderInterface::drawGlyphList(const DrawVertex *, int, GlyphTextureHandle) { }
+void RenderInterface::destroyGlyphTexture(GlyphTextureHandle)                    { }
+GlyphTextureHandle RenderInterface::createGlyphTexture(int, int, const void *)   { return nullptr; }
+
+} // namespace dd
+
+#undef DD_CONTEXT
+#undef DD_MALLOC
+#undef DD_MFREE
+
+// ================ End of implementation =================
+#endif // DEBUG_DRAW_IMPLEMENTATION
+// ================ End of implementation =================
\ No newline at end of file
diff --git a/include/fggl/gfx/ogl/renderer.hpp b/include/fggl/gfx/ogl/renderer.hpp
index 462b7052b58b1aad6c81ddde967dd2f203d11045..72afaa7bafc213be4000f02c2bc5d44fc99c82dd 100644
--- a/include/fggl/gfx/ogl/renderer.hpp
+++ b/include/fggl/gfx/ogl/renderer.hpp
@@ -8,6 +8,7 @@
 
 #include "fggl/gfx/ogl4/models.hpp"
 #include "fggl/gfx/ogl4/canvas.hpp"
+#include "fggl/gfx/ogl4/debug.hpp"
 
 #include <fggl/gfx/paint.hpp>
 
@@ -102,6 +103,7 @@ namespace fggl::gfx {
 		private:
 			std::unique_ptr<ogl4::StaticModelRenderer> m_modelRenderer;
 			std::unique_ptr<ogl4::CanvasRenderer> m_canvasRenderer;
+			std::unique_ptr<ogl4::DebugRenderer> m_debugRenderer;
 			std::unique_ptr<ShaderCache> m_cache;
 	};
 
diff --git a/include/fggl/gfx/ogl/types.hpp b/include/fggl/gfx/ogl/types.hpp
index b121b449953b263c8404d468ce85b81ba350361d..4be7b8f07c5b2eff423f7281d42a39259bc587bc 100644
--- a/include/fggl/gfx/ogl/types.hpp
+++ b/include/fggl/gfx/ogl/types.hpp
@@ -397,7 +397,7 @@ namespace fggl::gfx::ogl {
 			}
 
 			template<typename D>
-			void replace(std::size_t size, D* data) {
+			void replace(std::size_t size, const D* data) {
 				bind();
 				GLsizeiptr sizePtr = size * sizeof(D);
 				if ( sizePtr > m_capacity) {
diff --git a/include/fggl/gfx/ogl4/debug.hpp b/include/fggl/gfx/ogl4/debug.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f3128f42c36b61582c6d75603cd0220ce10be9c7
--- /dev/null
+++ b/include/fggl/gfx/ogl4/debug.hpp
@@ -0,0 +1,48 @@
+/*
+ * ${license.title}
+ * Copyright (C) 2022 ${license.owner}
+ * ${license.mailto}
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+//
+// Created by webpigeon on 30/05/22.
+//
+
+#ifndef FGGL_GFX_OGL4_DEBUG_HPP
+#define FGGL_GFX_OGL4_DEBUG_HPP
+
+#include "fggl/debug/draw.hpp"
+
+namespace fggl::gfx::ogl4 {
+
+	class DebugRenderer : public dd::RenderInterface {
+		public:
+			explicit DebugRenderer(GLuint shader);
+			~DebugRenderer() override = default;
+			void drawLineList(const dd::DrawVertex * lines, int count, bool depthEnabled) override;
+
+			math::mat4 mvpMatrix;
+		private:
+			ogl::Shader m_lineShader;
+			ogl::Location m_lineShaderMVP;
+			ogl::VertexArray m_lineVao;
+			ogl::ArrayBuffer m_lineVbo;
+	};
+
+}
+
+#endif //FGGL_GFX_OGL4_DEBUG_HPP
diff --git a/include/fggl/phys/bullet/phys_draw.hpp b/include/fggl/phys/bullet/phys_draw.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..daf5160ef1d2fe5fa66a7b91160133afff0b69c7
--- /dev/null
+++ b/include/fggl/phys/bullet/phys_draw.hpp
@@ -0,0 +1,66 @@
+/*
+ * ${license.title}
+ * Copyright (C) 2022 ${license.owner}
+ * ${license.mailto}
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+//
+// Created by webpigeon on 30/05/22.
+//
+
+#ifndef FGGL_PHYS_BULLET_DEBUG_DRAW_H
+#define FGGL_PHYS_BULLET_DEBUG_DRAW_H
+
+#include "LinearMath/btIDebugDraw.h"
+#include "fggl/gfx/ogl/types.hpp"
+
+#include <array>
+#include <variant>
+#include <vector>
+
+namespace fggl::debug {
+
+	class BulletDebugDrawList : public btIDebugDraw {
+		public:
+			BulletDebugDrawList();
+			virtual ~BulletDebugDrawList() = default;
+
+			void drawLine(const btVector3& from, const btVector3& to, const btVector3& fromColour, const btVector3& toColour) override;
+			void drawLine(const btVector3& from, const btVector3& to, const btVector3& colour) override;
+			void drawSphere(const btVector3& p, btScalar radius, const btVector3& color) override;
+
+			void drawTriangle(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& color, btScalar alpha) override;
+			void drawContactPoint(const btVector3& PointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime, const btVector3& color) override;
+
+			void reportErrorWarning(const char* warningString) override;
+			void draw3dText(const btVector3& location, const char* textString) override;
+
+			inline void setDebugMode(int debugMode) override {
+				m_mode = debugMode;
+			}
+
+			inline int getDebugMode() const override {
+				return m_mode;
+			}
+
+		private:
+			int m_mode;
+
+	};
+}
+
+#endif //FGGL_PHYS_BULLET_DEBUG_DRAW_H
diff --git a/include/fggl/phys/bullet/types.hpp b/include/fggl/phys/bullet/types.hpp
index f06b858fb658fd86c436a5890d2eb6e764c31941..78896b78d3e84526bda061f6eab566531fe30fd5 100644
--- a/include/fggl/phys/bullet/types.hpp
+++ b/include/fggl/phys/bullet/types.hpp
@@ -27,6 +27,7 @@
 
 #include "fggl/ecs3/ecs.hpp"
 #include "fggl/phys/types.hpp"
+#include "fggl/phys/bullet/phys_draw.hpp"
 
 #include <bullet/btBulletDynamicsCommon.h>
 #include <bullet/btBulletCollisionCommon.h>
@@ -65,6 +66,7 @@ namespace fggl::phys::bullet {
 			ecs3::World* m_ecs;
 			BulletConfiguration m_config;
 			btDiscreteDynamicsWorld* m_world;
+			std::unique_ptr<debug::BulletDebugDrawList> m_debug;
 
 			/**
 			 * Check for ECS components which aren't in the physics world and add them.