From 7472bd4955a68f54f65ba67a1a459b6d2bcc8215 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 10 Apr 2020 22:40:53 +0200 Subject: [PATCH] WIP: experiments on OpenGL view. --- .../tools/view_25d/lay_plugin/layD25Plugin.cc | 2 + .../view_25d/lay_plugin/layD25ViewWidget.cc | 331 +++++++++++++++++- .../view_25d/lay_plugin/layD25ViewWidget.h | 34 +- 3 files changed, 363 insertions(+), 4 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc index 12cd9d03c..7f92fcd62 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -27,6 +27,8 @@ #include "layPlugin.h" +#include + namespace lay { diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index c3fadabb0..e6d572686 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -22,19 +22,344 @@ #include "layD25ViewWidget.h" +#include "tlException.h" + +#include +#include + +#include "math.h" namespace lay { D25ViewWidget::D25ViewWidget (QWidget *parent) - : QOpenGLWidget (parent) + : QOpenGLWidget (parent), + m_program (0), m_dragging (false), m_rotating (false), m_cam_azimuth (0.0), m_cam_elevation (0.0) { - // @@@ + QSurfaceFormat format; + format.setDepthBufferSize (24); + format.setSamples (4); // more -> widget extends beyond boundary! + setFormat (format); + + m_cam_position = QVector3D (0.0, 0.0, 3.0); // @@@ } D25ViewWidget::~D25ViewWidget () { - // @@@ + // Make sure the context is current and then explicitly + // destroy all underlying OpenGL resources. + makeCurrent(); + + delete m_program; + + doneCurrent(); +} + +void +D25ViewWidget::initializeGL () +{ + QOpenGLFunctions::initializeOpenGLFunctions(); + + glEnable (GL_DEPTH_TEST); + glEnable (GL_BLEND); + // @@@ dark background + // glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // @@@ white background + glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + + static const char *vertexShaderSource = + "attribute highp vec4 posAttr;\n" + "uniform highp mat4 matrix;\n" + "attribute lowp vec4 colAttr;\n" + "varying lowp vec4 col;\n" + "void main() {\n" + " col = colAttr;\n" + " gl_Position = matrix * posAttr;\n" + "}\n"; + + static const char *fragmentShaderSource = + "varying lowp vec4 col;\n" + "void main() {\n" + " gl_FragColor = col;\n" + "}\n"; + + m_program = new QOpenGLShaderProgram (this); + if (! m_program->addShaderFromSourceCode (QOpenGLShader::Vertex, vertexShaderSource)) { + throw tl::Exception (std::string ("Vertex shader compilation failed:\n") + tl::to_string (m_program->log ())); + } + if (! m_program->addShaderFromSourceCode (QOpenGLShader::Fragment, fragmentShaderSource)) { + throw tl::Exception (std::string ("Fragment shader compilation failed:\n") + tl::to_string (m_program->log ())); + } + if (! m_program->link ()) { + throw tl::Exception (std::string ("Linking failed:\n") + tl::to_string (m_program->log ())); + } + + m_posAttr = m_program->attributeLocation ("posAttr"); + m_colAttr = m_program->attributeLocation ("colAttr"); + m_matrixUniform = m_program->uniformLocation ("matrix"); +} + +static QVector3D cam_direction (double azimuth, double elevation) +{ + // positive azimuth: camera looks left + // positive elevation: camera looks up + double y = sin (elevation * M_PI / 180.0); + double r = cos (elevation * M_PI / 180.0); + double x = r * sin (azimuth * M_PI / 180.0); + double z = r * cos (azimuth * M_PI / 180.0); + return QVector3D (x, y, -z); +} + +void +D25ViewWidget::wheelEvent (QWheelEvent *event) +{ + double cal = 0.6; + + int dx = event->pos ().x () - width () / 2; + int dy = -(event->pos ().y () - height () / 2); + + double da = atan (dx * cal * 2.0 / height ()) * 180 / M_PI; + double de = atan (dy * cal * 2.0 / height ()) * 180 / M_PI; + + m_cam_position += (event->angleDelta ().y () * (1.0 / (45 * 8))) * cam_direction (m_cam_azimuth + da, m_cam_elevation + de); + + update_cam_trans (); +} + +void +D25ViewWidget::mousePressEvent (QMouseEvent *event) +{ + m_dragging = m_rotating = false; + if (event->button () == Qt::MidButton) { + m_dragging = true; + } else if (event->button () == Qt::LeftButton) { + m_rotating = true; + } + + m_start_pos = event->pos (); + m_start_cam_position = m_cam_position; + m_start_cam_azimuth = m_cam_azimuth; + m_start_cam_elevation = m_cam_elevation; +} + +void +D25ViewWidget::mouseReleaseEvent (QMouseEvent *event) +{ + m_dragging = false; +} + +void +D25ViewWidget::mouseMoveEvent (QMouseEvent *event) +{ + double focus_dist = 4.0; // 4 times focal length + + if (m_dragging) { + + // for the chosen perspective transformation: + double cal = 0.6 * focus_dist; + + QPoint d = event->pos () - m_start_pos; + double f = cal * 2.0 / double (height ()); + double dx = d.x () * f; + double dy = -d.y () * f; + + QVector3D xv (cos (m_start_cam_azimuth * M_PI / 180.0), 0.0, -sin (m_start_cam_azimuth * M_PI / 180.0)); + double re = sin (m_start_cam_elevation * M_PI / 180.0); + QVector3D yv (-re * xv.z (), cos (m_start_cam_elevation * M_PI / 180.0), re * xv.x ()); + QVector3D drag = xv * dx + yv * dy; + + // "-drag" because we're not dragging the camera, we're dragging the scene + m_cam_position = m_start_cam_position - drag; + + update_cam_trans (); + + } else if (m_rotating) { + + QPoint d = event->pos () - m_start_pos; + + double ax = atan (d.x () / (0.5 * height ())) * 180 / M_PI; + double ay = atan (-d.y () / (0.5 * height ())) * 180 / M_PI; + + m_cam_elevation = m_start_cam_elevation + ay; + m_cam_azimuth = m_start_cam_azimuth + ax; + + m_cam_position = (cam_direction (m_cam_azimuth, m_cam_elevation) * -focus_dist) + cam_direction (m_start_cam_azimuth, m_start_cam_elevation) * focus_dist + m_start_cam_position; + + update_cam_trans (); + + } +} + +void +D25ViewWidget::update_cam_trans () +{ +printf("@@@ e=%g a=%g x,y,z=%g,%g,%g\n", m_cam_elevation, m_cam_azimuth, m_cam_position.x(), m_cam_position.y(), m_cam_position.z()); fflush(stdout); + QMatrix4x4 t; + + // third: elevation + t.rotate (-m_cam_elevation, 1.0, 0.0, 0.0); + + // second: azimuth + t.rotate (m_cam_azimuth, 0.0, 1.0, 0.0); + + // first: translate the origin into the cam's position + t.translate (-m_cam_position); + + m_cam_trans = t; + + update (); +} + +void +D25ViewWidget::paintGL () +{ + const qreal retinaScale = devicePixelRatio (); + glViewport (0, 0, width () * retinaScale, height () * retinaScale); + + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClearColor (1.0, 1.0, 1.0, 1.0); + + m_program->bind (); + + QMatrix4x4 matrix; + matrix.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); + matrix *= m_cam_trans; + + m_program->setUniformValue (m_matrixUniform, matrix); + + glEnableVertexAttribArray (m_posAttr); + glEnableVertexAttribArray (m_colAttr); + + GLfloat vertices[] = { + 0.0f, 0.707f, -1.0, + -0.5f, -0.5f, -1.0, + 0.5f, -0.5f, -1.0, + -0.6 + 0.0f, 0.0707f, -1.0, + -0.6 + -0.05f, -0.05f, -1.0, + -0.6 + 0.05f, -0.05f, -1.0, + 0.0f, 0.707f, -1.5, + -0.5f, -0.5f, -1.5, + 0.5f, -0.5f, -1.5, + 0.0f, 0.707f, -2.0, + -0.5f, -0.5f, -2.0, + 0.5f, -0.5f, -2.0 + }; + + GLfloat colors[] = { + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f + }; + + glVertexAttribPointer (m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, vertices); + glVertexAttribPointer (m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors); + + glDrawArrays (GL_TRIANGLES, 0, 12); + + GLfloat plane_vertices[] = { + -1.05, 0.0, -2.05, -1.05, 0.0, 0.05, 1.05, 0.0, 0.05, + -1.05, 0.0, -2.05, 1.05, 0.0, 0.05, 1.05, 0.0, -2.05 + }; + + GLfloat plane_colors[] = { + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f + }; + + glVertexAttribPointer (m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, plane_vertices); + glVertexAttribPointer (m_colAttr, 4, GL_FLOAT, GL_FALSE, 0, plane_colors); + + glDrawArrays (GL_TRIANGLES, 0, 6); + + GLfloat gridline_vertices[] = { + -1.0, 0.0, -2.0, -1.0, 0.0, 0.0, + -0.75, 0.0, -2.0, -0.75, 0.0, 0.0, + -0.5, 0.0, -2.0, -0.5, 0.0, 0.0, + -0.25, 0.0, -2.0, -0.25, 0.0, 0.0, + 0.0, 0.0, -2.0, 0.0, 0.0, 0.0, + 0.25, 0.0, -2.0, 0.25, 0.0, 0.0, + 0.5, 0.0, -2.0, 0.5, 0.0, 0.0, + 0.75, 0.0, -2.0, 0.75, 0.0, 0.0, + 1.0, 0.0, -2.0, 1.0, 0.0, 0.0, + 1.0, 0.0, -2.0, -1.0, 0.0, -2.0, + 1.0, 0.0, -1.75, -1.0, 0.0, -1.75, + 1.0, 0.0, -1.5 , -1.0, 0.0, -1.5, + 1.0, 0.0, -1.25, -1.0, 0.0, -1.25, + 1.0, 0.0, -1.0, -1.0, 0.0, -1.0, + 1.0, 0.0, -0.75, -1.0, 0.0, -0.75, + 1.0, 0.0, -0.5 , -1.0, 0.0, -0.5, + 1.0, 0.0, -0.25, -1.0, 0.0, -0.25, + 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 + }; + + GLfloat gridline_colors[] = { + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f + }; + + glVertexAttribPointer (m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, gridline_vertices); + glVertexAttribPointer (m_colAttr, 4, GL_FLOAT, GL_FALSE, 0, gridline_colors); + + glLineWidth (2.0); + glDrawArrays (GL_LINES, 0, 36); + + glDisableVertexAttribArray (m_posAttr); + glDisableVertexAttribArray (m_colAttr); + + m_program->release (); +} + +void +D25ViewWidget::resizeGL (int /*w*/, int /*h*/) +{ + update_cam_trans (); } } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index 428f466f3..aec8bbb33 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -24,18 +24,50 @@ #define HDR_layD25ViewWidget #include +#include +#include +#include +#include +#include +#include +#include namespace lay { class D25ViewWidget - : public QOpenGLWidget + : public QOpenGLWidget, + private QOpenGLFunctions { Q_OBJECT public: D25ViewWidget (QWidget *parent); ~D25ViewWidget (); + + void wheelEvent (QWheelEvent *event); + void mousePressEvent (QMouseEvent *event); + void mouseReleaseEvent (QMouseEvent *event); + void mouseMoveEvent (QMouseEvent *event); + +private: + QOpenGLShaderProgram *m_program; + GLuint m_posAttr; + GLuint m_colAttr; + GLuint m_matrixUniform; + QMatrix4x4 m_cam_trans; + bool m_dragging, m_rotating; + QVector3D m_cam_position; + double m_cam_azimuth, m_cam_elevation; + QPoint m_start_pos; + QVector3D m_start_cam_position; + double m_start_cam_azimuth, m_start_cam_elevation; + + void initializeGL (); + void paintGL (); + void resizeGL (int w, int h); + + void update_cam_trans (); }; }