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) :
|
FPGAViewWidget::FPGAViewWidget(QWidget *parent) :
|
||||||
QOpenGLWidget(parent), ctx_(nullptr), paintTimer_(this),
|
QOpenGLWidget(parent), ctx_(nullptr), paintTimer_(this),
|
||||||
lineShader_(this), zoom_(500.0f),
|
lineShader_(this), zoom_(10.0f),
|
||||||
rendererData_(new FPGAViewWidget::RendererData),
|
rendererArgs_(new FPGAViewWidget::RendererArgs),
|
||||||
rendererArgs_(new FPGAViewWidget::RendererArgs)
|
rendererData_(new FPGAViewWidget::RendererData)
|
||||||
{
|
{
|
||||||
colors_.background = QColor("#000000");
|
colors_.background = QColor("#000000");
|
||||||
colors_.grid = QColor("#333");
|
colors_.grid = QColor("#333");
|
||||||
@ -55,6 +55,7 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) :
|
|||||||
colors_.highlight[7] = QColor("#da70d6");
|
colors_.highlight[7] = QColor("#da70d6");
|
||||||
|
|
||||||
rendererArgs_->changed = false;
|
rendererArgs_->changed = false;
|
||||||
|
rendererArgs_->flags.zoomOutbound = true;
|
||||||
|
|
||||||
auto fmt = format();
|
auto fmt = format();
|
||||||
fmt.setMajorVersion(3);
|
fmt.setMajorVersion(3);
|
||||||
@ -87,6 +88,10 @@ void FPGAViewWidget::newContext(Context *ctx)
|
|||||||
onSelectedArchItem(std::vector<DecalXY>());
|
onSelectedArchItem(std::vector<DecalXY>());
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
onHighlightGroupChanged(std::vector<DecalXY>(), i);
|
onHighlightGroupChanged(std::vector<DecalXY>(), i);
|
||||||
|
{
|
||||||
|
QMutexLocker lock(&rendererArgsLock_);
|
||||||
|
rendererArgs_->flags.zoomOutbound = true;
|
||||||
|
}
|
||||||
pokeRenderer();
|
pokeRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,8 +263,7 @@ QMatrix4x4 FPGAViewWidget::getProjection(void)
|
|||||||
QMatrix4x4 matrix;
|
QMatrix4x4 matrix;
|
||||||
|
|
||||||
const float aspect = float(width()) / float(height());
|
const float aspect = float(width()) / float(height());
|
||||||
matrix.perspective(3.14 / 2, aspect, zoomNear_, zoomFar_);
|
matrix.perspective(90, aspect, zoomNear_, zoomFar_);
|
||||||
matrix.translate(0.0f, 0.0f, -zoom_);
|
|
||||||
return matrix;
|
return matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,6 +275,7 @@ void FPGAViewWidget::paintGL()
|
|||||||
gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
QMatrix4x4 matrix = getProjection();
|
QMatrix4x4 matrix = getProjection();
|
||||||
|
matrix.translate(0.0f, 0.0f, -zoom_);
|
||||||
|
|
||||||
matrix *= viewMove_;
|
matrix *= viewMove_;
|
||||||
|
|
||||||
@ -285,6 +290,8 @@ void FPGAViewWidget::paintGL()
|
|||||||
PolyLine(-100.0f, i, 100.0f, i).build(grid);
|
PolyLine(-100.0f, i, 100.0f, i).build(grid);
|
||||||
PolyLine(i, -100.0f, i, 100.0f).build(grid);
|
PolyLine(i, -100.0f, i, 100.0f).build(grid);
|
||||||
}
|
}
|
||||||
|
// Flags from pipeline.
|
||||||
|
PassthroughFlags flags;
|
||||||
// Draw grid.
|
// Draw grid.
|
||||||
lineShader_.draw(grid, colors_.grid, thick1Px, matrix);
|
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_->gfxSelected, colors_.selected, thick11Px, matrix);
|
||||||
lineShader_.draw(rendererData_->gfxHovered, colors_.hovered, thick2Px, 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;
|
DecalXY hoveredDecal;
|
||||||
std::vector<DecalXY> highlightedDecals[8];
|
std::vector<DecalXY> highlightedDecals[8];
|
||||||
bool highlightedOrSelectedChanged;
|
bool highlightedOrSelectedChanged;
|
||||||
|
PassthroughFlags flags;
|
||||||
{
|
{
|
||||||
// Take the renderer arguments lock, copy over all we need.
|
// Take the renderer arguments lock, copy over all we need.
|
||||||
QMutexLocker lock(&rendererArgsLock_);
|
QMutexLocker lock(&rendererArgsLock_);
|
||||||
|
|
||||||
selectedDecals = rendererArgs_->selectedDecals;
|
selectedDecals = rendererArgs_->selectedDecals;
|
||||||
hoveredDecal = rendererArgs_->hoveredDecal;
|
hoveredDecal = rendererArgs_->hoveredDecal;
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
highlightedDecals[i] = rendererArgs_->highlightedDecals[i];
|
highlightedDecals[i] = rendererArgs_->highlightedDecals[i];
|
||||||
|
|
||||||
highlightedOrSelectedChanged = rendererArgs_->changed;
|
highlightedOrSelectedChanged = rendererArgs_->changed;
|
||||||
rendererArgs_->changed = false;
|
rendererArgs_->changed = false;
|
||||||
|
|
||||||
|
flags = rendererArgs_->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -444,7 +469,7 @@ void FPGAViewWidget::renderLines(void)
|
|||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
data->gfxHighlighted[i] = rendererData_->gfxHighlighted[i];
|
data->gfxHighlighted[i] = rendererData_->gfxHighlighted[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
rendererData_ = std::move(data);
|
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)
|
void FPGAViewWidget::onSelectedArchItem(std::vector<DecalXY> decals)
|
||||||
@ -601,20 +631,29 @@ QVector4D FPGAViewWidget::mouseToWorldCoordinates(int x, int y)
|
|||||||
QMatrix4x4 vp;
|
QMatrix4x4 vp;
|
||||||
vp.viewport(0, 0, width() * retinaScale, height() * retinaScale);
|
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 = vp.inverted() * vec;
|
||||||
vec = projection.inverted() * vec;
|
vec = projection.inverted() * QVector4D(vec.x(), vec.y(), -1, 1);
|
||||||
|
|
||||||
auto ray = vec.toVector3DAffine();
|
// Hic sunt dracones.
|
||||||
auto world = QVector4D(ray.x()*ray.z(), -ray.y()*ray.z(), 0, 1);
|
// TODO(q3k): grab a book, remind yourselfl linear algebra and undo this
|
||||||
world = viewMove_.inverted() * world;
|
// 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)
|
QVector4D FPGAViewWidget::mouseToWorldDimensions(float x, float y)
|
||||||
{
|
{
|
||||||
QMatrix4x4 p = getProjection();
|
QMatrix4x4 p = getProjection();
|
||||||
|
p.translate(0.0f, 0.0f, -zoom_);
|
||||||
QVector2D unit = p.map(QVector4D(1, 1, 0, 1)).toVector2DAffine();
|
QVector2D unit = p.map(QVector4D(1, 1, 0, 1)).toVector2DAffine();
|
||||||
|
|
||||||
float sx = (((float)x) / (width() / 2));
|
float sx = (((float)x) / (width() / 2));
|
||||||
@ -632,17 +671,19 @@ void FPGAViewWidget::wheelEvent(QWheelEvent *event)
|
|||||||
|
|
||||||
void FPGAViewWidget::zoom(int level)
|
void FPGAViewWidget::zoom(int level)
|
||||||
{
|
{
|
||||||
if (zoom_ < zoomNear_) {
|
if (zoom_ < zoomLvl1_) {
|
||||||
zoom_ = zoomNear_;
|
zoom_ -= level / 500.0;
|
||||||
} else if (zoom_ < zoomLvl1_) {
|
|
||||||
zoom_ -= level / 10.0;
|
|
||||||
} else if (zoom_ < zoomLvl2_) {
|
} else if (zoom_ < zoomLvl2_) {
|
||||||
zoom_ -= level / 5.0;
|
zoom_ -= level / 100.0;
|
||||||
} else if (zoom_ < zoomFar_) {
|
|
||||||
zoom_ -= level;
|
|
||||||
} else {
|
} else {
|
||||||
zoom_ = zoomFar_;
|
zoom_ -= level / 10.0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (zoom_ < zoomNear_)
|
||||||
|
zoom_ = zoomNear_;
|
||||||
|
else if (zoom_ > zoomFar_)
|
||||||
|
zoom_ = zoomFar_;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,6 +693,29 @@ void FPGAViewWidget::zoomOut() { zoom(-10); }
|
|||||||
|
|
||||||
void FPGAViewWidget::zoomSelected() {}
|
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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -124,10 +124,10 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
|||||||
void clickedWire(WireId wire);
|
void clickedWire(WireId wire);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const float zoomNear_ = 1.0f; // do not zoom closer than this
|
const float zoomNear_ = 0.1f; // do not zoom closer than this
|
||||||
const float zoomFar_ = 10000.0f; // do not zoom further than this
|
const float zoomFar_ = 100.0f; // do not zoom further than this
|
||||||
const float zoomLvl1_ = 100.0f;
|
const float zoomLvl1_ = 1.0f;
|
||||||
const float zoomLvl2_ = 50.0f;
|
const float zoomLvl2_ = 5.0f;
|
||||||
|
|
||||||
struct PickedElement {
|
struct PickedElement {
|
||||||
ElementType type;
|
ElementType type;
|
||||||
@ -195,6 +195,43 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
|||||||
QColor highlight[8];
|
QColor highlight[8];
|
||||||
} colors_;
|
} 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
|
struct RendererData
|
||||||
{
|
{
|
||||||
LineShaderData gfxByStyle[GraphicElement::STYLE_MAX];
|
LineShaderData gfxByStyle[GraphicElement::STYLE_MAX];
|
||||||
@ -205,20 +242,12 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
|||||||
float bbX0, bbY0, bbX1, bbY1;
|
float bbX0, bbY0, bbX1, bbY1;
|
||||||
// Quadtree for picking objects.
|
// Quadtree for picking objects.
|
||||||
std::unique_ptr<PickQuadTree> qt;
|
std::unique_ptr<PickQuadTree> qt;
|
||||||
|
// Flags from args.
|
||||||
|
PassthroughFlags flags;
|
||||||
};
|
};
|
||||||
std::unique_ptr<RendererData> rendererData_;
|
std::unique_ptr<RendererData> rendererData_;
|
||||||
QMutex rendererDataLock_;
|
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 zoom(int level);
|
||||||
void renderLines(void);
|
void renderLines(void);
|
||||||
void renderGraphicElement(RendererData *data, LineShaderData &out, const GraphicElement &el, float x, float y);
|
void renderGraphicElement(RendererData *data, LineShaderData &out, const GraphicElement &el, float x, float y);
|
||||||
|
Loading…
Reference in New Issue
Block a user