gui: implement zoom to outbounds
This commit is contained in:
parent
48713be0eb
commit
0eb40da749
@ -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);
|
||||
|
||||
auto ray = vec.toVector3DAffine();
|
||||
auto world = QVector4D(ray.x()*ray.z(), -ray.y()*ray.z(), 0, 1);
|
||||
world = viewMove_.inverted() * world;
|
||||
// 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);
|
||||
|
||||
return world;
|
||||
vec = viewMove_.inverted() * QVector4D(ray.x(), ray.y(), ray.z(), 1.0);
|
||||
vec.setZ(0);
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user