292 lines
8.3 KiB
C++
292 lines
8.3 KiB
C++
/*
|
|
QGLView
|
|
Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "glcamera.h"
|
|
#include "qglview.h"
|
|
|
|
QGLWidget * 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(QGLShaderProgram * prog, QVector4D * corner_dirs, GLfloat x, GLfloat y, GLfloat w, GLfloat h) {
|
|
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) 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]); glVertexAttrib2f(loct, 0.f, 0.f); glVertexAttrib2f(locv, x, y);} glTexCoord2f(0.f, 0.f); glVertex2f(x, y);
|
|
if (prog) {if (corner_dirs) prog->setAttributeValue(locc, corner_dirs[1]); glVertexAttrib2f(loct, 1.f, 0.f); 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]); glVertexAttrib2f(loct, 1.f, 1.f); 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]); glVertexAttrib2f(loct, 0.f, 1.f); 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);
|
|
qreal qm[16];
|
|
for (int i = 0; i < 16; ++i)
|
|
qm[i] = gm[i];
|
|
return QMatrix4x4(qm).transposed();
|
|
}
|
|
|
|
|
|
void setGLMatrix(QMatrix4x4 matrix) {
|
|
GLdouble gm[16];
|
|
qreal 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];
|
|
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;
|
|
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 = 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.)), 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;
|
|
}
|