#include #include #include "render.h" #include "glm/vec3.hpp" #include "glm/vec4.hpp" #include "glm/gtc/type_ptr.hpp" //#include 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); auto spindle_xform = glm::translate(glm::mat4(1.0f), spindle_pos); auto spindle_view = mvp * spindle_xform; shader->set_mat4(glm::value_ptr(spindle_view), "mvp"); glBindVertexArray(spindle_vao_id); glDrawArrays(GL_LINES, 0, spindle_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); initialize_spindle_buffers(); initialize_program_buffers(); initialized = true; } // update program with machine status // build vbo and vao vertices_count = build_vbo(pgm); auto work_pos = cnc.get_status().machine_pos; auto offsets = cnc.get_current_work_offset_values(); for (int i = 0; i < 3; i++) { work_pos[i] -= offsets[i]; } spindle_pos = glm::vec3(work_pos[0], work_pos[1], work_pos[2]); } void grbl::program_renderer::initialize_spindle_buffers() { glGenBuffers(1, &spindle_vbo_id); glGenVertexArrays(1, &spindle_vao_id); // vertex format: x, y, z, r, g, b, a // stride: 28 bytes const GLsizei sizeOfVertexInBytes = 28; glBindVertexArray(spindle_vao_id); glBindBuffer(GL_ARRAY_BUFFER, spindle_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); // construct spindle model glm::vec4 col(1, 1, 0, 1); // yellow std::vector buffer_data; const float spindle_length = 3.5; const size_t cone_granularity = 20; for (int i = 0; i < cone_granularity; i++) { float x = sinf((i / (float) cone_granularity) * 2.0f * M_PI); float y = cosf((i / (float) cone_granularity) * 2.0f * M_PI); // from buffer_data.push_back(0); buffer_data.push_back(0); buffer_data.push_back(0); buffer_data.push_back(col.r); buffer_data.push_back(col.g); buffer_data.push_back(col.b); buffer_data.push_back(col.a); // to buffer_data.push_back(x); buffer_data.push_back(y); buffer_data.push_back(spindle_length); buffer_data.push_back(col.r); buffer_data.push_back(col.g); buffer_data.push_back(col.b); buffer_data.push_back(col.a); } glBindBuffer(GL_ARRAY_BUFFER, spindle_vbo_id); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * buffer_data.size(), buffer_data.data(), GL_STATIC_DRAW); spindle_vertices_count = buffer_data.size() * sizeof(float) / sizeOfVertexInBytes; } void grbl::program_renderer::initialize_program_buffers() { 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); } 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; buffer_data.clear(); 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 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; auto number_of_vertices = buffer_data.size() * sizeof(float) / sizeOfVertexInBytes; glBindBuffer(GL_ARRAY_BUFFER, vbo_id); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * buffer_data.size(), buffer_data.data(), GL_STATIC_DRAW); return number_of_vertices; } std::string get_shader_info_log(GLuint id) { GLint log_length = 0; glGetShaderiv(id, GL_INFO_LOG_LENGTH, &log_length); char error_log[log_length]; // length includes the NULL character glGetShaderInfoLog(id, log_length, &log_length, &error_log[0]); return std::string(error_log, log_length); } std::string get_program_info_log(GLuint id) { GLint log_length = 0; glGetProgramiv(id, GL_INFO_LOG_LENGTH, &log_length); char error_log[log_length]; // length includes the NULL character glGetProgramInfoLog(id, log_length, &log_length, &error_log[0]); return std::string(error_log, log_length); } bool check_compile_error(GLuint shader_id) { GLint is_compiled = 0; glGetShaderiv(shader_id, GL_COMPILE_STATUS, &is_compiled); if (is_compiled == GL_TRUE) return true; std::cerr << "Shader compile error: " << "(id: " << shader_id << ") - " << get_shader_info_log(shader_id) << std::endl; glDeleteShader(shader_id); return false; } bool check_link_error(GLuint program_id) { GLint is_linked = 0; glGetProgramiv(program_id, GL_LINK_STATUS, &is_linked); if (is_linked == GL_TRUE) return true; std::cerr << "Shader program link error: " << "(id: " << program_id << ") - " << get_program_info_log(program_id) << std::endl; glDeleteProgram(program_id); return false; } 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, nullptr); glCompileShader(shader_ids[0]); check_compile_error(shader_ids[0]); shader_ids[1] = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(shader_ids[1], 1, &ps_content, nullptr); glCompileShader(shader_ids[1]); check_compile_error(shader_ids[1]); program_id = glCreateProgram(); glAttachShader(program_id, shader_ids[0]); glAttachShader(program_id, shader_ids[1]); glLinkProgram(program_id); check_link_error(program_id); 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); }