355 lines
11 KiB
C++
355 lines
11 KiB
C++
|
|
#include <regex>
|
||
|
|
#include <iostream>
|
||
|
|
#include "render.h"
|
||
|
|
#include "glm/vec3.hpp"
|
||
|
|
#include "glm/vec4.hpp"
|
||
|
|
#include "glm/gtc/type_ptr.hpp"
|
||
|
|
//#include <GL/glext.h>
|
||
|
|
|
||
|
|
static const char *vs_code = R"(
|
||
|
|
#version 330
|
||
|
|
|
||
|
|
layout (location = 0) in vec3 position;
|
||
|
|
layout (location = 1) in vec4 in_color;
|
||
|
|
|
||
|
|
out vec4 interp_color;
|
||
|
|
|
||
|
|
out vec3 vertPos;
|
||
|
|
flat out vec3 startPos;
|
||
|
|
uniform mat4 mvp;
|
||
|
|
|
||
|
|
|
||
|
|
void main() {
|
||
|
|
vec4 pos = mvp * vec4(position, 1.0);
|
||
|
|
gl_Position = pos;
|
||
|
|
|
||
|
|
vertPos = pos.xyz / pos.w;
|
||
|
|
startPos = vertPos;
|
||
|
|
interp_color = in_color;
|
||
|
|
}
|
||
|
|
)";
|
||
|
|
|
||
|
|
|
||
|
|
static const char *ps_code = R"(
|
||
|
|
#version 330
|
||
|
|
|
||
|
|
flat in vec3 startPos;
|
||
|
|
in vec3 vertPos;
|
||
|
|
|
||
|
|
in vec4 interp_color;
|
||
|
|
out vec4 color;
|
||
|
|
|
||
|
|
uniform vec2 u_resolution;
|
||
|
|
float u_dashSize = 10; // make this uniform
|
||
|
|
float u_gapSize = 10; // make this uniform
|
||
|
|
|
||
|
|
void main() {
|
||
|
|
vec2 dir = (vertPos.xy - startPos.xy) * u_resolution/2.0;
|
||
|
|
float dist = length(dir);
|
||
|
|
|
||
|
|
if (fract(dist / (u_dashSize + u_gapSize)) > u_dashSize/(u_dashSize + u_gapSize))
|
||
|
|
discard;
|
||
|
|
|
||
|
|
color = interp_color;
|
||
|
|
}
|
||
|
|
)";
|
||
|
|
|
||
|
|
|
||
|
|
void grbl::program_renderer::render(glm::mat4 mvp, glm::vec2 viewport_size) {
|
||
|
|
shader->bind();
|
||
|
|
shader->set_mat4(glm::value_ptr(mvp), "mvp");
|
||
|
|
shader->set_vec2(glm::value_ptr(viewport_size), "u_resolution");
|
||
|
|
|
||
|
|
glBindVertexArray(vao_id);
|
||
|
|
glDrawArrays(GL_LINES, 0, vertices_count);
|
||
|
|
|
||
|
|
shader->unbind();
|
||
|
|
|
||
|
|
// draw bit location
|
||
|
|
}
|
||
|
|
|
||
|
|
void grbl::program_renderer::update(const grbl::program& pgm, const grbl::machine& cnc) {
|
||
|
|
if (!initialized) {
|
||
|
|
|
||
|
|
shader = new shader_program(vs_code, ps_code);
|
||
|
|
|
||
|
|
glGenBuffers(1, &vbo_id);
|
||
|
|
glGenVertexArrays(1, &vao_id);
|
||
|
|
|
||
|
|
// vertex format: x, y, z, r, g, b, a
|
||
|
|
// stride: 28 bytes
|
||
|
|
const GLsizei sizeOfVertexInBytes = 28;
|
||
|
|
|
||
|
|
glBindVertexArray(vao_id);
|
||
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||
|
|
|
||
|
|
glEnableVertexAttribArray(0); // vertices on stream 0
|
||
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeOfVertexInBytes, (void *) 0);
|
||
|
|
|
||
|
|
glEnableVertexAttribArray(1); // vertex colors on stream 1
|
||
|
|
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeOfVertexInBytes, (void *) (sizeof(float) * 3));
|
||
|
|
|
||
|
|
// unbind vao
|
||
|
|
glBindVertexArray(0);
|
||
|
|
|
||
|
|
initialized = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// update program with machine status
|
||
|
|
// build vbo and vao
|
||
|
|
vertices_count = build_vbo(pgm);
|
||
|
|
}
|
||
|
|
|
||
|
|
GLsizei grbl::program_renderer::build_vbo(const grbl::program& pgm) {
|
||
|
|
static auto movement_re = std::regex(R"(([gG]0*1?\s+|[xXyYzZ]\s*[0-9\.\-]+))");
|
||
|
|
bool is_tool_on = false;
|
||
|
|
|
||
|
|
std::vector<float> buffer_data;
|
||
|
|
|
||
|
|
glm::vec3 tool_pos;
|
||
|
|
min_pos = max_pos = tool_pos = glm::vec3(0);
|
||
|
|
|
||
|
|
for (auto& i: pgm.instructions) {
|
||
|
|
if (i.type == grbl::instruction_type::gcode) {
|
||
|
|
|
||
|
|
std::vector<std::string> tokens;
|
||
|
|
std::smatch res;
|
||
|
|
std::string::const_iterator start(i.command.cbegin());
|
||
|
|
while (std::regex_search(start, i.command.cend(), res, movement_re)) {
|
||
|
|
auto str = res[0].str();
|
||
|
|
|
||
|
|
// make upper case
|
||
|
|
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
|
||
|
|
|
||
|
|
// remove whitespace from things like "X 123.1234"
|
||
|
|
str.erase(remove_if(str.begin(), str.end(), isspace), str.end());
|
||
|
|
|
||
|
|
tokens.push_back(str);
|
||
|
|
start = res.suffix().first;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!tokens.empty()) {
|
||
|
|
auto new_pos = tool_pos;
|
||
|
|
|
||
|
|
for (auto& t: tokens) {
|
||
|
|
if (t[0] == 'X') {
|
||
|
|
new_pos.x = std::stof(t.substr(1));
|
||
|
|
} else if (t[0] == 'Y') {
|
||
|
|
new_pos.y = std::stof(t.substr(1));
|
||
|
|
} else if (t[0] == 'Z') {
|
||
|
|
new_pos.z = std::stof(t.substr(1));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool has_g1 = tokens[0][0] == 'G' && std::stoi(tokens[0].substr(1)) == 1;
|
||
|
|
bool has_g0 = tokens[0][0] == 'G' && std::stoi(tokens[0].substr(1)) == 0;
|
||
|
|
bool is_plunge = has_g1 && tokens.size() > 1 && tokens[1][0] == 'Z';
|
||
|
|
bool is_retract = has_g0 && tokens.size() > 1 && tokens[1][0] == 'Z';
|
||
|
|
|
||
|
|
is_tool_on = has_g1 || (is_retract ? false : is_tool_on);
|
||
|
|
|
||
|
|
auto from_color = glm::vec4(1.0f);
|
||
|
|
auto to_color = glm::vec4(1.0f);
|
||
|
|
if (is_tool_on) {
|
||
|
|
from_color = glm::vec4(1, 0, 0, 1);
|
||
|
|
to_color = glm::vec4(1, 0, 0, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (is_plunge) {
|
||
|
|
to_color = glm::vec4(1, 0, 0, 1);
|
||
|
|
} else if (is_retract) {
|
||
|
|
to_color = glm::vec4(0, 1, 0, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// from
|
||
|
|
buffer_data.push_back(tool_pos.x);
|
||
|
|
buffer_data.push_back(tool_pos.y);
|
||
|
|
buffer_data.push_back(tool_pos.z);
|
||
|
|
|
||
|
|
buffer_data.push_back(from_color.r);
|
||
|
|
buffer_data.push_back(from_color.g);
|
||
|
|
buffer_data.push_back(from_color.b);
|
||
|
|
buffer_data.push_back(from_color.a);
|
||
|
|
|
||
|
|
// to
|
||
|
|
buffer_data.push_back(new_pos.x);
|
||
|
|
buffer_data.push_back(new_pos.y);
|
||
|
|
buffer_data.push_back(new_pos.z);
|
||
|
|
|
||
|
|
buffer_data.push_back(to_color.r);
|
||
|
|
buffer_data.push_back(to_color.g);
|
||
|
|
buffer_data.push_back(to_color.b);
|
||
|
|
buffer_data.push_back(to_color.a);
|
||
|
|
|
||
|
|
// calculate extents
|
||
|
|
min_pos.x = std::min(min_pos.x, new_pos.x);
|
||
|
|
min_pos.y = std::min(min_pos.y, new_pos.y);
|
||
|
|
min_pos.z = std::min(min_pos.z, new_pos.z);
|
||
|
|
|
||
|
|
max_pos.x = std::max(max_pos.x, new_pos.x);
|
||
|
|
max_pos.y = std::max(max_pos.y, new_pos.y);
|
||
|
|
max_pos.z = std::max(max_pos.z, new_pos.z);
|
||
|
|
|
||
|
|
tool_pos = new_pos;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const GLsizei sizeOfVertexInBytes = 28;
|
||
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||
|
|
glBufferData(GL_ARRAY_BUFFER, sizeOfVertexInBytes * buffer_data.size(), buffer_data.data(), GL_DYNAMIC_DRAW);
|
||
|
|
|
||
|
|
auto number_of_vertices = buffer_data.size() * sizeof(float) / sizeOfVertexInBytes;
|
||
|
|
return number_of_vertices;
|
||
|
|
}
|
||
|
|
|
||
|
|
void check_compile_error(GLuint shader_id) {
|
||
|
|
GLint isCompiled = 0;
|
||
|
|
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &isCompiled);
|
||
|
|
if (!isCompiled) {
|
||
|
|
GLint maxLength = 0;
|
||
|
|
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &maxLength);
|
||
|
|
|
||
|
|
//The maxLength includes the NULL character
|
||
|
|
char errorLog[maxLength];
|
||
|
|
glGetShaderInfoLog(shader_id, maxLength, &maxLength, &errorLog[0]);
|
||
|
|
|
||
|
|
std::cerr << "Shader compile error: " << "(id: " << shader_id << ", code: " << isCompiled << ", bytes: "
|
||
|
|
<< maxLength << ") - " << std::string(errorLog, maxLength);
|
||
|
|
|
||
|
|
//Provide the infolog in whatever manor you deem best.
|
||
|
|
//Exit with failure.
|
||
|
|
glDeleteShader(shader_id); //Don't leak the shader.
|
||
|
|
} else {
|
||
|
|
std::cout << "Shader " << shader_id << " successfully compiled";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void check_link_error(GLuint program_id) {
|
||
|
|
GLint is_linked = 0;
|
||
|
|
glGetShaderiv(program_id, GL_LINK_STATUS, &is_linked);
|
||
|
|
if (!is_linked) {
|
||
|
|
GLint maxLength = 0;
|
||
|
|
glGetShaderiv(program_id, GL_INFO_LOG_LENGTH, &maxLength);
|
||
|
|
|
||
|
|
//The maxLength includes the NULL character
|
||
|
|
char errorLog[maxLength];
|
||
|
|
glGetShaderInfoLog(program_id, maxLength, &maxLength, &errorLog[0]);
|
||
|
|
|
||
|
|
std::cerr << "Shader program link error: " << "(id: " << program_id << ", code: " << is_linked << ", bytes: "
|
||
|
|
<< maxLength << ") - " << std::string(errorLog, maxLength);
|
||
|
|
|
||
|
|
//Provide the info log in whatever manner you deem best.
|
||
|
|
//Exit with failure.
|
||
|
|
glDeleteShader(program_id); //Don't leak the program shader.
|
||
|
|
} else {
|
||
|
|
std::cout << "Shader program " << program_id << " successfully linked";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
grbl::shader_program::shader_program(const char *vs_content, const char *ps_content)
|
||
|
|
: shader_ids{0, 0},
|
||
|
|
program_id{0} {
|
||
|
|
|
||
|
|
|
||
|
|
shader_ids[0] = glCreateShader(GL_VERTEX_SHADER);
|
||
|
|
glShaderSource(shader_ids[0], 1, &vs_content, NULL);
|
||
|
|
glCompileShader(shader_ids[0]);
|
||
|
|
int success;
|
||
|
|
char infoLog[512];
|
||
|
|
glGetShaderiv(shader_ids[0], GL_COMPILE_STATUS, &success);
|
||
|
|
if (!success) {
|
||
|
|
glGetShaderInfoLog(shader_ids[0], 512, NULL, infoLog);
|
||
|
|
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
shader_ids[1] = glCreateShader(GL_FRAGMENT_SHADER);
|
||
|
|
glShaderSource(shader_ids[1], 1, &ps_content, NULL);
|
||
|
|
glCompileShader(shader_ids[1]);
|
||
|
|
glGetShaderiv(shader_ids[1], GL_COMPILE_STATUS, &success);
|
||
|
|
if (!success) {
|
||
|
|
glGetShaderInfoLog(shader_ids[1], 512, NULL, infoLog);
|
||
|
|
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
program_id = glCreateProgram();
|
||
|
|
glAttachShader(program_id, shader_ids[0]);
|
||
|
|
glAttachShader(program_id, shader_ids[1]);
|
||
|
|
glLinkProgram(program_id);
|
||
|
|
|
||
|
|
glGetProgramiv(program_id, GL_LINK_STATUS, &success);
|
||
|
|
if (!success) {
|
||
|
|
glGetProgramInfoLog(program_id, 512, NULL, infoLog);
|
||
|
|
std::cout << "ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n" << infoLog << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
glUseProgram(program_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
grbl::shader_program::~shader_program() {
|
||
|
|
glDetachShader(program_id, shader_ids[0]);
|
||
|
|
glDetachShader(program_id, shader_ids[1]);
|
||
|
|
|
||
|
|
glDeleteShader(shader_ids[0]);
|
||
|
|
glDeleteShader(shader_ids[1]);
|
||
|
|
|
||
|
|
glDeleteProgram(program_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
void grbl::shader_program::bind() const {
|
||
|
|
glUseProgram(program_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
void grbl::shader_program::unbind() {
|
||
|
|
glUseProgram(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
int grbl::shader_program::get_uniform(const char *name) {
|
||
|
|
if (uniform_cache.count(name) == 0) {
|
||
|
|
uniform_cache[name] = glGetUniformLocation(program_id, name);
|
||
|
|
}
|
||
|
|
return uniform_cache[name];
|
||
|
|
}
|
||
|
|
|
||
|
|
void grbl::shader_program::set_mat3(float *matrix, const char *uniform_name) {
|
||
|
|
GLint location = get_uniform(uniform_name);
|
||
|
|
if (location != -1)
|
||
|
|
glUniformMatrix3fv(location, 1, false, matrix);
|
||
|
|
}
|
||
|
|
|
||
|
|
void grbl::shader_program::set_mat4(float *matrix, const char *uniform_name) {
|
||
|
|
GLint location = get_uniform(uniform_name);
|
||
|
|
if (location != -1)
|
||
|
|
glUniformMatrix4fv(location, 1, false, matrix);
|
||
|
|
}
|
||
|
|
|
||
|
|
void grbl::shader_program::set_vec2(float *value, const char *uniform_name) {
|
||
|
|
GLint location = get_uniform(uniform_name);
|
||
|
|
if (location != -1)
|
||
|
|
glUniform2fv(location, 1, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
void grbl::shader_program::set_vec3(float *value, const char *uniform_name) {
|
||
|
|
GLint location = get_uniform(uniform_name);
|
||
|
|
if (location != -1)
|
||
|
|
glUniform3fv(location, 1, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
void grbl::shader_program::set_vec4(float *value, const char *uniform_name) {
|
||
|
|
GLint location = get_uniform(uniform_name);
|
||
|
|
if (location != -1)
|
||
|
|
glUniform4fv(location, 1, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
void grbl::shader_program::set_int(int value, const char *uniform_name) {
|
||
|
|
GLint location = get_uniform(uniform_name);
|
||
|
|
if (location != -1)
|
||
|
|
glUniform1i(location, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
void grbl::shader_program::set_float(float value, const char *uniform_name) {
|
||
|
|
GLint location = get_uniform(uniform_name);
|
||
|
|
if (location != -1)
|
||
|
|
glUniform1f(location, value);
|
||
|
|
}
|