/* 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 "glcamera.h" #include "qglview.h" #include //__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(QOpenGLShaderProgram * prog, QVector4D * corner_dirs, GLfloat x, GLfloat y, GLfloat w, GLfloat h) { glResetAllTransforms(); glSetPolygonMode(GL_FILL); glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); int loc = prog ? prog->attributeLocation("qgl_Color") : -1, locv = prog ? prog->attributeLocation("qgl_Vertex") : -1, loct = prog ? prog->attributeLocation("qgl_Texture") : -1, locc = prog ? prog->attributeLocation("view_corner") : -1; //if (prog) {qDebug() << locv << loct << locc;} QOpenGLFunctions * glFuncs = QOpenGLContext::currentContext()->functions(); if (prog) { static const GLfloat cols [] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f}; static const GLfloat verts[] = {x, y, x+w, y, x, y+h, x+w, y+h}; static const GLfloat texs [] = {0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f}; GLfloat vcs[] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; if (corner_dirs) { vcs[0] = corner_dirs[0].x(); vcs[1] = corner_dirs[0].y(); vcs[2] = corner_dirs[0].z(); vcs[3] = corner_dirs[1].x(); vcs[4] = corner_dirs[1].y(); vcs[5] = corner_dirs[1].z(); vcs[6] = corner_dirs[2].x(); vcs[7] = corner_dirs[2].y(); vcs[8] = corner_dirs[2].z(); vcs[9] = corner_dirs[3].x(); vcs[10] = corner_dirs[3].y(); vcs[11] = corner_dirs[3].z(); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glFuncs->glBindBuffer(GL_ARRAY_BUFFER, 0); glFuncs->glEnableVertexAttribArray(loc); glFuncs->glVertexAttribPointer(loc, 3, GL_FLOAT, 0, 0, cols); glFuncs->glEnableVertexAttribArray(locv); glFuncs->glVertexAttribPointer(locv, 2, GL_FLOAT, 0, 0, verts); glFuncs->glEnableVertexAttribArray(loct); glFuncs->glVertexAttribPointer(loct, 2, GL_FLOAT, 0, 0, texs); glFuncs->glEnableVertexAttribArray(locc); glFuncs->glVertexAttribPointer(locc, 3, GL_FLOAT, 0, 0, vcs); glFuncs->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glFuncs->glDisableVertexAttribArray(loc); glFuncs->glDisableVertexAttribArray(locv); glFuncs->glDisableVertexAttribArray(loct); glFuncs->glDisableVertexAttribArray(locc); } else { glBegin(GL_TRIANGLE_STRIP); glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(0.f, 0.f); glVertex2f(x, y); glTexCoord2f(1.f, 0.f); glVertex2f(x+w, y); glTexCoord2f(0.f, 1.f); glVertex2f(x, y+h); glTexCoord2f(1.f, 1.f); glVertex2f(x+w, y+h); glEnd(); } } QMatrix4x4 getGLMatrix(GLenum matrix) { GLfloat gm[16]; glGetFloatv(matrix, gm); float qm[16]; for (int i = 0; i < 16; ++i) qm[i] = gm[i]; return QMatrix4x4(qm).transposed(); } void setGLMatrix(QMatrix4x4 matrix) { GLfloat gm[16]; float qm[16]; matrix.transposed().copyDataTo(qm); for (int i = 0; i < 16; ++i) gm[i] = qm[i]; glLoadMatrixf(gm); } void qglMultMatrix(const QMatrix4x4 & m) { GLfloat gm[16]; float qm[16]; m.transposed().copyDataTo(qm); for (int i = 0; i < 16; ++i) gm[i] = qm[i]; glMultMatrixf(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, nullptr); 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, nullptr); //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).convertToFormat(QImage::Format_ARGB32, Qt::ColorOnly); //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(float angle, float aspect, float near_, float far_) { QMatrix4x4 ret; float t = 1.f / (tanf(angle * deg2rad / 2.f)), e = 2.4e-7f; ret(0, 0) = t / aspect; ret(1, 1) = t; ret(2, 2) = e - 1.f;//far_ / (far_ - near_) - 1.; ret(2, 3) = (e - 2.f) * near_;//2. * far_ * near_ / (far_ - near_); ret(3, 2) = -1.f; ret(3, 3) = 0.f; 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"); float 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.f, g * 255.f, b * 255.f); } QVector3D orthToVector(const QVector3D & v, const float & scale) { if (v.isNull()) return QVector3D(); QVector3D rv, fn, sn; if (v.x() != 0.f) rv.setZ(1.); else if (v.y() != 0.f) 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 float & l) { float vl = v.length(); if (vl == 0.f) return; float c = l / vl; v *= c; } void lengthenVector(QVector3D & v, const float & l) { float vl = v.length(); if (l == 0.f || vl == 0.f) return; float c = 1.f + 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(); textures_manager = new GLTextureManager(); } QGLViewBase::~QGLViewBase() { delete textures_manager; } Camera * QGLViewBase::camera() { return camera_; } const Camera * QGLViewBase::camera() const { return camera_; } void QGLViewBase::setCamera(Camera * camera) { camera_ = camera; } GLTextureManagerBase * QGLViewBase::textureManager() { return textures_manager; } 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; }