/* QGLView Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "gltypes.h" #include "qglview.h" Camera::Camera() { type_ = glCamera; fov_ = 60.; angle_limit_lower_xy = 0.f; angle_limit_upper_xy = 360.f; angles_.setY(270.f); depth_start = 0.1f; depth_end = 1000.f; mirror_x = mirror_y = false; } void Camera::anglesFromPoints() { QVector3D dv = aim_ - pos_, tv; tv = QVector3D(dv.x(), dv.y(), 0.); angles_.setZ(atan2f(tv.x(), tv.y()) * rad2deg); angles_.setY(piClamp(atan2f(tv.length(), dv.z()) * rad2deg, angle_limit_lower_xy, angle_limit_upper_xy) + 180.f); } void Camera::apply(const GLfloat & aspect) { glMatrixMode(GL_PROJECTION); if (aspect <= 1.f) glScalef(aspect, aspect, 1.f); 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_) { QMatrix4x4 pmat = parent_->worldTransform(); offset_ = pmat.column(3).toVector3D(); pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.; pmat.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; mirror_x = c.mirror_x; mirror_y = c.mirror_y; depth_start = c.depth_start; depth_end = c.depth_end; buildTransform(); } GLObjectBase * Camera::clone(bool withChildren) { Camera * o = new Camera(*this); //GLObjectBase::clone(withChildren); o->is_init = false; o->name_ = name_ + "_copy"; o->view_ = nullptr; o->children_.clear(); if (withChildren) { for (int i = 0; i < children_.size(); ++i) o->addChild(children_[i]->clone(withChildren)); } o->pos_ = pos_; o->aim_ = aim_; o->fov_ = fov_; o->angles_ = angles_; o->angle_limit_lower_xy = angle_limit_lower_xy; o->angle_limit_upper_xy = angle_limit_upper_xy; o->mirror_x = mirror_x; o->mirror_y = mirror_y; o->depth_start = depth_start; o->depth_end = depth_end; o->meta = meta; return o; } void Camera::panZ(const float & a) { QVector3D dv = aim_ - pos_; float tl = QVector2D(dv.x(), dv.y()).length(); angles_.setZ(angles_.z() + a); dv = QVector3D(sinf(angles_.z() * deg2rad) * tl, cosf(angles_.z() * deg2rad) * tl, dv.z()); aim_ = pos_ + dv; buildTransform(); } void Camera::panXY(const float & a) { QVector3D dv = aim_ - pos_; float tl = dv.length(), tc; angles_.setY(angles_.y() + a); angles_.setY(piClamp(angles_.y(), angle_limit_lower_xy, angle_limit_upper_xy)); tc = -sinf(angles_.y() * deg2rad); dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad)); aim_ = pos_ + dv * tl; buildTransform(); } void Camera::rotateZ(const float & a) { QVector3D dv = aim_ - pos_; float tl = QVector2D(dv.x(), dv.y()).length(); angles_.setZ(angles_.z() + a); dv = QVector3D(sinf(angles_.z() * deg2rad) * tl, cosf(angles_.z() * deg2rad) * tl, dv.z()); aim_ = pos_ + dv; buildTransform(); } void Camera::rotateXY(const float & a) { QVector3D dv = aim_ - pos_; float tl = dv.length(), tc; angles_.setY(angles_.y() + a); angles_.setY(piClamp(angles_.y(), angle_limit_lower_xy, angle_limit_upper_xy)); tc = -sinf(angles_.y() * deg2rad); dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad)); aim_ = pos_ + dv * tl; buildTransform(); } void Camera::orbitZ(const float & a) { QVector3D dv = aim_ - pos_; float tl = QVector2D(dv.x(), dv.y()).length(); angles_.setZ(angles_.z() + a); dv = QVector3D(sinf(angles_.z() * deg2rad) * tl, cosf(angles_.z() * deg2rad) * tl, dv.z()); pos_ = aim_ - dv; buildTransform(); } void Camera::orbitXY(const float & a) { QVector3D dv = aim_ - pos_; float tl = dv.length(), tc; angles_.setY(angles_.y() + a); angles_.setY(piClamp(angles_.y(), angle_limit_lower_xy, angle_limit_upper_xy)); tc = -sinf(angles_.y() * deg2rad); dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad)); pos_ = aim_ - dv * tl; buildTransform(); } void Camera::setAngleZ(const float & a) { QVector3D dv = aim_ - pos_; float tl = QVector2D(dv.x(), dv.y()).length(); angles_.setZ(a); dv = QVector3D(sinf(angles_.z() * deg2rad) * tl, cosf(angles_.z() * deg2rad) * tl, dv.z()); aim_ = pos_ + dv; buildTransform(); } void Camera::setAngleXY(const float & a) { QVector3D dv = aim_ - pos_; float tl = dv.length(), tc; angles_.setY(a); tc = -sinf(angles_.y() * deg2rad); dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad)); //pos_ = aim_ - dv; aim_ = pos_ + dv * tl; buildTransform(); //anglesFromPoints(); } void Camera::moveForward(const float & x, bool withZ) { QVector3D dv;// = aim_ - pos_; float tc = -sinf(angles_.y() * deg2rad); dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, 0.); if (withZ) dv.setZ(-cosf(angles_.y() * deg2rad)); dv.normalize(); dv *= x; pos_ += dv; aim_ += dv; buildTransform(); } void Camera::moveLeft(const float & x, bool withZ) { QVector3D dv;// = aim_ - pos_; float tc = -sinf(angles_.y() * deg2rad); dv = QVector3D(sinf(angles_.z() * deg2rad - float(M_PI_2)) * tc, cosf(angles_.z() * deg2rad - float(M_PI_2)) * tc, 0.f); if (withZ) dv.setZ(-sinf(angles_.x() * deg2rad)); dv.normalize(); dv *= x; pos_ += dv; aim_ += dv; buildTransform(); } void Camera::moveUp(const float & x, bool onlyZ) { QVector3D dv; if (onlyZ) dv = QVector3D(0., 0., x); else { float tc = cosf(angles_.y() * deg2rad); dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -sinf(angles_.y() * deg2rad)); dv.normalize(); dv *= x; } pos_ += dv; aim_ += dv; buildTransform(); } void Camera::flyCloser(const float & s) { QVector3D dv = aim_ - pos_; float tl = dv.length() / (1.f + s), tc = -sinf(angles_.y() * deg2rad); dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad)); pos_ = aim_ - dv * tl; buildTransform(); } void Camera::flyFarer(const float & s) { QVector3D dv = aim_ - pos_; float tl = dv.length() * (1.f + s), tc = -sinf(angles_.y() * deg2rad); dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad)); pos_ = aim_ - dv * tl; buildTransform(); } void Camera::flyToDistance(const float & d) { QVector3D dv = aim_ - pos_; float tc = -sinf(angles_.y() * deg2rad); dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad)); pos_ = aim_ - dv * d; buildTransform(); }