diff --git a/cosets/CMakeLists.txt b/cosets/CMakeLists.txt index 5a14367..5e078ec 100644 --- a/cosets/CMakeLists.txt +++ b/cosets/CMakeLists.txt @@ -7,13 +7,16 @@ target_link_libraries(${PROJECT_NAME} PRIVATE glad glm glfw) add_custom_command( - TARGET cosets POST_BUILD + TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders ${CMAKE_CURRENT_BINARY_DIR}/shaders ) -add_executable(coxeter src/tc.cpp) +add_executable(coxeter src/coxeter.cpp) -add_executable(mirror src/mirror.cpp) +add_executable(mirror src/mirrors.cpp) target_link_libraries(mirror PRIVATE glm) + +add_executable(mesh src/mesh.cpp) +target_link_libraries(mesh PRIVATE glm) diff --git a/cosets/src/coxeter.cpp b/cosets/src/coxeter.cpp new file mode 100644 index 0000000..a4e3e9b --- /dev/null +++ b/cosets/src/coxeter.cpp @@ -0,0 +1,27 @@ +#include "util/coxeter.hpp" + +int main(int argc, char *argv[]) { + std::vector> ids{ + {0, 0}, + {1, 1}, + {2, 2}, + {0, 1, 0, 1, 0, 1, 0, 1}, + {1, 2, 1, 2, 1, 2}, + {0, 2, 0, 2} + }; + + Table *table = solve(3, {0, 1}, ids); + + std::cout << table->size() << std::endl; + std::cout << *table << std::endl; + + for (const auto &v : table->words()) { + std::cout << "[ "; + for (auto e : v) { + std::cout << e << " "; + } + std::cout << "]\n"; + } + + return 0; +} diff --git a/cosets/src/main.cpp b/cosets/src/main.cpp index de0e007..0ac8492 100644 --- a/cosets/src/main.cpp +++ b/cosets/src/main.cpp @@ -5,6 +5,9 @@ #include #include #include +#include + +#include "util/mesh.hpp" using namespace std; @@ -13,7 +16,7 @@ class CosetsWindow : public Window { GLuint tri; GLuint verts; - static const unsigned VERTS_N = 8; + std::vector verts_data; public: void init() override { @@ -29,21 +32,16 @@ public: program = build_program("main", vs, fs); - glm::vec4 verts_data[VERTS_N]{ - {+0.5, +0.5, +0.5, +0.0}, - {+0.5, -0.5, +0.5, +0.0}, - {-0.5, -0.5, +0.5, +0.0}, - {-0.5, +0.5, +0.5, +0.0}, - - {+0.5, +0.5, +0.5, -0.5}, - {+0.5, -0.5, +0.5, -0.5}, - {-0.5, -0.5, +0.5, +0.5}, - {-0.5, +0.5, +0.5, +0.5}, - }; + verts_data = vertices<3>({}, Multiplicites<3>({ + {0, 1, 5}, + {1, 2, 3} + }), { + 10, 1, 1 + }); glGenBuffers(1, &verts); glBindBuffer(GL_ARRAY_BUFFER, verts); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * VERTS_N, verts_data, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4) * verts_data.size(), &verts_data[0], GL_STATIC_DRAW); glGenVertexArrays(1, &tri); @@ -60,25 +58,32 @@ public: glViewport(0, 0, w, h); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - const glm::mat4 id = glm::mat4(1); - const glm::vec3 ax = glm::vec3(0, 0, 1); - double t = glfwGetTime(); - float angle = (float) t; + const auto id = glm::mat4(1); + const auto ax_1 = glm::vec3(0, 0, 1); + const auto ax_2 = glm::vec3(.5, 1, 0.2); + const auto t = glfwGetTime(); + const auto angle = (float) t / 2; - float ar = (float) w / (float) h; + const float sc = 1.5f; + const float ar = (float) w / (float) h; - const glm::mat4 proj = glm::ortho(-ar, ar, -1.f, 1.f, -1.f, 1.f); - const glm::mat4 view = glm::rotate(id, angle, ax); + const glm::mat4 proj = glm::ortho(-ar * sc, ar * sc, -sc, sc, -10.f, 10.f); + const glm::mat4 view = glm::rotate(id, angle, ax_1) * glm::rotate(id, angle, ax_2); const glm::mat4 mat = proj * view; glUseProgram(program); - glUniformMatrix4fv(0, 1, false, glm::value_ptr(mat)); + glUniformMatrix4fv(1, 1, false, glm::value_ptr(mat)); glEnable(GL_DEPTH_TEST); glEnable(GL_POINT_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPointSize(10.f); glBindVertexArray(tri); - glDrawArrays(GL_POINTS, 0, VERTS_N); + glUniform4f(0, 1, 1, 1, 1); + glDrawArrays(GL_POINTS, 0, verts_data.size() - 3); + glUniform4f(0, 1, 1, 1, .1); + glDrawArrays(GL_TRIANGLES, verts_data.size() - 3, 3); swapbuffers(); } diff --git a/cosets/src/mesh.cpp b/cosets/src/mesh.cpp new file mode 100644 index 0000000..eb26070 --- /dev/null +++ b/cosets/src/mesh.cpp @@ -0,0 +1,16 @@ +#include "util/mesh.hpp" + +int main(int argc, char *argv[]) { + auto vs = vertices<3>({}, Multiplicites<3>({ + {0, 1, 4}, + {1, 2, 3} + }), { + 1.0f, 1.0f, 1.0f + }); + + for (const auto &v : vs) { + std::cout << glm::to_string(v) << std::endl; + } + + return 0; +} \ No newline at end of file diff --git a/cosets/src/mirrors.cpp b/cosets/src/mirrors.cpp new file mode 100644 index 0000000..51ba1d6 --- /dev/null +++ b/cosets/src/mirrors.cpp @@ -0,0 +1,14 @@ +#include "util/mirrors.hpp" + +int main(int argc, char *argv[]) { + auto normals = mirror<3>(Multiplicites<3>({ + {0, 1, 4}, + {1, 2, 3} + })); + + for (const auto &normal : normals) { + std::cout << glm::to_string(normal) << std::endl; + } + + return 0; +} \ No newline at end of file diff --git a/cosets/src/shaders/main.fs.glsl b/cosets/src/shaders/main.fs.glsl index 25a8486..bf2946f 100644 --- a/cosets/src/shaders/main.fs.glsl +++ b/cosets/src/shaders/main.fs.glsl @@ -1,7 +1,11 @@ -#version 400 +#version 440 core + +uniform vec4 color; in vec4 v; +out vec4 fcolor; + vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); @@ -9,5 +13,5 @@ vec3 hsv2rgb(vec3 c) { } void main(){ - gl_FragColor = vec4(hsv2rgb(vec3(v.w, 1, 1)), 0); + fcolor = color; } diff --git a/cosets/src/shaders/main.vs.glsl b/cosets/src/shaders/main.vs.glsl index 01f2172..136fec0 100644 --- a/cosets/src/shaders/main.vs.glsl +++ b/cosets/src/shaders/main.vs.glsl @@ -1,4 +1,4 @@ -#version 400 +#version 440 core uniform mat4 proj; diff --git a/cosets/src/tc.cpp b/cosets/src/util/coxeter.hpp similarity index 83% rename from cosets/src/tc.cpp rename to cosets/src/util/coxeter.hpp index 013714e..054a49f 100644 --- a/cosets/src/tc.cpp +++ b/cosets/src/util/coxeter.hpp @@ -1,9 +1,43 @@ +#pragma once + #include #include #include #include #include +struct Mult { + int a, b, mult; +}; + +template +struct Multiplicites { + std::vector mults; + + explicit Multiplicites(const std::vector &vals) { + mults = std::vector(N * (N - 1) / 2, 2); + for (const auto &mult : vals) { + set(mult.a, mult.b, mult.mult); + } + } + + void set(int a, int b, int mult) { + if (a > N or b > N) throw std::logic_error("mirror does not exist"); + if (a == b) throw std::logic_error("cannot compare mirror to itself"); + if (a < b) std::swap(a, b); // a is bigger + + mults[a + b] = mult; + } + + [[nodiscard]] int get(int a, int b) const { + if (a > N or b > N) throw std::logic_error("mirror does not exist"); + if (a == b) throw std::logic_error("cannot compare mirror to itself"); + if (a < b) std::swap(a, b); // a is bigger + + return mults[a + b]; + } +}; + struct Table { int N; @@ -195,29 +229,3 @@ std::ostream &operator<<(std::ostream &out, const Table &table) { return out; } - -int main(int argc, char *argv[]) { - std::vector> ids{ - {0, 0}, - {1, 1}, - {2, 2}, - {0, 1, 0, 1, 0, 1, 0, 1}, - {1, 2, 1, 2, 1, 2}, - {0, 2, 0, 2} - }; - - Table *table = solve(3, {0, 1}, ids); - - std::cout << table->size() << std::endl; - std::cout << *table << std::endl; - - for (const auto &v : table->words()) { - std::cout << "[ "; - for (auto e : v) { - std::cout << e << " "; - } - std::cout << "]\n"; - } - - return 0; -} diff --git a/cosets/src/util/mesh.hpp b/cosets/src/util/mesh.hpp new file mode 100644 index 0000000..9380bb6 --- /dev/null +++ b/cosets/src/util/mesh.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "coxeter.hpp" +#include "mirrors.hpp" +#include "numeric.hpp" + +#include + +template +std::vector +vertices(const std::vector &subgens, const Multiplicites &mults, const float (&coords)[N]) { + std::vector> rels{}; + rels.reserve(N + N * (N - 1) / 2); + + for (int i = 0; i < N; ++i) { + rels.push_back({i, i}); + } + for (int a = 0; a < N; ++a) { + for (int b = 0; b < a; ++b) { + int mult = mults.get(a, b); + + std::vector rel{}; + for (int i = 0; i < mult; ++i) { + rel.push_back(a); + rel.push_back(b); + } + rels.push_back(rel); + } + } + + Table *table = solve(N, subgens, rels); + +// std::cout << table->size() << std::endl; +// std::cout << *table << std::endl; + +// for (const auto &v : table->words()) { +// std::cout << "[ "; +// for (auto e : v) { +// std::cout << e << " "; +// } +// std::cout << "]\n"; +// } + + const std::vector &normals = mirror<3>(mults); + const std::vector &corners = plane_intersections(normals); + const std::vector coords_vec(coords, coords + N); + const glm::vec4 &identity = glm::normalize(barycentric(corners, coords_vec)); + + std::vector verts{}; + + for (const auto &word : table->words()) { + glm::vec4 vert = identity; + for (const auto &gen : word) { + vert = reflect(vert, normals[gen]); + } + verts.push_back(vert); + } + + for (const auto &e : corners) { + verts.push_back(e * 1.1f); + } + + return verts; +} \ No newline at end of file diff --git a/cosets/src/mirror.cpp b/cosets/src/util/mirrors.hpp similarity index 63% rename from cosets/src/mirror.cpp rename to cosets/src/util/mirrors.hpp index 098e5c4..6a629bd 100644 --- a/cosets/src/mirror.cpp +++ b/cosets/src/util/mirrors.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include #include @@ -5,10 +7,11 @@ #include #include -#include "util/numeric.hpp" +#include "numeric.hpp" +#include "coxeter.hpp" template -std::vector mirror(const float (&arr)[N][N]) { +std::vector mirror(const Multiplicites &mults) { static_assert(1 <= N and N <= 4, "Vector size is unsupported"); std::vector mirrors{}; @@ -16,7 +19,7 @@ std::vector mirror(const float (&arr)[N][N]) { glm::vec4 vp{}; for (int m = 0; m < p; ++m) { glm::vec4 vq = mirrors[m]; - vp[m] = (cos(M_PI / arr[p][m]) - dot(m, vp, vq)) / vq[m]; + vp[m] = (cos(M_PI / mults.get(p, m)) - dot(m, vp, vq)) / vq[m]; } vp[p] = std::sqrt(1 - glm::dot(vp, vp)); @@ -32,17 +35,3 @@ std::vector mirror(const float (&arr)[N][N]) { return mirrors; } - -int main(int argc, char *argv[]) { - auto normals = mirror<3>({ - {}, - {4}, - {2, 3} - }); - - for (const auto &normal : normals) { - std::cout << glm::to_string(normal) << std::endl; - } - - return 0; -} \ No newline at end of file diff --git a/cosets/src/util/numeric.hpp b/cosets/src/util/numeric.hpp index b4ab66c..663be4a 100644 --- a/cosets/src/util/numeric.hpp +++ b/cosets/src/util/numeric.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include glm::vec4 round(glm::vec4 f, int prec) { auto dec = (float) pow(10, prec); @@ -15,3 +17,43 @@ float dot(int n, glm::vec4 a, glm::vec4 b) { } return sum; } + +glm::vec4 project(glm::vec4 vec, glm::vec4 target) { + return glm::dot(vec, target) / glm::dot(target, target) * target; +} + +glm::vec4 reflect(glm::vec4 vec, glm::vec4 axis) { + return vec - 2.0f * project(vec, axis); +} + +glm::vec4 gram_schmidt_last(std::vector vecs) { + int N = vecs.size(); + for (int i = 0; i < N; ++i) { + for (int j = 0; j < i; ++j) { + vecs[i] -= project(vecs[i], vecs[j]); + } + } + + return glm::normalize(vecs[N - 1]); +} + +glm::vec4 barycentric(std::vector basis, std::vector coords) { + glm::vec4 res{}; + int N = std::min(basis.size(), coords.size()); + for (int i = 0; i < N; ++i) { + res += basis[i] * coords[i]; + } + return glm::normalize(res); +} + +std::vector plane_intersections(std::vector normals) { + int N = normals.size(); + std::vector results(N); + + for (int i = 0; i < N; ++i) { + std::rotate(normals.begin(), normals.begin() + 1, normals.end()); + results[i] = gram_schmidt_last(normals); + } + + return results; +} diff --git a/cosets/src/util/window.hpp b/cosets/src/util/window.hpp index a90adb1..49dc274 100644 --- a/cosets/src/util/window.hpp +++ b/cosets/src/util/window.hpp @@ -31,6 +31,7 @@ public: glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, _gl_major); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, _gl_minor); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_ALPHA_BITS, 8); _window = glfwCreateWindow(640, 480, "GLFW App", nullptr, nullptr);