/* 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 "glcamera.h" #include "qglview.h" __GLWidget__ * currentQGLView; 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(__GLShaderProgram__ * prog, QVector4D * corner_dirs, GLfloat x, GLfloat y, GLfloat w, GLfloat h) { QGLCI glResetAllTransforms(); glSetPolygonMode(GL_FILL); int loc = prog ? prog->attributeLocation("qgl_Color") : 0, locv = prog ? prog->attributeLocation("qgl_Vertex") : 0, loct = prog ? prog->attributeLocation("qgl_Texture") : 0, locc = prog ? prog->attributeLocation("view_corner") : 0; glBegin(GL_QUADS); if (prog) {QGLC glVertexAttrib3f(loc, 1.f, 1.f, 1.f);} glColor3f(1.f, 1.f, 1.f); if (prog) {if (corner_dirs) prog->setAttributeValue(locc, corner_dirs[0]); QGLC glVertexAttrib2f(loct, 0.f, 0.f); QGLC glVertexAttrib2f(locv, x, y);} glTexCoord2f(0.f, 0.f); glVertex2f(x, y); if (prog) {if (corner_dirs) prog->setAttributeValue(locc, corner_dirs[1]); QGLC glVertexAttrib2f(loct, 1.f, 0.f); QGLC glVertexAttrib2f(locv, x + w, y);} glTexCoord2f(1.f, 0.f); glVertex2f(x + w, y); if (prog) {if (corner_dirs) prog->setAttributeValue(locc, corner_dirs[2]); QGLC glVertexAttrib2f(loct, 1.f, 1.f); QGLC glVertexAttrib2f(locv, x + w, y + h);} glTexCoord2f(1.f, 1.f); glVertex2f(x + w, y + h); if (prog) {if (corner_dirs) prog->setAttributeValue(locc, corner_dirs[3]); QGLC glVertexAttrib2f(loct, 0.f, 1.f); QGLC glVertexAttrib2f(locv, x, y + h);} glTexCoord2f(0.f, 1.f); glVertex2f(x, y + h); glEnd(); } QMatrix4x4 getGLMatrix(GLenum matrix) { GLdouble gm[16]; glGetDoublev(matrix, gm); #if QT_VERSION < 0x050600 qreal #else float #endif qm[16]; for (int i = 0; i < 16; ++i) qm[i] = gm[i]; return QMatrix4x4(qm).transposed(); } void setGLMatrix(QMatrix4x4 matrix) { GLdouble gm[16]; #if QT_VERSION < 0x050600 qreal #else float #endif qm[16]; matrix.transposed().copyDataTo(qm); for (int i = 0; i < 16; ++i) gm[i] = qm[i]; glLoadMatrixd(gm); } void qglMultMatrix(const QMatrix4x4 & m) { GLdouble gm[16]; #if QT_VERSION < 0x050600 qreal #else float #endif 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; int f = GL_RGBA; if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGBA32F || format == GL_RGBA16F) t = GL_FLOAT; if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGB8 || format == GL_RGB) f = GL_RGB; glTexImage2D(target, 0, format, width, height, 0, f, t, 0); //glGenerateMipmap(target); //qDebug() << "glTexImage2D" << width << height << QString::number(t, 16); } //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 = image.mirrored(false, true);///__GLWidget__::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_BGRA, 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.)), e = 2.4e-7; ret(0, 0) = t / aspect; ret(1, 1) = t; ret(2, 2) = e - 1.;//far_ / (far_ - near_) - 1.; ret(2, 3) = (e - 2.) * near_;//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; } 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(0.); if (depth) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); else glClear(GL_COLOR_BUFFER_BIT); } QGLViewBase::QGLViewBase() { camera_ = new Camera(); } Camera & QGLViewBase::camera() { return *camera_; } const Camera & QGLViewBase::camera() const { return *camera_; } void QGLViewBase::setCamera(const Camera & camera) { *camera_ = camera; } Box3D::Box3D(const QVector & points) { x = y = z = width = length = height = angle_z = angle_xy = angle_roll = 0.f; if (points.isEmpty()) return; float ix, iy, iz, ax, ay, az; ix = ax = points[0].x(); iy = ay = points[0].y(); iz = az = points[0].z(); for (int i = 1; i < points.size(); ++i) { ix = qMin(ix, points[i].x()); ax = qMax(ax, points[i].x()); iy = qMin(iy, points[i].y()); ay = qMax(ay, points[i].y()); iz = qMin(iz, points[i].z()); az = qMax(az, points[i].z()); } x = ix; y = iy; z = iz; length = ax - ix; width = ay - iy; height = az - iz; } QVector Box3D::corners() const { QVector ret; ret << QVector3D(x, y, z) << QVector3D(x, y + width, z) << QVector3D(x, y, z + height) << QVector3D(x, y + width, z + height) << QVector3D(x + length, y, z) << QVector3D(x + length, y + width, z) << QVector3D(x + length, y, z + height) << QVector3D(x + length, y + width, z + height); return ret; } Box3D & Box3D::operator |=(const Box3D & o) { if (isEmpty()) *this = o; else { GLfloat mx = x + length, my = y + width, mz = z + height; GLfloat omx = o.x + o.length, omy = o.y + o.width, omz = o.z + o.height; x = qMin(x, o.x); y = qMin(y, o.y); z = qMin(z, o.z); mx = qMax(mx, omx); my = qMax(my, omy); mz = qMax(mz, omz); length = mx - x; width = my - y; height = mz - z; } return *this; }