From ec09506a74aab258365dfb91ef53eb50c21add59 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Sun, 28 Jun 2020 15:21:00 -0400 Subject: [PATCH] remove glm dependency; split solver and geometry classes --- .gitmodules | 3 - CMakeLists.txt | 1 - vis/CMakeLists.txt | 2 +- vis/include/geometry.hpp | 220 ------------------------------------- vis/include/mirror.hpp | 18 +-- vis/include/solver.hpp | 231 +++++++++++++++++++++++++++++++++++++++ vis/src/main.cpp | 27 +++-- 7 files changed, 254 insertions(+), 248 deletions(-) create mode 100644 vis/include/solver.hpp diff --git a/.gitmodules b/.gitmodules index 23b08b4..aaf82ce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "vendor/glfw"] path = vendor/glfw url = https://github.com/glfw/glfw.git -[submodule "vendor/glm"] - path = vendor/glm - url = https://github.com/g-truc/glm.git [submodule "vendor/toddcox"] path = vendor/toddcox url = https://github.com/JCRaymond/toddcox-faster.git diff --git a/CMakeLists.txt b/CMakeLists.txt index ab68484..8dd4c4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,6 @@ add_subdirectory(vendor/toddcox) add_subdirectory(vendor/yaml-cpp) add_subdirectory(vendor/cgl) add_subdirectory(vendor/glfw) -add_subdirectory(vendor/glm) add_subdirectory(vis) diff --git a/vis/CMakeLists.txt b/vis/CMakeLists.txt index dcac46b..ed9e82f 100644 --- a/vis/CMakeLists.txt +++ b/vis/CMakeLists.txt @@ -14,5 +14,5 @@ add_custom_command( add_executable(vis src/main.cpp) target_include_directories(vis PRIVATE include) -target_link_libraries(vis PRIVATE tc glm glfw yaml-cpp cgl glad) +target_link_libraries(vis PRIVATE tc glfw yaml-cpp cgl glad) add_dependencies(vis shaders presets) diff --git a/vis/include/geometry.hpp b/vis/include/geometry.hpp index a8a5b2a..a8e62b2 100644 --- a/vis/include/geometry.hpp +++ b/vis/include/geometry.hpp @@ -34,223 +34,3 @@ struct Primitive { } } }; - -/** - * Produce a list of all generators for the group context. The range [0..group.ngens). - */ -std::vector generators(const tc::Group &context) { - std::vector g_gens(context.ngens); - std::iota(g_gens.begin(), g_gens.end(), 0); - return g_gens; -} - -/** - * Determine which of g_gens are the correct names for sg_gens within the current context - */ -std::vector recontext_gens( - const tc::Group &context, - std::vector g_gens, - std::vector sg_gens) { - - std::sort(g_gens.begin(), g_gens.end()); - - int inv_gen_map[context.ngens]; - for (size_t i = 0; i < g_gens.size(); i++) { - inv_gen_map[g_gens[i]] = i; - } - - std::vector s_sg_gens; - s_sg_gens.reserve(sg_gens.size()); - for (const auto gen : sg_gens) { - s_sg_gens.push_back(inv_gen_map[gen]); - } - std::sort(s_sg_gens.begin(), s_sg_gens.end()); - - return s_sg_gens; -} - -/** - * Solve the cosets generated by sg_gens within the subgroup generated by g_gens of the group context - */ -tc::Cosets solve( - const tc::Group &context, - const std::vector &g_gens, - const std::vector &sg_gens -) { - const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); - return context.subgroup(g_gens).solve(proper_sg_gens); -} - -/** - * Apply some context transformation to all primitives of this mesh. - */ -template -std::vector> apply(std::vector> prims, const tc::Cosets &table, int gen) { - for (auto &prim : prims) { - prim.apply(table, gen); - } - return prims; -} - -/** - * Convert the indexes of this mesh to those of a different context, using g_gens to build the parent context and sg_gens to build this context. - */ -template -[[nodiscard]] -std::vector> recontext( - std::vector> prims, - const tc::Group &context, - const std::vector &g_gens, - const std::vector &sg_gens -) { - const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); - const auto table = solve(context, g_gens, {}); - const auto path = solve(context, sg_gens, {}).path; - - auto map = path.template walk(0, proper_sg_gens, [table](int coset, int gen) { - return table.get(coset, gen); - }); - - std::vector> res(prims); - for (Primitive &prim : res) { - for (auto &ind : prim.inds) { - ind = map[ind]; - } - } - - return res; -} - -/** - * Union several meshes of the same dimension - */ -template -std::vector> merge(const std::vector>> &meshes) { - size_t size = 0; - for (const auto &mesh : meshes) { - size += mesh.size(); - } - - std::vector> res; - res.reserve(size); - for (const auto &mesh : meshes) { - res.insert(res.end(), mesh.begin(), mesh.end()); - } - - return res; -} - -template -[[nodiscard]] -std::vector>> each_tile( - std::vector> prims, - const tc::Group &context, - const std::vector &g_gens, - const std::vector &sg_gens -) { - std::vector> base = recontext(prims, context, g_gens, sg_gens); - const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); - - const auto table = solve(context, g_gens, {}); - const auto path = solve(context, g_gens, sg_gens).path; - - auto _gens = generators(context); - - auto res = path.walk>, int>(base, generators(context), [&](auto from, auto gen) { - return apply(from, table, gen); - }); - - return res; -} - -template -[[nodiscard]] -std::vector> tile( - std::vector> prims, - const tc::Group &context, - const std::vector &g_gens, - const std::vector &sg_gens -) { - auto res = each_tile(prims, context, g_gens, sg_gens); - - return merge(res); -} - -/** - * Produce a mesh of higher dimension by fanning a single point to all primitives in this mesh. - */ -template -[[nodiscard]] -std::vector> fan(std::vector> prims, int root) { - std::vector> res(prims.size()); - std::transform(prims.begin(), prims.end(), res.begin(), - [root](const Primitive &prim) { - return Primitive(prim, root); - } - ); - return res; -} - -/** - * Produce a mesh of primitives that fill out the volume of the subgroup generated by generators g_gens within the group context - */ -template -std::vector> triangulate( - const tc::Group &context, - const std::vector &g_gens -) { - if (g_gens.size() + 1 != N) // todo make static assert - throw std::logic_error("g_gens size must be one less than N"); - - const auto &combos = Combos(g_gens, g_gens.size() - 1); - - std::vector>> meshes; - - for (const auto &sg_gens : combos) { - auto base = triangulate(context, sg_gens); - auto raised = tile(base, context, g_gens, sg_gens); - raised.erase(raised.begin(), raised.begin() + base.size()); - meshes.push_back(fan(raised, 0)); - } - - return merge(meshes); -} - -/** - * Single-index primitives should not be further triangulated. - */ -template<> -std::vector> triangulate( - const tc::Group &context, - const std::vector &g_gens -) { - if (not g_gens.empty()) // todo make static assert - throw std::logic_error("g_gens must be empty for a trivial Mesh"); - - std::vector> res; - res.emplace_back(); - return res; -} - -template -auto hull(const tc::Group &group, T all_sg_gens, const std::vector> &exclude) { - std::vector>> parts; - auto g_gens = generators(group); - for (const std::vector &sg_gens : all_sg_gens) { - bool excluded = false; - for (const auto &test : exclude) { - if (sg_gens == test) { - excluded = true; - break; - } - } - if (excluded) continue; - - const auto &base = triangulate(group, sg_gens); - const auto &tiles = each_tile(base, group, g_gens, sg_gens); - for (const auto &tile : tiles) { - parts.push_back(tile); - } - } - return parts; -} diff --git a/vis/include/mirror.hpp b/vis/include/mirror.hpp index 8402411..c8f8003 100644 --- a/vis/include/mirror.hpp +++ b/vis/include/mirror.hpp @@ -226,15 +226,6 @@ std::vector plane_intersections(std::vector normals) { return results; } -glm::mat4 utilRotate(const int u, const int v, const float theta) { - auto res = glm::identity(); - res[u][u] = std::cos(theta); - res[u][v] = std::sin(theta); - res[v][u] = -std::sin(theta); - res[v][v] = std::cos(theta); - return res; -} - template mat identity() { mat res{}; @@ -251,4 +242,13 @@ mat rot(int u, int v, float theta) { res[v][u] = -std::sin(theta); res[v][v] = std::cos(theta); return res; +} + +mat4 ortho(float left, float right, float bottom, float top, float front, float back) { + return { + 2 / (right - left), 0, 0, -(right + left) / (right - left), + 0, 2 / (top - bottom), 0, -(top + bottom) / (top - bottom), + 0, 0, 2 / (front - back), -(front + back) / (front - back), + 0, 0, 0, 1, + }; } \ No newline at end of file diff --git a/vis/include/solver.hpp b/vis/include/solver.hpp new file mode 100644 index 0000000..0d01288 --- /dev/null +++ b/vis/include/solver.hpp @@ -0,0 +1,231 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include "combo_iterator.hpp" + +/** + * Produce a list of all generators for the group context. The range [0..group.ngens). + */ +std::vector generators(const tc::Group &context) { + std::vector g_gens(context.ngens); + std::iota(g_gens.begin(), g_gens.end(), 0); + return g_gens; +} + +/** + * Determine which of g_gens are the correct names for sg_gens within the current context + */ +std::vector recontext_gens( + const tc::Group &context, + std::vector g_gens, + std::vector sg_gens) { + + std::sort(g_gens.begin(), g_gens.end()); + + int inv_gen_map[context.ngens]; + for (size_t i = 0; i < g_gens.size(); i++) { + inv_gen_map[g_gens[i]] = i; + } + + std::vector s_sg_gens; + s_sg_gens.reserve(sg_gens.size()); + for (const auto gen : sg_gens) { + s_sg_gens.push_back(inv_gen_map[gen]); + } + std::sort(s_sg_gens.begin(), s_sg_gens.end()); + + return s_sg_gens; +} + +/** + * Solve the cosets generated by sg_gens within the subgroup generated by g_gens of the group context + */ +tc::Cosets solve( + const tc::Group &context, + const std::vector &g_gens, + const std::vector &sg_gens +) { + const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); + return context.subgroup(g_gens).solve(proper_sg_gens); +} + +/** + * Apply some context transformation to all primitives of this mesh. + */ +template +std::vector> apply(std::vector> prims, const tc::Cosets &table, int gen) { + for (auto &prim : prims) { + prim.apply(table, gen); + } + return prims; +} + +/** + * Convert the indexes of this mesh to those of a different context, using g_gens to build the parent context and sg_gens to build this context. + */ +template +[[nodiscard]] +std::vector> recontext( + std::vector> prims, + const tc::Group &context, + const std::vector &g_gens, + const std::vector &sg_gens +) { + const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); + const auto table = solve(context, g_gens, {}); + const auto path = solve(context, sg_gens, {}).path; + + auto map = path.template walk(0, proper_sg_gens, [table](int coset, int gen) { + return table.get(coset, gen); + }); + + std::vector> res(prims); + for (Primitive &prim : res) { + for (auto &ind : prim.inds) { + ind = map[ind]; + } + } + + return res; +} + +/** + * Union several meshes of the same dimension + */ +template +std::vector> merge(const std::vector>> &meshes) { + size_t size = 0; + for (const auto &mesh : meshes) { + size += mesh.size(); + } + + std::vector> res; + res.reserve(size); + for (const auto &mesh : meshes) { + res.insert(res.end(), mesh.begin(), mesh.end()); + } + + return res; +} + +template +[[nodiscard]] +std::vector>> each_tile( + std::vector> prims, + const tc::Group &context, + const std::vector &g_gens, + const std::vector &sg_gens +) { + std::vector> base = recontext(prims, context, g_gens, sg_gens); + const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); + + const auto table = solve(context, g_gens, {}); + const auto path = solve(context, g_gens, sg_gens).path; + + auto _gens = generators(context); + + auto res = path.walk>, int>(base, generators(context), [&](auto from, auto gen) { + return apply(from, table, gen); + }); + + return res; +} + +template +[[nodiscard]] +std::vector> tile( + std::vector> prims, + const tc::Group &context, + const std::vector &g_gens, + const std::vector &sg_gens +) { + auto res = each_tile(prims, context, g_gens, sg_gens); + + return merge(res); +} + +/** + * Produce a mesh of higher dimension by fanning a single point to all primitives in this mesh. + */ +template +[[nodiscard]] +std::vector> fan(std::vector> prims, int root) { + std::vector> res(prims.size()); + std::transform(prims.begin(), prims.end(), res.begin(), + [root](const Primitive &prim) { + return Primitive(prim, root); + } + ); + return res; +} + +/** + * Produce a mesh of primitives that fill out the volume of the subgroup generated by generators g_gens within the group context + */ +template +std::vector> triangulate( + const tc::Group &context, + const std::vector &g_gens +) { + if (g_gens.size() + 1 != N) // todo make static assert + throw std::logic_error("g_gens size must be one less than N"); + + const auto &combos = Combos(g_gens, g_gens.size() - 1); + + std::vector>> meshes; + + for (const auto &sg_gens : combos) { + auto base = triangulate(context, sg_gens); + auto raised = tile(base, context, g_gens, sg_gens); + raised.erase(raised.begin(), raised.begin() + base.size()); + meshes.push_back(fan(raised, 0)); + } + + return merge(meshes); +} + +/** + * Single-index primitives should not be further triangulated. + */ +template<> +std::vector> triangulate( + const tc::Group &context, + const std::vector &g_gens +) { + if (not g_gens.empty()) // todo make static assert + throw std::logic_error("g_gens must be empty for a trivial Mesh"); + + std::vector> res; + res.emplace_back(); + return res; +} + +template +auto hull(const tc::Group &group, T all_sg_gens, const std::vector> &exclude) { + std::vector>> parts; + auto g_gens = generators(group); + for (const std::vector &sg_gens : all_sg_gens) { + bool excluded = false; + for (const auto &test : exclude) { + if (sg_gens == test) { + excluded = true; + break; + } + } + if (excluded) continue; + + const auto &base = triangulate(group, sg_gens); + const auto &tiles = each_tile(base, group, g_gens, sg_gens); + for (const auto &tile : tiles) { + parts.push_back(tile); + } + } + return parts; +} diff --git a/vis/src/main.cpp b/vis/src/main.cpp index 17a2788..a06a85d 100644 --- a/vis/src/main.cpp +++ b/vis/src/main.cpp @@ -1,25 +1,24 @@ #include #include + +#include #include #include +#include -#include +#include #include -#include "util.hpp" -#include "mirror.hpp" -#include "geometry.hpp" - #include #include #include -#include - -#include -#include +#include +#include #include +#include +#include #ifdef _WIN32 extern "C" { @@ -28,12 +27,12 @@ __attribute__((unused)) __declspec(dllexport) int NvOptimusEnablement = 0x000000 #endif struct Matrices { - glm::mat4 proj; - glm::mat4 view; + mat4 proj; + mat4 view; Matrices() = default; - Matrices(const glm::mat4 &proj, const glm::mat4 &view) + Matrices(const mat4 &proj, const mat4 &view) : proj(proj), view(view) { } }; @@ -54,13 +53,13 @@ Matrices build(GLFWwindow *window, State &state) { auto aspect = (float) width / (float) height; auto pheight = 1.4f; auto pwidth = aspect * pheight; - glm::mat4 proj = glm::ortho(-pwidth, pwidth, -pheight, pheight, -10.0f, 10.0f); + mat4 proj = ortho(-pwidth, pwidth, -pheight, pheight, -10.0f, 10.0f); if (!glfwGetKey(window, GLFW_KEY_LEFT_SHIFT)) { state.st += state.time_delta / 8; } - auto view = glm::identity(); + auto view = identity<4>(); return Matrices(proj, view); }