diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b65e0c..f5b9818 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,10 @@ include(External/glfw.cmake) include(External/imgui.cmake) include(External/eigen.cmake) include(External/glad.cmake) +include(External/json.cmake) add_executable(vis main.cpp) -target_link_libraries(vis glfw glad imgui eigen) +target_link_libraries(vis glfw glad imgui eigen nlohmann_json) + +add_executable(serial serialtest.cpp) +target_link_libraries(serial eigen nlohmann_json) diff --git a/External/json.cmake b/External/json.cmake new file mode 100644 index 0000000..fe5ed3a --- /dev/null +++ b/External/json.cmake @@ -0,0 +1,7 @@ +FetchContent_Declare( + json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.10.5 +) +SET(JSON_ImplicitConversions OFF CACHE INTERNAL "") +FetchContent_MakeAvailable(json) diff --git a/include/ml/meshlib_json.hpp b/include/ml/meshlib_json.hpp new file mode 100644 index 0000000..55b19cd --- /dev/null +++ b/include/ml/meshlib_json.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include "meshlib.hpp" + +#include +#include + +namespace Eigen { + template + void to_json(nlohmann::json &json, const Eigen::PlainObjectBase &mat) { + using Scalar = typename Derived::Scalar; + + auto rows = mat.rows(); + auto cols = mat.cols(); + + std::vector vals(mat.size()); + Map(vals.data(), rows, cols) = mat; + + json = { + {"rows", rows}, + {"cols", cols}, + {"vals", vals}, + }; + } + + template + void from_json(const nlohmann::json &j, Derived &mat) { + using Scalar = typename Derived::Scalar; + + auto rows = j["rows"].get(); + auto cols = j["cols"].get(); + auto vals = j["vals"].get>(); + + mat = Eigen::Map(vals.data(), rows, cols); + } +} + +namespace ml { + static void to_json(nlohmann::json &json, const ml::MeshBase &mesh) { + json = { + {"points", mesh.points()}, + {"cells", mesh.cells()}, + }; + } + + static void from_json(const nlohmann::json &j, ml::DynamicMesh &mesh) { + mesh = { + j["points"].get(), + j["cells"].get(), + }; + } + + void write(const ml::MeshBase &mesh, std::ostream &out) { + nlohmann::json json = mesh; + nlohmann::json::to_msgpack(json, out); + } + + void write(const ml::MeshBase &mesh, const std::string &path) { + std::ofstream file(path, std::ios::out | std::ios::binary); + write(mesh, file); + } + + ml::DynamicMesh read(std::istream &in) { + nlohmann::json json = nlohmann::json::from_msgpack(in); + return json.get(); + } + + ml::DynamicMesh read(const std::string &path) { + std::ifstream file(path, std::ios::in | std::ios::binary); + return read(file); + } +} diff --git a/meshlib.hpp b/meshlib.hpp new file mode 100644 index 0000000..4f6724b --- /dev/null +++ b/meshlib.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include +#include +#include +#include + +#include + +namespace ml { + class MeshBase { + public: + using PointsType = Eigen::MatrixXf; + using CellsType = Eigen::MatrixXi; + + [[nodiscard]] virtual PointsType points() const = 0; + + [[nodiscard]] virtual CellsType cells() const = 0; + }; + + class DynamicMesh : public MeshBase { + PointsType _points; + CellsType _cells; + + public: + DynamicMesh() = default; + + explicit DynamicMesh(const MeshBase &mesh) + : _points(mesh.points()), _cells(mesh.cells()) {} + + DynamicMesh(PointsType points, CellsType cells) + : _points(std::move(points)), _cells(std::move(cells)) {} + + [[nodiscard]] PointsType &points() { + return _points; + } + + [[nodiscard]] PointsType points() const override { + return _points; + } + + [[nodiscard]] CellsType &cells() { + return _cells; + } + + [[nodiscard]] CellsType cells() const override { + return _cells; + } + }; + + class CubeMesh : public MeshBase { + PointsType::Scalar radius; + + public: + explicit CubeMesh(PointsType::Scalar radius = 0.5) + : radius(radius) {} + + [[nodiscard]] PointsType points() const override { + PointsType out(3, 8); + out.transpose() << + +radius, +radius, +radius, + +radius, +radius, -radius, + +radius, -radius, +radius, + +radius, -radius, -radius, + -radius, +radius, +radius, + -radius, +radius, -radius, + -radius, -radius, +radius, + -radius, -radius, -radius; + return out; + } + + CellsType cells() const override { + CellsType out(3, 12); + out.transpose() << + 0b000, 0b001, 0b010, 0b001, 0b010, 0b011, + 0b100, 0b101, 0b110, 0b101, 0b110, 0b111, + + 0b000, 0b001, 0b100, 0b001, 0b100, 0b101, + 0b010, 0b011, 0b110, 0b011, 0b110, 0b111, + + 0b000, 0b010, 0b100, 0b010, 0b100, 0b110, + 0b001, 0b011, 0b101, 0b011, 0b101, 0b111; + return out; + } + }; + +// class CubeMesh : public MeshBase { +// public: +// const Eigen::MatrixBase &points() const override { +// return PointsType::Random(3, 8); +// } +// +// const Eigen::MatrixBase &cells() const override { +// return <#initializer#>; +// } +// }; +} diff --git a/main.cpp b/src/main.cpp similarity index 66% rename from main.cpp rename to src/main.cpp index ef8dae1..de1da54 100644 --- a/main.cpp +++ b/src/main.cpp @@ -4,10 +4,19 @@ #include #include #include +#include #include "gldebug.hpp" -void show_overlay(float* clear_color) { +#include "meshlib.hpp" +#include "meshlib_json.hpp" + +struct State { + float bg[4] = {0.45f, 0.55f, 0.60f, 1.00f}; + float fg[4] = {0.19f, 0.86f, 0.33f, 1.00f}; +}; + +void show_overlay(State &state) { static std::string gl_vendor = (const char *) glGetString(GL_VENDOR); static std::string gl_renderer = (const char *) glGetString(GL_RENDERER); static std::string gl_version = (const char *) glGetString(GL_VERSION); @@ -48,7 +57,7 @@ void show_overlay(float* clear_color) { ImGui::Separator(); ImGui::ColorEdit3("Background", state.bg, ImGuiColorEditFlags_Float); - ImGui::SliderFloat("Alpha", &state.fg[3], 0.0f, 1.0f, "%.2f"); + ImGui::ColorEdit3("Foreground", state.fg, ImGuiColorEditFlags_Float); ImGui::End(); } @@ -66,17 +75,10 @@ void set_style() { int run(GLFWwindow *window, ImGuiContext *context) { State state; - float points[]{ - +0.5f, +0.5f, 0.0f, 1.0f, - +0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, +0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.0f, 1.0f, - }; + auto mesh = ml::CubeMesh(0.5f); +// auto mesh = ml::read("circle.pak"); - unsigned int inds[]{ - 0, 1, 2, - 1, 2, 3, - }; + auto dynamic = (ml::DynamicMesh) mesh; GLuint vao; glCreateVertexArrays(1, &vao); @@ -84,21 +86,55 @@ int run(GLFWwindow *window, ImGuiContext *context) { GLuint vbo; glCreateBuffers(1, &vbo); - glNamedBufferData(vbo, sizeof(points), (void *) points, GL_STATIC_DRAW); + constexpr size_t point_scalar_size = sizeof(ml::DynamicMesh::PointsType::Scalar); + constexpr size_t cell_scalar_size = sizeof(ml::DynamicMesh::CellsType::Scalar); + + glNamedBufferData( + vbo, + (GLsizeiptr) (point_scalar_size * dynamic.points().size()), + dynamic.points().data(), + GL_STATIC_DRAW + ); glEnableVertexArrayAttrib(vao, 0); - glVertexArrayVertexBuffer(vao, 0, vbo, 0, sizeof(float) * 4); - glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, GL_FALSE, 0); + glVertexArrayVertexBuffer(vao, 0, + vbo, 0, + (GLsizeiptr) (point_scalar_size * dynamic.points().rows()) + ); + glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0); GLuint ibo; glCreateBuffers(1, &ibo); glGetError(); - glNamedBufferData(ibo, sizeof(inds), (void *) inds, GL_STATIC_DRAW); + glNamedBufferData( + ibo, + (GLsizeiptr) (cell_scalar_size * dynamic.cells().size()), + dynamic.cells().data(), + GL_STATIC_DRAW + ); glVertexArrayElementBuffer(vao, ibo); const char *vs_src = "#version 440\n" - "layout(location=0) in vec4 pos;" + "layout(location=1) uniform float time;" + "layout(location=2) uniform mat4 proj;" + "layout(location=0) in vec3 pos;" "void main() {" - " gl_Position = pos;" + " float c2 = cos(time * 0.2);" + " float s2 = sin(time * 0.2);" + " float c3 = cos(time * 0.3);" + " float s3 = sin(time * 0.3);" + " 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" + ");" + " gl_Position = proj * r2 * r1 * vec4(pos, 1.0);" "}"; GLuint vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs, 1, &vs_src, nullptr); @@ -108,7 +144,10 @@ int run(GLFWwindow *window, ImGuiContext *context) { "layout(location=0) uniform vec4 ucol;" "layout(location=0) out vec4 col;" "void main() {" + " float d = 1.0 - gl_FragCoord.z;" + " d = (d - 0.5) / 0.7 + 0.5;" " col = ucol;" + " col.xyz *= d;" "}"; GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs, 1, &fs_src, nullptr); @@ -119,6 +158,10 @@ int run(GLFWwindow *window, ImGuiContext *context) { glAttachShader(pgm, fs); glLinkProgram(pgm); + glEnable(GL_DEPTH_TEST); + + Eigen::Projective3f proj; + while (!glfwWindowShouldClose(window)) { glfwPollEvents(); @@ -132,12 +175,17 @@ int run(GLFWwindow *window, ImGuiContext *context) { glfwGetFramebufferSize(window, &display_w, &display_h); glViewport(0, 0, display_w, display_h); glClearColor(state.bg[0], state.bg[1], state.bg[2], state.bg[3]); - glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + auto aspect = (float) display_h / (float) display_w; + proj = Eigen::AlignedScaling3f(aspect, 1.0, -1.0); glUseProgram(pgm); glBindVertexArray(vao); glUniform4fv(0, 1, state.fg); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); + glUniform1f(1, (GLfloat) glfwGetTime()); + glUniformMatrix4fv(2, 1, false, proj.data()); + glDrawElements(GL_TRIANGLES, (GLsizei) dynamic.cells().size(), GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); glUseProgram(0); diff --git a/src/serialtest.cpp b/src/serialtest.cpp new file mode 100644 index 0000000..7b65e18 --- /dev/null +++ b/src/serialtest.cpp @@ -0,0 +1,53 @@ +#include + +#include +#include + +#include "meshlib.hpp" +#include "meshlib_json.hpp" + +class Circle : public ml::MeshBase { +public: + PointsType::Scalar radius; + + Circle(PointsType::Scalar radius) : radius(radius) {} + + PointsType points() const override { + PointsType t(1, 32); + for (int i = 0; i < t.size(); ++i) { + t(i) = 6.28318f * (float) i / 32; + } + + PointsType out(3, 32); + out.array().row(0) = t.array().sin(); + out.array().row(1) = t.array().cos(); + out.array().row(2).setZero(); + return out; + } + + CellsType cells() const override { + CellsType t(1, 31); + for (int i = 0; i < t.size(); ++i) { + t(i) = i; + } + + CellsType out(3, 31); + out.array().row(0) = 0; + out.array().row(1) = t.array(); + out.array().row(2) = t.array() + 1; + return out; + } +}; + +int main() { + auto omesh = Circle(1.0f); + + ml::write(omesh, "circle.pak"); + + auto imesh = ml::read("circle.pak"); + + std::cout << "= points ===============" << std::endl; + std::cout << imesh.points() << std::endl; + std::cout << "= cells ================" << std::endl; + std::cout << imesh.cells() << std::endl; +}