From c302cc03a571409dde75fd74c780541c724f8394 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Wed, 16 Feb 2022 18:07:30 -0500 Subject: [PATCH] Add wireframe hypercube --- include/ml/meshlib.hpp | 70 ++++++++++++++++++++++++++++++++++ res/shaders/4d.vert.glsl | 40 ++++++++++++++++++++ res/shaders/main.frag.glsl | 1 + src/main.cpp | 77 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 res/shaders/4d.vert.glsl diff --git a/include/ml/meshlib.hpp b/include/ml/meshlib.hpp index ff71147..21714d1 100644 --- a/include/ml/meshlib.hpp +++ b/include/ml/meshlib.hpp @@ -13,8 +13,12 @@ namespace ml { using PointsType = Eigen::MatrixXf; using CellsType = Eigen::MatrixXi; + [[nodiscard]] virtual Eigen::Index dim() const = 0; + [[nodiscard]] virtual PointsType points() const = 0; + [[nodiscard]] virtual Eigen::Index rank() const = 0; + [[nodiscard]] virtual CellsType cells() const = 0; }; @@ -31,6 +35,10 @@ namespace ml { DynamicMesh(PointsType points, CellsType cells) : _points(std::move(points)), _cells(std::move(cells)) {} + Eigen::Index dim() const override { + return _points.rows(); + } + [[nodiscard]] PointsType &points() { return _points; } @@ -39,6 +47,10 @@ namespace ml { return _points; } + Eigen::Index rank() const override { + return _points.rows(); + } + [[nodiscard]] CellsType &cells() { return _cells; } @@ -55,6 +67,10 @@ namespace ml { explicit CubeMesh(PointsType::Scalar radius = 0.5) : radius(radius) {} + Eigen::Index dim() const override { + return 3; + } + [[nodiscard]] PointsType points() const override { PointsType out(3, 8); out.transpose() << @@ -69,6 +85,10 @@ namespace ml { return out; } + Eigen::Index rank() const override { + return 3; + } + CellsType cells() const override { CellsType out(3, 12); out.transpose() << @@ -83,4 +103,54 @@ namespace ml { return out; } }; + + class WireCubeMesh : public MeshBase { + PointsType::Scalar radius; + long _dim; + long _npoints; + long _nlines; + + public: + explicit WireCubeMesh(long dim = 3, PointsType::Scalar radius = 0.5) + : _dim(dim), radius(radius) { + _npoints = 1 << _dim; + _nlines = _dim * (_npoints >> 1); + } + + Eigen::Index dim() const override { + return _dim; + } + + [[nodiscard]] PointsType points() const override { + PointsType out(_dim, _npoints); + out.fill(radius); + for (int i = 0; i < out.cols(); ++i) { + for (int j = 0; j < _dim; ++j) { + if ((i >> j) & 1) { + out(j, i) *= -1; + } + } + } + return out; + } + + Eigen::Index rank() const override { + return 2; + } + + [[nodiscard]] CellsType cells() const override { + CellsType out(2, _nlines); + int k = 0; + for (int i = 0; i < _npoints; ++i) { + for (int j = 0; j < _dim; ++j) { + if ((i >> j) & 1) { + out(0, k) = i; + out(1, k) = i ^ (1 << j); + k++; + } + } + } + return out; + } + }; } diff --git a/res/shaders/4d.vert.glsl b/res/shaders/4d.vert.glsl new file mode 100644 index 0000000..2e5912c --- /dev/null +++ b/res/shaders/4d.vert.glsl @@ -0,0 +1,40 @@ +#version 440 + +layout(location=1) uniform float time; +layout(location=2) uniform mat4 proj; + +layout(location=0) in vec4 pos; + +void main() { + float c2 = cos(time * 0.2); + float s2 = sin(time * 0.2); + float c3 = cos(time * 0.3); + float s3 = sin(time * 0.3); + float c4 = cos(time * 0.25); + float s4 = sin(time * 0.25); + + mat4 r1 = mat4( + c2, -s2, 0.0, 0.0, + s2, c2, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ); + + mat4 r2 = mat4( + c3, 0.0, -s3, 0.0, + 0.0, 1.0, 0.0, 0.0, + s3, 0.0, c3, 0.0, + 0.0, 0.0, 0.0, 1.0 + ); + + mat4 r3 = mat4( + 1.0, 0.0, 0.0, 0.0, + 0.0, c4, 0.0, -s4, + 0.0, 0.0, 1.0, 0.0, + 0.0, s4, 0.0, c4 + ); + + vec4 pos = r2 * r1 * r3 * pos; + + gl_Position = proj * vec4(pos.xyz / (1 - pos.w), 1.0); +} diff --git a/res/shaders/main.frag.glsl b/res/shaders/main.frag.glsl index 7d9b9db..539d64e 100644 --- a/res/shaders/main.frag.glsl +++ b/res/shaders/main.frag.glsl @@ -1,6 +1,7 @@ #version 440 layout(location=0) uniform vec4 ucol; + layout(location=0) out vec4 col; void main() { diff --git a/src/main.cpp b/src/main.cpp index dff2f69..0dd3c51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,7 +75,7 @@ void set_style() { int run(GLFWwindow *window, ImGuiContext *context) { State state; - auto mesh = ml::CubeMesh(0.5f); + auto mesh = ml::CubeMesh(0.25f); // auto mesh = ml::read("circle.pak"); auto dynamic = (ml::DynamicMesh) mesh; @@ -113,6 +113,39 @@ int run(GLFWwindow *window, ImGuiContext *context) { ); glVertexArrayElementBuffer(vao, ibo); + auto wire_mesh = ml::WireCubeMesh(4, 0.33f); + auto wire_dynamic = (ml::DynamicMesh) wire_mesh; + + GLuint wire_vao; + glCreateVertexArrays(1, &wire_vao); + + GLuint wire_vbo; + glCreateBuffers(1, &wire_vbo); + + glNamedBufferData( + wire_vbo, + (GLsizeiptr) (point_scalar_size * wire_dynamic.points().size()), + wire_dynamic.points().data(), + GL_STATIC_DRAW + ); + glEnableVertexArrayAttrib(wire_vao, 0); + glVertexArrayVertexBuffer(wire_vao, 0, + wire_vbo, 0, + (GLsizeiptr) (point_scalar_size * wire_dynamic.points().rows()) + ); + glVertexArrayAttribFormat(wire_vao, 0, 4, GL_FLOAT, GL_FALSE, 0); + + GLuint wire_ibo; + glCreateBuffers(1, &wire_ibo); + glGetError(); + glNamedBufferData( + wire_ibo, + (GLsizeiptr) (cell_scalar_size * wire_dynamic.cells().size()), + wire_dynamic.cells().data(), + GL_STATIC_DRAW + ); + glVertexArrayElementBuffer(wire_vao, wire_ibo); + std::ifstream vs_file("res/shaders/main.vert.glsl"); std::string vs_src( (std::istreambuf_iterator(vs_file)), @@ -125,6 +158,18 @@ int run(GLFWwindow *window, ImGuiContext *context) { glShaderSource(vs, 1, &vs_str, nullptr); glCompileShader(vs); + std::ifstream wire_vs_file("res/shaders/4d.vert.glsl"); + std::string wire_vs_src( + (std::istreambuf_iterator(wire_vs_file)), + std::istreambuf_iterator() + ); + wire_vs_file.close(); + const char *wire_vs_str = wire_vs_src.c_str(); + + GLuint wire_vs = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(wire_vs, 1, &wire_vs_str, nullptr); + glCompileShader(wire_vs); + std::ifstream fs_file("res/shaders/main.frag.glsl"); std::string fs_src( (std::istreambuf_iterator(fs_file)), @@ -142,6 +187,11 @@ int run(GLFWwindow *window, ImGuiContext *context) { glAttachShader(pgm, fs); glLinkProgram(pgm); + GLuint wire_pgm = glCreateProgram(); + glAttachShader(wire_pgm, wire_vs); + glAttachShader(wire_pgm, fs); + glLinkProgram(wire_pgm); + GLint link_status; glGetProgramiv(pgm, GL_LINK_STATUS, &link_status); if (!link_status) { @@ -154,8 +204,16 @@ int run(GLFWwindow *window, ImGuiContext *context) { return EXIT_FAILURE; } - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glGetProgramiv(wire_pgm, GL_LINK_STATUS, &link_status); + if (!link_status) { + std::cerr << "Wire program link failed." << std::endl; + GLint vs_comp_status, fs_comp_status; + glGetShaderiv(vs, GL_COMPILE_STATUS, &vs_comp_status); + glGetShaderiv(fs, GL_COMPILE_STATUS, &fs_comp_status); + std::cerr << "vs compiled: " << std::boolalpha << (bool) vs_comp_status << std::endl; + std::cerr << "fs compiled: " << std::boolalpha << (bool) fs_comp_status << std::endl; + return EXIT_FAILURE; + } glEnable(GL_DEPTH_TEST); @@ -188,6 +246,15 @@ int run(GLFWwindow *window, ImGuiContext *context) { glBindVertexArray(0); glUseProgram(0); + glUseProgram(wire_pgm); + glBindVertexArray(wire_vao); + glUniform4fv(0, 1, state.fg); + glUniform1f(1, (GLfloat) glfwGetTime()); + glUniformMatrix4fv(2, 1, false, proj.data()); + glDrawElements(GL_LINES, (GLsizei) wire_dynamic.cells().size(), GL_UNSIGNED_INT, nullptr); + glBindVertexArray(0); + glUseProgram(0); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); glfwSwapBuffers(window); } @@ -196,6 +263,10 @@ int run(GLFWwindow *window, ImGuiContext *context) { glDeleteBuffers(1, &ibo); glDeleteVertexArrays(1, &vao); + glDeleteBuffers(1, &wire_vbo); + glDeleteBuffers(1, &wire_ibo); + glDeleteVertexArrays(1, &wire_vao); + return EXIT_SUCCESS; }