mirror of
https://github.com/allemangD/toddcox-visualize.git
synced 2025-11-10 12:02:47 -05:00
Serializable mesh with nlohmann_json
Displays a cube generated by meshlib.hpp (serialtest)
This commit is contained in:
@@ -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)
|
||||
|
||||
7
External/json.cmake
vendored
Normal file
7
External/json.cmake
vendored
Normal file
@@ -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)
|
||||
72
include/ml/meshlib_json.hpp
Normal file
72
include/ml/meshlib_json.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "meshlib.hpp"
|
||||
|
||||
#include <Eigen/Eigen>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace Eigen {
|
||||
template<class Derived>
|
||||
void to_json(nlohmann::json &json, const Eigen::PlainObjectBase<Derived> &mat) {
|
||||
using Scalar = typename Derived::Scalar;
|
||||
|
||||
auto rows = mat.rows();
|
||||
auto cols = mat.cols();
|
||||
|
||||
std::vector<Scalar> vals(mat.size());
|
||||
Map<Derived>(vals.data(), rows, cols) = mat;
|
||||
|
||||
json = {
|
||||
{"rows", rows},
|
||||
{"cols", cols},
|
||||
{"vals", vals},
|
||||
};
|
||||
}
|
||||
|
||||
template<class Derived>
|
||||
void from_json(const nlohmann::json &j, Derived &mat) {
|
||||
using Scalar = typename Derived::Scalar;
|
||||
|
||||
auto rows = j["rows"].get<Eigen::Index>();
|
||||
auto cols = j["cols"].get<Eigen::Index>();
|
||||
auto vals = j["vals"].get<std::vector<Scalar>>();
|
||||
|
||||
mat = Eigen::Map<Derived>(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<DynamicMesh::PointsType>(),
|
||||
j["cells"].get<DynamicMesh::CellsType>(),
|
||||
};
|
||||
}
|
||||
|
||||
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>();
|
||||
}
|
||||
|
||||
ml::DynamicMesh read(const std::string &path) {
|
||||
std::ifstream file(path, std::ios::in | std::ios::binary);
|
||||
return read(file);
|
||||
}
|
||||
}
|
||||
97
meshlib.hpp
Normal file
97
meshlib.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
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<Eigen::MatrixXf, Eigen::MatrixXi> {
|
||||
// public:
|
||||
// const Eigen::MatrixBase<PointsType> &points() const override {
|
||||
// return PointsType::Random(3, 8);
|
||||
// }
|
||||
//
|
||||
// const Eigen::MatrixBase<CellsType> &cells() const override {
|
||||
// return <#initializer#>;
|
||||
// }
|
||||
// };
|
||||
}
|
||||
@@ -4,10 +4,19 @@
|
||||
#include <backends/imgui_impl_glfw.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#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);
|
||||
|
||||
53
src/serialtest.cpp
Normal file
53
src/serialtest.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user