aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--voronoisplat.cpp104
-rw-r--r--voronoisplat.h12
2 files changed, 87 insertions, 29 deletions
diff --git a/voronoisplat.cpp b/voronoisplat.cpp
index 910f17f..1b3f462 100644
--- a/voronoisplat.cpp
+++ b/voronoisplat.cpp
@@ -8,7 +8,6 @@
#include <QOpenGLVertexArrayObject>
#include "colormap.h"
-#include "scale.h"
#include "scatterplot.h"
#include "skelft.h"
@@ -27,6 +26,8 @@ static int nextPow2(int n)
VoronoiSplat::VoronoiSplat(QQuickItem *parent)
: QQuickFramebufferObject(parent)
+ , m_sx(0.0f, 1.0f, 0.0f, 1.0f)
+ , m_sy(0.0f, 1.0f, 0.0f, 1.0f)
, m_alpha(DEFAULT_ALPHA)
, m_beta(DEFAULT_BETA)
{
@@ -46,23 +47,16 @@ void VoronoiSplat::setSites(const arma::mat &points)
}
// Copy 'points' to internal data structure(s)
- double minX = points.col(0).min();
- double maxX = points.col(0).max();
- double minY = points.col(1).min();
- double maxY = points.col(1).max();
-
// Coords are packed into 'm_sites' as [ x1, y1, x2, y2, ... ]
m_sites.resize(2*points.n_rows);
- LinearScale<float> sx(minX, maxX, Scatterplot::PADDING, width() - Scatterplot::PADDING);
const double *col = points.colptr(0);
for (unsigned i = 0; i < points.n_rows; i++) {
- m_sites[2*i] = sx(col[i]);
+ m_sites[2*i] = col[i];
}
col = points.colptr(1);
- LinearScale<float> sy(minY, maxY, height() - Scatterplot::PADDING, Scatterplot::PADDING);
for (unsigned i = 0; i < points.n_rows; i++) {
- m_sites[2*i + 1] = sy(col[i]);
+ m_sites[2*i + 1] = col[i];
}
setSitesChanged(true);
@@ -95,15 +89,26 @@ void VoronoiSplat::setColorScale(const ColorScale &scale)
update();
}
+void VoronoiSplat::setScale(const LinearScale<float> &sx,
+ const LinearScale<float> &sy)
+{
+ m_sx = sx;
+ m_sy = sy;
+ emit scaleChanged(m_sx, m_sy);
+ update();
+}
+
void VoronoiSplat::setAlpha(float alpha)
{
m_alpha = alpha;
+ emit alphaChanged(m_alpha);
update();
}
void VoronoiSplat::setBeta(float beta)
{
m_beta = beta;
+ emit betaChanged(m_beta);
update();
}
@@ -131,11 +136,14 @@ private:
void updateSites();
void updateValues();
void updateColorScale();
+ void updateTransform();
void computeDT();
QSize m_size;
const std::vector<float> *m_sites, *m_values, *m_cmap;
float m_alpha, m_beta;
+ GLfloat m_transform[4][4];
+ LinearScale<float> m_sx, m_sy;
QQuickWindow *m_window; // used to reset OpenGL state (as per docs)
QOpenGLFunctions gl;
@@ -153,8 +161,18 @@ QQuickFramebufferObject::Renderer *VoronoiSplat::createRenderer() const
}
VoronoiSplatRenderer::VoronoiSplatRenderer()
- : gl(QOpenGLContext::currentContext())
+ : m_transform{
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 1.0f },
+ }
+ , m_sx(0.0f, 1.0f, 0.0f, 1.0f)
+ , m_sy(0.0f, 1.0f, 0.0f, 1.0f)
+ , gl(QOpenGLContext::currentContext())
{
+ m_transform[3][3] = 1.0f;
+
gl.glGenFramebuffers(1, &m_FBO);
setupShaders();
@@ -170,7 +188,7 @@ R"EOF(#version 440
uniform float rad_blur;
uniform float rad_max;
-uniform float fb_size;
+uniform mat4 transform;
in vec2 vert;
in float scalar;
@@ -178,8 +196,8 @@ in float scalar;
out float value;
void main() {
- gl_PointSize = (rad_max + rad_blur) * 2.0;
- gl_Position = vec4(2.0 * vert / fb_size - 1.0, 0, 1.0);
+ gl_PointSize = 2.0 * (rad_max + rad_blur);
+ gl_Position = transform * vec4(vert, 0.0, 1.0);
value = scalar;
}
)EOF");
@@ -199,7 +217,7 @@ void main() {
if (dt > rad_max)
discard;
else {
- float r = distance(gl_PointCoord, vec2(0.5, 0.5)) * (rad_max + rad_blur) * 2.0;
+ float r = 2.0 * distance(gl_PointCoord, vec2(0.5, 0.5)) * (rad_max + rad_blur);
float r2 = r * r;
float rad = dt + rad_blur;
float rad2 = rad * rad;
@@ -221,7 +239,7 @@ R"EOF(#version 440
in vec2 vert;
void main() {
- gl_Position = vec4(vert, 0, 1);
+ gl_Position = vec4(vert, 0.0, 1.0);
}
)EOF");
m_program2->addShaderFromSourceCode(QOpenGLShader::Fragment,
@@ -274,8 +292,8 @@ void VoronoiSplatRenderer::setupVAOs()
// 2ndPassVAO: VBO 2 is a quad mapping the final texture to the framebuffer
m_2ndPassVAO.create();
m_2ndPassVAO.bind();
- GLfloat verts[] = {-1.0f, -1.0f, -1.0f, 1.0f,
- 1.0f, -1.0f, 1.0f, 1.0f};
+ GLfloat verts[] = { -1.0f, -1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f, 1.0f };
gl.glBindBuffer(GL_ARRAY_BUFFER, m_VBOs[2]);
gl.glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
vertAttrib = m_program2->attributeLocation("vert");
@@ -357,7 +375,7 @@ void VoronoiSplatRenderer::render()
m_program1->bind();
m_program1->setUniformValue("rad_max", m_beta);
m_program1->setUniformValue("rad_blur", m_alpha);
- m_program1->setUniformValue("fb_size", float(m_size.width()));
+ m_program1->setUniformValue("transform", m_transform);
gl.glActiveTexture(GL_TEXTURE0);
gl.glBindTexture(GL_TEXTURE_2D, m_textures[0]);
@@ -429,12 +447,39 @@ void VoronoiSplatRenderer::synchronize(QQuickFramebufferObject *item)
splat->setValuesChanged(false);
splat->setColorScaleChanged(false);
- m_alpha = splat->alpha();
- m_beta = splat->beta();
- m_sites = &(splat->sites());
- m_values = &(splat->values());
- m_cmap = &(splat->colorScale());
- m_window = splat->window();
+ m_sites = &(splat->sites());
+ m_values = &(splat->values());
+ m_cmap = &(splat->colorScale());
+ m_sx = splat->scaleX();
+ m_sy = splat->scaleY();
+ m_alpha = splat->alpha();
+ m_beta = splat->beta();
+ m_window = splat->window();
+}
+
+void VoronoiSplatRenderer::updateTransform()
+{
+ GLfloat w = m_size.width(), h = m_size.height();
+
+ GLfloat rangeOffset = Scatterplot::PADDING / w;
+ m_sx.setRange(rangeOffset, 1.0f - rangeOffset);
+ GLfloat sx = 2.0f * m_sx.slope();
+ GLfloat tx = 2.0f * m_sx.offset() - 1.0f;
+
+ rangeOffset = Scatterplot::PADDING / h;
+ m_sy.setRange(1.0f - rangeOffset, rangeOffset);
+ GLfloat sy = 2.0f * m_sy.slope();
+ GLfloat ty = 2.0f * m_sy.offset() - 1.0f;
+
+ // The transform matrix should be this (but transposed -- column major):
+ // [ sx 0.0f 0.0f -tx ]
+ // [ 0.0f sy 0.0f -ty ]
+ // [ 0.0f 0.0f 0.0f 0.0f ]
+ // [ 0.0f 0.0f 0.0f 1.0f ]
+ m_transform[0][0] = sx;
+ m_transform[1][1] = sy;
+ m_transform[3][0] = tx;
+ m_transform[3][1] = ty;
}
void VoronoiSplatRenderer::updateSites()
@@ -446,6 +491,9 @@ void VoronoiSplatRenderer::updateSites()
// Compute DT values for the new positions
computeDT();
+ // Update transform used when drawing sites
+ updateTransform();
+
m_sitesChanged = false;
}
@@ -472,10 +520,12 @@ void VoronoiSplatRenderer::computeDT()
int w = m_size.width(), h = m_size.height();
// Compute FT of the sites
- std::vector<float> buf(w*h);
+ m_sx.setRange(Scatterplot::PADDING, w - Scatterplot::PADDING);
+ m_sy.setRange(h - Scatterplot::PADDING, Scatterplot::PADDING);
const std::vector<float> &sites = *m_sites;
+ std::vector<float> buf(w*h);
for (unsigned i = 0; i < sites.size(); i += 2) {
- buf[int(sites[i + 1])*h + int(sites[i])] = i/2.0f + 1.0f;
+ buf[int(m_sy(sites[i + 1]))*h + int(m_sx(sites[i]))] = i/2.0f + 1.0f;
}
skelft2DFT(0, buf.data(), 0, 0, w, h, w);
diff --git a/voronoisplat.h b/voronoisplat.h
index 6682fed..21d2fb9 100644
--- a/voronoisplat.h
+++ b/voronoisplat.h
@@ -6,6 +6,7 @@
#include <armadillo>
#include "colorscale.h"
+#include "scale.h"
class VoronoiSplat
: public QQuickFramebufferObject
@@ -19,8 +20,10 @@ public:
const std::vector<float> &sites() const { return m_sites; }
const std::vector<float> &values() const { return m_values; }
const std::vector<float> &colorScale() const { return m_cmap; }
- Q_INVOKABLE float alpha() const { return m_alpha; }
- Q_INVOKABLE float beta() const { return m_beta; }
+ LinearScale<float> scaleX() const { return m_sx; }
+ LinearScale<float> scaleY() const { return m_sy; }
+ Q_INVOKABLE float alpha() const { return m_alpha; }
+ Q_INVOKABLE float beta() const { return m_beta; }
bool sitesChanged() const { return m_sitesChanged; }
bool valuesChanged() const { return m_valuesChanged; }
@@ -40,7 +43,9 @@ signals:
void sitesChanged(const arma::mat &sites) const;
void valuesChanged(const arma::vec &values) const;
void colorScaleChanged(const ColorScale &scale) const;
+ void scaleChanged(const LinearScale<float> &sx, const LinearScale<float> &sy) const;
void alphaChanged(float alpha) const;
+ void betaChanged(float alpha) const;
public slots:
// 'points' should be a 2D points matrix (each point in a row)
@@ -52,6 +57,8 @@ public slots:
// Set colorScale data based on the given color scale
void setColorScale(const ColorScale &scale);
+ void setScale(const LinearScale<float> &sx, const LinearScale<float> &sy);
+
// Shepard blur radius
Q_INVOKABLE void setAlpha(float alpha);
@@ -60,6 +67,7 @@ public slots:
private:
std::vector<float> m_sites, m_values, m_cmap;
+ LinearScale<float> m_sx, m_sy;
float m_alpha, m_beta;
bool m_sitesChanged, m_valuesChanged, m_colorScaleChanged;
};