diff --git a/tc/include/tc/core.hpp b/tc/include/tc/core.hpp index 89ab80b..8d2268e 100644 --- a/tc/include/tc/core.hpp +++ b/tc/include/tc/core.hpp @@ -11,4 +11,20 @@ namespace tc { Cosets solve(const Group &group, const std::vector &sub_gens, const Coset &bound = UNBOUNDED); + + // todo + ///** + // * 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 + // ) { + // // todo this should also be handled with 'global' generators. + // const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); + // + // return tc::solve(context.subgroup(g_gens), proper_sg_gens); + // } + } diff --git a/tc/include/tc/group.hpp b/tc/include/tc/group.hpp index 2c560f3..81eff7a 100644 --- a/tc/include/tc/group.hpp +++ b/tc/include/tc/group.hpp @@ -67,14 +67,14 @@ namespace tc { return _orders(i, j); } - [[nodiscard]] SubGroup subgroup(const std::vector &gens) const; + [[nodiscard]] SubGroup subgroup(const std::vector &gens) const; }; struct SubGroup : public Group { - std::vector gen_map; + std::vector gen_map; const Group &parent; - SubGroup(const Group &parent, std::vector gen_map) + SubGroup(const Group &parent, std::vector gen_map) : Group(gen_map.size()), parent(parent), gen_map() { std::sort(gen_map.begin(), gen_map.end()); diff --git a/tc/src/core.cpp b/tc/src/core.cpp index 04bf1a3..0808e59 100644 --- a/tc/src/core.cpp +++ b/tc/src/core.cpp @@ -6,7 +6,7 @@ #include namespace tc { - SubGroup Group::subgroup(const std::vector &gens) const { + SubGroup Group::subgroup(const std::vector &gens) const { return {*this, gens}; } diff --git a/vis/include/geo/solver.hpp b/vis/include/geo/solver.hpp index 7c6c897..7939b3b 100644 --- a/vis/include/geo/solver.hpp +++ b/vis/include/geo/solver.hpp @@ -11,12 +11,12 @@ #include "combo.hpp" /** - * Produce a list of all generators for the group context. The range [0..group.ngens). + * Produce a list of all generators for the group context. The range [0..group.rank). */ -std::vector generators(const tc::Group &context) { +std::vector generators(const tc::Group &context) { // todo if tc::Group has 'global' generators, then this will be a member of tc::Group. // std::iota would populate a 'default' list of names, if names are not provided. - std::vector g_gens(context.ngens); + std::vector g_gens(context.rank); std::iota(g_gens.begin(), g_gens.end(), 0); return g_gens; } @@ -24,20 +24,20 @@ std::vector generators(const tc::Group &context) { /** * Determine which of g_gens are the correct names for sg_gens within the current context */ -std::vector recontext_gens( +std::vector recontext_gens( const tc::Group &context, - std::vector g_gens, - std::vector sg_gens) { + std::vector g_gens, + std::vector sg_gens) { // todo ideally tc::Group will deal in 'global' generators so this stell will be unecessary. std::sort(g_gens.begin(), g_gens.end()); - int inv_gen_map[context.ngens]; + tc::Gen inv_gen_map[context.rank]; for (size_t i = 0; i < g_gens.size(); i++) { inv_gen_map[g_gens[i]] = i; } - std::vector s_sg_gens; + 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]); @@ -52,21 +52,22 @@ std::vector recontext_gens( */ tc::Cosets solve( const tc::Group &context, - const std::vector &g_gens, - const std::vector &sg_gens + const std::vector &g_gens, + const std::vector &sg_gens ) { // todo this should also be handled with 'global' generators. const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); - return context.subgroup(g_gens).solve(proper_sg_gens); + + return tc::solve(context.subgroup(g_gens), proper_sg_gens); } /** * Apply some context transformation to all primitives of this mesh. */ template -void apply(const tc::Cosets &table, int gen, Prims &mat) { +void apply(const tc::Cosets &table, tc::Gen gen, Prims &mat) { auto data = mat.data(); - for (int i = 0; i < mat.size(); ++i) { + for (tc::Gen i = 0; i < mat.size(); ++i) { data[i] = table.get(data[i], gen); } } @@ -79,15 +80,15 @@ template Prims recontext( Prims prims, const tc::Group &context, - const std::vector &g_gens, - const std::vector &sg_gens + const std::vector &g_gens, + const std::vector &sg_gens ) { // todo this will be simpler with 'global' gens, but it's still not free... 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) { + auto map = path.template walk(0, proper_sg_gens, [table](tc::Coset coset, tc::Gen gen) { return table.get(coset, gen); }); @@ -127,8 +128,8 @@ template std::vector> tile( Prims prims, const tc::Group &context, - const std::vector &g_gens, - const std::vector &sg_gens + const std::vector &g_gens, + const std::vector &sg_gens ) { // todo convert to nullaryexpr. // some stuff will be easier with global generators, but not all. @@ -138,11 +139,11 @@ std::vector> tile( const auto table = solve(context, g_gens, {}); const auto path = solve(context, g_gens, sg_gens).path; - std::vector _gens = generators(context); + std::vector _gens = generators(context); - std::vector> res = path.walk, int>( + std::vector> res = path.walk, tc::Gen>( base, _gens, - [&](Prims from, int gen) { + [&](Prims from, tc::Gen gen) { apply(table, gen, from); return from; } @@ -172,7 +173,7 @@ Prims fan(Prims prims, int root) { template Prims triangulate( const tc::Group &context, - const std::vector &g_gens + const std::vector &g_gens ) { // todo (?) might be possible with nullaryexpr // not so sure, though. @@ -201,7 +202,7 @@ Prims triangulate( template<> Prims<1> triangulate<1>( const tc::Group &context, - const std::vector &g_gens + 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"); @@ -210,10 +211,10 @@ Prims<1> triangulate<1>( } template -auto hull(const tc::Group &group, T all_sg_gens, const std::vector> &exclude) { +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) { + for (const std::vector &sg_gens: all_sg_gens) { bool excluded = false; for (const auto &test: exclude) { if (sg_gens == test) { diff --git a/vis/include/gl/vertexarray.hpp b/vis/include/gl/vertexarray.hpp index 7b863e6..e9b395c 100644 --- a/vis/include/gl/vertexarray.hpp +++ b/vis/include/gl/vertexarray.hpp @@ -15,6 +15,7 @@ public: private: GLuint id = 0; + GLuint count = 0; template inline void formatall( diff --git a/vis/src/main.cpp b/vis/src/main.cpp index f329443..aa66478 100644 --- a/vis/src/main.cpp +++ b/vis/src/main.cpp @@ -118,23 +118,34 @@ void set_style() { int run(GLFWwindow *window, ImGuiContext *context) { State state; + PointCloud pc; + LineCloud lc; PointRenderer point_render; + LineRenderer line_render; { tc::Group group = tc::coxeter("3 4 3"); Eigen::Vector4f coords{1, 1, 1, 1}; auto cosets = tc::solve(group, {}, 1000000); - + auto mirrors = mirror<4>(group); auto corners = plane_intersections(mirrors); auto start = barycentric(corners, coords); start.normalize(); - + auto points = cosets.path.walk(start, mirrors, reflect); - point_render.upload(points); + std::vector edges = { + 0, 1, + 0, 2, + 0, 3, + 0, 4, + }; + + pc.upload(points); + lc.upload(points, edges); } glEnable(GL_DEPTH_TEST); @@ -158,7 +169,8 @@ int run(GLFWwindow *window, ImGuiContext *context) { auto aspect = (float) display_h / (float) display_w; state.proj = Eigen::AlignedScaling3f(aspect, 1.0, -0.6); - point_render.draw(state); + point_render.draw(pc, state); + line_render.draw(lc, state); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); glfwSwapBuffers(window); diff --git a/vis/src/render/pointrender.hpp b/vis/src/render/pointrender.hpp index a950172..55a9c16 100644 --- a/vis/src/render/pointrender.hpp +++ b/vis/src/render/pointrender.hpp @@ -18,18 +18,13 @@ struct State { }; template -struct PointRenderer { +struct PointCloud { using Vertex = V_; - VertexShader vs{std::ifstream("res/shaders/main.vert.glsl")}; - FragmentShader fs{std::ifstream("res/shaders/main.frag.glsl")}; - - Program pgm{vs, fs}; - Buffer vbo; VertexArray vao{vbo}; - GLuint count; + GLuint count{}; template void upload(const T &points) { @@ -38,15 +33,69 @@ struct PointRenderer { // Buffer ind_buf; // glVertexArrayElementBuffer(vao, ind_buf); } +}; - void draw(const State &state) { +template +struct PointRenderer { + using Vertex = V_; + + VertexShader vs{std::ifstream("res/shaders/main.vert.glsl")}; + FragmentShader fs{std::ifstream("res/shaders/main.frag.glsl")}; + + Program pgm{vs, fs}; + + void draw(const PointCloud &obj, const State &state) { glUseProgram(pgm); - glBindVertexArray(vao); + glBindVertexArray(obj.vao); glUniform4fv(0, 1, state.fg.data()); glUniform1f(1, state.time); glUniformMatrix4fv(2, 1, false, state.proj.data()); glUniformMatrix4fv(3, 1, false, state.view.data()); - glDrawArrays(GL_POINTS, 0, count); + glDrawArrays(GL_POINTS, 0, obj.count); + glBindVertexArray(0); + glUseProgram(0); + } +}; + +template +struct LineCloud { + using Vertex = V_; + + Buffer vbo{}; + Buffer ibo{}; + VertexArray vao{vbo}; + + GLuint count{}; + + LineCloud() { + glVertexArrayElementBuffer(vao, ibo); + } + + template + void upload(const T &points, const U &inds) { + vbo.upload(points); + + count = ibo.upload(inds); + } +}; + +template +struct LineRenderer { + using Vertex = V_; + + VertexShader vs{std::ifstream("res/shaders/main.vert.glsl")}; + FragmentShader fs{std::ifstream("res/shaders/main.frag.glsl")}; + + Program pgm{vs, fs}; + + void draw(const LineCloud &obj, const State &state) { + glUseProgram(pgm); + glBindVertexArray(obj.vao); + glUniform4fv(0, 1, state.fg.data()); + glUniform1f(1, state.time); + glUniformMatrix4fv(2, 1, false, state.proj.data()); + glUniformMatrix4fv(3, 1, false, state.view.data()); + glDrawElements(GL_LINES, obj.count, GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); glUseProgram(0); }