/* QGLView Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "gltypes.h" #include "qglview.h" Camera * currentCamera; QMatrix4x4 globCameraMatrix; Camera::Camera() { type_ = glCamera; fov_ = 60.; angle_limit_lower_xy = 0.; angle_limit_upper_xy = 360.; angles_.setY(270.); depth_start = 0.1; depth_end = 1000.; mirror_x = mirror_y = false; } void Camera::anglesFromPoints() { QVector3D dv = aim_ - pos_, tv; tv = QVector3D(dv.x(), dv.y(), 0.); angles_.setZ(atan2(tv.x(), tv.y()) * rad2deg); angles_.setY(piClamp(atan2(tv.length(), dv.z()) * rad2deg, angle_limit_lower_xy, angle_limit_upper_xy) + 180.); } void Camera::apply(const GLdouble & aspect) { glMatrixMode(GL_PROJECTION); if (aspect <= 1.) glScaled(aspect, aspect, 1.); QMatrix4x4 pm = glMatrixPerspective(fov_, aspect, depth_start, depth_end); //pm.perspective(fov_, aspect, depth_start, depth_end); //qDebug() << pm;// << glMatrixPerspective(fov_, aspect, depth_start, depth_end); //qDebug() << pm; setGLMatrix(pm); glMatrixMode(GL_MODELVIEW); pm.setToIdentity(); pm.translate(0., 0., -distance()); pm.rotate(angles_.y(), 1., 0., 0.); pm.rotate(angles_.x(), 0., 1., 0.); pm.rotate(angles_.z(), 0., 0., 1.); //pm.translate(-aim_); if (parent_) { //double dist = pm(2, 3); QMatrix4x4 pmat = parent_->worldTransform();//.inverted(); //offset_.setZ(offset_.z() - dist); offset_ = pmat.column(3).toVector3D(); pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.; pmat.translate(aim_); //pm.translate(-aim_); pm *= pmat.inverted(); //qDebug() << pmat; } setGLMatrix(pm); //qDebug() << angles_; } QMatrix4x4 Camera::offsetMatrix() const { QMatrix4x4 ret; ret.translate(parent_ ? -offset_ : -aim_); return ret; } /* void Camera::localTransform(QMatrix4x4 & m) { return; if (parent_) m *= parent_->worldTransform(); QMatrix4x4 ret; //qDebug() << "local camera"; ret.translate(0., 0., -distance()); ret.rotate(angles_.y(), 1., 0., 0.); ret.rotate(angles_.x(), 0., 1., 0.); ret.rotate(angles_.z(), 0., 0., 1.); //m *= ret.inverted(); } */ void Camera::assign(const Camera & c) { pos_ = c.pos_; aim_ = c.aim_; fov_ = c.fov_; angles_ = c.angles_; angle_limit_lower_xy = c.angle_limit_lower_xy; angle_limit_upper_xy = c.angle_limit_upper_xy; buildTransform(); } void Camera::panZ(const double & a) { QVector3D dv = aim_ - pos_; double tl = QVector2D(dv.x(), dv.y()).length(); angles_.setZ(angles_.z() + a); dv = QVector3D(sin(angles_.z() * deg2rad) * tl, cos(angles_.z() * deg2rad) * tl, dv.z()); aim_ = pos_ + dv; buildTransform(); } void Camera::panXY(const double & a) { QVector3D dv = aim_ - pos_; double tl = dv.length(), tc; angles_.setY(angles_.y() + a); angles_.setY(piClamp(angles_.y(), angle_limit_lower_xy, angle_limit_upper_xy)); tc = -sin(angles_.y() * deg2rad); dv = QVector3D(sin(angles_.z() * deg2rad) * tc, cos(angles_.z() * deg2rad) * tc, -cos(angles_.y() * deg2rad)); aim_ = pos_ + dv * tl; buildTransform(); } void Camera::rotateZ(const double & a) { QVector3D dv = aim_ - pos_; double tl = QVector2D(dv.x(), dv.y()).length(); angles_.setZ(angles_.z() + a); dv = QVector3D(sin(angles_.z() * deg2rad) * tl, cos(angles_.z() * deg2rad) * tl, dv.z()); aim_ = pos_ + dv; buildTransform(); } void Camera::rotateXY(const double & a) { QVector3D dv = aim_ - pos_; double tl = dv.length(), tc; angles_.setY(angles_.y() + a); angles_.setY(piClamp(angles_.y(), angle_limit_lower_xy, angle_limit_upper_xy)); tc = -sin(angles_.y() * deg2rad); dv = QVector3D(sin(angles_.z() * deg2rad) * tc, cos(angles_.z() * deg2rad) * tc, -cos(angles_.y() * deg2rad)); aim_ = pos_ + dv * tl; buildTransform(); } void Camera::orbitZ(const double & a) { QVector3D dv = aim_ - pos_; double tl = QVector2D(dv.x(), dv.y()).length(); angles_.setZ(angles_.z() + a); dv = QVector3D(sin(angles_.z() * deg2rad) * tl, cos(angles_.z() * deg2rad) * tl, dv.z()); pos_ = aim_ - dv; buildTransform(); } void Camera::orbitXY(const double & a) { QVector3D dv = aim_ - pos_; double tl = dv.length(), tc; angles_.setY(angles_.y() + a); angles_.setY(piClamp(angles_.y(), angle_limit_lower_xy, angle_limit_upper_xy)); tc = -sin(angles_.y() * deg2rad); dv = QVector3D(sin(angles_.z() * deg2rad) * tc, cos(angles_.z() * deg2rad) * tc, -cos(angles_.y() * deg2rad)); pos_ = aim_ - dv * tl; buildTransform(); } void Camera::setAngleZ(const double & a) { QVector3D dv = aim_ - pos_; double tl = QVector2D(dv.x(), dv.y()).length(); angles_.setZ(a); dv = QVector3D(sin(angles_.z() * deg2rad) * tl, cos(angles_.z() * deg2rad) * tl, dv.z()); aim_ = pos_ + dv; buildTransform(); } void Camera::setAngleXY(const double & a) { QVector3D dv = aim_ - pos_; double tl = dv.length(), tc; angles_.setY(a); tc = -sin(angles_.y() * deg2rad); dv = QVector3D(sin(angles_.z() * deg2rad) * tc, cos(angles_.z() * deg2rad) * tc, -cos(angles_.y() * deg2rad)); //pos_ = aim_ - dv; aim_ = pos_ + dv * tl; buildTransform(); //anglesFromPoints(); } void Camera::moveForward(const double & x, bool withZ) { QVector3D dv;// = aim_ - pos_; double tc = -sin(angles_.y() * deg2rad); dv = QVector3D(sin(angles_.z() * deg2rad) * tc, cos(angles_.z() * deg2rad) * tc, 0.); if (withZ) dv.setZ(-cos(angles_.y() * deg2rad)); dv.normalize(); dv *= x; pos_ += dv; aim_ += dv; buildTransform(); } void Camera::moveLeft(const double & x, bool withZ) { QVector3D dv;// = aim_ - pos_; double tc = -sin(angles_.y() * deg2rad); dv = QVector3D(sin(angles_.z() * deg2rad - M_PI_2) * tc, cos(angles_.z() * deg2rad - M_PI_2) * tc, 0.); if (withZ) dv.setZ(-sin(angles_.x() * deg2rad)); dv.normalize(); dv *= x; pos_ += dv; aim_ += dv; buildTransform(); } void Camera::moveUp(const double & x, bool onlyZ) { QVector3D dv; if (onlyZ) dv = QVector3D(0., 0., x); else { double tc = cos(angles_.y() * deg2rad); dv = QVector3D(sin(angles_.z() * deg2rad) * tc, cos(angles_.z() * deg2rad) * tc, -sin(angles_.y() * deg2rad)); dv.normalize(); dv *= x; } pos_ += dv; aim_ += dv; buildTransform(); } void Camera::flyCloser(const double & s) { QVector3D dv = aim_ - pos_; double tl = dv.length() / (1. + s), tc = -sin(angles_.y() * deg2rad); dv = QVector3D(sin(angles_.z() * deg2rad) * tc, cos(angles_.z() * deg2rad) * tc, -cos(angles_.y() * deg2rad)); pos_ = aim_ - dv * tl; buildTransform(); } void Camera::flyFarer(const double & s) { QVector3D dv = aim_ - pos_; double tl = dv.length() * (1. + s), tc = -sin(angles_.y() * deg2rad); dv = QVector3D(sin(angles_.z() * deg2rad) * tc, cos(angles_.z() * deg2rad) * tc, -cos(angles_.y() * deg2rad)); pos_ = aim_ - dv * tl; buildTransform(); } void Camera::flyToDistance(const double & d) { QVector3D dv = aim_ - pos_; double tc = -sin(angles_.y() * deg2rad); dv = QVector3D(sin(angles_.z() * deg2rad) * tc, cos(angles_.z() * deg2rad) * tc, -cos(angles_.y() * deg2rad)); pos_ = aim_ - dv * d; buildTransform(); } /* QVector3D Camera::pointFromViewport(int x_, int y_, double z_) { GLsizei mx = x_, my = viewport[3] - y_, mz = z_; GLdouble x,y,z; gluUnProject(mx, my, mz, modelview, projection, viewport, &x, &y, &z); return QVector3D(x,y,z); } */