/* QGLView Copyright (C) 2012 Ivan Pelipenko peri4ko@gmail.com 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" QGLWidget * currentQGLView; Camera * currentCamera; QMatrix4x4 globCameraMatrix; QMutex globMutex; QString readCharsUntilNull(QDataStream & s) { QString str; char ch; s.readRawData(&ch, 1); while (ch != '\0') { str += ch; s.readRawData(&ch, 1); } return str; } QString findFile(const QString & file, const QStringList & pathes) { QFileInfo fi(QString(file).replace("\\", "/")); //qDebug() << "search" << file << "in" << pathes; if (fi.exists()) return fi.absoluteFilePath(); QString fn = fi.fileName(); if (fn.contains("/")) fn = fn.mid(fn.lastIndexOf("/")); foreach (QString p, pathes) { QFileInfoList fil = QDir(p).entryInfoList(QStringList(fn), QDir::Files | QDir::NoDotAndDotDot); //qDebug() << "findFile" << fn << "in" << p << "->" << fil.size(); if (!fil.isEmpty()) return fil[0].absoluteFilePath(); } return QString(); } void glDrawQuad(GLfloat x, GLfloat y, GLfloat w, GLfloat h) { glResetAllTransforms(); glSetPolygonMode(GL_FILL); glBegin(GL_QUADS); glColor3f(1.f, 1.f, 1.f); glTexCoord2f(0.f, 0.f); glVertex2f(x, y); glTexCoord2f(1.f, 0.f); glVertex2f(x + w, y); glTexCoord2f(1.f, 1.f); glVertex2f(x + w, y + h); glTexCoord2f(0.f, 1.f); glVertex2f(x, y + h); glEnd(); } QMatrix4x4 getGLMatrix(GLenum matrix) { GLfloat gm[16]; glGetFloatv(matrix, gm); qreal qm[16]; for (int i = 0; i < 16; ++i) qm[i] = gm[i]; return QMatrix4x4(qm).transposed(); } void setGLMatrix(QMatrix4x4 matrix) { GLfloat gm[16]; qreal qm[16]; matrix.transposed().copyDataTo(qm); for (int i = 0; i < 16; ++i) gm[i] = qm[i]; glLoadMatrixf(gm); } void qglMultMatrix(const QMatrix4x4 & m) { GLdouble gm[16]; qreal qm[16]; m.transposed().copyDataTo(qm); for (int i = 0; i < 16; ++i) gm[i] = qm[i]; glMultMatrixd(gm); } void createGLTexture(GLuint & tex, int width, int height, const GLenum & format, const GLenum & target) { glClearError(); if (tex == 0) { glGenTextures(1, &tex); glBindTexture(target, tex); } //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_COMPONENT16 || format == GL_DEPTH_COMPONENT24 || format == GL_DEPTH_COMPONENT32) glTexImage2D(target, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); else { int t = GL_UNSIGNED_BYTE; if (format == GL_RGB32F || format == GL_RGB16F) t = GL_FLOAT; glTexImage2D(target, 0, format, width, height, 0, GL_RGBA, t, 0); } //qDebug() << QString::number(glGetError(), 16); } void createGLTexture(GLuint & tex, const QImage & image, const GLenum & format, const GLenum & target) { if (tex == 0) { glGenTextures(1, &tex); glBindTexture(target, tex); } QImage im = QGLWidget::convertToGLFormat(image); //const QImage & cim(im); //glClearError(); //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if (target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_3D) { glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); } glTexImage2D(target, 0, format, im.width(), im.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, im.bits()); //qDebug() << tex << im.width() << im.height() << im.bits() << glGetError(); } QMatrix4x4 glMatrixPerspective(double angle, double aspect, double near_, double far_) { QMatrix4x4 ret; double t = 1. / (tan(angle * deg2rad / 2.)); ret(0, 0) = t / aspect; ret(1, 1) = t; ret(2, 2) = far_ / (far_ - near_) - 1.; ret(2, 3) = 2. * far_ * near_ / (far_ - near_); ret(3, 2) = -1; ret(3, 3) = 0.; return ret; } QImage rotateQImageLeft(const QImage & im) { QImage ri(im.height(), im.width(), im.format()); QPainter p(&ri); p.rotate(90); p.drawImage(0, -im.height(), im); p.end(); return ri; } QImage rotateQImageRight(const QImage & im) { QImage ri(im.height(), im.width(), im.format()); QPainter p(&ri); p.rotate(-90); p.drawImage(-im.width(), 0, im); p.end(); return ri; } void Camera::anglesFromPoints() { QVector3D dv = aim_ - pos_, tv; tv = QVector3D(dv.x(), dv.y(), 0.); angle_z = atan2(tv.x(), tv.y()) * rad2deg; angle_xy = piClamp(atan2(tv.length(), dv.z()) * rad2deg + 180., angle_limit_lower_xy, angle_limit_upper_xy); } void Camera::apply(const GLdouble & aspect) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); 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);; setGLMatrix(pm); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslated(0., 0., -distance()); glRotated(angle_xy, 1., 0., 0.); glRotated(angle_roll, 0., -1., 0.); glRotated(angle_z, 0., 0., 1.); //glTranslated(pos_.x(), pos_.y(), pos_.z()); //if (mirror_y) glScalef(1,-1,-1); //if (mirror_x) glScalef(-1,1,-1); //glScalef(-1,-1,1); glTranslated(-aim_.x(), -aim_.y(), -aim_.z()); glGetIntegerv(GL_VIEWPORT, viewport); glGetDoublev(GL_PROJECTION_MATRIX, projection); glGetDoublev(GL_MODELVIEW_MATRIX, modelview); //qDebug() << "viewport" << viewport[0] << viewport[1] << viewport[2] << viewport[3]; } void Camera::panZ(const double & a) { QVector3D dv = aim_ - pos_; double tl = QVector2D(dv.x(), dv.y()).length(); angle_z += a; dv = QVector3D(sin(angle_z * deg2rad) * tl, cos(angle_z * deg2rad) * tl, dv.z()); aim_ = pos_ + dv; } void Camera::panXY(const double & a) { QVector3D dv = aim_ - pos_; double tl = dv.length(), tc; angle_xy += a; angle_xy = piClamp(angle_xy, angle_limit_lower_xy, angle_limit_upper_xy); tc = -sin(angle_xy * deg2rad); dv = QVector3D(sin(angle_z * deg2rad) * tl * tc, cos(angle_z * deg2rad) * tl * tc, -cos(angle_xy * deg2rad) * tl); aim_ = pos_ + dv; } void Camera::rotateZ(const double & a) { QVector3D dv = aim_ - pos_; double tl = QVector2D(dv.x(), dv.y()).length(); angle_z += a; dv = QVector3D(sin(angle_z * deg2rad) * tl, cos(angle_z * deg2rad) * tl, dv.z()); aim_ = pos_ + dv; } void Camera::rotateXY(const double & a) { QVector3D dv = aim_ - pos_; double tl = dv.length(), tc; angle_xy += a; angle_xy = piClamp(angle_xy, angle_limit_lower_xy, angle_limit_upper_xy); tc = -sin(angle_xy * deg2rad); dv = QVector3D(sin(angle_z * deg2rad) * tl * tc, cos(angle_z * deg2rad) * tl * tc, -cos(angle_xy * deg2rad) * tl); aim_ = pos_ + dv; } void Camera::orbitZ(const double & a) { QVector3D dv = aim_ - pos_; double tl = QVector2D(dv.x(), dv.y()).length(); angle_z += a; dv = QVector3D(sin(angle_z * deg2rad) * tl, cos(angle_z * deg2rad) * tl, dv.z()); pos_ = aim_ - dv; } void Camera::orbitXY(const double & a) { QVector3D dv = aim_ - pos_; double tl = dv.length(), tc; angle_xy += a; angle_xy = piClamp(angle_xy, angle_limit_lower_xy, angle_limit_upper_xy); tc = -sin(angle_xy * deg2rad); dv = QVector3D(sin(angle_z * deg2rad) * tl * tc, cos(angle_z * deg2rad) * tl * tc, -cos(angle_xy * deg2rad) * tl); pos_ = aim_ - dv; } void Camera::setAngleZ(const double & a) { QVector3D dv = aim_ - pos_; double tl = QVector2D(dv.x(), dv.y()).length(); angle_z = a; dv = QVector3D(sin(angle_z * deg2rad) * tl, cos(angle_z * deg2rad) * tl, dv.z()); aim_ = pos_ + dv; } void Camera::setAngleXY(const double & a) { QVector3D dv = aim_ - pos_; double tl = dv.length(), tc; angle_xy = a; tc = -sin(angle_xy * deg2rad); dv = QVector3D(sin(angle_z * deg2rad) * tl * tc, cos(angle_z * deg2rad) * tl * tc, -cos(angle_xy * deg2rad) * tl); //pos_ = aim_ - dv; aim_ = pos_ + dv; //anglesFromPoints(); } void Camera::moveForward(const double & x, bool withZ) { QVector3D dv;// = aim_ - pos_; double tc = -sin(angle_xy * deg2rad); dv = QVector3D(sin(angle_z * deg2rad) * tc, cos(angle_z * deg2rad) * tc, 0.); if (withZ) dv.setZ(-cos(angle_xy * deg2rad)); dv.normalize(); dv *= x; pos_ += dv; aim_ += dv; } void Camera::moveLeft(const double & x, bool withZ) { QVector3D dv;// = aim_ - pos_; double tc = -sin(angle_xy * deg2rad); dv = QVector3D(sin(angle_z * deg2rad - M_PI_2) * tc, cos(angle_z * deg2rad - M_PI_2) * tc, 0.); if (withZ) dv.setZ(-sin(angle_roll * deg2rad)); dv.normalize(); dv *= x; pos_ += dv; aim_ += dv; } void Camera::moveUp(const double & x, bool onlyZ) { QVector3D dv; if (onlyZ) dv = QVector3D(0., 0., x); else { double tc = cos(angle_xy * deg2rad); dv = QVector3D(sin(angle_z * deg2rad) * tc, cos(angle_z * deg2rad) * tc, -sin(angle_xy * deg2rad)); dv.normalize(); dv *= x; } pos_ += dv; aim_ += dv; } void Camera::flyCloser(const double & s) { QVector3D dv = aim_ - pos_; double tl = dv.length() / (1. + s), tc = -sin(angle_xy * deg2rad); dv = QVector3D(sin(angle_z * deg2rad) * tl * tc, cos(angle_z * deg2rad) * tl * tc, -cos(angle_xy * deg2rad) * tl); pos_ = aim_ - dv; } void Camera::flyFarer(const double & s) { QVector3D dv = aim_ - pos_; double tl = dv.length() * (1. + s), tc = -sin(angle_xy * deg2rad); dv = QVector3D(sin(angle_z * deg2rad) * tl * tc, cos(angle_z * deg2rad) * tl * tc, -cos(angle_xy * deg2rad) * tl); pos_ = aim_ - dv; } void Camera::flyToDistance(const double & d) { QVector3D dv = aim_ - pos_; double tc = -sin(angle_xy * deg2rad); dv = QVector3D(sin(angle_z * deg2rad) * d * tc, cos(angle_z * deg2rad) * d * tc, -cos(angle_xy * deg2rad) * d); pos_ = aim_ - dv; } 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); } QColor colorFromString(const QString & str) { QString s = str.trimmed(); int i = s.indexOf("\t"); double r, g, b; r = s.left(i).toFloat(); s = s.right(s.length() - i - 1); i = s.indexOf("\t"); g = s.left(i).toFloat(); s = s.right(s.length() - i - 1); b = s.toFloat(); return QColor(r * 255., g * 255., b * 255.); } QVector3D orthToVector(const QVector3D & v, const double & scale) { if (v.isNull()) return QVector3D(); QVector3D rv, fn, sn; if (v.x() != 0) rv.setZ(1.); else if (v.y() != 0) rv.setX(1.); else rv.setY(1.); fn = QVector3D::crossProduct(v, rv).normalized(); sn = QVector3D::crossProduct(v, fn).normalized(); return fn * urand(scale) + sn * urand(scale); } QVector3D rotateVector(const QVector3D & v, const QVector3D & a) { QMatrix4x4 m; m.rotate(a.z(), 0., 0., 1.); m.rotate(a.y(), 0., 1., 0.); m.rotate(a.x(), 1., 0., 0.); return m * v; } void setVectorLength(QVector3D & v, const double & l) { double vl = v.length(); if (vl == 0.) return; double c = l / vl; v *= c; } void lengthenVector(QVector3D & v, const double & l) { double vl = v.length(); if (l == 0. || vl == 0.) return; double c = 1. + l / vl; v *= c; } Vector3d::Vector3d(const QString & str) { QString s = str.trimmed(); int i = s.indexOf("\t"); x = s.left(i).toFloat(); s = s.right(s.length() - i - 1); i = s.indexOf("\t"); y = s.left(i).toFloat(); s = s.right(s.length() - i - 1); z = s.toFloat(); } Vector3i::Vector3i(const QString & str) { QString s = str.trimmed(); int i = s.indexOf("\t"); p0 = s.left(i).toInt(); s = s.right(s.length() - i - 1); i = s.indexOf("\t"); p1 = s.left(i).toInt(); s = s.right(s.length() - i - 1); p2 = s.toInt(); } void glEnableDepth() { glEnable(GL_DEPTH_TEST); //glDepthFunc(GL_GREATER); glDepthFunc(GL_LESS); glDepthMask(GL_TRUE); } void glDisableDepth() { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); } void glClearFramebuffer(const QColor & color, bool depth) { glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF()); glClearDepth(1.); if (depth) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); else glClear(GL_COLOR_BUFFER_BIT); }