5 Commits

Author SHA1 Message Date
6ff09dc375 Introduce perspective projection matrix.
Also correct a bug where the view matrix was not being used.
2020-10-13 10:57:30 -04:00
49927568e4 Introduce cgl::Buffer::put<E> for Eigen matrices and other containers.
Make put(std::vector<T>) more generic by specializing the new put<E> method.
2020-10-13 10:56:55 -04:00
David Allemang
6b34694784 Replace Primitive vector with Eigen matrices.
template<unsigned N>
Prims<N> = Eigen::Matrix<unsigned, N, Eigen::Dynamic>

Replaces std::vector<Primitive<N>>
2020-10-12 21:57:18 -04:00
David Allemang
0534c4322c Refactor Slice / SliceRenderer to be less general; get away from "prop" overhead. 2020-10-11 18:55:43 -04:00
David Allemang
c164c319fc Cleanup and tweaks for nanogui
- clean up main-gui.cpp
- Add Primitive constructor from vector
- move ubo bindbufferbase to correct location
2020-10-11 18:00:38 -04:00
9 changed files with 288 additions and 491 deletions

View File

@@ -15,7 +15,7 @@ add_custom_command(
add_definitions(${NANOGUI_EXTRA_DEFS})
include_directories(${NANOGUI_EXTRA_INCS})
add_executable(vis-gui src/main-gui.cpp)
target_include_directories(vis-gui PRIVATE include)
target_link_libraries(vis-gui PRIVATE tc nanogui yaml-cpp ${NANOGUI_EXTRA_LIBS})
add_dependencies(vis-gui shaders presets)
add_executable(vis src/main.cpp)
target_include_directories(vis PRIVATE include)
target_link_libraries(vis PRIVATE tc nanogui yaml-cpp ${NANOGUI_EXTRA_LIBS})
add_dependencies(vis shaders presets)

View File

@@ -53,8 +53,18 @@ namespace cgl {
glNamedBufferData(id, sizeof(T), &data, usage);
}
void put(const std::vector<T> &data, GLenum usage = GL_STATIC_DRAW) {
glNamedBufferData(id, sizeof(T) * data.size(), &data[0], usage);
void put(const T *data, const size_t &size, GLenum usage = GL_STATIC_DRAW) {
glNamedBufferData(id, sizeof(T) * size, data, usage);
}
template<class E>
void put(const E &data, GLenum usage = GL_STATIC_DRAW) {
put(data.data(), data.size(), usage);
}
template<>
void put<std::vector<T>>(const std::vector<T> &data, GLenum usage = GL_STATIC_DRAW) {
put(data.data, data.size(), usage);
}
void bound(GLenum target, const std::function<void()> &action) const {

View File

@@ -7,30 +7,54 @@
#include <iostream>
#include "combo_iterator.hpp"
/**
* An primitive stage N indices.
* @tparam N
*/
template<unsigned N>
struct Primitive {
static_assert(N > 0, "Primitives must contain at least one point. Primitive<0> or lower is impossible.");
using Prims = Eigen::Matrix<unsigned, N, Eigen::Dynamic>;
std::array<unsigned, N> inds;
template<int N>
using vec = Eigen::Matrix<float, N, 1>;
template<int N>
using mat = Eigen::Matrix<float, N, N>;
Primitive() = default;
using vec1 = vec<1>;
using vec2 = vec<2>;
using vec3 = vec<3>;
using vec4 = vec<4>;
using vec5 = vec<5>;
Primitive(const Primitive<N> &) = default;
using mat1 = mat<1>;
using mat2 = mat<2>;
using mat3 = mat<3>;
using mat4 = mat<4>;
using mat5 = mat<5>;
Primitive(const Primitive<N - 1> &sub, unsigned root) {
std::copy(sub.inds.begin(), sub.inds.end(), inds.begin());
inds[N - 1] = root;
mat4 orthographic(float left, float right, float bottom, float top, float front, float back) {
mat4 res = mat4();
res <<
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;
return res;
}
~Primitive() = default;
mat4 perspective(float fovy, float aspect, float zNear, float zFar) {
float tanHalfFovy(std::tan(fovy / 2));
void apply(const tc::Cosets &table, int gen) {
for (auto &ind : inds) {
ind = table.get(ind, gen);
mat4 res = mat4::Identity();
res(0, 0) = 1 / (aspect * tanHalfFovy);
res(1, 1) = 1 / (tanHalfFovy);
res(2, 2) = -(zFar + zNear) / (zFar - zNear);
res(3, 2) = -1;
res(2, 3) = -(2 + zFar * zNear) / (zFar - zNear);
return res;
}
mat4 translation(float x, float y, float z) {
mat4 res = mat4();
res <<
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1;
return res;
}
};

View File

@@ -8,22 +8,7 @@
#include <nanogui/glutil.h>
template<int N>
using vec = Eigen::Matrix<float, N, 1>;
template<int N>
using mat = Eigen::Matrix<float, N, N>;
using vec1 = vec<1>;
using vec2 = vec<2>;
using vec3 = vec<3>;
using vec4 = vec<4>;
using vec5 = vec<5>;
using mat1 = mat<1>;
using mat2 = mat<2>;
using mat3 = mat<3>;
using mat4 = mat<4>;
using mat5 = mat<5>;
#include <geometry.hpp>
template<class V>
float dot(int n, const V &a, const V &b) {
@@ -143,13 +128,3 @@ mat<N> rot(int u, int v, float theta) {
res(v, v) = std::cos(theta);
return res;
}
mat4 ortho(float left, float right, float bottom, float top, float front, float back) {
mat<4> res = mat4();
res <<
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;
return res;
}

View File

@@ -3,26 +3,79 @@
#include <cgl/vertexarray.hpp>
#include <cgl/buffer.hpp>
#include <cgl/pipeline.hpp>
#include <geometry.hpp>
#include "mirror.hpp"
#include <tuple>
struct Matrices {
mat4 proj = mat4::Identity();
mat4 view = mat4::Identity();
template<unsigned N, class... T>
struct Prop {
Matrices() = default;
Matrices(mat4 proj, mat4 view) : proj(std::move(proj)), view(std::move(view)) {}
static Matrices build(const nanogui::Screen &screen) {
auto aspect = (float) screen.width() / (float) screen.height();
auto pheight = 1.4f;
auto pwidth = aspect * pheight;
// auto proj = orthographic(-pwidth, pwidth, -pheight, pheight, -10.0f, 10.0f);
// auto proj = perspective(-pwidth, pwidth, pheight, -pheight, 10.0f, 0.01f);
auto proj = perspective(0.4, aspect, 0.1, 10.0);
auto view = translation(0, 0, -4);
return Matrices(proj, view);
}
};
template<class T>
class Renderer {
public:
virtual void draw(const T &prop) const = 0;
};
template<unsigned N>
class Slice {
private:
const tc::Group group;
public:
cgl::Buffer<unsigned> ibo;
cgl::Buffer<vec4> vbo;
cgl::VertexArray vao;
std::tuple<cgl::Buffer<T>...> vbos;
cgl::Buffer<Primitive<N>> ibo;
template<class T>
Slice(const tc::Group &g, T all_sg_gens, const std::vector<std::vector<int>> &exclude) : group(g) {
const auto &data = merge<N>(hull<N>(g, all_sg_gens, exclude));
ibo.put(data);
vao.ipointer(0, ibo, 4, GL_UNSIGNED_INT);
}
void setPoints(const vec5 &root, const mat5 &transform = mat5::Identity()) {
auto cosets = group.solve();
auto mirrors = mirror<5>(group);
auto corners = plane_intersections(mirrors);
auto start = barycentric(corners, root);
auto higher = cosets.path.walk<vec5, vec5>(start, mirrors, reflect<vec5>);
std::transform(
higher.begin(), higher.end(), higher.begin(),
[&](const vec5& v) { return transform * v; }
);
std::vector<vec4> lower(higher.size());
std::transform(higher.begin(), higher.end(), lower.begin(), stereo<4>);
vbo.put(lower);
}
};
template<unsigned N, class T>
struct Renderer {
cgl::pipeline pipe;
virtual void draw(const Prop<N, T> &prop) const = 0;
};
template<unsigned N, class T>
struct SliceRenderer : public Renderer<N, T> {
template<unsigned N>
class SliceRenderer : public Renderer<Slice<N>> {
private:
cgl::pgm::vert defer = cgl::pgm::vert::file(
"shaders/slice/deferred.vs.glsl");
cgl::pgm::geom slice = cgl::pgm::geom::file(
@@ -32,20 +85,20 @@ struct SliceRenderer : public Renderer<N, T> {
cgl::pipeline pipe;
cgl::Buffer<Matrices> ubo;
public:
SliceRenderer() {
pipe.stage(defer);
pipe.stage(slice);
pipe.stage(solid);
}
void draw(const Prop<N, T> &prop) const override {
pipe.bound([&]() {
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, std::get<0>(prop.vbos));
//// glProgramUniform3fv(solid, 2, 1, &prop.color.front());
void draw(const Slice<N> &prop) const {
glBindProgramPipeline(pipe);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, prop.vbo);
glProgramUniform3f(solid, 2, 1.f, 1.f, 1.f);
prop.vao.bound([&]() {
glBindVertexArray(prop.vao);
glDrawArrays(GL_POINTS, 0, prop.ibo.count() * N);
});
});
}
};

View File

@@ -60,11 +60,11 @@ tc::Cosets solve(
* Apply some context transformation to all primitives of this mesh.
*/
template<unsigned N>
std::vector<Primitive<N>> apply(std::vector<Primitive<N>> prims, const tc::Cosets &table, int gen) {
for (auto &prim : prims) {
prim.apply(table, gen);
void apply(const tc::Cosets &table, int gen, Prims<N> &mat) {
auto data = mat.data();
for (int i = 0; i < mat.size(); ++i) {
data[i] = table.get(data[i], gen);
}
return prims;
}
/**
@@ -72,8 +72,8 @@ std::vector<Primitive<N>> apply(std::vector<Primitive<N>> prims, const tc::Coset
*/
template<unsigned N>
[[nodiscard]]
std::vector<Primitive<N>> recontext(
std::vector<Primitive<N>> prims,
Prims<N> recontext(
Prims<N> prims,
const tc::Group &context,
const std::vector<int> &g_gens,
const std::vector<int> &sg_gens
@@ -86,11 +86,10 @@ std::vector<Primitive<N>> recontext(
return table.get(coset, gen);
});
std::vector<Primitive<N>> res(prims);
for (Primitive<N> &prim : res) {
for (auto &ind : prim.inds) {
ind = map[ind];
}
Prims<N> res(prims);
auto data = res.data();
for (int i = 0; i < prims.size(); ++i) {
data[i] = map[data[i]];
}
return res;
@@ -100,16 +99,18 @@ std::vector<Primitive<N>> recontext(
* Union several meshes of the same dimension
*/
template<unsigned N>
std::vector<Primitive<N>> merge(const std::vector<std::vector<Primitive<N>>> &meshes) {
size_t size = 0;
Prims<N> merge(const std::vector<Prims<N>> &meshes) {
size_t cols = 0;
for (const auto &mesh : meshes) {
size += mesh.size();
cols += mesh.cols();
}
std::vector<Primitive<N>> res;
res.reserve(size);
for (const auto &mesh : meshes) {
res.insert(res.end(), mesh.begin(), mesh.end());
Prims<N> res(N, cols);
size_t offset = 0;
for (const Prims<N> &mesh : meshes) {
res.middleCols(offset, mesh.cols()) = mesh;
offset += mesh.cols();
}
return res;
@@ -117,52 +118,42 @@ std::vector<Primitive<N>> merge(const std::vector<std::vector<Primitive<N>>> &me
template<unsigned N>
[[nodiscard]]
std::vector<std::vector<Primitive<N>>> each_tile(
std::vector<Primitive<N>> prims,
std::vector<Prims<N>> tile(
Prims<N> prims,
const tc::Group &context,
const std::vector<int> &g_gens,
const std::vector<int> &sg_gens
) {
std::vector<Primitive<N>> base = recontext(prims, context, g_gens, sg_gens);
Prims<N> base = recontext<N>(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);
std::vector<int> _gens = generators(context);
auto res = path.walk<std::vector<Primitive<N>>, int>(base, generators(context), [&](auto from, auto gen) {
return apply(from, table, gen);
});
std::vector<Prims<N>> res = path.walk<Prims<N>, int>(
base, _gens,
[&](Prims<N> from, int gen) {
apply<N>(table, gen, from);
return from;
}
);
return res;
}
template<unsigned N>
[[nodiscard]]
std::vector<Primitive<N>> tile(
std::vector<Primitive<N>> prims,
const tc::Group &context,
const std::vector<int> &g_gens,
const std::vector<int> &sg_gens
) {
auto res = each_tile<N>(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<unsigned N>
[[nodiscard]]
std::vector<Primitive<N + 1>> fan(std::vector<Primitive<N>> prims, int root) {
std::vector<Primitive<N + 1>> res(prims.size());
std::transform(prims.begin(), prims.end(), res.begin(),
[root](const Primitive<N> &prim) {
return Primitive<N + 1>(prim, root);
}
);
Prims<N + 1> fan(Prims<N> prims, int root) {
Prims<N + 1> res(N + 1, prims.cols());
res.topRows(1) = Prims<1>::Constant(1, prims.cols(), root);
res.bottomRows(N) = prims;
return res;
}
@@ -170,7 +161,7 @@ std::vector<Primitive<N + 1>> fan(std::vector<Primitive<N>> prims, int root) {
* Produce a mesh of primitives that fill out the volume of the subgroup generated by generators g_gens within the group context
*/
template<unsigned N>
std::vector<Primitive<N>> triangulate(
Prims<N> triangulate(
const tc::Group &context,
const std::vector<int> &g_gens
) {
@@ -179,37 +170,37 @@ std::vector<Primitive<N>> triangulate(
const auto &combos = Combos(g_gens, g_gens.size() - 1);
std::vector<std::vector<Primitive<N>>> meshes;
std::vector<Prims<N>> meshes;
for (const auto &sg_gens : combos) {
auto base = triangulate<N - 1>(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));
auto parts = tile<N - 1>(base, context, g_gens, sg_gens);
parts.erase(parts.begin(), parts.begin() + 1);
auto raised = merge<N - 1>(parts);
auto fanned = fan<N - 1>(raised, 0);
meshes.push_back(fanned);
}
return merge(meshes);
return merge<N>(meshes);
}
/**
* Single-index primitives should not be further triangulated.
*/
template<>
std::vector<Primitive<1>> triangulate(
Prims<1> triangulate<1>(
const tc::Group &context,
const std::vector<int> &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<Primitive<1>> res;
res.emplace_back();
return res;
return Prims<1>::Zero(1, 1);
}
template<unsigned N, class T>
auto hull(const tc::Group &group, T all_sg_gens, const std::vector<std::vector<int>> &exclude) {
std::vector<std::vector<Primitive<N>>> parts;
std::vector<Prims<N>> parts;
auto g_gens = generators(group);
for (const std::vector<int> &sg_gens : all_sg_gens) {
bool excluded = false;
@@ -222,7 +213,7 @@ auto hull(const tc::Group &group, T all_sg_gens, const std::vector<std::vector<i
if (excluded) continue;
const auto &base = triangulate<N>(group, sg_gens);
const auto &tiles = each_tile(base, group, g_gens, sg_gens);
const auto &tiles = tile<N>(base, group, g_gens, sg_gens);
for (const auto &tile : tiles) {
parts.push_back(tile);
}

View File

@@ -30,7 +30,7 @@ float unmix(float u, float v) {
void emit(vec4 v) {
pos = v;
col = vCol[0];
gl_Position = proj * vec4(v.xyz, 1);
gl_Position = proj * view * vec4(v.xyz, 1);
EmitVertex();
}

View File

@@ -1,189 +0,0 @@
/*
src/example4.cpp -- C++ version of an example application that shows
how to use the OpenGL widget. For a Python implementation, see
'../python/example4.py'.
NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>.
The widget drawing code is based on the NanoVG demo application
by Mikko Mononen.
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE.txt file.
*/
#include <nanogui/opengl.h>
#include <nanogui/nanogui.h>
#include <nanogui/glutil.h>
#include <iostream>
#include <string>
#include <geometry.hpp>
#include <solver.hpp>
#include <rendering.hpp>
#include <mirror.hpp>
#include <util.hpp>
#include <tc/groups.hpp>
struct Matrices {
mat4 proj = mat4::Identity();
mat4 view = mat4::Identity();
Matrices() = default;
Matrices(mat4 proj, mat4 view) : proj(std::move(proj)), view(std::move(view)) {}
static Matrices build(const nanogui::Screen &screen) {
auto aspect = (float) screen.width() / (float) screen.height();
auto pheight = 1.4f;
auto pwidth = aspect * pheight;
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 = mat4::Identity();
return Matrices(proj, view);
}
};
template<class C>
std::vector<vec4> points(const tc::Group &group, const C &coords, const float time) {
auto cosets = group.solve();
auto mirrors = mirror<5>(group);
auto corners = plane_intersections(mirrors);
auto start = barycentric(corners, coords);
auto higher = cosets.path.walk<vec5, vec5>(start, mirrors, reflect<vec5>);
mat5 r = mat5::Identity();
r *= rot<5>(0, 2, time * .21f);
// r *= rot<5>(1, 4, time * .27f);
r *= rot<5>(0, 3, time * .17f);
r *= rot<5>(1, 3, time * .25f);
r *= rot<5>(2, 3, time * .12f);
std::transform(higher.begin(), higher.end(), higher.begin(), [&](vec5 v) { return r * v; });
std::vector<vec4> lower(higher.size());
std::transform(higher.begin(), higher.end(), lower.begin(), stereo<4>);
return lower;
}
template<int N, class T, class C>
Prop<4, vec4> make_slice(
const tc::Group &g,
const C &coords,
vec3 color,
T all_sg_gens,
const std::vector<std::vector<int>> &exclude
) {
Prop<N, vec4> res{};
// res.vbo.put(points(g, coords));
res.ibo.put(merge<N>(hull<N>(g, all_sg_gens, exclude)));
res.vao.ipointer(0, res.ibo, 4, GL_UNSIGNED_INT);
return res;
}
class ExampleApplication : public nanogui::Screen {
public:
vec5 root;
std::unique_ptr<tc::Group> group;
std::unique_ptr<Prop<4, vec4>> prop;
std::unique_ptr<cgl::Buffer<Matrices>> ubo;
std::unique_ptr<SliceRenderer<4, vec4>> ren;
float glfw_time = 0;
float last_frame = 0;
float frame_time = 0;
float time = 0;
bool paused = false;
ExampleApplication() : nanogui::Screen(
Eigen::Vector2i(1920, 1080),
"Coset Visualization",
true, false,
8, 8, 24, 8,
4,
4, 5) {
using namespace nanogui;
Window *window = new Window(this, "Sample Window");
window->setPosition(Vector2i(15, 15));
window->setFixedWidth(250);
window->setLayout(new BoxLayout(Orientation::Vertical));
auto pause = new ToolButton(window, ENTYPO_ICON_CONTROLLER_PAUS);
pause->setFlags(Button::ToggleButton);
pause->setChangeCallback([&](bool value) { this->paused = value; });
performLayout();
std::cout << utilInfo();
std::vector<int> symbol = {5, 3, 3, 2};
root << .80, .02, .02, .02, .02;
group = std::make_unique<tc::Group>(tc::schlafli(symbol));
auto gens = generators(*group);
std::vector<std::vector<int>> exclude = {{0, 1, 2}};
auto combos = Combos<int>(gens, 3);
prop = std::make_unique<Prop<4, vec4>>(make_slice<4>(*group, root, {}, combos, exclude));
ubo = std::make_unique<cgl::Buffer<Matrices>>();
glBindBufferBase(GL_UNIFORM_BUFFER, 1, *ubo);
ren = std::make_unique<SliceRenderer<4, vec4>>();
}
void drawContents() override {
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, width(), height());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfw_time = (float) glfwGetTime();
frame_time = glfw_time - last_frame;
last_frame = glfw_time;
if (!paused) time += frame_time;
std::get<0>(prop->vbos).put(points(*group, root, time));
Matrices mats = Matrices::build(*this);
ubo->put(mats);
ren->draw(*prop);
}
};
int main(int /* argc */, char ** /* argv */) {
try {
nanogui::init();
/* scoped variables */ {
nanogui::ref<ExampleApplication> app = new ExampleApplication();
app->drawAll();
app->setVisible(true);
nanogui::mainloop(1);
}
nanogui::shutdown();
} catch (const std::runtime_error &e) {
std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what());
std::cerr << error_msg << std::endl;
return -1;
}
return 0;
}

View File

@@ -1,196 +1,129 @@
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <nanogui/opengl.h>
#include <nanogui/nanogui.h>
#include <nanogui/glutil.h>
#include <chrono>
#include <cmath>
#include <iostream>
#include <random>
#include <yaml-cpp/yaml.h>
#include <string>
#include <geometry.hpp>
#include <solver.hpp>
#include <rendering.hpp>
#include <mirror.hpp>
#include <util.hpp>
#include <tc/groups.hpp>
#include <cgl/vertexarray.hpp>
#include <cgl/shaderprogram.hpp>
#include <cgl/pipeline.hpp>
mat5 wander(float time) {
mat5 r = mat5::Identity();
r *= rot<5>(0, 2, time * .15f);
r *= rot<5>(1, 2, time * .13f);
r *= rot<5>(0, 1, time * .20f);
#include <util.hpp>
#include <mirror.hpp>
#include <rendering.hpp>
#include <solver.hpp>
#include <geometry.hpp>
r *= rot<5>(0, 3, time * .17f);
r *= rot<5>(1, 3, time * .25f);
r *= rot<5>(2, 3, time * .12f);
#ifdef _WIN32
extern "C" {
__attribute__((unused)) __declspec(dllexport) int NvOptimusEnablement = 0x00000001;
}
#endif
// r *= rot<5>(1, 4, time * .27f);
struct Matrices {
mat4 proj;
mat4 view;
Matrices() = default;
Matrices(const mat4 &proj, const mat4 &view)
: proj(proj), view(view) {
}
};
struct State {
float time;
float time_delta;
float st;
int dimension;
};
Matrices build(GLFWwindow *window, State &state) {
int width, height;
glfwGetFramebufferSize(window, &width, &height);
auto aspect = (float) width / (float) height;
auto pheight = 1.4f;
auto pwidth = aspect * pheight;
mat4 proj = ortho(-pwidth, pwidth, -pheight, pheight, -10.0f, 10.0f);
if (!glfwGetKey(window, GLFW_KEY_LEFT_SHIFT)) {
state.st += state.time_delta / 8;
return r;
}
auto view = identity<4>();
return Matrices(proj, view);
class ExampleApplication : public nanogui::Screen {
public:
vec5 root;
// std::unique_ptr<tc::Group> group;
std::unique_ptr<SliceRenderer<4>> ren;
std::unique_ptr<cgl::Buffer<Matrices>> ubo;
std::unique_ptr<Slice<4>> slice;
float glfw_time = 0;
float last_frame = 0;
float frame_time = 0;
float time = 0;
bool paused = false;
ExampleApplication() : nanogui::Screen(
Eigen::Vector2i(1920, 1080),
"Coset Visualization",
true, false,
8, 8, 24, 8,
4,
4, 5) {
using namespace nanogui;
Window *window = new Window(this, "Sample Window");
window->setPosition(Vector2i(15, 15));
window->setFixedWidth(250);
window->setLayout(new BoxLayout(Orientation::Vertical));
auto pause = new ToolButton(window, ENTYPO_ICON_CONTROLLER_PAUS);
pause->setFlags(Button::ToggleButton);
pause->setChangeCallback([&](bool value) { this->paused = value; });
performLayout();
std::cout << utilInfo();
std::vector<int> symbol = {3, 4, 3, 2};
root << .80, .02, .02, .02, .02;
auto group = tc::schlafli(symbol);
auto gens = generators(group);
auto combos = Combos<int>(gens, 3);
std::vector<std::vector<int>> exclude = {{0, 1, 2}};
slice = std::make_unique<Slice<4>>(group, combos, exclude);
ren = std::make_unique<SliceRenderer<4>>();
ubo = std::make_unique<cgl::Buffer<Matrices>>();
}
template<class C>
std::vector<vec4> points(const tc::Group &group, const C &coords, const float time) {
auto cosets = group.solve();
auto mirrors = mirror<5>(group);
auto corners = plane_intersections(mirrors);
auto start = barycentric(corners, coords);
auto higher = cosets.path.walk<vec5, vec5>(start, mirrors, reflect<vec5>);
auto r = identity<5>();
r = mul(r, rot<5>(0, 2, time * .21f));
r = mul(r, rot<5>(1, 4, time * .27f));
r = mul(r, rot<5>(0, 3, time * .17f));
r = mul(r, rot<5>(1, 3, time * .25f));
r = mul(r, rot<5>(2, 3, time * .12f));
std::transform(higher.begin(), higher.end(), higher.begin(), [&](vec5 v) { return mul(v, r); });
std::vector<vec4> lower(higher.size());
std::transform(higher.begin(), higher.end(), lower.begin(), stereo<4>);
return lower;
}
template<int N, class T, class C>
Prop<4, vec4> make_slice(
const tc::Group &g,
const C &coords,
vec3 color,
T all_sg_gens,
const std::vector<std::vector<int>> &exclude
) {
Prop<N, vec4> res{};
// res.vbo.put(points(g, coords));
res.ibo.put(merge<N>(hull<N>(g, all_sg_gens, exclude)));
res.vao.ipointer(0, res.ibo, 4, GL_UNSIGNED_INT);
return res;
}
void run(const std::string &config_file, GLFWwindow *window) {
void drawContents() override {
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
std::vector<int> symbol = {4, 3, 3, 3};
vec5 root = {.80, .02, .02, .02, .02};
auto group = tc::schlafli(symbol);
auto gens = generators(group);
std::vector<std::vector<int>> exclude = {{0, 1, 2}};
auto combos = Combos<int>(gens, 3);
SliceRenderer<4, vec4> ren{};
Prop<4, vec4> prop = make_slice<4>(group, root, {}, combos, exclude);
State state{};
state.dimension = 4;
glfwSetWindowUserPointer(window, &state);
auto ubo = cgl::Buffer<Matrices>();
glBindBufferBase(GL_UNIFORM_BUFFER, 1, ubo);
while (!glfwWindowShouldClose(window)) {
auto time = (float) glfwGetTime();
state.time_delta = state.time - time;
state.time = time;
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, width(), height());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLineWidth(1.5);
glfw_time = (float) glfwGetTime();
frame_time = glfw_time - last_frame;
last_frame = glfw_time;
if (!paused) time += frame_time;
std::get<0>(prop.vbos).put(points(group, root, time));
auto rotation = wander(time);
slice->setPoints(root, rotation);
Matrices mats{};
glViewport(0, 0, width, height);
mats = build(window, state);
ubo.put(mats);
ren.draw(prop);
glfwSwapInterval(2);
glfwSwapBuffers(window);
glfwPollEvents();
Matrices mats = Matrices::build(*this);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, *ubo);
ubo->put(mats);
ren->draw(*slice);
}
};
int main(int argc, char ** argv) {
try {
nanogui::init();
/* scoped variables */ {
nanogui::ref<ExampleApplication> app = new ExampleApplication();
app->drawAll();
app->setVisible(true);
nanogui::mainloop(1);
}
int main(int argc, char *argv[]) {
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl;
return EXIT_FAILURE;
nanogui::shutdown();
} catch (const std::runtime_error &e) {
std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what());
std::cerr << error_msg << std::endl;
return -1;
}
glfwWindowHint(GLFW_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_VERSION_MAJOR, 5);
// glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
auto window = glfwCreateWindow(
1920, 1080,
"Coset Visualization",
nullptr, nullptr);
if (!window) {
std::cerr << "Failed to create window" << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
glfwSwapInterval(1);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
std::cout << utilInfo();
std::string config_file = "presets/default.yaml";
if (argc > 1) config_file = std::string(argv[1]);
run(config_file, window);
glfwTerminate();
return EXIT_SUCCESS;
return 0;
}