Skip to content

Commit

Permalink
Cleanup Visualisation OpenGL rendering (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
p3p committed Apr 24, 2024
1 parent 42a8c3f commit be1d44c
Show file tree
Hide file tree
Showing 6 changed files with 651 additions and 417 deletions.
8 changes: 6 additions & 2 deletions src/MarlinSimulator/hardware/print_bed.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class PrintBed : public VirtualPrinter::Component {
updated |= ImGui::SliderFloat("bed level(front left)", &bed_level_points[1].z, -5.0f, 5.0f);
updated |= ImGui::SliderFloat("bed level(front right)", &bed_level_points[2].z, -5.0f, 5.0f);
// Add a checkbox to choose whether to show a bed gradient
updated |= ImGui::Checkbox("Z height gradient", &gradient_enabled);
updated |= ImGui::Checkbox("Z height gradient", &gradient_enabled);

// Add combo box with the options "flat", "bowl" and "dome"
static const char* items[] = { "flat", "parabolic", "chip", "ripple", "x ripple", "y ripple", "xy ripple" };
Expand All @@ -39,7 +39,10 @@ class PrintBed : public VirtualPrinter::Component {

updated |= ImGui::SliderFloat("amplitude", &bed_shape_amplitude, -5.0f, 5.0f);

if (updated) build_3point(bed_level_points[0], bed_level_points[1], bed_level_points[2]);
if (updated) {
dirty = true;
build_3point(bed_level_points[0], bed_level_points[1], bed_level_points[2]);
}
}

void build_3point(glm::vec3 p1, glm::vec3 p2, glm::vec3 p3) {
Expand Down Expand Up @@ -95,4 +98,5 @@ class PrintBed : public VirtualPrinter::Component {
bool gradient_enabled = false;
bed_shape_t bed_shape = flat;
float bed_shape_amplitude = 1.0f;
bool dirty = true;
};
64 changes: 64 additions & 0 deletions src/MarlinSimulator/renderer/gl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once

#include <gl.h>
#include <glm/glm.hpp>

namespace renderer {

template<typename T> struct type_to_gl_enum;
template<> struct type_to_gl_enum<float> { static constexpr uint32_t value = GL_FLOAT; };
template<> struct type_to_gl_enum<glm::vec2> { static constexpr uint32_t value = GL_FLOAT_VEC2; };
template<> struct type_to_gl_enum<glm::vec3> { static constexpr uint32_t value = GL_FLOAT_VEC3; };
template<> struct type_to_gl_enum<glm::vec4> { static constexpr uint32_t value = GL_FLOAT_VEC4; };
template<> struct type_to_gl_enum<double> { static constexpr uint32_t value = GL_DOUBLE; };
template<> struct type_to_gl_enum<int32_t> { static constexpr uint32_t value = GL_INT; };
template<> struct type_to_gl_enum<glm::ivec2> { static constexpr uint32_t value = GL_INT_VEC2; };
template<> struct type_to_gl_enum<glm::ivec3> { static constexpr uint32_t value = GL_INT_VEC3; };
template<> struct type_to_gl_enum<glm::ivec4> { static constexpr uint32_t value = GL_INT_VEC4; };
template<> struct type_to_gl_enum<uint32_t> { static constexpr uint32_t value = GL_UNSIGNED_INT; };
template<> struct type_to_gl_enum<glm::uvec2> { static constexpr uint32_t value = GL_UNSIGNED_INT_VEC2; };
template<> struct type_to_gl_enum<glm::uvec3> { static constexpr uint32_t value = GL_UNSIGNED_INT_VEC3; };
template<> struct type_to_gl_enum<glm::uvec4> { static constexpr uint32_t value = GL_UNSIGNED_INT_VEC4; };
template<> struct type_to_gl_enum<bool> { static constexpr uint32_t value = GL_BOOL; };
template<> struct type_to_gl_enum<glm::bvec2> { static constexpr uint32_t value = GL_BOOL_VEC2; };
template<> struct type_to_gl_enum<glm::bvec3> { static constexpr uint32_t value = GL_BOOL_VEC3; };
template<> struct type_to_gl_enum<glm::bvec4> { static constexpr uint32_t value = GL_BOOL_VEC4; };
template<> struct type_to_gl_enum<glm::mat2> { static constexpr uint32_t value = GL_FLOAT_MAT2; };
template<> struct type_to_gl_enum<glm::mat3> { static constexpr uint32_t value = GL_FLOAT_MAT3; };
template<> struct type_to_gl_enum<glm::mat4> { static constexpr uint32_t value = GL_FLOAT_MAT4; };
template<> struct type_to_gl_enum<glm::mat2x3> { static constexpr uint32_t value = GL_FLOAT_MAT2x3; };
template<> struct type_to_gl_enum<glm::mat2x4> { static constexpr uint32_t value = GL_FLOAT_MAT2x4; };
template<> struct type_to_gl_enum<glm::mat3x2> { static constexpr uint32_t value = GL_FLOAT_MAT3x2; };
template<> struct type_to_gl_enum<glm::mat3x4> { static constexpr uint32_t value = GL_FLOAT_MAT3x4; };
template<> struct type_to_gl_enum<glm::mat4x2> { static constexpr uint32_t value = GL_FLOAT_MAT4x2; };
template<> struct type_to_gl_enum<glm::mat4x3> { static constexpr uint32_t value = GL_FLOAT_MAT4x3; };
template<> struct type_to_gl_enum<uint8_t>{ static constexpr uint32_t value = GL_UNSIGNED_BYTE; };
template<> struct type_to_gl_enum<int16_t> { static constexpr uint32_t value = GL_SHORT; };
template<> struct type_to_gl_enum<uint16_t>{ static constexpr uint32_t value = GL_UNSIGNED_SHORT; };
template<> struct type_to_gl_enum<int8_t>{ static constexpr uint32_t value = GL_BYTE; };

struct data_descriptor_element_t {
public:
template <typename T> static constexpr data_descriptor_element_t build(){ return data_descriptor_element_t(T::length(), type_to_gl_enum<typename T::value_type>::value, sizeof(T)); };
const uint32_t elements;
const uint32_t gl_enum;
const uint32_t length;
private:
constexpr data_descriptor_element_t(const uint32_t elements, const uint32_t gl_enum, const uint32_t length) : elements{elements}, gl_enum{gl_enum}, length{length} {};
};

enum class Primitive : uint32_t {
POINTS = GL_POINTS,
LINE_STRIP = GL_LINE_STRIP,
LINE_LOOP = GL_LINE_LOOP,
LINES = GL_LINES,
LINE_STRIP_ADJACENCY = GL_LINE_STRIP_ADJACENCY,
LINES_ADJACENCY = GL_LINES_ADJACENCY,
TRIANGLE_STRIP = GL_TRIANGLE_STRIP,
TRIANGLE_FAN = GL_TRIANGLE_FAN,
TRIANGLES = GL_TRIANGLES,
TRIANGLE_STRIP_ADJACENCY = GL_TRIANGLE_STRIP_ADJACENCY,
TRIANGLES_ADJACENCY = GL_TRIANGLES_ADJACENCY
};

}
196 changes: 196 additions & 0 deletions src/MarlinSimulator/renderer/renderer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
#pragma once

#include <memory>
#include <vector>

#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>

#include "gl.h"

namespace renderer {

struct vertex_data_t {
glm::vec3 position;
glm::vec3 normal;
glm::vec4 color;

static constexpr std::size_t elements = 3;
static constexpr std::array<data_descriptor_element_t, vertex_data_t::elements> descriptor {
data_descriptor_element_t::build<decltype(position)>(),
data_descriptor_element_t::build<decltype(normal)>(),
data_descriptor_element_t::build<decltype(color)>()
};
};

class BufferBase {
public:
virtual ~BufferBase() {
if (m_vbo) glDeleteBuffers(1, &m_vbo);
if (m_vao) glDeleteBuffers(1, &m_vao);
}
virtual void generate() = 0;
virtual void bind() = 0;
virtual void upload() = 0;
virtual void render() = 0;
GLuint m_vao = 0;
GLuint m_vbo = 0;
size_t m_geometry_offset = 0;
GLuint m_storage_hint = GL_STATIC_DRAW;
Primitive m_geometry_type = Primitive::TRIANGLES;
bool m_dirty = true;
bool m_generated = false;
};

template <typename ElementType> class Buffer : public BufferBase {
public:
virtual void generate() override {
glGenVertexArrays( 1, &m_vao );
glGenBuffers( 1, &m_vbo );
glBindVertexArray( m_vao );
glBindBuffer( GL_ARRAY_BUFFER, m_vbo );

size_t index = 0, offset = 0;
for (auto& attrib : ElementType::descriptor) {
glEnableVertexAttribArray(index);
glVertexAttribPointer(index, attrib.elements, attrib.gl_enum, GL_FALSE, sizeof(ElementType), (void *)offset);
++index;
offset += attrib.length;
}
m_generated = true;
}

virtual void bind() override {
if (!m_generated) generate();
glBindVertexArray( m_vao );
glBindBuffer( GL_ARRAY_BUFFER, m_vbo );
}

virtual void upload() override {
if (m_dirty) {
glBufferData( GL_ARRAY_BUFFER, m_data.size() * sizeof(ElementType), &m_data[0], m_storage_hint );
m_dirty = false;
}
}

virtual void render() override {
bind();
upload();
glDrawArrays( (GLenum)m_geometry_type, m_geometry_offset, m_data.size());
}

static std::shared_ptr<Buffer<ElementType>> create() {
return std::shared_ptr<Buffer<ElementType>>( new Buffer<ElementType>() );
}

std::vector<ElementType>& data() {
m_dirty = true;
return m_data;
}

std::vector<ElementType> const & cdata() const {
return m_data;
}

size_t size() {
return m_data.size();
}

void add_vertex(ElementType elem) {
m_dirty = true;
m_data.push_back(elem);
}

private:
std::vector<ElementType> m_data {};
Buffer() { }
};

class Mesh {
public:
void render(glm::mat4 global_transform) {
if (!m_visible) return;
if (m_dirty) {
build_transform();
m_dirty = false;
}
if (m_shader_dirty) {
update_shader_locations();
m_shader_dirty = false;
}
glUseProgram( m_shader_program );
global_transform = global_transform * m_transform;
glUniformMatrix4fv( m_shader_index_mvp, 1, GL_FALSE, glm::value_ptr(global_transform));
for (auto buffer : m_buffer) {
buffer->render();
}
}

void build_transform() {
m_transform = glm::translate(glm::mat4(1.0), m_position);
m_transform = m_transform * glm::mat4_cast(m_rotation);
m_transform = glm::scale(m_transform, m_scale);
m_transform = glm::translate(m_transform, m_origin);
}

template <typename VertexType> static std::shared_ptr<Mesh> create(std::shared_ptr<VertexType> buffer) {
auto mesh = std::shared_ptr<Mesh>(new Mesh());
mesh->m_buffer.push_back(buffer);
return mesh;
}

template <typename VertexType> static std::shared_ptr<Mesh> create() {
auto mesh = std::shared_ptr<Mesh>(new Mesh());
mesh->m_buffer.push_back(Buffer<VertexType>::create());
return mesh;
}

template <typename VertexType> std::shared_ptr<Buffer<VertexType>> buffer() {
return std::reinterpret_pointer_cast<Buffer<VertexType>>(m_buffer.back());
}

template <typename VertexType> std::vector<std::shared_ptr<Buffer<VertexType>>>& buffer_vector() {
return *reinterpret_cast<std::vector<std::shared_ptr<Buffer<VertexType>>>*>(&m_buffer);
}

void update_shader_locations() {
m_shader_index_mvp = glGetUniformLocation( m_shader_program, "u_mvp" );
}

void set_shader_program(GLuint program) {
m_shader_program = program;
}

glm::mat4 m_transform {1.0};
glm::vec3 m_origin {0.0, 0.0, 0.0};
glm::vec3 m_position {0.0, 0.0, 0.0};
glm::vec3 m_scale {1.0, 1.0, 1.0};
glm::quat m_rotation {};
bool m_visible = true;
bool m_dirty = true;
bool m_shader_dirty = true;
bool m_delete = false;
std::vector<std::shared_ptr<BufferBase>> m_buffer {};

GLuint m_shader_program = 0;
GLuint m_shader_index_mvp = 0;

private:
Mesh() {}
};

class Renderer {
public:
void render(glm::mat4 global_transform) {
//TODO: mutex for modifying mesh vector
m_mesh.erase(std::remove_if(m_mesh.begin(), m_mesh.end(), [](auto& mesh) { return mesh->m_delete; }), m_mesh.end());
for (auto& mesh : m_mesh) {
mesh->render(global_transform);
}
}

std::vector<std::shared_ptr<Mesh>> m_mesh;
static constexpr size_t MAX_BUFFER_SIZE = 100000;
};

}
Loading

0 comments on commit be1d44c

Please sign in to comment.