aboutsummaryrefslogtreecommitdiff
path: root/barchart.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'barchart.cpp')
-rw-r--r--barchart.cpp211
1 files changed, 194 insertions, 17 deletions
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
{