// CC-BY Edouard.Thiel@univ-amu.fr - 22/01/2019 #include "glarea.h" #include #include #include #include static const QString vertexShaderFile = ":/basic.vsh"; static const QString fragmentShaderFile = ":/basic.fsh"; GLArea::GLArea(QWidget *parent) : QOpenGLWidget(parent) { qDebug() << "init GLArea" ; QSurfaceFormat sf; sf.setDepthBufferSize(24); sf.setSamples(16); setFormat(sf); qDebug() << "Depth is"<< format().depthBufferSize(); setEnabled(true); // Événements clavier et souris. setFocusPolicy(Qt::StrongFocus); // Accepte focus. setFocus(); // Donne le focus. timer = new QTimer(this); timer->setInterval(16); // ms connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout())); } GLArea::~GLArea() { qDebug() << "destroy GLArea"; delete timer; // Contrairement aux méthodes virtuelles initializeGL, resizeGL et repaintGL, // dans le destructeur le contexte GL n'est pas automatiquement rendu courant. makeCurrent(); // ici destructions de ressources GL doneCurrent(); } void GLArea::initializeGL() { qDebug() << __FUNCTION__ ; initializeOpenGLFunctions(); glEnable(GL_DEPTH_TEST); // Shaders. program = new QOpenGLShaderProgram(this); program->addShaderFromSourceFile (QOpenGLShader::Vertex, vertexShaderFile); program->addShaderFromSourceFile (QOpenGLShader::Fragment, fragmentShaderFile); if (!program->link()) { qWarning("Failed to compile and link shader program:"); qWarning() << program->log(); } // Récupère identifiants de "variables" dans les shaders. posAttr = program->attributeLocation("posAttr"); colAttr = program->attributeLocation("colAttr"); matrix_uniform = program->uniformLocation("matrix"); } void GLArea::resizeGL(int w, int h) { qDebug() << __FUNCTION__ << w << h; // C'est fait par défaut glViewport(0, 0, w, h); ratio = (double) w / h; // doProjection(); } void GLArea::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); program->bind(); QMatrix4x4 matrix; GLfloat hr = focal_length; GLfloat wr = hr * ratio; matrix.frustum(-wr, wr, -hr, hr, near_clip, far_clip); matrix.translate(0, 0, -distance); matrix.rotate(angle, 0, 1, 0); matrix.rotate(horiz_angle, 0, cos(vert_angle * 2*M_PI /360), sin(vert_angle * 2*M_PI /360)); matrix.rotate(vert_angle, 1, 0, 0); program->setUniformValue(matrix_uniform, matrix); scene.draw((QOpenGLFunctions&) (*this), program, matrix_uniform, anim * 360, matrix, posAttr, colAttr); program->release(); } void GLArea::keyPressEvent(QKeyEvent *ev) { QString text = ev->text(); switch(ev->key()) { case Qt::Key_A: timer->isActive() ? timer->stop() : timer->start(); break; case Qt::Key_Z: setDistance(distance + (text == "z" ? -distance_step : distance_step)); break; case Qt::Key_R: setFocalLength(focal_length + (text == "r" ? -focal_length_step : focal_length_step)); break; case Qt::Key_N: setNearClip(near_clip + (text == "n" ? -near_clip_step : near_clip_step)); break; case Qt::Key_F: setFarClip(far_clip + (text == "f" ? -far_clip_step : far_clip_step)); break; case Qt::Key_Space: setAngle(angle + angle_step); update(); break; } } void GLArea::mousePressEvent(QMouseEvent *ev) { mouse_last[0] = ev->x() / (float) width(); mouse_last[1] = ev->y() / (float) height(); } void GLArea::mouseMoveEvent(QMouseEvent *ev) { float x = ev->x() / (float) width(); float y = ev->y() / (float) height(); float dx = x - mouse_last[0]; float dy = y - mouse_last[1]; horiz_angle += dx * 200; vert_angle += dy * 200; if (vert_angle > 90) vert_angle = 90; if (vert_angle < -90) vert_angle = -90; mouse_last[0] = x; mouse_last[1] = y; update(); } void GLArea::wheelEvent(QWheelEvent *ev) { setDistance(distance - ev->angleDelta().y() / 1000.); update(); } void GLArea::onTimeout() { anim += 0.0001; if (anim > 1) anim--; update(); } #define SET_VALUE(orig, signal) \ qDebug() << "GLArea, setting " #orig " from" << orig << "to" << value; \ if (value > orig##_max) value = orig##_max;\ if (value < orig##_min) value = orig##_min;\ if (value != orig) {\ orig = value;\ emit signal(orig);\ update();\ } void GLArea::setDistance(double value) { SET_VALUE(distance, distanceChanged); } void GLArea::setFocalLength(double value) { SET_VALUE(focal_length, focalLengthChanged); } void GLArea::setNearClip(double value) { SET_VALUE(near_clip, nearClipChanged); } void GLArea::setFarClip(double value) { SET_VALUE(far_clip, farClipChanged); } void GLArea::setAngle(double value) { while (value > angle_max) value -= angle_max; while (value < angle_min) value += angle_min; SET_VALUE(angle, angleChanged); } #undef SET_VALUE