aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Fadel <samuel@nihil.ws>2023-06-06 16:58:40 +0200
committerSamuel Fadel <samuel@nihil.ws>2023-06-06 16:58:40 +0200
commit4ef37f16257b42512ec610cc5def338707308747 (patch)
treea00986754f6792a4b991a4927a9dc98f7b1919f7
parent4f05d891f05a038bad7b911ce52d27e01b34f7cb (diff)
BarChart, Wayland.
* Makefile: Added some Wayland stuff to cflags/libs in pkg-config * barchart: Rendering works, no interactivity * main.cpp: Reposition some components for a more compact view * manifest.scm: glfw-wayland: Added GLFW variant with Wayland * scatterplot.cpp and voronoisplat.cpp: Cleanup
-rw-r--r--Makefile4
-rw-r--r--barchart.cpp211
-rw-r--r--barchart.h20
-rw-r--r--main.cpp59
-rw-r--r--manifest.scm24
-rw-r--r--scatterplot.cpp3
-rw-r--r--voronoisplat.cpp5
7 files changed, 273 insertions, 53 deletions
diff --git a/Makefile b/Makefile
index 7203205..42127c2 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-CFLAGS=-O2 -Iinclude `pkg-config --cflags armadillo glfw3`
-LIBS=`pkg-config --libs armadillo gl glfw3`
+CFLAGS=-O2 -Iinclude `pkg-config --cflags armadillo egl gl glfw3 xkbcommon`
+LIBS=`pkg-config --libs armadillo egl gl glfw3 xkbcommon`
OBJS=barchart.o brushinghandler.o colormap.o colorscale.o continuouscolorscale.o divergentcolorscale.o dist.o forcescheme.o geometry.o lamp.o manipulationhandler.o mapscalehandler.o measures.o projectionhistory.o quadtree.o scale.o scatterplot.o shader.o voronoisplat.o
all: pm
diff --git a/barchart.cpp b/barchart.cpp
index a21d353..eb20384 100644
--- a/barchart.cpp
+++ b/barchart.cpp
@@ -22,22 +22,167 @@ static inline T clamp(T value, T min, T max)
return std::min(std::max(min, value), max);
}
+static const char *shaderVertex = R"EOF(#version 330
+
+precision mediump float;
+
+uniform int num;
+uniform float minimum;
+uniform float maximum;
+uniform sampler2D colormap;
+
+layout (location = 0) in float value;
+
+out VS_OUT {
+ vec4 color;
+} vs_out;
+
+vec3 getRGB(float value) {
+ return texture(colormap, vec2(mix(0.005, 0.995, value), 0)).rgb;
+}
+
+void main()
+{
+ float v = (value - minimum) / (maximum - minimum);
+ vs_out.color = vec4(getRGB(v), 1.0);
+ // Position here is top-left of the rectangle (bar), the geometry shader does
+ // the rest of the job
+ float width = max(0.01, 2.0 / num);
+ gl_Position = vec4(gl_VertexID * width - 1.0,
+ mix(1.0, -1.0, v),
+ 0.0, 1.0);
+}
+)EOF";
+
+static const char *shaderFragment = R"EOF(#version 330
+in vec4 color;
+
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = color;
+ // FragColor = vec4(1.0);
+}
+)EOF";
+
+static const char *shaderGeometry = R"EOF(#version 330
+layout (points) in;
+layout (triangle_strip, max_vertices = 4) out;
+
+uniform int num;
+
+in VS_OUT {
+ vec4 color;
+} gs_in[];
+
+out vec4 color;
+
+void main() {
+ float width = max(0.01, 2.0 / num);
+ float x = gl_in[0].gl_Position.x;
+ float y = gl_in[0].gl_Position.y;
+ color = gs_in[0].color;
+
+ // top-left
+ gl_Position = vec4(x, y, 0.0, 1.0);
+ EmitVertex();
+
+ // bottom-left
+ gl_Position = vec4(x, 1.0, 0.0, 1.0);
+ EmitVertex();
+
+ // top-right
+ gl_Position = vec4(x + width, y, 0.0, 1.0);
+ EmitVertex();
+
+ // bottom-right
+ gl_Position = vec4(x + width, 1.0, 0.0, 1.0);
+ EmitVertex();
+ EndPrimitive();
+}
+)EOF";
+
BarChart::BarChart()
- : m_shouldUpdateBars(false)
+ : m_redraw(false)
+ , m_shouldUpdateBars(false)
, m_shouldUpdatePreSelection(false)
, m_dragStartPos(-1.0f)
, m_dragLastPos(-1.0f)
, m_shouldUpdateSelection(false)
, m_brushedItem(-1)
- , m_colorScale(0)
, m_scale(0.0f, 1.0f, 0.0f, 1.0f)
, m_width(0)
, m_height(0)
{
+ glGenFramebuffers(1, &m_FBO);
+ glGenTextures(1, &m_outTex);
+
+ glGenBuffers(1, &m_VBO);
+ glGenVertexArrays(1, &m_VAO);
+ glBindVertexArray(m_VAO);
+ glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
+ // glVertexAttribDivisor(0, 1);
+ glBindVertexArray(0);
+
+ m_shader = std::make_unique<Shader>(
+ shaderVertex,
+ shaderFragment,
+ shaderGeometry);
}
void BarChart::update()
{
+ m_redraw = m_values.n_elem != 0;
+
+ if (m_shouldUpdateBars) {
+ // TODO
+ updateBars();
+ }
+}
+
+void BarChart::updateValues(const arma::vec &values)
+{
+ if (m_values.n_elem != values.n_elem) {
+ return;
+ }
+
+ m_values = values;
+ m_shouldUpdateBars = true;
+ update();
+}
+
+void BarChart::updateBars()
+{
+ std::vector<float> sortedValues(m_values.n_elem);
+ size_t i = 0;
+ for (auto j : m_originalIndices) {
+ sortedValues[i] = m_values[j];
+ i++;
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
+ glBufferData(GL_ARRAY_BUFFER, sortedValues.size() * sizeof(float),
+ sortedValues.data(), GL_DYNAMIC_DRAW);
+
+ m_shouldUpdateBars = false;
+}
+
+void BarChart::setSize(size_t width, size_t height)
+{
+ m_width = width;
+ m_height = height;
+
+ glBindTexture(GL_TEXTURE_2D, m_outTex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, m_width, m_height, 0, GL_RGBA,
+ GL_FLOAT, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ update();
}
void BarChart::setValues(const arma::vec &values)
@@ -72,23 +217,10 @@ void BarChart::setValues(const arma::vec &values)
update();
}
-void BarChart::updateValues(const arma::vec &values)
+void BarChart::setColormap(GLuint texture)
{
- if (m_values.n_elem != values.n_elem) {
- return;
- }
+ m_colormapTex = texture;
- m_values = values;
- m_shouldUpdateBars = true;
- update();
-}
-
-void BarChart::setColorScale(std::shared_ptr<const ColorScale> scale)
-{
- m_colorScale = scale;
- colorScaleChanged(m_colorScale);
-
- m_shouldUpdateBars = true;
update();
}
@@ -124,6 +256,51 @@ void BarChart::brushItem(int item)
update();
}
+void BarChart::draw()
+{
+ if (!m_redraw) {
+ return;
+ }
+ m_redraw = false;
+
+ int originalFBO;
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originalFBO);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, m_outTex, 0);
+
+ glViewport(0, 0, m_width, m_height);
+ m_shader->use();
+ m_shader->setUniform("num", static_cast<GLint>(m_values.size()));
+ m_shader->setUniform("minimum", static_cast<GLfloat>(m_values.min()));
+ m_shader->setUniform("maximum", static_cast<GLfloat>(m_values.max()));
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, m_colormapTex);
+ m_shader->setUniform("colormap", 0);
+
+ glEnable(GL_BLEND);
+ // glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFunc(GL_ONE, GL_ZERO);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glBindVertexArray(m_VAO);
+ glDrawArrays(GL_POINTS, 0, m_values.size());
+ m_shader->release();
+ glDisable(GL_BLEND);
+
+ /*
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ checkGLError("draw():");
+ }
+ */
+
+ glBindFramebuffer(GL_FRAMEBUFFER, originalFBO);
+}
+
/*
QSGNode *BarChart::newSceneGraph() const
{
diff --git a/barchart.h b/barchart.h
index 9e2b421..947fe2b 100644
--- a/barchart.h
+++ b/barchart.h
@@ -5,10 +5,11 @@
#include <vector>
#include <armadillo>
+#include <glad/gl.h>
#include <nod.hpp>
-#include "colorscale.h"
#include "scale.h"
+#include "shader.h"
class BarChart
{
@@ -17,23 +18,25 @@ public:
size_t width() const { return m_width; }
size_t height() const { return m_height; }
+ GLuint texture() const { return m_outTex; }
nod::signal<void(const arma::vec &)> valuesChanged;
- nod::signal<void(std::shared_ptr<const ColorScale>)> colorScaleChanged;
nod::signal<void(const std::vector<bool> &)> selectionChanged;
nod::signal<void(const std::vector<bool> &)> selectionInteractivelyChanged;
nod::signal<void(int, float)> itemBrushed;
nod::signal<void(int)> itemInteractivelyBrushed;
+ void setSize(size_t, size_t);
void setValues(const arma::vec &values);
void updateValues(const arma::vec &values);
- void setColorScale(std::shared_ptr<const ColorScale> scale);
+ void setColormap(GLuint texture);
void setSelection(const std::vector<bool> &selection);
void brushItem(int item);
void update();
+ void draw();
-protected:
+ // protected:
// QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *);
// void hoverEnterEvent(QHoverEvent *event);
@@ -45,6 +48,8 @@ protected:
// void mouseReleaseEvent(QMouseEvent *event);
private:
+ void updateBars();
+
// QSGNode *newSceneGraph() const;
// QSGNode *newBarNode() const;
// QSGNode *newSelectionBarNode() const;
@@ -53,6 +58,7 @@ private:
// void updateBarNodeGeom(QSGNode *barNode, float x, float width, float height) const;
// void updateBarNodeColor(QSGNode *barNode, const QColor &color) const;
// void updateBars(QSGNode *node) const;
+ bool m_redraw;
bool m_shouldUpdateBars;
// void updatePreSelection(QSGNode *node) const;
@@ -71,11 +77,13 @@ private:
int itemAt(float x, bool includeSelectorWidth = false) const;
+ size_t m_width, m_height;
+ GLuint m_FBO, m_VAO, m_VBO, m_colormapTex, m_outTex;
+ std::unique_ptr<Shader> m_shader;
+
arma::vec m_values;
- std::shared_ptr<const ColorScale> m_colorScale;
std::vector<int> m_originalIndices, m_currentIndices;
LinearScale<float> m_scale;
- size_t m_width, m_height;
};
#endif // BARCHART_H
diff --git a/main.cpp b/main.cpp
index 39aa830..b9209a8 100644
--- a/main.cpp
+++ b/main.cpp
@@ -57,7 +57,8 @@ static const int MAX_ELEMENT_MEMORY = 128 * 1024;
static const int RNG_SEED = 123;
static const int WINDOW_WIDTH = 1000;
static const int WINDOW_HEIGHT = 800;
-
+static const size_t PLOT_WIDTH = 512;
+static const size_t PLOT_HEIGHT = 512;
static const std::vector<std::string> COLORMAP_NAMES{
"Categorical",
@@ -415,6 +416,7 @@ public:
cpColormap->setColorScale(colorScaleCPs);
// bundlePlot->setColorScale(colorScaleCPs);
cpPlot->update();
+ cpBarChart->update();
}
void setRPColorScale(ColorScaleType colorScaleType) {
@@ -428,10 +430,10 @@ public:
colorScaleRPs = getColorScale(colorScaleType);
colorScaleRPs->setExtents(min, max);
- // rpBarChart->setColorScale(colorScaleRPs);
rpColormap->setColorScale(colorScaleRPs);
rpPlot->update();
splat->update();
+ rpBarChart->update();
}
// Pointers to visual components whose values are set in the main() function
@@ -655,13 +657,13 @@ int main(int argc, char *argv[])
glfwGetWindowSize(win, &width, &height);
glfwGetFramebufferSize(win, &display_width, &display_height);
- GLFWmonitor* primary = glfwGetPrimaryMonitor();
+ GLFWmonitor *primary = glfwGetPrimaryMonitor();
float xscale, yscale;
glfwGetMonitorContentScale(primary, &xscale, &yscale);
std::cout << "glfw: Detected scaling: "
<< xscale << "x" << yscale
<< std::endl;
- const GLFWvidmode * mode = glfwGetVideoMode(primary);
+ const GLFWvidmode *mode = glfwGetVideoMode(primary);
std::cout << "glfw: Detected resolution: "
<< mode->width << "x" << mode->height
<< std::endl;
@@ -721,13 +723,17 @@ int main(int argc, char *argv[])
// rpColormap.setOrientation(Colormap::Vertical);
Scatterplot cpPlot, rpPlot;
VoronoiSplat splat;
- cpPlot.setSize(512, 512);
- rpPlot.setSize(512, 512);
+ cpPlot.setSize(PLOT_WIDTH, PLOT_HEIGHT);
+ rpPlot.setSize(PLOT_WIDTH, PLOT_HEIGHT);
rpPlot.setGlyphSize(3.0f);
rpPlot.setColormap(rpColormap.texture());
- splat.setSize(512, 512);
+ splat.setSize(PLOT_WIDTH, PLOT_HEIGHT);
splat.setColormap(rpColormap.texture());
BarChart cpBarChart, rpBarChart;
+ cpBarChart.setSize(PLOT_WIDTH, 60);
+ cpBarChart.setColormap(cpColormap.texture());
+ rpBarChart.setSize(PLOT_WIDTH, 60);
+ rpBarChart.setColormap(rpColormap.texture());
m.cpPlot = &cpPlot;
m.rpPlot = &rpPlot;
m.splat = &splat;
@@ -934,11 +940,11 @@ int main(int argc, char *argv[])
// setColorData, so we just call it here
cpPlot.setColorData(v);
});
- history.rpValuesChanged.connect(
- std::bind(&VoronoiSplat::setValues, &splat, std::placeholders::_1));
history.cpValuesChanged.connect(
std::bind(&BarChart::setValues, &cpBarChart, std::placeholders::_1));
history.rpValuesChanged.connect(
+ std::bind(&VoronoiSplat::setValues, &splat, std::placeholders::_1));
+ history.rpValuesChanged.connect(
std::bind(&BarChart::setValues, &rpBarChart, std::placeholders::_1));
// ProjectionHistory takes special care of separate CP/RP selections
@@ -1006,6 +1012,8 @@ int main(int argc, char *argv[])
struct nk_image splat_img = nk_image_id((int) splat.texture());
struct nk_image cpColormap_img = nk_image_id((int) cpColormap.texture());
struct nk_image rpColormap_img = nk_image_id((int) rpColormap.texture());
+ struct nk_image cpBarChart_img = nk_image_id((int) cpBarChart.texture());
+ struct nk_image rpBarChart_img = nk_image_id((int) rpBarChart.texture());
while (!glfwWindowShouldClose(win)) {
struct nk_vec2 scale;
glfwGetWindowSize(win, &width, &height);
@@ -1114,10 +1122,15 @@ int main(int argc, char *argv[])
nk_combo_end(&ctx);
}
nk_layout_row_end(&ctx);
+
+ nk_layout_row_dynamic(&ctx, 10, 1);
+ nk_spacer(&ctx);
+ nk_layout_row_dynamic(&ctx, 10, 1);
+ nk_image(&ctx, cpColormap_img);
}
nk_end(&ctx);
- if (nk_begin(&ctx, "Regular points", nk_rect(550, 340, 350, 400),
+ if (nk_begin(&ctx, "Regular points", nk_rect(550, 340, 350, 410),
NK_WINDOW_BORDER | NK_WINDOW_TITLE)) {
ui_header(&ctx, &media, "Splat");
nk_layout_row_dynamic(&ctx, 30, 1);
@@ -1194,6 +1207,11 @@ int main(int argc, char *argv[])
nk_combo_end(&ctx);
}
nk_layout_row_end(&ctx);
+
+ nk_layout_row_dynamic(&ctx, 10, 1);
+ nk_spacer(&ctx);
+ nk_layout_row_dynamic(&ctx, 10, 1);
+ nk_image(&ctx, rpColormap_img);
}
nk_end(&ctx);
@@ -1201,14 +1219,14 @@ int main(int argc, char *argv[])
nk_style_push_color(&ctx, &s->window.background, nk_rgba(0, 0, 0, 0));
nk_style_push_style_item(&ctx, &s->window.fixed_background,
nk_style_item_color(nk_rgba(0,0,0,0)));
- if (nk_begin(&ctx, "Scatterplot", nk_rect(20, 20, splat.width(), splat.height()),
+ if (nk_begin(&ctx, "Scatterplot", nk_rect(20, 20, PLOT_WIDTH, PLOT_HEIGHT),
NK_WINDOW_NO_SCROLLBAR)) {
// Render components to their textures
splat.draw();
rpPlot.draw();
cpPlot.draw();
- nk_layout_space_begin(&ctx, NK_STATIC, splat.height(), 4);
+ nk_layout_space_begin(&ctx, NK_STATIC, PLOT_HEIGHT, 4);
struct nk_rect region = nk_layout_space_bounds(&ctx);
// Add white background rect and draw textures on top
@@ -1218,8 +1236,8 @@ int main(int argc, char *argv[])
// Rest uses custom region
region.x = region.y = 0.0f;
- region.w = static_cast<float>(splat.width());
- region.h = static_cast<float>(splat.height());
+ region.w = static_cast<float>(PLOT_WIDTH);
+ region.h = static_cast<float>(PLOT_HEIGHT);
nk_layout_space_push(&ctx, region);
nk_image(&ctx, splat_img);
nk_layout_space_push(&ctx, region);
@@ -1232,16 +1250,19 @@ int main(int argc, char *argv[])
nk_style_pop_color(&ctx);
nk_style_pop_style_item(&ctx);
- if (nk_begin(&ctx, "Colormap", nk_rect(20, 40 + splat.height(), splat.width(), 120),
+ if (nk_begin(&ctx, "Values", nk_rect(20, 40 + PLOT_HEIGHT, PLOT_WIDTH, 220),
NK_WINDOW_BORDER | NK_WINDOW_TITLE | NK_WINDOW_NO_SCROLLBAR)) {
+ cpBarChart.draw();
+ rpBarChart.draw();
+
// nk_widget(&bounds, &ctx);
ui_header(&ctx, &media, "Control points");
- nk_layout_row_dynamic(&ctx, 10, 1);
- nk_image(&ctx, cpColormap_img);
+ nk_layout_row_dynamic(&ctx, cpBarChart.height(), 1);
+ nk_image(&ctx, cpBarChart_img);
ui_header(&ctx, &media, "Regular points");
- nk_layout_row_dynamic(&ctx, 10, 1);
- nk_image(&ctx, rpColormap_img);
+ nk_layout_row_dynamic(&ctx, rpBarChart.height(), 1);
+ nk_image(&ctx, rpBarChart_img);
}
nk_end(&ctx);
diff --git a/manifest.scm b/manifest.scm
index 83035ed..22c6a6f 100644
--- a/manifest.scm
+++ b/manifest.scm
@@ -2,24 +2,42 @@
(gnu packages cmake)
(gnu packages commencement)
(gnu packages cpp)
+ (gnu packages freedesktop)
(gnu packages gdb)
(gnu packages gl)
+ (gnu packages kde-frameworks)
(gnu packages maths)
(gnu packages pkg-config)
(gnu packages xdisorg)
(gnu packages xorg))
+(define glfw-wayland
+ (package
+ (inherit glfw)
+ (arguments
+ '(#:tests? #f ; no test target
+ #:configure-flags '("-DBUILD_SHARED_LIBS=ON"
+ "-DGLFW_USE_WAYLAND=1")))
+ (propagated-inputs
+ (list mesa
+ extra-cmake-modules
+ egl-wayland
+ libxkbcommon
+ pkg-config
+ wayland
+ wayland-protocols))))
+
(packages->manifest
(list
armadillo
ccls
cmake
- egl-wayland
+ ;egl-wayland
gcc-toolchain
gdb
glew
- glfw
+ glfw-wayland
gnu-make
libxkbcommon
- mesa
+ ;mesa
pkg-config))
diff --git a/scatterplot.cpp b/scatterplot.cpp
index 64859b3..d27b295 100644
--- a/scatterplot.cpp
+++ b/scatterplot.cpp
@@ -57,7 +57,6 @@ vec3 getRGB(float value) {
void main()
{
vs_out.color = vec4(mix(vec3(1.0), getRGB(value), colormask), 1.0);
- // vs_out.color = vec4(1.0);
gl_Position = transform * vec4(pos.xy, 0.0, 1.0);
}
)EOF";
@@ -404,6 +403,7 @@ void Scatterplot::draw()
if (!m_redraw) {
return;
}
+ m_redraw = false;
int originalFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originalFBO);
@@ -464,7 +464,6 @@ void Scatterplot::draw()
*/
glBindFramebuffer(GL_FRAMEBUFFER, originalFBO);
- m_redraw = false;
}
/*
diff --git a/voronoisplat.cpp b/voronoisplat.cpp
index 749ec42..e4a42cf 100644
--- a/voronoisplat.cpp
+++ b/voronoisplat.cpp
@@ -98,8 +98,6 @@ void main() {
vec2 point = gl_PointCoord - vec2(0.5, 0.5);
float d2 = dot(point, point);
float radius = rad_max + rad_blur;
- // float r = 2.0 * distance(gl_PointCoord, vec2(0.5, 0.5)) * radius;
- // float r2 = r * r;
float r2 = 4.0 * d2 * radius * radius;
float dt_blur = dt + rad_blur;
float dt_blur2 = dt_blur * dt_blur;
@@ -110,7 +108,6 @@ void main() {
fragColor = vec4(w * value, w, 0.0, 0.0);
}
}
- // fragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
)EOF";
@@ -448,6 +445,7 @@ void VoronoiSplat::draw()
if (!m_redraw) {
return;
}
+ m_redraw = false;
int originalFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originalFBO);
@@ -519,7 +517,6 @@ void VoronoiSplat::draw()
*/
glBindFramebuffer(GL_FRAMEBUFFER, originalFBO);
- m_redraw = false;
}
// ----------------------------------------------------------------------------