aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergiusz Bazanski <q3k@q3k.org>2018-07-27 01:21:50 +0100
committerSergiusz Bazanski <q3k@q3k.org>2018-07-27 01:21:50 +0100
commit0eb40da749d22a8bb74306d38c090a85258015e9 (patch)
tree7b39dfc0333575b7dd0b34fc957cd5c3376b478a
parent48713be0eb8876fdb1ddfce323d59efbac2c8785 (diff)
downloadnextpnr-0eb40da749d22a8bb74306d38c090a85258015e9.tar.gz
nextpnr-0eb40da749d22a8bb74306d38c090a85258015e9.tar.bz2
nextpnr-0eb40da749d22a8bb74306d38c090a85258015e9.zip
gui: implement zoom to outbounds
-rw-r--r--gui/fpgaviewwidget.cc106
-rw-r--r--gui/fpgaviewwidget.h57
2 files changed, 128 insertions, 35 deletions
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc
index 46008ece..7e7b6e4f 100644
--- a/gui/fpgaviewwidget.cc
+++ b/gui/fpgaviewwidget.cc
@@ -33,9 +33,9 @@ NEXTPNR_NAMESPACE_BEGIN
FPGAViewWidget::FPGAViewWidget(QWidget *parent) :
QOpenGLWidget(parent), ctx_(nullptr), paintTimer_(this),
- lineShader_(this), zoom_(500.0f),
- rendererData_(new FPGAViewWidget::RendererData),
- rendererArgs_(new FPGAViewWidget::RendererArgs)
+ lineShader_(this), zoom_(10.0f),
+ rendererArgs_(new FPGAViewWidget::RendererArgs),
+ rendererData_(new FPGAViewWidget::RendererData)
{
colors_.background = QColor("#000000");
colors_.grid = QColor("#333");
@@ -55,6 +55,7 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) :
colors_.highlight[7] = QColor("#da70d6");
rendererArgs_->changed = false;
+ rendererArgs_->flags.zoomOutbound = true;
auto fmt = format();
fmt.setMajorVersion(3);
@@ -87,6 +88,10 @@ void FPGAViewWidget::newContext(Context *ctx)
onSelectedArchItem(std::vector<DecalXY>());
for (int i = 0; i < 8; i++)
onHighlightGroupChanged(std::vector<DecalXY>(), i);
+ {
+ QMutexLocker lock(&rendererArgsLock_);
+ rendererArgs_->flags.zoomOutbound = true;
+ }
pokeRenderer();
}
@@ -258,8 +263,7 @@ QMatrix4x4 FPGAViewWidget::getProjection(void)
QMatrix4x4 matrix;
const float aspect = float(width()) / float(height());
- matrix.perspective(3.14 / 2, aspect, zoomNear_, zoomFar_);
- matrix.translate(0.0f, 0.0f, -zoom_);
+ matrix.perspective(90, aspect, zoomNear_, zoomFar_);
return matrix;
}
@@ -271,6 +275,7 @@ void FPGAViewWidget::paintGL()
gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 matrix = getProjection();
+ matrix.translate(0.0f, 0.0f, -zoom_);
matrix *= viewMove_;
@@ -285,6 +290,8 @@ void FPGAViewWidget::paintGL()
PolyLine(-100.0f, i, 100.0f, i).build(grid);
PolyLine(i, -100.0f, i, 100.0f).build(grid);
}
+ // Flags from pipeline.
+ PassthroughFlags flags;
// Draw grid.
lineShader_.draw(grid, colors_.grid, thick1Px, matrix);
@@ -303,6 +310,18 @@ void FPGAViewWidget::paintGL()
lineShader_.draw(rendererData_->gfxSelected, colors_.selected, thick11Px, matrix);
lineShader_.draw(rendererData_->gfxHovered, colors_.hovered, thick2Px, matrix);
+
+ flags = rendererData_->flags;
+ }
+
+ {
+ QMutexLocker locker(&rendererArgsLock_);
+ rendererArgs_->flags.clear();
+ }
+
+ // Check flags passed through pipeline.
+ if (flags.zoomOutbound) {
+ zoomOutbound();
}
}
@@ -374,15 +393,21 @@ void FPGAViewWidget::renderLines(void)
DecalXY hoveredDecal;
std::vector<DecalXY> highlightedDecals[8];
bool highlightedOrSelectedChanged;
+ PassthroughFlags flags;
{
// Take the renderer arguments lock, copy over all we need.
QMutexLocker lock(&rendererArgsLock_);
+
selectedDecals = rendererArgs_->selectedDecals;
hoveredDecal = rendererArgs_->hoveredDecal;
+
for (int i = 0; i < 8; i++)
highlightedDecals[i] = rendererArgs_->highlightedDecals[i];
+
highlightedOrSelectedChanged = rendererArgs_->changed;
rendererArgs_->changed = false;
+
+ flags = rendererArgs_->flags;
}
@@ -444,7 +469,7 @@ void FPGAViewWidget::renderLines(void)
for (int i = 0; i < 8; i++)
data->gfxHighlighted[i] = rendererData_->gfxHighlighted[i];
}
-
+
rendererData_ = std::move(data);
}
}
@@ -476,6 +501,11 @@ void FPGAViewWidget::renderLines(void)
}
}
}
+
+ {
+ QMutexLocker locker(&rendererDataLock_);
+ rendererData_->flags = flags;
+ }
}
void FPGAViewWidget::onSelectedArchItem(std::vector<DecalXY> decals)
@@ -601,20 +631,29 @@ QVector4D FPGAViewWidget::mouseToWorldCoordinates(int x, int y)
QMatrix4x4 vp;
vp.viewport(0, 0, width() * retinaScale, height() * retinaScale);
- QVector4D vec(x, y, 0, 1);
+ QVector4D vec(x, y, 1, 1);
vec = vp.inverted() * vec;
- vec = projection.inverted() * vec;
+ vec = projection.inverted() * QVector4D(vec.x(), vec.y(), -1, 1);
+
+ // Hic sunt dracones.
+ // TODO(q3k): grab a book, remind yourselfl linear algebra and undo this
+ // operation properly.
+ QVector3D ray = vec.toVector3DAffine();
+ ray.normalize();
+ ray.setX((ray.x()/-ray.z()) * zoom_);
+ ray.setY((ray.y()/ray.z()) * zoom_);
+ ray.setZ(1.0);
- auto ray = vec.toVector3DAffine();
- auto world = QVector4D(ray.x()*ray.z(), -ray.y()*ray.z(), 0, 1);
- world = viewMove_.inverted() * world;
+ vec = viewMove_.inverted() * QVector4D(ray.x(), ray.y(), ray.z(), 1.0);
+ vec.setZ(0);
- return world;
+ return vec;
}
QVector4D FPGAViewWidget::mouseToWorldDimensions(float x, float y)
{
QMatrix4x4 p = getProjection();
+ p.translate(0.0f, 0.0f, -zoom_);
QVector2D unit = p.map(QVector4D(1, 1, 0, 1)).toVector2DAffine();
float sx = (((float)x) / (width() / 2));
@@ -632,17 +671,19 @@ void FPGAViewWidget::wheelEvent(QWheelEvent *event)
void FPGAViewWidget::zoom(int level)
{
- if (zoom_ < zoomNear_) {
- zoom_ = zoomNear_;
- } else if (zoom_ < zoomLvl1_) {
- zoom_ -= level / 10.0;
+ if (zoom_ < zoomLvl1_) {
+ zoom_ -= level / 500.0;
} else if (zoom_ < zoomLvl2_) {
- zoom_ -= level / 5.0;
- } else if (zoom_ < zoomFar_) {
- zoom_ -= level;
+ zoom_ -= level / 100.0;
} else {
- zoom_ = zoomFar_;
+ zoom_ -= level / 10.0;
+
}
+
+ if (zoom_ < zoomNear_)
+ zoom_ = zoomNear_;
+ else if (zoom_ > zoomFar_)
+ zoom_ = zoomFar_;
update();
}
@@ -652,6 +693,29 @@ void FPGAViewWidget::zoomOut() { zoom(-10); }
void FPGAViewWidget::zoomSelected() {}
-void FPGAViewWidget::zoomOutbound() {}
+void FPGAViewWidget::zoomOutbound()
+{
+ // Get design bounding box.
+ float x0, y0, x1, y1;
+ {
+ QMutexLocker lock(&rendererDataLock_);
+ x0 = rendererData_->bbX0;
+ y0 = rendererData_->bbY0;
+ x1 = rendererData_->bbX1;
+ y1 = rendererData_->bbY1;
+ }
+ float w = x1 - x0;
+ float h = y1 - y0;
+
+ viewMove_.setToIdentity();
+ viewMove_.translate(-w/2, -h/2);
+
+ // Our FOV is π/2, so distance for camera to see a plane of width H is H/2.
+ // We add 1 unit to cover half a unit of extra space around.
+ float distance_w = w/2 + 1;
+ float distance_h = h/2 + 1;
+ zoom_ = std::max(distance_w, distance_h);
+ update();
+}
NEXTPNR_NAMESPACE_END
diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h
index b1eda33a..067f3b7f 100644
--- a/gui/fpgaviewwidget.h
+++ b/gui/fpgaviewwidget.h
@@ -124,10 +124,10 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
void clickedWire(WireId wire);
private:
- const float zoomNear_ = 1.0f; // do not zoom closer than this
- const float zoomFar_ = 10000.0f; // do not zoom further than this
- const float zoomLvl1_ = 100.0f;
- const float zoomLvl2_ = 50.0f;
+ const float zoomNear_ = 0.1f; // do not zoom closer than this
+ const float zoomFar_ = 100.0f; // do not zoom further than this
+ const float zoomLvl1_ = 1.0f;
+ const float zoomLvl2_ = 5.0f;
struct PickedElement {
ElementType type;
@@ -195,6 +195,43 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
QColor highlight[8];
} colors_;
+ // Flags that are passed through from renderer arguments to renderer data.
+ // These are used by the UI code to signal events that will only fire when
+ // the next frame gets rendered.
+ struct PassthroughFlags
+ {
+ bool zoomOutbound;
+
+ PassthroughFlags() :
+ zoomOutbound(false) {}
+ PassthroughFlags &operator=(const PassthroughFlags &other) noexcept {
+ zoomOutbound = other.zoomOutbound;
+ return *this;
+ }
+
+ void clear()
+ {
+ zoomOutbound = false;
+ }
+ };
+
+ struct RendererArgs
+ {
+ // Decals that he user selected.
+ std::vector<DecalXY> selectedDecals;
+ // Decals that the user highlighted.
+ std::vector<DecalXY> highlightedDecals[8];
+ // Decals that the user's mouse is hovering in.
+ DecalXY hoveredDecal;
+ // Whether to render the above three or skip it.
+ bool changed;
+
+ // Flags to pass back into the RendererData.
+ PassthroughFlags flags;
+ };
+ std::unique_ptr<RendererArgs> rendererArgs_;
+ QMutex rendererArgsLock_;
+
struct RendererData
{
LineShaderData gfxByStyle[GraphicElement::STYLE_MAX];
@@ -205,20 +242,12 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
float bbX0, bbY0, bbX1, bbY1;
// Quadtree for picking objects.
std::unique_ptr<PickQuadTree> qt;
+ // Flags from args.
+ PassthroughFlags flags;
};
std::unique_ptr<RendererData> rendererData_;
QMutex rendererDataLock_;
- struct RendererArgs
- {
- std::vector<DecalXY> selectedDecals;
- std::vector<DecalXY> highlightedDecals[8];
- DecalXY hoveredDecal;
- bool changed;
- };
- std::unique_ptr<RendererArgs> rendererArgs_;
- QMutex rendererArgsLock_;
-
void zoom(int level);
void renderLines(void);
void renderGraphicElement(RendererData *data, LineShaderData &out, const GraphicElement &el, float x, float y);