diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | barchart.cpp | 211 | ||||
-rw-r--r-- | barchart.h | 20 | ||||
-rw-r--r-- | main.cpp | 59 | ||||
-rw-r--r-- | manifest.scm | 24 | ||||
-rw-r--r-- | scatterplot.cpp | 3 | ||||
-rw-r--r-- | voronoisplat.cpp | 5 |
7 files changed, 273 insertions, 53 deletions
@@ -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 { @@ -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 @@ -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; } // ---------------------------------------------------------------------------- |