diff --git a/include/ml/meshlib.hpp b/include/ml/meshlib.hpp index 21714d1..d84d887 100644 --- a/include/ml/meshlib.hpp +++ b/include/ml/meshlib.hpp @@ -8,149 +8,75 @@ #include namespace ml { - class MeshBase { + using Matrix2Xui = Eigen::Matrix; + using Matrix3Xui = Eigen::Matrix; + using Matrix4Xui = Eigen::Matrix; + + template + class Mesh { public: - using PointsType = Eigen::MatrixXf; - using CellsType = Eigen::MatrixXi; + using Points = PT_; + using Cells = CT_; - [[nodiscard]] virtual Eigen::Index dim() const = 0; + Points points; + Cells cells; - [[nodiscard]] virtual PointsType points() const = 0; - - [[nodiscard]] virtual Eigen::Index rank() const = 0; - - [[nodiscard]] virtual CellsType cells() const = 0; + Mesh(Points points, Cells cells) + : points(std::move(points)), cells(std::move(cells)) {} }; - 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)) {} - - Eigen::Index dim() const override { - return _points.rows(); - } - - [[nodiscard]] PointsType &points() { - return _points; - } - - [[nodiscard]] PointsType points() const override { - return _points; - } - - Eigen::Index rank() const override { - return _points.rows(); - } - - [[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) {} - - Eigen::Index dim() const override { - return 3; - } - - [[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; - } - - Eigen::Index rank() const override { - return 3; - } - - 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 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; - } + auto make_cube(float radius) { + Eigen::Matrix3Xf points(3, 8); + points.fill(radius); + for (int i = 0; i < points.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + if ((i >> j) & 1) { + points(j, i) *= -1; } } - return out; } - Eigen::Index rank() const override { - return 2; - } + Matrix3Xui cells(3, 12); + cells.transpose() + << 0b000, 0b001, 0b010, 0b001, 0b010, 0b011, + 0b100, 0b101, 0b110, 0b101, 0b110, 0b111, - [[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++; - } + 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 Mesh(points, cells); + } + + template + auto make_cube_wire(float radius) { + constexpr size_t NPoints = 1 << Dim; + constexpr size_t NCells = Dim * (NPoints >> 1); + + Eigen::Matrix points; + points.fill(radius); + for (int i = 0; i < points.cols(); ++i) { + for (int j = 0; j < Dim; ++j) { + if ((i >> j) & 1) { + points(j, i) *= -1; } } - return out; } - }; + + Eigen::Matrix cells; + int k = 0; + for (int i = 0; i < NPoints; ++i) { + for (int j = 0; j < Dim; ++j) { + if ((i >> j) & 1) { + cells(0, k) = i; + cells(1, k) = i ^ (1 << j); + k++; + } + } + } + + return Mesh(points, cells); + } } diff --git a/include/ml/meshlib_json.hpp b/include/ml/meshlib_json.hpp index 55b19cd..555ac3d 100644 --- a/include/ml/meshlib_json.hpp +++ b/include/ml/meshlib_json.hpp @@ -24,49 +24,45 @@ namespace Eigen { } template - void from_json(const nlohmann::json &j, Derived &mat) { + void from_json(const nlohmann::json &j, Derived &d) { using Scalar = typename Derived::Scalar; - auto rows = j["rows"].get(); - auto cols = j["cols"].get(); + auto rows = j["rows"].get(); + auto cols = j["cols"].get(); auto vals = j["vals"].get>(); - mat = Eigen::Map(vals.data(), rows, cols); + d = Map(vals.data(), rows, cols); } } +namespace nlohmann { + template + struct adl_serializer> { + static void to_json(json &j, const ml::Mesh &m) { + j = { + {"points", m.points}, + {"cells", m.cells}, + }; + } + + static ml::Mesh from_json(const json &j) { + return ml::Mesh( + j["points"].get(), + j["cells"].get() + ); + } + }; +} + 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) { + template + void write(const ml::Mesh &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); + template + M_ read(std::istream &&in) { + return nlohmann::json::from_msgpack(in).get(); } } diff --git a/src/gl/buffer.hpp b/src/gl/buffer.hpp index 3771443..4e91dd1 100644 --- a/src/gl/buffer.hpp +++ b/src/gl/buffer.hpp @@ -41,6 +41,11 @@ public: return count; } + template + GLuint upload(const T& data, GLenum mode = GL_STATIC_DRAW) { + return upload(data.begin(), data.end(), mode); + } + ~Buffer() { // delete silently ignores 0. glDeleteBuffers(1, &id); diff --git a/src/gl/types.hpp b/src/gl/types.hpp index 7149868..e31111d 100644 --- a/src/gl/types.hpp +++ b/src/gl/types.hpp @@ -4,7 +4,7 @@ #include -template +template struct Buffer; template @@ -66,18 +66,23 @@ struct AutoFormat { }; template<> -struct AutoFormat { - using Fmt = LFormat; +struct AutoFormat { + using Fmt = LFormat; }; template<> -struct AutoFormat { - using Fmt = Format; +struct AutoFormat { + using Fmt = Format; }; template<> -struct AutoFormat { - using Fmt = IFormat; +struct AutoFormat { + using Fmt = IFormat; +}; + +template<> +struct AutoFormat { + using Fmt = IFormat; }; template diff --git a/src/main.cpp b/src/main.cpp index d4fa6e5..26913d2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -128,45 +128,23 @@ int run(GLFWwindow *window, ImGuiContext *context) { Buffer ind_buf; Buffer vert_buf; - Buffer vert2_buf; + + Buffer ind4d_buf; + Buffer vert4d_buf; VertexArray vao(vert_buf); glVertexArrayElementBuffer(vao, ind_buf); - auto mesh = ml::CubeMesh(0.25f); - - auto ind_data = mesh.cells(); - auto ind_flat = ind_data.reshaped(); - auto elements = ind_buf.upload(ind_flat.begin(), ind_flat.end(), GL_STATIC_DRAW); - - // todo add to DynamicMesh - // need to do weird piping because dynamicmesh returns dynamic-sized matrix, VertexArray requires a static-sized matrix - auto vert_data_dyn = mesh.points(); - Eigen::Ref vert_data(vert_data_dyn); - auto vert_flat = vert_data.colwise(); - vert_buf.upload(vert_flat.begin(), vert_flat.end(), GL_STATIC_DRAW); - - auto mesh2 = ml::CubeMesh(0.5f); - auto vert2_data_dyn = mesh2.points(); - Eigen::Ref vert2_data(vert2_data_dyn); - auto vert2_flat = vert2_data.colwise(); - vert2_buf.upload(vert2_flat.begin(), vert2_flat.end(), GL_STATIC_DRAW); - - auto mesh4d = ml::WireCubeMesh(4, 0.33f); - - Buffer ind4d_buf; - Buffer vert4d_buf; VertexArray vao4d(vert4d_buf); glVertexArrayElementBuffer(vao4d, ind4d_buf); - auto ind4d_data = mesh4d.cells(); - auto ind4d_flat = ind4d_data.reshaped(); - auto elements4d = ind4d_buf.upload(ind4d_flat.begin(), ind4d_flat.end(), GL_STATIC_DRAW); + auto mesh = ml::make_cube(0.22f); + auto elements = (GLint) ind_buf.upload(mesh.cells.reshaped()); + vert_buf.upload(mesh.points.colwise()); - auto vert4d_data_dyn = mesh4d.points(); - Eigen::Ref vert4d_data(vert4d_data_dyn); - auto vert4d_flat = vert4d_data.colwise(); - vert4d_buf.upload(vert4d_flat.begin(), vert4d_flat.end(), GL_STATIC_DRAW); + auto mesh4d = ml::make_cube_wire<4>(0.33f); + auto elements4d = (GLint) ind4d_buf.upload(mesh4d.cells.reshaped()); + vert4d_buf.upload(mesh4d.points.colwise()); VertexShader vs(std::ifstream("res/shaders/main.vert.glsl")); VertexShader vs4d(std::ifstream("res/shaders/4d.vert.glsl")); diff --git a/src/serialtest.cpp b/src/serialtest.cpp index 514b4f7..9938ac5 100644 --- a/src/serialtest.cpp +++ b/src/serialtest.cpp @@ -6,48 +6,40 @@ #include #include -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; +auto make_circle(float radius, size_t npoints = 32) { + Eigen::Array theta(1, npoints); + for (int i = 0; i < theta.size(); ++i) { + theta(i) = (float) M_PI * 2.0f * (float) i / (float) npoints; } - CellsType cells() const override { - CellsType t(1, 31); - for (int i = 0; i < t.size(); ++i) { - t(i) = i; - } + Eigen::Array points(3, npoints); + points.row(0) = theta.sin(); + points.row(1) = theta.cos(); + points.row(2).setZero(); - CellsType out(3, 31); - out.array().row(0) = 0; - out.array().row(1) = t.array(); - out.array().row(2) = t.array() + 1; - return out; + Eigen::Array idx(1, npoints - 1); + for (int i = 0; i < idx.size(); ++i) { + idx(i) = i; } -}; + + Eigen::Array cells(3, npoints - 1); + cells.row(0) = 0; + cells.row(1) = idx; + cells.row(2) = idx + 1; + + return ml::Mesh(points, cells); +} int main() { - auto omesh = Circle(1.0f); + std::string path = "circle.pak"; - ml::write(omesh, "circle.pak"); + auto omesh = make_circle(1.0f); + using MT = decltype(omesh); - auto imesh = ml::read("circle.pak"); + ml::write(omesh, std::ofstream(path, std::ios::out | std::ios::binary)); - std::cout << "= points ===============" << std::endl; - std::cout << imesh.points() << std::endl; - std::cout << "= cells ================" << std::endl; - std::cout << imesh.cells() << std::endl; + auto imesh = ml::read(std::ifstream(path, std::ios::in | std::ios::binary)); + + std::cout << imesh.points << std::endl; + std::cout << imesh.cells << std::endl; }