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.