2018-06-22 02:12:20 +08:00
|
|
|
/*
|
|
|
|
* nextpnr -- Next Generation Place and Route
|
|
|
|
*
|
|
|
|
* Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-06-06 03:03:06 +08:00
|
|
|
#ifndef MAPGLWIDGET_H
|
|
|
|
#define MAPGLWIDGET_H
|
|
|
|
|
2018-06-11 02:48:52 +08:00
|
|
|
#include <QMainWindow>
|
2018-06-22 02:12:20 +08:00
|
|
|
#include <QOpenGLBuffer>
|
2018-06-06 03:03:06 +08:00
|
|
|
#include <QOpenGLFunctions>
|
2018-06-22 02:12:20 +08:00
|
|
|
#include <QOpenGLShaderProgram>
|
2018-06-23 03:16:49 +08:00
|
|
|
#include <QOpenGLVertexArrayObject>
|
2018-06-07 04:53:52 +08:00
|
|
|
#include <QOpenGLWidget>
|
2018-06-06 03:03:06 +08:00
|
|
|
#include <QPainter>
|
2018-06-22 02:12:20 +08:00
|
|
|
|
2018-06-12 02:12:57 +08:00
|
|
|
#include "nextpnr.h"
|
2018-06-06 03:03:06 +08:00
|
|
|
|
2018-06-22 02:12:20 +08:00
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
// Vertex2DPOD is a structure of X, Y coordinates that can be passed to OpenGL
|
|
|
|
// directly.
|
2018-07-07 01:19:18 +08:00
|
|
|
NPNR_PACKED_STRUCT(struct Vertex2DPOD {
|
2018-06-22 02:12:20 +08:00
|
|
|
GLfloat x;
|
|
|
|
GLfloat y;
|
|
|
|
|
|
|
|
Vertex2DPOD(GLfloat X, GLfloat Y) : x(X), y(Y) {}
|
2018-07-05 16:14:19 +08:00
|
|
|
});
|
2018-06-22 02:12:20 +08:00
|
|
|
|
|
|
|
// LineShaderData is a built set of vertices that can be rendered by the
|
|
|
|
// LineShader.
|
|
|
|
// Each LineShaderData can have its' own color and thickness.
|
|
|
|
struct LineShaderData
|
|
|
|
{
|
|
|
|
std::vector<Vertex2DPOD> vertices;
|
|
|
|
std::vector<Vertex2DPOD> normals;
|
|
|
|
std::vector<GLfloat> miters;
|
|
|
|
std::vector<GLuint> indices;
|
|
|
|
|
2018-07-15 02:12:29 +08:00
|
|
|
LineShaderData(void) {}
|
2018-07-15 01:50:50 +08:00
|
|
|
|
2018-07-14 03:53:52 +08:00
|
|
|
void clear(void)
|
|
|
|
{
|
|
|
|
vertices.clear();
|
|
|
|
normals.clear();
|
|
|
|
miters.clear();
|
|
|
|
indices.clear();
|
|
|
|
}
|
2018-06-22 02:12:20 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// PolyLine is a set of segments defined by points, that can be built to a
|
|
|
|
// ShaderLine for GPU rendering.
|
|
|
|
class PolyLine
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
std::vector<QVector2D> points_;
|
|
|
|
bool closed_;
|
|
|
|
|
2018-06-23 22:06:49 +08:00
|
|
|
void buildPoint(LineShaderData *building, const QVector2D *prev, const QVector2D *cur, const QVector2D *next) const;
|
2018-06-22 02:12:20 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
// Create an empty PolyLine.
|
|
|
|
PolyLine(bool closed = false) : closed_(closed) {}
|
|
|
|
|
|
|
|
// Create a non-closed polyline consisting of one segment.
|
|
|
|
PolyLine(float x0, float y0, float x1, float y1) : closed_(false)
|
|
|
|
{
|
|
|
|
point(x0, y0);
|
|
|
|
point(x1, y1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add a point to the PolyLine.
|
|
|
|
void point(float x, float y) { points_.push_back(QVector2D(x, y)); }
|
|
|
|
|
|
|
|
// Built PolyLine to shader data.
|
|
|
|
void build(LineShaderData &target) const;
|
|
|
|
|
|
|
|
// Set whether line is closed (ie. a loop).
|
|
|
|
void setClosed(bool closed) { closed_ = closed; }
|
|
|
|
};
|
|
|
|
|
|
|
|
// LineShader is an OpenGL shader program that renders LineShaderData on the
|
|
|
|
// GPU.
|
|
|
|
// The LineShader expects two vertices per line point. It will push those
|
|
|
|
// vertices along the given normal * miter. This is used to 'stretch' the line
|
|
|
|
// to be as wide as the given thickness. The normal and miter are calculated
|
|
|
|
// by the PolyLine build method in order to construct a constant thickness line
|
|
|
|
// with miter edge joints.
|
|
|
|
//
|
|
|
|
// +------+------+
|
|
|
|
//
|
|
|
|
// |
|
|
|
|
// PolyLine.build()
|
|
|
|
// |
|
|
|
|
// V
|
|
|
|
//
|
|
|
|
// ^ ^ ^
|
|
|
|
// | | | <--- normal vectors (x2, pointing in the same
|
|
|
|
// +/+----+/+----+/+ direction)
|
|
|
|
//
|
|
|
|
// |
|
|
|
|
// vertex shader
|
|
|
|
// |
|
|
|
|
// V
|
|
|
|
//
|
|
|
|
// +------+------+ ^ by normal * miter * thickness/2
|
|
|
|
// | | |
|
|
|
|
// +------+------+ V by normal * miter * thickness/2
|
|
|
|
//
|
|
|
|
// (miter is flipped for every second vertex generated)
|
|
|
|
class LineShader
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
QObject *parent_;
|
|
|
|
QOpenGLShaderProgram *program_;
|
|
|
|
|
|
|
|
// GL attribute locations.
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
// original position of line vertex
|
|
|
|
GLuint position;
|
|
|
|
// normal by which vertex should be translated
|
|
|
|
GLuint normal;
|
|
|
|
// scalar defining:
|
|
|
|
// - how stretched the normal vector should be to
|
|
|
|
// compensate for bends
|
|
|
|
// - which way the normal should be applied (+1 for one vertex, -1
|
|
|
|
// for the other)
|
|
|
|
GLuint miter;
|
|
|
|
} attributes_;
|
|
|
|
|
2018-06-23 03:16:49 +08:00
|
|
|
// GL buffers
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
QOpenGLBuffer position;
|
|
|
|
QOpenGLBuffer normal;
|
|
|
|
QOpenGLBuffer miter;
|
|
|
|
QOpenGLBuffer index;
|
|
|
|
} buffers_;
|
|
|
|
|
2018-06-22 02:12:20 +08:00
|
|
|
// GL uniform locations.
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
// combines m/v/p matrix to apply
|
|
|
|
GLuint projection;
|
|
|
|
// desired thickness of line
|
|
|
|
GLuint thickness;
|
|
|
|
// color of line
|
|
|
|
GLuint color;
|
|
|
|
} uniforms_;
|
|
|
|
|
2018-06-23 03:16:49 +08:00
|
|
|
QOpenGLVertexArrayObject vao_;
|
|
|
|
|
2018-06-22 02:12:20 +08:00
|
|
|
public:
|
2018-06-23 03:16:49 +08:00
|
|
|
LineShader(QObject *parent) : parent_(parent), program_(nullptr)
|
|
|
|
{
|
|
|
|
buffers_.position = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
|
|
|
|
buffers_.position.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
|
|
|
|
|
|
|
buffers_.normal = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
|
|
|
|
buffers_.normal.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
|
|
|
|
|
|
|
buffers_.miter = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
|
|
|
|
buffers_.miter.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
|
|
|
|
|
|
|
buffers_.index = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
|
|
|
|
buffers_.index.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
|
|
|
}
|
2018-06-22 02:12:20 +08:00
|
|
|
|
|
|
|
static constexpr const char *vertexShaderSource_ =
|
2018-07-03 17:48:05 +08:00
|
|
|
"#version 110\n"
|
2018-06-22 02:12:20 +08:00
|
|
|
"attribute highp vec2 position;\n"
|
|
|
|
"attribute highp vec2 normal;\n"
|
|
|
|
"attribute highp float miter;\n"
|
|
|
|
"uniform highp float thickness;\n"
|
|
|
|
"uniform highp mat4 projection;\n"
|
|
|
|
"void main() {\n"
|
|
|
|
" vec2 p = position.xy + vec2(normal * thickness/2.0 / miter);\n"
|
|
|
|
" gl_Position = projection * vec4(p, 0.0, 1.0);\n"
|
|
|
|
"}\n";
|
|
|
|
|
2018-07-03 17:48:05 +08:00
|
|
|
static constexpr const char *fragmentShaderSource_ = "#version 110\n"
|
|
|
|
"uniform lowp vec4 color;\n"
|
2018-06-23 22:06:49 +08:00
|
|
|
"void main() {\n"
|
|
|
|
" gl_FragColor = color;\n"
|
|
|
|
"}\n";
|
2018-06-22 02:12:20 +08:00
|
|
|
|
|
|
|
// Must be called on initialization.
|
|
|
|
bool compile(void);
|
|
|
|
|
|
|
|
// Render a LineShaderData with a given M/V/P transformation.
|
2018-07-15 02:12:29 +08:00
|
|
|
void draw(const LineShaderData &data, const QColor &color, float thickness, const QMatrix4x4 &projection);
|
2018-06-22 02:12:20 +08:00
|
|
|
};
|
2018-06-12 20:24:59 +08:00
|
|
|
|
2018-06-06 03:03:06 +08:00
|
|
|
class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
2018-07-13 18:38:49 +08:00
|
|
|
Q_PROPERTY(QColor backgroundColor MEMBER backgroundColor_ DESIGNABLE true)
|
|
|
|
Q_PROPERTY(QColor gridColor MEMBER gridColor_ DESIGNABLE true)
|
|
|
|
Q_PROPERTY(QColor gFrameColor MEMBER gFrameColor_ DESIGNABLE true)
|
|
|
|
Q_PROPERTY(QColor gHiddenColor MEMBER gHiddenColor_ DESIGNABLE true)
|
|
|
|
Q_PROPERTY(QColor gInactiveColor MEMBER gInactiveColor_ DESIGNABLE true)
|
|
|
|
Q_PROPERTY(QColor gActiveColor MEMBER gActiveColor_ DESIGNABLE true)
|
2018-07-15 01:44:37 +08:00
|
|
|
Q_PROPERTY(QColor gSelectedColor MEMBER gSelectedColor_ DESIGNABLE true)
|
2018-07-13 18:38:49 +08:00
|
|
|
Q_PROPERTY(QColor frameColor MEMBER frameColor_ DESIGNABLE true)
|
2018-06-06 03:03:06 +08:00
|
|
|
|
2018-06-07 04:53:52 +08:00
|
|
|
public:
|
2018-06-06 03:03:06 +08:00
|
|
|
FPGAViewWidget(QWidget *parent = 0);
|
|
|
|
~FPGAViewWidget();
|
|
|
|
|
|
|
|
QSize minimumSizeHint() const override;
|
|
|
|
QSize sizeHint() const override;
|
|
|
|
|
|
|
|
void setXTranslation(float t_x);
|
|
|
|
void setYTranslation(float t_y);
|
|
|
|
void setZoom(float t_z);
|
|
|
|
|
|
|
|
void xRotationChanged(int angle);
|
|
|
|
void yRotationChanged(int angle);
|
|
|
|
void zRotationChanged(int angle);
|
|
|
|
|
2018-06-07 04:53:52 +08:00
|
|
|
protected:
|
2018-06-06 03:03:06 +08:00
|
|
|
void initializeGL() Q_DECL_OVERRIDE;
|
|
|
|
void paintGL() Q_DECL_OVERRIDE;
|
|
|
|
void resizeGL(int width, int height) Q_DECL_OVERRIDE;
|
|
|
|
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
|
|
|
void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
|
|
|
void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
|
2018-07-15 01:50:50 +08:00
|
|
|
void drawDecal(LineShaderData &data, const DecalXY &decal);
|
|
|
|
void drawDecal(LineShaderData out[], const DecalXY &decal);
|
2018-06-26 21:47:22 +08:00
|
|
|
public Q_SLOTS:
|
|
|
|
void newContext(Context *ctx);
|
2018-07-15 01:44:37 +08:00
|
|
|
void onSelectedArchItem(std::vector<DecalXY> decals);
|
2018-07-15 23:50:58 +08:00
|
|
|
void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
|
2018-07-15 18:39:19 +08:00
|
|
|
|
2018-06-07 04:53:52 +08:00
|
|
|
private:
|
2018-06-22 02:12:20 +08:00
|
|
|
QPoint lastPos_;
|
|
|
|
LineShader lineShader_;
|
2018-07-13 03:22:53 +08:00
|
|
|
QMatrix4x4 viewMove_;
|
|
|
|
float zoom_;
|
|
|
|
QMatrix4x4 getProjection(void);
|
|
|
|
QVector4D mouseToWorldCoordinates(int x, int y);
|
|
|
|
|
2018-07-13 04:04:13 +08:00
|
|
|
const float zoomNear_ = 1.0f; // do not zoom closer than this
|
2018-07-13 03:22:53 +08:00
|
|
|
const float zoomFar_ = 10000.0f; // do not zoom further than this
|
|
|
|
|
|
|
|
const float zoomLvl1_ = 100.0f;
|
|
|
|
const float zoomLvl2_ = 50.0f;
|
2018-06-22 02:12:20 +08:00
|
|
|
|
2018-06-23 03:16:49 +08:00
|
|
|
Context *ctx_;
|
2018-07-13 18:38:49 +08:00
|
|
|
|
|
|
|
QColor backgroundColor_;
|
|
|
|
QColor gridColor_;
|
|
|
|
QColor gFrameColor_;
|
|
|
|
QColor gHiddenColor_;
|
|
|
|
QColor gInactiveColor_;
|
|
|
|
QColor gActiveColor_;
|
2018-07-15 01:44:37 +08:00
|
|
|
QColor gSelectedColor_;
|
2018-07-13 18:38:49 +08:00
|
|
|
QColor frameColor_;
|
2018-07-14 03:53:52 +08:00
|
|
|
|
2018-07-15 01:44:37 +08:00
|
|
|
LineShaderData selectedShader_;
|
|
|
|
std::vector<DecalXY> selectedItems_;
|
2018-07-15 23:50:58 +08:00
|
|
|
bool selectedItemsChanged_;
|
|
|
|
|
|
|
|
LineShaderData highlightShader_[8];
|
|
|
|
std::vector<DecalXY> highlightItems_[8];
|
|
|
|
bool highlightItemsChanged_[8];
|
|
|
|
QColor highlightColors[8];
|
2018-06-06 03:03:06 +08:00
|
|
|
};
|
2018-06-12 20:24:59 +08:00
|
|
|
|
2018-06-22 02:12:20 +08:00
|
|
|
NEXTPNR_NAMESPACE_END
|
|
|
|
|
2018-06-06 03:03:06 +08:00
|
|
|
#endif
|