diff options
Diffstat (limited to 'barchart.cpp')
-rw-r--r-- | barchart.cpp | 211 |
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 { |