mirror of
https://github.com/allemangD/toddcox-visualize.git
synced 2025-11-10 03:52:48 -05:00
ENH: Dynamically enable and color tilings
Use multidraw and command buffer
This commit is contained in:
@@ -8,6 +8,7 @@ namespace cgl {
|
|||||||
template<class T>
|
template<class T>
|
||||||
class Buffer {
|
class Buffer {
|
||||||
GLuint id{};
|
GLuint id{};
|
||||||
|
size_t _count = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Element = T;
|
using Element = T;
|
||||||
@@ -32,25 +33,26 @@ namespace cgl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] size_t size() const {
|
[[nodiscard]] size_t size() const {
|
||||||
GLint res;
|
return _count * sizeof(T);
|
||||||
glGetNamedBufferParameteriv(id, GL_BUFFER_SIZE, &res);
|
|
||||||
return (size_t) res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] size_t count() const {
|
[[nodiscard]] size_t count() const {
|
||||||
return size() / sizeof(T);
|
return _count;
|
||||||
}
|
|
||||||
|
|
||||||
void put(const T &data, GLenum usage = GL_STATIC_DRAW) {
|
|
||||||
glNamedBufferData(id, sizeof(T), &data, usage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It>
|
template<typename It>
|
||||||
void put(It begin, It end, GLenum usage = GL_STATIC_DRAW) {
|
void put(It begin, It end, GLenum usage = GL_STATIC_DRAW) {
|
||||||
glNamedBufferData(id, sizeof(T) * (end - begin), nullptr, usage);
|
_count = end - begin;
|
||||||
|
|
||||||
|
glNamedBufferData(id, sizeof(T) * _count, nullptr, usage);
|
||||||
void* ptr = glMapNamedBuffer(id, GL_WRITE_ONLY);
|
void* ptr = glMapNamedBuffer(id, GL_WRITE_ONLY);
|
||||||
std::copy(begin, end, (T*) ptr);
|
std::copy(begin, end, (T*) ptr);
|
||||||
glUnmapNamedBuffer(id);
|
glUnmapNamedBuffer(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void put(const T &data, GLenum usage = GL_STATIC_DRAW) {
|
||||||
|
T const* ptr = &data;
|
||||||
|
put(ptr, ptr + 1, usage);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ Indices<N> cell(
|
|||||||
|
|
||||||
std::vector<Indices<N - 1>> facets;
|
std::vector<Indices<N - 1>> facets;
|
||||||
|
|
||||||
for (auto H : G.subs(N - 2)) {
|
for (auto H: G.subs(N - 2)) {
|
||||||
auto sub_base = cell<N - 1>(H);
|
auto sub_base = cell<N - 1>(H);
|
||||||
auto base = recontext(sub_base, G, H);
|
auto base = recontext(sub_base, G, H);
|
||||||
auto tiles = tile(base, G, H);
|
auto tiles = tile(base, G, H);
|
||||||
@@ -140,17 +140,53 @@ Indices<1> cell<1>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<int N>
|
template<int N>
|
||||||
auto hull(
|
struct Hull {
|
||||||
const tc::Group &G
|
struct Tiling {
|
||||||
) {
|
Eigen::Index first;
|
||||||
std::vector<Indices<N>> parts;
|
Eigen::Index count;
|
||||||
|
};
|
||||||
|
|
||||||
for (auto H: G.subs(N - 1)) {
|
std::vector<Tiling> tilings{};
|
||||||
auto sub_base = cell<N>(H);
|
std::vector<std::vector<size_t>> subgroups{};
|
||||||
auto base = recontext(sub_base, G, H);
|
|
||||||
auto tiles = tile(base, G, H);
|
Indices<N> inds{};
|
||||||
parts.push_back(merge(tiles));
|
|
||||||
|
explicit Hull(tc::Group const &G) {
|
||||||
|
std::vector<Indices<N>> parts;
|
||||||
|
|
||||||
|
Eigen::Index first = 0;
|
||||||
|
for (const auto &H: G.subs(N - 1)) {
|
||||||
|
auto sub_base = cell<N>(H);
|
||||||
|
auto base = recontext(sub_base, G, H);
|
||||||
|
auto tiles = tile(base, G, H);
|
||||||
|
auto tiling = merge(tiles);
|
||||||
|
|
||||||
|
subgroups.push_back(H.gens());
|
||||||
|
tilings.push_back({first, tiling.cols()});
|
||||||
|
|
||||||
|
parts.push_back(tiling);
|
||||||
|
first += tiling.cols();
|
||||||
|
}
|
||||||
|
|
||||||
|
inds = merge(parts);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return parts;
|
struct Points {
|
||||||
}
|
Eigen::Array<float, 4, Eigen::Dynamic> verts;
|
||||||
|
|
||||||
|
explicit Points(tc::Group const &G, Eigen::Vector<float, 5> root) {
|
||||||
|
auto mirrors = mirror<5>(G);
|
||||||
|
auto corners = plane_intersections(mirrors);
|
||||||
|
|
||||||
|
auto start = corners * root;
|
||||||
|
|
||||||
|
tc::Cosets table = G.solve();
|
||||||
|
tc::Path<vec5> path(table, mirrors.colwise());
|
||||||
|
|
||||||
|
Eigen::Array<float, 5, Eigen::Dynamic> higher(5, path.order());
|
||||||
|
path.walk(start, Reflect(), higher.matrix().colwise().begin());
|
||||||
|
|
||||||
|
verts = Stereo()(higher);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ layout(std140, binding=2) uniform ModelMatrices {
|
|||||||
};
|
};
|
||||||
|
|
||||||
layout(location=0) in ivec4 inds;
|
layout(location=0) in ivec4 inds;
|
||||||
layout(location=1) in vec4 col;
|
layout(location=1) in vec3 col;
|
||||||
|
|
||||||
out ivec4 vInds;
|
out ivec4 vInds;
|
||||||
out vec4 vCol;
|
out vec3 vCol;
|
||||||
|
|
||||||
out gl_PerVertex {
|
out gl_PerVertex {
|
||||||
vec4 gl_Position;
|
vec4 gl_Position;
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ layout(std140, binding=2) uniform ModelMatrices {
|
|||||||
};
|
};
|
||||||
|
|
||||||
in ivec4 vInds[];
|
in ivec4 vInds[];
|
||||||
in vec4 vCol[];
|
in vec3 vCol[];
|
||||||
|
|
||||||
layout(location=0) out vec4 pos;
|
layout(location=0) out vec4 pos;
|
||||||
layout(location=1) out vec4 col;
|
layout(location=1) out vec3 col;
|
||||||
layout(location=2) out vec3 normal;
|
layout(location=2) out vec3 normal;
|
||||||
|
|
||||||
out gl_PerVertex {
|
out gl_PerVertex {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#version 430
|
#version 430
|
||||||
|
|
||||||
layout(location=2) uniform vec3 col;
|
|
||||||
|
|
||||||
layout(location=0) in vec3 pos;
|
layout(location=0) in vec3 pos;
|
||||||
|
layout(location=1) in vec3 col;
|
||||||
layout(location=2) in vec3 normal;
|
layout(location=2) in vec3 normal;
|
||||||
|
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|||||||
@@ -18,65 +18,93 @@
|
|||||||
#include <shaders.hpp>
|
#include <shaders.hpp>
|
||||||
|
|
||||||
namespace vis {
|
namespace vis {
|
||||||
struct Group {
|
template<int N>
|
||||||
tc::Group group;
|
struct Structure {
|
||||||
vec5 root;
|
using Affine4f = Eigen::Transform<float, 4, Eigen::Affine>;
|
||||||
vec3 color;
|
|
||||||
|
using Vertex = Eigen::Vector<float, 4>;
|
||||||
|
using Color = Eigen::Vector<float, 3>;
|
||||||
|
using Cell = Eigen::Array<unsigned int, 4, 1>;
|
||||||
|
|
||||||
|
Points points;
|
||||||
|
Hull<N> hull;
|
||||||
|
|
||||||
|
std::vector<char> enabled;
|
||||||
|
std::vector<Eigen::Vector3f> colors;
|
||||||
|
|
||||||
|
Affine4f transform = Affine4f::Identity();
|
||||||
|
|
||||||
|
template<typename P, typename H>
|
||||||
|
explicit Structure(P &&points_, H &&hull_, Color color_ = Color::Ones()):
|
||||||
|
points(std::forward<P>(points_)),
|
||||||
|
hull(std::forward<H>(hull_)),
|
||||||
|
enabled(hull.tilings.size(), true),
|
||||||
|
colors(hull.tilings.size(), color_),
|
||||||
|
transform(Affine4f::Identity()) {
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VBOs {
|
struct VBOs {
|
||||||
struct ModelMatrix {
|
struct Uniform {
|
||||||
Eigen::Matrix4f linear;
|
Eigen::Matrix4f linear;
|
||||||
Eigen::Vector4f translation;
|
Eigen::Vector4f translation;
|
||||||
};
|
};
|
||||||
|
|
||||||
cgl::Buffer<vec4> verts;
|
struct Command {
|
||||||
cgl::Buffer<Eigen::Array<unsigned int, 4, 1>> ibo;
|
unsigned int count, instanceCount, first, baseInstance;
|
||||||
cgl::Buffer<ModelMatrix> ubo;
|
};
|
||||||
|
|
||||||
using Affine4f = Eigen::Transform<float, 4, Eigen::Affine>;
|
cgl::Buffer<Structure<4>::Vertex> vertices;
|
||||||
|
cgl::Buffer<Structure<4>::Color> colors;
|
||||||
Affine4f tform = Affine4f::Identity();
|
cgl::Buffer<Structure<4>::Cell> indices;
|
||||||
|
cgl::Buffer<Uniform> uniform;
|
||||||
|
cgl::Buffer<Command> commands;
|
||||||
};
|
};
|
||||||
|
|
||||||
void upload_groups(entt::registry ®) {
|
void upload_structure(entt::registry ®istry) {
|
||||||
auto view = reg.view<const Group, VBOs>();
|
auto view = registry.view<Structure<4>, VBOs>();
|
||||||
|
|
||||||
for (auto [entity, group, vbos]: view.each()) {
|
for (auto [entity, structure, vbos]: view.each()) {
|
||||||
auto cosets = group.group.solve();
|
auto vertices = structure.points.verts.colwise();
|
||||||
auto mirrors = mirror<5>(group.group);
|
auto indices = structure.hull.inds.colwise();
|
||||||
auto corners = plane_intersections(mirrors);
|
|
||||||
|
|
||||||
vec5 start = corners * group.root;
|
vbos.vertices.put(vertices.begin(), vertices.end());
|
||||||
|
vbos.indices.put(indices.begin(), indices.end());
|
||||||
tc::Path<vec5> path(cosets, mirrors.colwise());
|
|
||||||
|
|
||||||
Eigen::Array<float, 5, Eigen::Dynamic> higher(5, path.order());
|
|
||||||
path.walk(start, Reflect(), higher.matrix().colwise().begin());
|
|
||||||
|
|
||||||
Eigen::Array<float, 4, Eigen::Dynamic> lower = Stereo()(higher);
|
|
||||||
|
|
||||||
vbos.verts.put(lower.colwise().begin(), lower.colwise().end());
|
|
||||||
|
|
||||||
// todo generate all, then mask using glMultiDraw.
|
|
||||||
const Eigen::Index N = 4;
|
|
||||||
|
|
||||||
auto tiles = hull<N>(group.group);
|
|
||||||
|
|
||||||
tiles.erase(tiles.begin()); // remove {0, 1, 2} cells
|
|
||||||
|
|
||||||
auto inds = merge<N>(tiles);
|
|
||||||
|
|
||||||
vbos.ibo.put(inds.colwise().begin(), inds.colwise().end());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void upload_ubo(entt::registry ®) {
|
void upload_uniforms(entt::registry ®istry) {
|
||||||
auto view = reg.view<VBOs>();
|
auto view = registry.view<Structure<4>, VBOs>();
|
||||||
|
|
||||||
for (auto [entity, vbos]: view.each()) {
|
for (auto [entity, structure, vbos]: view.each()) {
|
||||||
vbos.ubo.put({vbos.tform.linear(),
|
auto colors = structure.colors;
|
||||||
vbos.tform.translation()});
|
VBOs::Uniform uniform{
|
||||||
|
structure.transform.linear(),
|
||||||
|
structure.transform.translation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
vbos.colors.put(colors.begin(), colors.end());
|
||||||
|
vbos.uniform.put(uniform, GL_STREAM_DRAW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void upload_commands(entt::registry ®istry) {
|
||||||
|
auto view = registry.view<Structure<4>, VBOs>();
|
||||||
|
|
||||||
|
for (auto [entity, structure, vbos]: view.each()) {
|
||||||
|
const auto &tilings = structure.hull.tilings;
|
||||||
|
|
||||||
|
std::vector<VBOs::Command> commands;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < tilings.size(); ++i) {
|
||||||
|
if (structure.enabled[i]) {
|
||||||
|
auto [first, count] = tilings[i];
|
||||||
|
commands.push_back({(unsigned int) count, 1, (unsigned int) first, i});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vbos.commands.put(commands.begin(), commands.end(), GL_STREAM_DRAW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,25 +123,29 @@ namespace vis {
|
|||||||
pipe.stage(solid);
|
pipe.stage(solid);
|
||||||
|
|
||||||
vao.iformat(0, 4, GL_UNSIGNED_INT);
|
vao.iformat(0, 4, GL_UNSIGNED_INT);
|
||||||
|
vao.format(1, 3, GL_FLOAT);
|
||||||
|
|
||||||
|
glVertexArrayBindingDivisor(vao, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(entt::registry ®) {
|
void operator()(entt::registry ®) {
|
||||||
auto view = reg.view<const Group, VBOs>();
|
auto view = reg.view<VBOs>();
|
||||||
|
|
||||||
for (auto [entity, group, vbos]: view.each()) {
|
for (auto [entity, vbos]: view.each()) {
|
||||||
const size_t N = 4;
|
const size_t N = 4;
|
||||||
|
|
||||||
glBindProgramPipeline(pipe);
|
glBindProgramPipeline(pipe);
|
||||||
|
|
||||||
glProgramUniform3fv(solid, 2, 1, group.color.data());
|
glBindBufferBase(GL_UNIFORM_BUFFER, 2, vbos.uniform);
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, 2, vbos.ubo);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, vbos.vertices);
|
||||||
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, vbos.verts);
|
vao.vertexBuffer(0, vbos.indices);
|
||||||
|
vao.vertexBuffer(1, vbos.colors);
|
||||||
|
|
||||||
vao.vertexBuffer(0, vbos.ibo);
|
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, vbos.commands);
|
||||||
|
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
glDrawArrays(GL_POINTS, 0, vbos.ibo.count());
|
glMultiDrawArraysIndirect(GL_POINTS, nullptr, vbos.commands.count(), 0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
glBindProgramPipeline(0);
|
glBindProgramPipeline(0);
|
||||||
|
|||||||
@@ -15,11 +15,13 @@
|
|||||||
|
|
||||||
#include "comps.hpp"
|
#include "comps.hpp"
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
|
#include "fmt/ranges.h"
|
||||||
|
|
||||||
#include <shaders.hpp>
|
#include <shaders.hpp>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#include <cgl/debug.hpp>
|
#include <cgl/debug.hpp>
|
||||||
|
#include <utility>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -36,8 +38,8 @@ struct Matrices {
|
|||||||
Eigen::Matrix4f proj;
|
Eigen::Matrix4f proj;
|
||||||
Eigen::Matrix4f view;
|
Eigen::Matrix4f view;
|
||||||
|
|
||||||
Matrices(const Eigen::Matrix4f &proj, const Eigen::Matrix4f &view)
|
Matrices(Eigen::Matrix4f proj, Eigen::Matrix4f view)
|
||||||
: proj(proj), view(view) {
|
: proj(std::move(proj)), view(std::move(view)) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -106,6 +108,23 @@ void show_overlay(State &state) {
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void show_options(entt::registry ®istry) {
|
||||||
|
auto view = registry.view<vis::Structure<4>>();
|
||||||
|
|
||||||
|
for (auto [entity, structure]: view.each()) {
|
||||||
|
ImGui::Begin("Structure View Options");
|
||||||
|
|
||||||
|
for (int i = 0; i < structure.hull.tilings.size(); ++i) {
|
||||||
|
std::string label = fmt::format("{}", structure.hull.subgroups[i]);
|
||||||
|
|
||||||
|
ImGui::Checkbox(label.c_str(), (bool*) (&(structure.enabled[i])));
|
||||||
|
ImGui::ColorEdit3(label.c_str(), structure.colors[i].data(), ImGuiColorEditFlags_NoLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void set_style() {
|
void set_style() {
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
|
|
||||||
@@ -135,16 +154,21 @@ int run(GLFWwindow* window, ImGuiContext* ctx) {
|
|||||||
state.dimension = 4;
|
state.dimension = 4;
|
||||||
|
|
||||||
auto entity = registry.create();
|
auto entity = registry.create();
|
||||||
|
{
|
||||||
|
// todo move symbol and root to structure
|
||||||
|
// cache and recompute cells/points on frame (only if changed) in a system.
|
||||||
|
|
||||||
registry.emplace<vis::Group>(
|
tc::Group group = tc::schlafli({5, 3, 3, 2});
|
||||||
entity,
|
Points points(group, vec5{0.80, 0.3, 0.15, 0.15, 0.03});
|
||||||
tc::schlafli({5, 3, 3, 2}),
|
Hull<4> hull(group);
|
||||||
vec5{0.80, 0.09, 0.09, 0.09, 0.09},
|
|
||||||
vec3{0.90, 0.90, 0.90}
|
|
||||||
);
|
|
||||||
registry.emplace<vis::VBOs>(entity);
|
|
||||||
|
|
||||||
vis::upload_groups(registry);
|
auto& structure = registry.emplace<vis::Structure<4>>(entity, std::move(points), std::move(hull));
|
||||||
|
registry.emplace<vis::VBOs>(entity);
|
||||||
|
|
||||||
|
structure.enabled[0] = false; // disable {0,1,2} cells
|
||||||
|
}
|
||||||
|
|
||||||
|
vis::upload_structure(registry);
|
||||||
|
|
||||||
auto ubo = cgl::Buffer<Matrices>();
|
auto ubo = cgl::Buffer<Matrices>();
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, 1, ubo);
|
glBindBufferBase(GL_UNIFORM_BUFFER, 1, ubo);
|
||||||
@@ -163,6 +187,7 @@ int run(GLFWwindow* window, ImGuiContext* ctx) {
|
|||||||
|
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
show_overlay(state);
|
show_overlay(state);
|
||||||
|
show_options(registry);
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
@@ -171,10 +196,10 @@ int run(GLFWwindow* window, ImGuiContext* ctx) {
|
|||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
ubo.put(build(window, state, ctx));
|
ubo.put(build(window, state, ctx), GL_STREAM_DRAW);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto &tform = registry.get<vis::VBOs>(entity).tform;
|
auto &tform = registry.get<vis::Structure<4>>(entity).transform;
|
||||||
|
|
||||||
if (!io.KeysDown[GLFW_KEY_SPACE]) {
|
if (!io.KeysDown[GLFW_KEY_SPACE]) {
|
||||||
float speed = 1.0 / 8.0;
|
float speed = 1.0 / 8.0;
|
||||||
@@ -202,7 +227,8 @@ int run(GLFWwindow* window, ImGuiContext* ctx) {
|
|||||||
tform.translation().w() = std::sin(state.time * 1.4) * 1.0;
|
tform.translation().w() = std::sin(state.time * 1.4) * 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vis::upload_ubo(registry);
|
vis::upload_commands(registry);
|
||||||
|
vis::upload_uniforms(registry);
|
||||||
|
|
||||||
renderer(registry);
|
renderer(registry);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user