1498 lines
34 KiB
C++
1498 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_2/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);
|
|
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 120\n"
|
|
"uniform mat4 projectionMatrix;\n"
|
|
"attribute vec3 v_position;\n"
|
|
"attribute vec4 v_color;\n"
|
|
"attribute float v_size;\n"
|
|
"varying 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 120\n"
|
|
"varying vec4 f_color;\n"
|
|
"void main(void)\n"
|
|
"{\n"
|
|
" gl_FragColor = f_color;\n"
|
|
"}\n";
|
|
|
|
m_programId = CreateShaderProgram(vs, fs);
|
|
m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix");
|
|
m_vertexAttribute = glGetAttribLocation(m_programId, "v_position");
|
|
m_colorAttribute = glGetAttribLocation(m_programId, "v_color");
|
|
m_sizeAttribute = glGetAttribLocation(m_programId, "v_size");
|
|
|
|
glGenBuffers(3, m_vboIds);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
|
|
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Vec3), m_vertices, GL_DYNAMIC_DRAW);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
|
|
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Color), m_colors, GL_DYNAMIC_DRAW);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]);
|
|
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(float32), m_sizes, GL_DYNAMIC_DRAW);
|
|
|
|
AssertGL();
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
m_count = 0;
|
|
}
|
|
|
|
~DrawPoints()
|
|
{
|
|
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);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Vec3), m_vertices);
|
|
glVertexAttribPointer(m_vertexAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
|
glEnableVertexAttribArray(m_vertexAttribute);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Color), m_colors);
|
|
glEnableVertexAttribArray(m_colorAttribute);
|
|
glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(float32), m_sizes);
|
|
glEnableVertexAttribArray(m_sizeAttribute);
|
|
glVertexAttribPointer(m_sizeAttribute, 1, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
|
|
|
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
|
glDrawArrays(GL_POINTS, 0, m_count);
|
|
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
|
|
|
glDisableVertexAttribArray(m_sizeAttribute);
|
|
|
|
glDisableVertexAttribArray(m_colorAttribute);
|
|
|
|
glDisableVertexAttribArray(m_vertexAttribute);
|
|
|
|
AssertGL();
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 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];
|
|
};
|
|
|
|
struct DrawLines
|
|
{
|
|
DrawLines()
|
|
{
|
|
const char* vs = \
|
|
"#version 120\n"
|
|
"uniform mat4 projectionMatrix;\n"
|
|
"attribute vec3 v_position;\n"
|
|
"attribute vec4 v_color;\n"
|
|
"varying 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 120\n"
|
|
"varying vec4 f_color;\n"
|
|
"void main(void)\n"
|
|
"{\n"
|
|
" gl_FragColor = f_color;\n"
|
|
"}\n";
|
|
|
|
m_programId = CreateShaderProgram(vs, fs);
|
|
m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix");
|
|
m_vertexAttribute = glGetAttribLocation(m_programId, "v_position");
|
|
m_colorAttribute = glGetAttribLocation(m_programId, "v_color");
|
|
|
|
glGenBuffers(2, m_vboIds);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
|
|
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Vec3), m_vertices, GL_DYNAMIC_DRAW);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
|
|
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Color), m_colors, GL_DYNAMIC_DRAW);
|
|
|
|
AssertGL();
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
m_count = 0;
|
|
}
|
|
|
|
~DrawLines()
|
|
{
|
|
glDeleteProgram(m_programId);
|
|
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);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Vec3), m_vertices);
|
|
glVertexAttribPointer(m_vertexAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
|
glEnableVertexAttribArray(m_vertexAttribute);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Color), m_colors);
|
|
glEnableVertexAttribArray(m_colorAttribute);
|
|
glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
|
|
|
glDrawArrays(GL_LINES, 0, m_count);
|
|
|
|
AssertGL();
|
|
|
|
glDisableVertexAttribArray(m_colorAttribute);
|
|
|
|
glEnableVertexAttribArray(m_vertexAttribute);
|
|
|
|
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];
|
|
};
|
|
|
|
struct DrawTriangles
|
|
{
|
|
DrawTriangles()
|
|
{
|
|
const char* vs = \
|
|
"#version 120\n"
|
|
"uniform mat4 projectionMatrix;\n"
|
|
"attribute vec3 v_position;\n"
|
|
"attribute vec4 v_color;\n"
|
|
"attribute vec3 v_normal;\n"
|
|
"varying 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 120\n"
|
|
"varying vec4 f_color;\n"
|
|
"void main(void)\n"
|
|
"{\n"
|
|
" gl_FragColor = f_color;\n"
|
|
"}\n";
|
|
|
|
m_programId = CreateShaderProgram(vs, fs);
|
|
m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix");
|
|
m_vertexAttribute = glGetAttribLocation(m_programId, "v_position");
|
|
m_colorAttribute = glGetAttribLocation(m_programId, "v_color");
|
|
m_normalAttribute = glGetAttribLocation(m_programId, "v_normal");
|
|
|
|
glGenBuffers(3, m_vboIds);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
|
|
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Vec3), m_vertices, GL_DYNAMIC_DRAW);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
|
|
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Color), m_colors, GL_DYNAMIC_DRAW);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]);
|
|
glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Vec3), m_normals, GL_DYNAMIC_DRAW);
|
|
|
|
AssertGL();
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
m_count = 0;
|
|
}
|
|
|
|
~DrawTriangles()
|
|
{
|
|
glDeleteProgram(m_programId);
|
|
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);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Vec3), m_vertices);
|
|
glVertexAttribPointer(m_vertexAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
|
glEnableVertexAttribArray(m_vertexAttribute);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Color), m_colors);
|
|
glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
|
glEnableVertexAttribArray(m_colorAttribute);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Vec3), m_normals);
|
|
glVertexAttribPointer(m_normalAttribute, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
|
glEnableVertexAttribArray(m_normalAttribute);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, m_count);
|
|
|
|
AssertGL();
|
|
|
|
glDisableVertexAttribArray(m_normalAttribute);
|
|
|
|
glDisableVertexAttribArray(m_colorAttribute);
|
|
|
|
glDisableVertexAttribArray(m_vertexAttribute);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 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];
|
|
};
|
|
|
|
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 120\n"
|
|
"uniform vec4 color;\n"
|
|
"uniform mat4 projectionMatrix;\n"
|
|
"attribute vec3 v_position;\n"
|
|
"varying 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 120\n"
|
|
"varying vec4 f_color;\n"
|
|
"void main(void)\n"
|
|
"{\n"
|
|
" gl_FragColor = f_color;\n"
|
|
"}\n";
|
|
|
|
m_programId = CreateShaderProgram(vs, fs);
|
|
m_colorUniform = glGetUniformLocation(m_programId, "color");
|
|
m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix");
|
|
m_vertexAttribute = glGetAttribLocation(m_programId, "v_position");
|
|
}
|
|
|
|
~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));
|
|
|
|
glDisableVertexAttribArray(m_vertexAttribute);
|
|
|
|
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 120\n"
|
|
"uniform vec4 color;\n"
|
|
"uniform mat4 modelMatrix;\n"
|
|
"uniform mat4 projectionMatrix;\n"
|
|
"attribute vec3 v_position;\n"
|
|
"attribute vec3 v_normal;\n"
|
|
"varying 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 120\n"
|
|
"varying vec4 f_color;\n"
|
|
"void main(void)\n"
|
|
"{\n"
|
|
" gl_FragColor = 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 = glGetAttribLocation(m_programId, "v_position");
|
|
m_normalAttribute = glGetAttribLocation(m_programId, "v_normal");
|
|
}
|
|
|
|
~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));
|
|
|
|
glDisableVertexAttribArray(m_normalAttribute);
|
|
|
|
glDisableVertexAttribArray(m_vertexAttribute);
|
|
|
|
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));
|
|
|
|
glDisableVertexAttribArray(m_normalAttribute);
|
|
|
|
glDisableVertexAttribArray(m_vertexAttribute);
|
|
|
|
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, 20.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();
|
|
} |