bounce/examples/testbed/framework/debug_draw_4.cpp
Irlan bd09b243c2 use mvc for the testbed, update almost all tests, bugfixes, improvements, cleanup
Since I started altering the testbed for better maintainability, I prefered to drop this (tested) large change with a single commit. Some changes below:

Put some globals in their correct place,

Now Testbed uses the MVC pattern (Model-View Controller). This way it becomes better to maintain than using no pattern  in my opinion.

Fixed some bugs in the debug draw interface.

Of course, updated almost all tests because of the differences.

Update script.
2018-04-10 00:57:14 -03:00

1506 lines
34 KiB
C++

/*
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <testbed/framework/debug_draw.h>
#include <glad_4/glad.h>
#include <imgui/imgui.h>
#include <stdio.h>
#include <stdarg.h>
//
DebugDraw* g_debugDraw = nullptr;
Camera* g_camera = nullptr;
const char* g_overlayName = nullptr;
#define BUFFER_OFFSET(i) ((char*)NULL + (i))
static void AssertGL()
{
GLenum errorCode = glGetError();
if (errorCode != GL_NO_ERROR)
{
fprintf(stderr, "OpenGL error = %d\n", errorCode);
assert(false);
}
}
static void PrintLog(GLuint id)
{
GLint log_length = 0;
if (glIsShader(id))
{
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &log_length);
}
else if (glIsProgram(id))
{
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &log_length);
}
else
{
fprintf(stderr, "Not a shader or a program\n");
return;
}
char* log = (char*)malloc(log_length);
if (glIsShader(id))
{
glGetShaderInfoLog(id, log_length, NULL, log);
}
else if (glIsProgram(id))
{
glGetProgramInfoLog(id, log_length, NULL, log);
}
fprintf(stderr, "%s", log);
free(log);
}
static GLuint CreateShader(const char* source, GLenum type)
{
GLuint shaderId = glCreateShader(type);
const char* sources[] = { source };
glShaderSource(shaderId, 1, sources, NULL);
glCompileShader(shaderId);
GLint status = GL_FALSE;
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
fprintf(stderr, "Error compiling %d shader.\n", type);
PrintLog(shaderId);
glDeleteShader(shaderId);
return 0;
}
return shaderId;
}
//
static GLuint CreateShaderProgram(const char* vs, const char* fs)
{
GLuint vsId = CreateShader(vs, GL_VERTEX_SHADER);
GLuint fsId = CreateShader(fs, GL_FRAGMENT_SHADER);
assert(vsId != 0 && fsId != 0);
GLuint programId = glCreateProgram();
glAttachShader(programId, vsId);
glAttachShader(programId, fsId);
glBindFragDataLocation(programId, 0, "color");
glLinkProgram(programId);
glDeleteShader(vsId);
glDeleteShader(fsId);
GLint status = GL_FALSE;
glGetProgramiv(programId, GL_LINK_STATUS, &status);
assert(status != GL_FALSE);
return programId;
}
struct DrawPoints
{
DrawPoints()
{
const char* vs = \
"#version 400\n"
"uniform mat4 projectionMatrix;\n"
"layout(location = 0) in vec3 v_position;\n"
"layout(location = 1) in vec4 v_color;\n"
"layout(location = 2) in float v_size;\n"
"out vec4 f_color;\n"
"void main()\n"
"{\n"
" f_color = v_color;\n"
" gl_Position = projectionMatrix * vec4(v_position, 1.0f);\n"
" gl_PointSize = v_size;\n"
"}\n";
const char* fs = \
"#version 400\n"
"in vec4 f_color;\n"
"out vec4 color;\n"
"void main(void)\n"
"{\n"
" color = f_color;\n"
"}\n";
m_programId = CreateShaderProgram(vs, fs);
m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix");
m_vertexAttribute = 0;
m_colorAttribute = 1;
m_sizeAttribute = 2;
glGenBuffers(3, m_vboIds);
glGenVertexArrays(1, &m_vaoId);
glBindVertexArray(m_vaoId);
glEnableVertexAttribArray(m_vertexAttribute);
glEnableVertexAttribArray(m_colorAttribute);
glEnableVertexAttribArray(m_sizeAttribute);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
glVertexAttribPointer(m_vertexAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Vec3), m_vertices, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Color), m_colors, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]);
glVertexAttribPointer(m_sizeAttribute, 1, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(float32), m_sizes, GL_DYNAMIC_DRAW);
AssertGL();
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_count = 0;
}
~DrawPoints()
{
glDeleteVertexArrays(1, &m_vaoId);
glDeleteProgram(m_programId);
glDeleteBuffers(3, m_vboIds);
}
void Vertex(const b3Vec3& v, float32 size, const b3Color& color)
{
if (m_count == e_vertexCapacity)
{
Submit();
}
m_vertices[m_count] = v;
m_colors[m_count] = color;
m_sizes[m_count] = size;
++m_count;
}
void Submit()
{
if (m_count == 0)
{
return;
}
glUseProgram(m_programId);
b3Mat44 m1 = g_camera->BuildViewMatrix();
b3Mat44 m2 = g_camera->BuildProjectionMatrix();
b3Mat44 m = m2 * m1;
glUniformMatrix4fv(m_projectionUniform, 1, GL_FALSE, &m.x.x);
glBindVertexArray(m_vaoId);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Vec3), m_vertices);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Color), m_colors);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(float32), m_sizes);
glEnable(GL_PROGRAM_POINT_SIZE);
glDrawArrays(GL_POINTS, 0, m_count);
glDisable(GL_PROGRAM_POINT_SIZE);
AssertGL();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glUseProgram(0);
m_count = 0;
}
enum
{
e_vertexCapacity = 1024
};
b3Vec3 m_vertices[e_vertexCapacity];
b3Color m_colors[e_vertexCapacity];
float32 m_sizes[e_vertexCapacity];
u32 m_count;
GLuint m_programId;
GLuint m_projectionUniform;
GLuint m_vertexAttribute;
GLuint m_colorAttribute;
GLuint m_sizeAttribute;
GLuint m_vboIds[3];
GLuint m_vaoId;
};
struct DrawLines
{
DrawLines()
{
const char* vs = \
"#version 400\n"
"uniform mat4 projectionMatrix;\n"
"layout(location = 0) in vec3 v_position;\n"
"layout(location = 1) in vec4 v_color;\n"
"out vec4 f_color;\n"
"void main(void)\n"
"{\n"
" f_color = v_color;\n"
" gl_Position = projectionMatrix * vec4(v_position, 1.0f);\n"
"}\n";
const char* fs = \
"#version 400\n"
"in vec4 f_color;\n"
"out vec4 color;\n"
"void main(void)\n"
"{\n"
" color = f_color;\n"
"}\n";
m_programId = CreateShaderProgram(vs, fs);
m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix");
m_vertexAttribute = 0;
m_colorAttribute = 1;
glGenVertexArrays(1, &m_vaoId);
glGenBuffers(2, m_vboIds);
glBindVertexArray(m_vaoId);
glEnableVertexAttribArray(m_vertexAttribute);
glEnableVertexAttribArray(m_colorAttribute);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
glVertexAttribPointer(m_vertexAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Vec3), m_vertices, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Color), m_colors, GL_DYNAMIC_DRAW);
AssertGL();
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_count = 0;
}
~DrawLines()
{
glDeleteProgram(m_programId);
glDeleteVertexArrays(1, &m_vaoId);
glDeleteBuffers(2, m_vboIds);
}
void Vertex(const b3Vec3& v, const b3Color& c)
{
if (m_count == e_vertexCapacity)
{
Submit();
}
m_vertices[m_count] = v;
m_colors[m_count] = c;
++m_count;
}
void Submit()
{
if (m_count == 0)
{
return;
}
glUseProgram(m_programId);
b3Mat44 m1 = g_camera->BuildViewMatrix();
b3Mat44 m2 = g_camera->BuildProjectionMatrix();
b3Mat44 m = m2 * m1;
glUniformMatrix4fv(m_projectionUniform, 1, GL_FALSE, &m.x.x);
glBindVertexArray(m_vaoId);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Vec3), m_vertices);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Color), m_colors);
glDrawArrays(GL_LINES, 0, m_count);
AssertGL();
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
m_count = 0;
}
enum
{
e_vertexCapacity = 2 * 1024
};
b3Vec3 m_vertices[e_vertexCapacity];
b3Color m_colors[e_vertexCapacity];
u32 m_count;
GLuint m_programId;
GLuint m_projectionUniform;
GLuint m_vertexAttribute;
GLuint m_colorAttribute;
GLuint m_vboIds[2];
GLuint m_vaoId;
};
struct DrawTriangles
{
DrawTriangles()
{
const char* vs = \
"#version 400\n"
"uniform mat4 projectionMatrix;\n"
"layout(location = 0) in vec3 v_position;\n"
"layout(location = 1) in vec4 v_color;\n"
"layout(location = 2) in vec3 v_normal;\n"
"out vec4 f_color;\n"
"void main(void)\n"
"{\n"
" vec3 La = vec3(0.5f, 0.5f, 0.5f);\n"
" vec3 Ld = vec3(0.5f, 0.5f, 0.5f);\n"
" vec3 L = vec3(0.0f, 0.3f, 0.7f);\n"
" vec3 Ma = v_color.xyz;\n"
" vec3 Md = v_color.xyz;\n"
" vec3 a = La * Ma;\n"
" vec3 d = max(dot(v_normal, L), 0.0f) * Ld * Md;\n"
" f_color = vec4(a + d, v_color.w);\n"
" gl_Position = projectionMatrix * vec4(v_position, 1.0f);\n"
"}\n";
const char* fs = \
"#version 400\n"
"in vec4 f_color;\n"
"out vec4 color;\n"
"void main(void)\n"
"{\n"
" color = f_color;\n"
"}\n";
m_programId = CreateShaderProgram(vs, fs);
m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix");
m_vertexAttribute = 0;
m_colorAttribute = 1;
m_normalAttribute = 2;
glGenVertexArrays(1, &m_vaoId);
glGenBuffers(3, m_vboIds);
glBindVertexArray(m_vaoId);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Vec3), m_vertices, GL_DYNAMIC_DRAW);
glVertexAttribPointer(m_vertexAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_vertexAttribute);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Color), m_colors, GL_DYNAMIC_DRAW);
glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_colorAttribute);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]);
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Vec3), m_normals, GL_DYNAMIC_DRAW);
glVertexAttribPointer(m_normalAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_normalAttribute);
AssertGL();
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_count = 0;
}
~DrawTriangles()
{
glDeleteProgram(m_programId);
glDeleteVertexArrays(1, &m_vaoId);
glDeleteBuffers(3, m_vboIds);
}
void Vertex(const b3Vec3& v, const b3Color& c, const b3Vec3& n)
{
if (m_count == e_vertexCapacity)
{
Submit();
}
m_vertices[m_count] = v;
m_colors[m_count] = c;
m_normals[m_count] = n;
++m_count;
}
void Submit()
{
if (m_count == 0)
{
return;
}
glUseProgram(m_programId);
b3Mat44 m1 = g_camera->BuildViewMatrix();
b3Mat44 m2 = g_camera->BuildProjectionMatrix();
b3Mat44 m = m2 * m1;
glUniformMatrix4fv(m_projectionUniform, 1, GL_FALSE, &m.x.x);
glBindVertexArray(m_vaoId);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Vec3), m_vertices);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Color), m_colors);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Vec3), m_normals);
glDrawArrays(GL_TRIANGLES, 0, m_count);
AssertGL();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glUseProgram(0);
m_count = 0;
}
enum
{
e_vertexCapacity = 3 * 512
};
b3Vec3 m_vertices[e_vertexCapacity];
b3Color m_colors[e_vertexCapacity];
b3Vec3 m_normals[e_vertexCapacity];
u32 m_count;
GLuint m_programId;
GLuint m_projectionUniform;
GLuint m_vertexAttribute;
GLuint m_colorAttribute;
GLuint m_normalAttribute;
GLuint m_vboIds[3];
GLuint m_vaoId;
};
struct DrawWireSphere
{
enum
{
e_rings = 12,
e_sectors = 12,
e_vertexCount = e_rings * e_sectors,
e_indexCount = (e_rings - 1) * (e_sectors - 1) * 8
};
DrawWireSphere()
{
float32 R = 1.0f / float32(e_rings - 1);
float32 S = 1.0f / float32(e_sectors - 1);
b3Vec3 vs[e_vertexCount];
b3Vec3 ns[e_vertexCount];
b3Color cs[e_vertexCount];
u32 vc = 0;
for (u32 r = 0; r < e_rings; r++)
{
for (u32 s = 0; s < e_sectors; s++)
{
float32 y = sin(-0.5f * B3_PI + B3_PI * r * R);
float32 x = cos(2.0f * B3_PI * s * S) * sin(B3_PI * r * R);
float32 z = sin(2.0f * B3_PI * s * S) * sin(B3_PI * r * R);
vs[vc].Set(x, y, z);
cs[vc] = b3Color(1.0f, 1.0f, 1.0f, 1.0f);
++vc;
}
}
u32 is[e_indexCount];
u32 ic = 0;
for (u32 r = 0; r < e_rings - 1; r++)
{
for (u32 s = 0; s < e_sectors - 1; s++)
{
u32 i1 = r * e_sectors + s;
u32 i2 = (r + 1) * e_sectors + s;
u32 i3 = (r + 1) * e_sectors + (s + 1);
u32 i4 = r * e_sectors + (s + 1);
is[ic++] = i1;
is[ic++] = i2;
is[ic++] = i2;
is[ic++] = i3;
is[ic++] = i3;
is[ic++] = i4;
is[ic++] = i4;
is[ic++] = i1;
}
}
glGenBuffers(1, &m_vboId);
glGenBuffers(1, &m_iboId);
glBindBuffer(GL_ARRAY_BUFFER, m_vboId);
glBufferData(GL_ARRAY_BUFFER, vc * sizeof(b3Vec3), vs, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_iboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ic * sizeof(u32), is, GL_STATIC_DRAW);
AssertGL();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
~DrawWireSphere()
{
glDeleteBuffers(1, &m_vboId);
glDeleteBuffers(1, &m_iboId);
}
GLuint m_vboId;
GLuint m_iboId;
};
struct DrawWire
{
DrawWire()
{
const char* vs = \
"#version 400\n"
"uniform vec4 color;\n"
"uniform mat4 projectionMatrix;\n"
"layout(location = 0) in vec3 v_position;\n"
"out vec4 f_color;\n"
"void main(void)\n"
"{\n"
" f_color = color;\n"
" gl_Position = projectionMatrix * vec4(v_position, 1.0f);\n"
"}\n";
const char* fs = \
"#version 400\n"
"in vec4 f_color;\n"
"out vec4 color;\n"
"void main(void)\n"
"{\n"
" color = f_color;\n"
"}\n";
m_programId = CreateShaderProgram(vs, fs);
m_colorUniform = glGetUniformLocation(m_programId, "color");
m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix");
m_vertexAttribute = 0;
}
~DrawWire()
{
glDeleteProgram(m_programId);
}
void DrawSphere(float32 radius, const b3Color& c, const b3Transform& xf)
{
glUseProgram(m_programId);
b3Mat44 m1 = MakeMat44(xf);
m1.x = radius * m1.x;
m1.y = radius * m1.y;
m1.z = radius * m1.z;
b3Mat44 m2 = g_camera->BuildViewMatrix();
b3Mat44 m3 = g_camera->BuildProjectionMatrix();
b3Mat44 m = m3 * m2 * m1;
glUniformMatrix4fv(m_projectionUniform, 1, GL_FALSE, &m.x.x);
glBindBuffer(GL_ARRAY_BUFFER, m_sphere.m_vboId);
glVertexAttribPointer(m_vertexAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_vertexAttribute);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_sphere.m_iboId);
glDrawElements(GL_LINES, m_sphere.e_indexCount, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
}
GLuint m_programId;
GLuint m_colorUniform;
GLuint m_projectionUniform;
GLuint m_vertexAttribute;
DrawWireSphere m_sphere;
};
struct DrawSolidSphere
{
enum
{
e_rings = 18,
e_sectors = 18,
e_vertexCount = e_rings * e_sectors,
e_indexCount = (e_rings - 1) * (e_sectors - 1) * 6,
e_faceCount = e_indexCount / 3
};
DrawSolidSphere()
{
float32 R = 1.0f / float32(e_rings - 1);
float32 S = 1.0f / float32(e_sectors - 1);
b3Vec3 vs[e_vertexCount];
b3Vec3 ns[e_vertexCount];
u32 vc = 0;
for (u32 r = 0; r < e_rings; r++)
{
for (u32 s = 0; s < e_sectors; s++)
{
float32 a1 = 2.0f * B3_PI * float32(s) * S;
float32 c1 = cos(a1);
float32 s1 = sin(a1);
float32 a2 = -0.5f * B3_PI + B3_PI * float32(r) * R;
float32 s2 = sin(a2);
float32 a3 = B3_PI * float32(r) * R;
float32 s3 = sin(a3);
float32 x = c1 * s3;
float32 y = s2;
float32 z = s1 * s3;
b3Vec3 v(x, y, z);
v.Normalize();
vs[vc] = v;
ns[vc] = v;
++vc;
}
}
u32 is[e_indexCount];
u32 ic = 0;
for (u32 r = 0; r < e_rings - 1; r++)
{
for (u32 s = 0; s < e_sectors - 1; s++)
{
u32 i1 = r * e_sectors + s;
u32 i2 = (r + 1) * e_sectors + s;
u32 i3 = (r + 1) * e_sectors + (s + 1);
u32 i4 = r * e_sectors + (s + 1);
is[ic++] = i1;
is[ic++] = i2;
is[ic++] = i3;
is[ic++] = i1;
is[ic++] = i3;
is[ic++] = i4;
}
}
glGenBuffers(3, m_vboIds);
glGenBuffers(1, &m_iboId);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, vc * sizeof(b3Vec3), vs, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
glBufferData(GL_ARRAY_BUFFER, vc * sizeof(b3Vec3), ns, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_iboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ic * sizeof(u32), is, GL_STATIC_DRAW);
AssertGL();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
~DrawSolidSphere()
{
glDeleteBuffers(2, m_vboIds);
glDeleteBuffers(1, &m_iboId);
}
GLuint m_vboIds[2];
GLuint m_iboId;
};
struct DrawSolidCylinder
{
enum
{
e_segments = 64,
e_vertexCount = e_segments * 6,
};
DrawSolidCylinder()
{
b3Vec3 vs[e_vertexCount];
b3Vec3 ns[e_vertexCount];
u32 vc = 0;
for (u32 i = 0; i < e_segments; ++i)
{
float32 t0 = 2.0f * B3_PI * float32(i) / float32(e_segments);
float32 t1 = 2.0f * B3_PI * float32(i + 1) / float32(e_segments);
float32 c0 = cos(t0);
float32 s0 = sin(t0);
float32 c1 = cos(t1);
float32 s1 = sin(t1);
b3Vec3 v1;
v1.x = s0;
v1.y = -0.5f;
v1.z = c0;
b3Vec3 v2;
v2.x = s1;
v2.y = -0.5f;
v2.z = c1;
b3Vec3 v3;
v3.x = s1;
v3.y = 0.5f;
v3.z = c1;
b3Vec3 v4;
v4.x = s0;
v4.y = 0.5f;
v4.z = c0;
b3Vec3 n = b3Cross(v2 - v1, v3 - v1);
n.Normalize();
vs[vc] = v1;
ns[vc] = n;
++vc;
vs[vc] = v2;
ns[vc] = n;
++vc;
vs[vc] = v3;
ns[vc] = n;
++vc;
vs[vc] = v1;
ns[vc] = n;
++vc;
vs[vc] = v3;
ns[vc] = n;
++vc;
vs[vc] = v4;
ns[vc] = n;
++vc;
}
u32 is[e_vertexCount];
u32 ic = vc;
for (u32 i = 0; i < vc; ++i)
{
is[i] = i;
}
glGenBuffers(2, m_vboIds);
glGenBuffers(1, &m_iboId);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, vc * sizeof(b3Vec3), vs, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
glBufferData(GL_ARRAY_BUFFER, vc * sizeof(b3Vec3), ns, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_iboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ic * sizeof(u32), is, GL_STATIC_DRAW);
AssertGL();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
~DrawSolidCylinder()
{
glDeleteBuffers(2, m_vboIds);
glDeleteBuffers(1, &m_iboId);
}
GLuint m_vboIds[2];
GLuint m_iboId;
};
struct DrawSolid
{
DrawSolid()
{
const char* vs = \
"#version 400\n"
"uniform vec4 color;\n"
"uniform mat4 modelMatrix;\n"
"uniform mat4 projectionMatrix;\n"
"layout(location = 0) in vec3 v_position;\n"
"layout(location = 1) in vec3 v_normal;\n"
"out vec4 f_color;\n"
"void main(void)\n"
"{\n"
" vec3 f_normal = normalize( ( modelMatrix * vec4(v_normal, 0.0f) ).xyz );\n"
" gl_Position = projectionMatrix * vec4(v_position, 1.0f);\n"
" vec3 La = vec3(0.5f, 0.5f, 0.5f);\n"
" vec3 Ld = vec3(0.5f, 0.5f, 0.5f);\n"
" vec3 L = vec3(0.0f, 0.3f, 0.7f);\n"
" vec3 Ma = color.xyz;\n"
" vec3 Md = color.xyz;\n"
" vec3 a = La * Ma;\n"
" vec3 d = max(dot(f_normal, L), 0.0f) * Ld * Md;\n"
" f_color = vec4(a + d, color.w);\n"
"}\n";
const char* fs = \
"#version 400\n"
"in vec4 f_color;\n"
"out vec4 color;\n"
"void main(void)\n"
"{\n"
" color = f_color;\n"
"}\n";
m_programId = CreateShaderProgram(vs, fs);
m_colorUniform = glGetUniformLocation(m_programId, "color");
m_modelUniform = glGetUniformLocation(m_programId, "modelMatrix");
m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix");
m_vertexAttribute = 0;
m_normalAttribute = 1;
}
~DrawSolid()
{
}
void DrawCylinder(float32 radius, float32 height, const b3Color& c, const b3Transform& xf)
{
glUseProgram(m_programId);
b3Mat44 m1 = MakeMat44(xf);
m1.x = radius * m1.x;
m1.y = height * m1.y;
m1.z = radius * m1.z;
b3Mat44 m2 = g_camera->BuildViewMatrix();
b3Mat44 m3 = g_camera->BuildProjectionMatrix();
b3Mat44 m = m3 * m2 * m1;
glUniform4fv(m_colorUniform, 1, &c.r);
glUniformMatrix4fv(m_modelUniform, 1, GL_FALSE, &m1.x.x);
glUniformMatrix4fv(m_projectionUniform, 1, GL_FALSE, &m.x.x);
glBindBuffer(GL_ARRAY_BUFFER, m_cylinder.m_vboIds[0]);
glVertexAttribPointer(m_vertexAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_vertexAttribute);
glBindBuffer(GL_ARRAY_BUFFER, m_cylinder.m_vboIds[1]);
glVertexAttribPointer(m_normalAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_normalAttribute);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_cylinder.m_iboId);
glDrawElements(GL_TRIANGLES, m_cylinder.e_vertexCount, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
}
void DrawSphere(float32 radius, const b3Color& c, const b3Transform& xf)
{
glUseProgram(m_programId);
b3Mat44 m1 = MakeMat44(xf);
m1.x = radius * m1.x;
m1.y = radius * m1.y;
m1.z = radius * m1.z;
b3Mat44 m2 = g_camera->BuildViewMatrix();
b3Mat44 m3 = g_camera->BuildProjectionMatrix();
b3Mat44 m = m3 * m2 * m1;
glUniform4fv(m_colorUniform, 1, &c.r);
glUniformMatrix4fv(m_modelUniform, 1, GL_FALSE, &m1.x.x);
glUniformMatrix4fv(m_projectionUniform, 1, GL_FALSE, &m.x.x);
glBindBuffer(GL_ARRAY_BUFFER, m_sphere.m_vboIds[0]);
glVertexAttribPointer(m_vertexAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_vertexAttribute);
glBindBuffer(GL_ARRAY_BUFFER, m_sphere.m_vboIds[1]);
glVertexAttribPointer(m_normalAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_normalAttribute);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_sphere.m_iboId);
glDrawElements(GL_TRIANGLES, m_sphere.e_indexCount, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
}
GLuint m_programId;
GLuint m_colorUniform;
GLuint m_modelUniform;
GLuint m_projectionUniform;
GLuint m_vertexAttribute;
GLuint m_normalAttribute;
DrawSolidSphere m_sphere;
DrawSolidCylinder m_cylinder;
};
DebugDraw::DebugDraw()
{
m_points = new DrawPoints();
m_lines = new DrawLines();
m_triangles = new DrawTriangles();
m_wire = new DrawWire();
m_solid = new DrawSolid();
}
DebugDraw::~DebugDraw()
{
delete m_points;
delete m_lines;
delete m_triangles;
delete m_wire;
delete m_solid;
}
void DebugDraw::DrawPoint(const b3Vec3& p, float32 size, const b3Color& color)
{
m_points->Vertex(p, size, color);
}
void DebugDraw::DrawSegment(const b3Vec3& p1, const b3Vec3& p2, const b3Color& color)
{
m_lines->Vertex(p1, color);
m_lines->Vertex(p2, color);
}
void DebugDraw::DrawTriangle(const b3Vec3& p1, const b3Vec3& p2, const b3Vec3& p3, const b3Color& color)
{
DrawSegment(p1, p2, color);
DrawSegment(p2, p3, color);
DrawSegment(p3, p1, color);
}
void DebugDraw::DrawSolidTriangle(const b3Vec3& normal, const b3Vec3& p1, const b3Vec3& p2, const b3Vec3& p3, const b3Color& color)
{
m_triangles->Vertex(p1, color, normal);
m_triangles->Vertex(p2, color, normal);
m_triangles->Vertex(p3, color, normal);
b3Color edgeColor(0.0f, 0.0f, 0.0f, 1.0f);
DrawTriangle(p1, p2, p3, edgeColor);
}
void DebugDraw::DrawSolidTriangle(const b3Vec3& normal, const b3Vec3& p1, const b3Color& color1, const b3Vec3& p2, const b3Color& color2, const b3Vec3& p3, const b3Color& color3)
{
m_triangles->Vertex(p1, color1, normal);
m_triangles->Vertex(p2, color2, normal);
m_triangles->Vertex(p3, color3, normal);
b3Color edgeColor(0.0f, 0.0f, 0.0f, 1.0f);
DrawTriangle(p1, p2, p3, edgeColor);
}
void DebugDraw::DrawPolygon(const b3Vec3* vertices, u32 count, const b3Color& color)
{
b3Vec3 p1 = vertices[count - 1];
for (u32 i = 0; i < count; ++i)
{
b3Vec3 p2 = vertices[i];
m_lines->Vertex(p1, color);
m_lines->Vertex(p2, color);
p1 = p2;
}
}
void DebugDraw::DrawSolidPolygon(const b3Vec3& normal, const b3Vec3* vertices, u32 count, const b3Color& color)
{
b3Color fillColor(color.r, color.g, color.b, color.a);
b3Vec3 p1 = vertices[0];
for (u32 i = 1; i < count - 1; ++i)
{
b3Vec3 p2 = vertices[i];
b3Vec3 p3 = vertices[i + 1];
m_triangles->Vertex(p1, fillColor, normal);
m_triangles->Vertex(p2, fillColor, normal);
m_triangles->Vertex(p3, fillColor, normal);
}
b3Color frameColor(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 1.0f);
DrawPolygon(vertices, count, frameColor);
}
void DebugDraw::DrawCircle(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color)
{
// Build a tangent vector to normal.
b3Vec3 u = b3Cross(normal, b3Vec3(1.0f, 0.0f, 0.0f));
b3Vec3 v = b3Cross(normal, b3Vec3(0.0f, 1.0f, 0.0f));
// Handle edge cases (zero cross product).
b3Vec3 n1;
if (b3LengthSquared(u) > b3LengthSquared(v))
{
n1 = u;
}
else
{
n1 = v;
}
n1.Normalize();
// Build a quaternion to rotate the tangent about the normal.
u32 kEdgeCount = 20;
float32 kAngleInc = 2.0f * B3_PI / float32(kEdgeCount);
b3Quat q(normal, kAngleInc);
b3Vec3 p1 = center + radius * n1;
for (u32 i = 0; i < kEdgeCount; ++i)
{
b3Vec3 n2 = b3Mul(q, n1);
b3Vec3 p2 = center + radius * n2;
m_lines->Vertex(p1, color);
m_lines->Vertex(p2, color);
n1 = n2;
p1 = p2;
}
}
void DebugDraw::DrawSolidCircle(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color)
{
b3Color fillColor(color.r, color.g, color.b, color.a);
b3Color frameColor(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 1.0f);
// Build a tangent vector to normal.
b3Vec3 u = b3Cross(normal, b3Vec3(1.0f, 0.0f, 0.0f));
b3Vec3 v = b3Cross(normal, b3Vec3(0.0f, 1.0f, 0.0f));
// Handle edge cases (zero cross product).
b3Vec3 n1;
if (b3LengthSquared(u) > b3LengthSquared(v))
{
n1 = u;
}
else
{
n1 = v;
}
n1.Normalize();
// Build a quaternion to rotate the tangent about the normal.
const u32 kEdgeCount = 20;
const float32 kAngleInc = 2.0f * B3_PI / float32(kEdgeCount);
b3Quat q(normal, kAngleInc);
b3Vec3 p1 = center + radius * n1;
for (u32 i = 0; i < kEdgeCount; ++i)
{
b3Vec3 n2 = b3Mul(q, n1);
b3Vec3 p2 = center + radius * n2;
m_triangles->Vertex(center, fillColor, normal);
m_triangles->Vertex(p1, fillColor, normal);
m_triangles->Vertex(p2, fillColor, normal);
m_lines->Vertex(p1, frameColor);
m_lines->Vertex(p2, frameColor);
n1 = n2;
p1 = p2;
}
}
void DebugDraw::DrawSphere(const b3Vec3& center, float32 radius, const b3Color& color)
{
b3Transform xf;
xf.SetIdentity();
xf.position = center;
m_wire->DrawSphere(radius, color, xf);
}
void DebugDraw::DrawSolidSphere(const b3Vec3& center, float32 radius, const b3Color& color)
{
b3Transform xf;
xf.SetIdentity();
xf.position = center;
m_solid->DrawSphere(radius, color, xf);
}
void DebugDraw::DrawCapsule(const b3Vec3& c1, const b3Vec3& c2, float32 radius, const b3Color& color)
{
float32 height = b3Length(c1 - c2);
{
b3Transform xfc;
xfc.rotation.SetIdentity();
xfc.position = c1;
m_wire->DrawSphere(radius, color, xfc);
}
if (height > 0.0f)
{
DrawSegment(c1, c2, color);
{
b3Transform xfc;
xfc.rotation.SetIdentity();
xfc.position = c2;
m_wire->DrawSphere(radius, color, xfc);
}
}
}
void DebugDraw::DrawSolidCapsule(const b3Vec3& c1, const b3Vec3& c2, float32 radius, const b3Color& c)
{
float32 height = b3Length(c1 - c2);
{
b3Transform xfc;
xfc.rotation.SetIdentity();
xfc.position = c1;
m_solid->DrawSphere(radius, c, xfc);
}
if (height > 0.0f)
{
{
b3Mat33 R;
R.y = (1.0f / height) * (c1 - c2);
R.z = b3Perp(R.y);
R.x = b3Cross(R.y, R.z);
b3Transform xfc;
xfc.position = 0.5f * (c1 + c2);
xfc.rotation = R;
m_solid->DrawCylinder(radius, height, c, xfc);
}
{
b3Transform xfc;
xfc.rotation.SetIdentity();
xfc.position = c2;
m_solid->DrawSphere(radius, c, xfc);
}
}
}
void DebugDraw::DrawTransform(const b3Transform& xf)
{
float32 lenght = 1.0f;
b3Color red(1.0f, 0.0f, 0.0f, 1.0f);
b3Color green(0.0f, 1.0f, 0.0f, 1.0f);
b3Color blue(0.0f, 0.0f, 1.0f, 1.0f);
b3Vec3 position = xf.position;
b3Mat33 rotation = xf.rotation;
b3Vec3 A = position + lenght * rotation.x;
b3Vec3 B = position + lenght * rotation.y;
b3Vec3 C = position + lenght * rotation.z;
DrawSegment(position, A, red);
DrawSegment(position, B, green);
DrawSegment(position, C, blue);
}
void DebugDraw::DrawAABB(const b3AABB3& aabb, const b3Color& color)
{
b3Vec3 lower = aabb.m_lower;
b3Vec3 upper = aabb.m_upper;
b3Vec3 vs[8];
vs[0] = lower;
vs[1] = b3Vec3(lower.x, upper.y, lower.z);
vs[2] = b3Vec3(upper.x, upper.y, lower.z);
vs[3] = b3Vec3(upper.x, lower.y, lower.z);
vs[4] = upper;
vs[5] = b3Vec3(upper.x, lower.y, upper.z);
vs[6] = b3Vec3(lower.x, lower.y, upper.z);
vs[7] = b3Vec3(lower.x, upper.y, upper.z);
DrawSegment(vs[0], vs[1], color);
DrawSegment(vs[1], vs[2], color);
DrawSegment(vs[2], vs[3], color);
DrawSegment(vs[3], vs[0], color);
DrawSegment(vs[4], vs[5], color);
DrawSegment(vs[5], vs[6], color);
DrawSegment(vs[6], vs[7], color);
DrawSegment(vs[7], vs[4], color);
DrawSegment(vs[2], vs[4], color);
DrawSegment(vs[5], vs[3], color);
DrawSegment(vs[6], vs[0], color);
DrawSegment(vs[1], vs[7], color);
}
void DebugDraw::DrawString(const b3Color& color, const char* text, ...)
{
va_list args;
va_start(args, text);
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f));
ImGui::SetNextWindowSize(ImVec2(g_camera->m_width, g_camera->m_height));
ImGui::Begin(g_overlayName, NULL, ImVec2(0.0f, 0.0f), 0.0f, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar);
ImGui::TextColoredV(ImVec4(color.r, color.g, color.b, color.a), text, args);
ImGui::End();
va_end(args);
}
void DebugDraw::DrawSphere(const b3SphereShape* s, const b3Color& c, const b3Transform& xf)
{
b3Transform xfc;
xfc.rotation = xf.rotation;
xfc.position = xf * s->m_center;
m_solid->DrawSphere(s->m_radius, c, xfc);
}
void DebugDraw::DrawCapsule(const b3CapsuleShape* s, const b3Color& c, const b3Transform& xf)
{
b3Vec3 c1 = s->m_centers[0];
b3Vec3 c2 = s->m_centers[1];
float32 height = b3Length(c1 - c2);
float32 radius = s->m_radius;
{
b3Transform xfc;
xfc.rotation = xf.rotation;
xfc.position = xf * c1;
m_solid->DrawSphere(radius, c, xfc);
}
if (height > 0.0f)
{
{
b3Mat33 R;
R.y = (1.0f / height) * (c1 - c2);
R.z = b3Perp(R.y);
R.x = b3Cross(R.y, R.z);
b3Transform xfc;
xfc.position = xf * (0.5f * (c1 + c2));
xfc.rotation = xf.rotation * R;
m_solid->DrawCylinder(radius, height, c, xfc);
}
{
b3Transform xfc;
xfc.rotation = xf.rotation;
xfc.position = xf * c2;
m_solid->DrawSphere(radius, c, xfc);
}
}
}
void DebugDraw::DrawHull(const b3HullShape* s, const b3Color& c, const b3Transform& xf)
{
const b3Hull* hull = s->m_hull;
for (u32 i = 0; i < hull->faceCount; ++i)
{
const b3Face* face = hull->GetFace(i);
const b3HalfEdge* begin = hull->GetEdge(face->edge);
b3Vec3 n = xf.rotation * hull->planes[i].normal;
const b3HalfEdge* edge = hull->GetEdge(begin->next);
do
{
u32 i1 = begin->origin;
u32 i2 = edge->origin;
const b3HalfEdge* next = hull->GetEdge(edge->next);
u32 i3 = next->origin;
b3Vec3 p1 = xf * hull->vertices[i1];
b3Vec3 p2 = xf * hull->vertices[i2];
b3Vec3 p3 = xf * hull->vertices[i3];
m_triangles->Vertex(p1, c, n);
m_triangles->Vertex(p2, c, n);
m_triangles->Vertex(p3, c, n);
edge = next;
} while (hull->GetEdge(edge->next) != begin);
}
}
void DebugDraw::DrawMesh(const b3MeshShape* s, const b3Color& c, const b3Transform& xf)
{
const b3Mesh* mesh = s->m_mesh;
for (u32 i = 0; i < mesh->triangleCount; ++i)
{
const b3Triangle* t = mesh->triangles + i;
b3Vec3 p1 = xf * mesh->vertices[t->v1];
b3Vec3 p2 = xf * mesh->vertices[t->v2];
b3Vec3 p3 = xf * mesh->vertices[t->v3];
b3Vec3 n1 = b3Cross(p2 - p1, p3 - p1);
n1.Normalize();
m_triangles->Vertex(p1, c, n1);
m_triangles->Vertex(p2, c, n1);
m_triangles->Vertex(p3, c, n1);
b3Vec3 n2 = -n1;
m_triangles->Vertex(p1, c, n2);
m_triangles->Vertex(p3, c, n2);
m_triangles->Vertex(p2, c, n2);
}
}
void DebugDraw::DrawShape(const b3Shape* s, const b3Color& c, const b3Transform& xf)
{
switch (s->GetType())
{
case e_sphereShape:
{
DrawSphere((b3SphereShape*)s, c, xf);
break;
}
case e_capsuleShape:
{
DrawCapsule((b3CapsuleShape*)s, c, xf);
break;
}
case e_hullShape:
{
DrawHull((b3HullShape*)s, c, xf);
break;
}
case e_meshShape:
{
DrawMesh((b3MeshShape*)s, c, xf);
break;
}
default:
{
break;
}
}
}
void DebugDraw::Draw(const b3World& world)
{
for (b3Body* b = world.GetBodyList().m_head; b; b = b->GetNext())
{
b3Color c;
if (b->IsAwake() == false)
{
c = b3Color(0.5f, 0.25f, 0.25f, 1.0f);
}
else if (b->GetType() == e_staticBody)
{
c = b3Color(0.5f, 0.5f, 0.5f, 1.0f);
}
else if (b->GetType() == e_dynamicBody)
{
c = b3Color(1.0f, 0.5f, 0.5f, 1.0f);
}
else
{
c = b3Color(0.5f, 0.5f, 1.0f, 1.0f);
}
b3Transform xf = b->GetTransform();
for (b3Shape* s = b->GetShapeList().m_head; s; s = s->GetNext())
{
DrawShape(s, c, xf);
}
}
g_debugDraw->Submit();
}
void DebugDraw::Submit()
{
m_triangles->Submit();
m_lines->Submit();
m_points->Submit();
}