/* 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 . */ #ifndef GLTYPES_H #define GLTYPES_H #if WIN32 || WIN64 || _WIN32 || _WIN64 || __WIN32__ || __WIN64__ # define WINDOWS #endif #if __QNX__ || __QNXNTO__ # define QNX #endif #ifdef __APPLE__ # define MAC #endif #ifndef WINDOWS # ifndef QNX # ifndef MAC # define LINUX # endif # endif #endif #if __GNUC__ # define CC_GCC #elif _MSC_VER # define CC_VC #endif #include #ifndef WINDOWS # ifdef MAC # include # include # include # else # include # include # include # endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef QNX # include # include #else # include # include #endif #include #ifdef WINDOWS # define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF # define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #endif #ifndef M_PI # define M_PI 3.14159265358979323846 #endif #ifndef M_2PI # define M_2PI 6.28318530717958647692 #endif #ifndef M_PI_3 # define M_PI_3 1.04719755119659774615 #endif #ifndef GL_RGBA16F # define GL_RGBA16F GL_RGBA16F_ARB #endif using std::complex; #ifndef PIP_VERSION typedef long long llong; typedef unsigned char uchar; typedef unsigned short int ushort; typedef unsigned int uint; typedef unsigned long ulong; typedef unsigned long long ullong; typedef long double ldouble; const float deg2rad = atanf(1.f) / 45.f; const float rad2deg = 45.f / atanf(1.f); # ifdef WINDOWS inline int random() { return rand(); } # endif #else # define random randomi #endif #ifdef CC_VC inline float round(const float & v) { return floor(v + 0.5); } #endif inline float randomu() { return float(random()) / RAND_MAX; } inline const QSizeF operator*(const QSizeF & f, const QSizeF & s) { return QSizeF(f.width() * s.width(), f.height() * s.height()); } #ifndef PIP_VERSION template inline void piSwap(T & f, T & s) { T t(f); f = s; s = t; } template inline Type piMin(const Type & f, const Type & s) { return (f > s) ? s : f; } template inline Type piMin(const Type & f, const Type & s, const Type & t) { return (f < s && f < t) ? f : ((s < t) ? s : t); } template inline Type piMax(const Type & f, const Type & s) { return (f < s) ? s : f; } template inline Type piMax(const Type & f, const Type & s, const Type & t) { return (f > s && f > t) ? f : ((s > t) ? s : t); } template inline Type piClamp(const Type & v, const Type & min, const Type & max) { return (v > max ? max : (v < min ? min : v)); } inline ushort letobe_s(ushort v) { return (v << 8) | (v >> 8); } #endif // return [-1, 1] inline float urand(const float & scale = 1.) { return ((float)rand() / RAND_MAX - .5f) * (scale + scale); } // return [0, 1] inline float uprand(const float & scale = 1.) { return ((float)rand() / RAND_MAX) * scale; } QString readCharsUntilNull(QDataStream & s); QString findFile(const QString & file, const QStringList & pathes); inline QColor operator*(const QColor & c, float v) { return QColor(piClamp(c.red() * v, 0, 255), piClamp(c.green() * v, 0, 255), piClamp(c.blue() * v, 0, 255), piClamp(c.alpha() * v, 0, 255)); } inline QColor operator/(const QColor & c, float v) { return QColor(piClamp(c.red() / v, 0, 255), piClamp(c.green() / v, 0, 255), piClamp(c.blue() / v, 0, 255), piClamp(c.alpha() / v, 0, 255)); } // extern __GLWidget__ * currentQGLView; inline void qglColor(const QColor & c) { glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF()); } void qglMultMatrix(const QMatrix4x4 & m); void glEnableDepth(); void glDisableDepth(); inline void glResetAllTransforms() { glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } inline void glClearError() { int c = 100; while (glGetError() != GL_NO_ERROR && --c > 0) glGetError(); } inline void glClearAccumulation(const QColor & color = Qt::black) { glClearAccum(color.redF(), color.greenF(), color.blueF(), color.alphaF()); glClear(GL_ACCUM_BUFFER_BIT); } void glClearFramebuffer(const QColor & color = Qt::black, bool depth = true); inline void glSetCapEnabled(GLenum cap, bool on = true) { if (on) glEnable(cap); else glDisable(cap); } inline void glSetLightEnabled(bool on) { if (on) glEnable(GL_LIGHTING); else glDisable(GL_LIGHTING); } inline void glSetFogEnabled(bool on) { if (on) glEnable(GL_FOG); else glDisable(GL_FOG); } inline void glSetPolygonMode(GLenum mode) { glPolygonMode(GL_FRONT_AND_BACK, mode); } void glDrawQuad(QOpenGLShaderProgram * prog = 0, QVector4D * corner_dirs = 0, GLfloat x = -1.f, GLfloat y = -1.f, GLfloat w = 2.f, GLfloat h = 2.f); QMatrix4x4 getGLMatrix(GLenum matrix); void setGLMatrix(QMatrix4x4 matrix); inline void deleteGLTexture(GLuint & tex) { if (tex != 0) glDeleteTextures(1, &tex); tex = 0; } // # define QGLCI if (!QOpenGLContext::currentContext()) return; QOpenGLFunctions gf(QOpenGLContext::currentContext()); // # define QGLC gf. // inline void glActiveTextureChannel(int channel) {QGLCI gf.glActiveTexture(GL_TEXTURE0 + channel);} // inline void glDisableTextures(int channels = 8) {QGLCI for (int i = channels - 1; i >= 0; --i) {glActiveTextureChannel(i); // glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_CUBE_MAP);}} inline void glReleaseTextures(int channels = 8) {QGLCI for (int i = channels // - 1; i >= 0; --i) {glActiveTextureChannel(i); glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, 0);}} inline void // glReleaseFramebuffer() {QGLCI gf.glBindFramebuffer(GL_FRAMEBUFFER, 0);} inline void glReleaseShaders() {QGLCI gf.glUseProgram(0);} inline // void deleteGLFramebuffer(GLuint & fbo) {QGLCI if (fbo != 0) gf.glDeleteFramebuffers(1, &fbo); fbo = 0;} inline void // deleteGLRenderbuffer(GLuint & drbo) {QGLCI if (drbo != 0) gf.glDeleteRenderbuffers(1, &drbo); drbo = 0;} inline void // deleteGLBuffer(GLuint & bo) {QGLCI if (bo != 0) gf.glDeleteBuffers(1, &bo); bo = 0;} inline void deleteGLVertexArray(GLuint & va) {QGLCI // if (va != 0) gf.glDeleteVertexArrays(1, &va); va = 0;} void createGLTexture(GLuint & tex, int width, int height, const GLenum & format = GL_RGBA8, const GLenum & target = GL_TEXTURE_2D); void createGLTexture(GLuint & tex, const QImage & image, const GLenum & format = GL_RGBA8, const GLenum & target = GL_TEXTURE_2D); inline void qglTranslate(const QVector3D & v) { glTranslatef(v.x(), v.y(), v.z()); } inline void qglScale(const QVector3D & v) { glScalef(v.x(), v.y(), v.z()); } QMatrix4x4 glMatrixPerspective(float angle, float aspect, float near_, float far_); QImage rotateQImageLeft(const QImage & im); QImage rotateQImageRight(const QImage & im); inline QImage rotateQImage180(const QImage & im) { return im.mirrored(true, true); } // const double deg2rad = atan(1.) / 45.; // const double rad2deg = 45. / atan(1.); struct Box3D { GLfloat x; GLfloat y; GLfloat z; GLfloat width; GLfloat length; GLfloat height; GLfloat angle_z; GLfloat angle_xy; GLfloat angle_roll; Box3D() { x = y = z = width = length = height = angle_z = angle_xy = angle_roll = 0.f; } Box3D(const QVector3D & center, GLfloat hwid, GLfloat hlen, GLfloat hhei) { x = center.x() - hwid; y = center.y() - hlen; z = center.z() - hhei; width = 2 * hwid; length = 2 * hlen; height = 2 * hhei; angle_z = angle_xy = angle_roll = 0.f; } Box3D(const QVector & points); bool isEmpty() const { return (qAbs(width) < 1E-6f) || (qAbs(length) < 1E-6f) || (qAbs(height) < 1E-6f); } QVector3D randomPoint() const { return QVector3D(uprand(length) + x, uprand(width) + y, uprand(height) + z); } QVector3D pos() const { return QVector3D(x, y, z); } QVector3D size() const { return QVector3D(length, width, height); } QVector3D center() const { return QVector3D(length / 2.f + x, width / 2.f + y, height / 2.f + z); } QVector3D angles() const { return QVector3D(angle_xy, angle_roll, angle_z); } QVector corners() const; void setPos(const QVector3D & p) { x = p.x(); y = p.y(); z = p.z(); } void setAngles(const QVector3D & a) { angle_xy = a.x(); angle_roll = a.y(); angle_z = a.z(); } void setSize(const QVector3D & s) { length = s.x(); width = s.y(); height = s.z(); } Box3D & moveTo(const QVector3D & v) { x = v.x(); y = v.y(); z = v.z(); return *this; } Box3D & move(const QVector3D & v) { x += v.x(); y += v.y(); z += v.z(); return *this; } Box3D movedTo(const QVector3D & v) const { Box3D t(*this); t.x = v.x(); t.y = v.y(); t.z = v.z(); return t; } Box3D moved(const QVector3D & v) const { Box3D t(*this); t.x += v.x(); t.y += v.y(); t.z += v.z(); return t; } Box3D & operator|=(const Box3D & o); }; inline QDebug operator<<(QDebug d, const Box3D & v) { d << "Box3D {start (" << v.x << "," << v.y << "," << v.z << "), size (" << v.length << "," << v.width << "," << v.height << ")}"; return d; } struct Vector3d; GLfloat dot(const Vector3d & v0, const Vector3d & v1); struct Vector3d { GLfloat x; GLfloat y; GLfloat z; Vector3d(GLfloat x_ = 0., GLfloat y_ = 0., GLfloat z_ = 0.) { x = x_; y = y_; z = z_; } Vector3d(const QVector3D & v) { x = v.x(); y = v.y(); z = v.z(); } Vector3d(const QString & str); inline void clear() { x = y = z = 0.; } inline GLfloat length() const { return sqrtf(x * x + y * y + z * z); } inline GLfloat lengthSquared() const { return x * x + y * y + z * z; } Vector3d & normalize() { GLfloat l = length(); if (l == 0.f) return *this; x /= l; y /= l; z /= l; return *this; } Vector3d normalized() { return Vector3d(*this).normalize(); } Vector3d projectTo(Vector3d dir) { dir.normalize(); return dir * dot(dir, *this); } Vector3d operator*(const GLfloat v) { return Vector3d(x * v, y * v, z * v); } Vector3d operator/(const GLfloat v) { return Vector3d(x / v, y / v, z / v); } Vector3d operator+(const GLfloat v) { return Vector3d(x + v, y + v, z + v); } Vector3d operator-(const GLfloat v) { return Vector3d(x - v, y - v, z - v); } Vector3d operator+(const Vector3d & v) { return Vector3d(x + v.x, y + v.y, z + v.z); } Vector3d operator-(const Vector3d & v) { return Vector3d(x - v.x, y - v.y, z - v.z); } Vector3d operator-() { return Vector3d(-x, -y, -z); } Vector3d & operator*=(const GLfloat & v) { x *= v; y *= v; z *= v; return *this; } Vector3d & operator/=(const GLfloat & v) { x /= v; y /= v; z /= v; return *this; } Vector3d & operator+=(const GLfloat & v) { x += v; y += v; z += v; return *this; } Vector3d & operator-=(const GLfloat & v) { x -= v; y -= v; z -= v; return *this; } Vector3d & operator+=(const Vector3d & v) { x += v.x; y += v.y; z += v.z; return *this; } Vector3d & operator-=(const Vector3d & v) { x -= v.x; y -= v.y; z -= v.z; return *this; } bool operator==(const Vector3d & v) { return x == v.x && y == v.y && z == v.z; } QVector3D toQVector3D() const { return QVector3D(x, y, z); } }; inline Vector3d operator*(const Vector3d & v0, const Vector3d & v1) { return Vector3d(v0.y * v1.z - v1.y * v0.z, v1.x * v0.z - v0.x * v1.z, v0.x * v1.y - v1.x * v0.y); } inline GLfloat dot(const Vector3d & v0, const Vector3d & v1) { return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z; } struct Vector2d { GLfloat x; GLfloat y; Vector2d(GLfloat x_ = 0., GLfloat y_ = 0.) { x = x_; y = y_; } Vector2d(const Vector3d & v3) { x = v3.x; y = v3.y; } Vector2d operator*(const GLfloat v) { return Vector2d(x * v, y * v); } Vector2d operator/(const GLfloat v) { return Vector2d(x / v, y / v); } Vector2d operator+(const GLfloat v) { return Vector2d(x + v, y + v); } Vector2d operator-(const GLfloat v) { return Vector2d(x - v, y - v); } Vector2d operator+(const Vector3d & v) { return Vector3d(x + v.x, y + v.y); } Vector2d operator-(const Vector3d & v) { return Vector3d(x - v.x, y - v.y); } Vector2d operator+(const Vector2d & v) { return Vector2d(x + v.x, y + v.y); } Vector2d operator-(const Vector2d & v) { return Vector2d(x - v.x, y - v.y); } Vector2d & operator*=(const GLfloat & v) { x *= v; y *= v; return *this; } Vector2d & operator/=(const GLfloat & v) { x /= v; y /= v; return *this; } Vector2d & operator+=(const GLfloat & v) { x += v; y += v; return *this; } Vector2d & operator-=(const GLfloat & v) { x -= v; y -= v; return *this; } Vector2d & operator+=(const Vector3d & v) { x += v.x; y += v.y; ; return *this; } Vector2d & operator-=(const Vector3d & v) { x -= v.x; y -= v.y; ; return *this; } }; struct Vector3i { Vector3i(int p0_ = 0, int p1_ = 0, int p2_ = 0) { p0 = p0_; p1 = p1_; p2 = p2_; } Vector3i(const QString & str); Vector3i movedX(const int & o) { return Vector3i(p0 + o, p1, p2); } Vector3i movedY(const int & o) { return Vector3i(p0, p1 + o, p2); } Vector3i movedZ(const int & o) { return Vector3i(p0, p1, p2 + o); } Vector3i moved(const int & x, const int & y, const int & z) { return Vector3i(p0 + x, p1 + y, p2 + z); } int p0; int p1; int p2; bool operator==(const Vector3i & o) const { return p0 == o.p0 && p1 == o.p1 && p2 == o.p2; } bool operator!=(const Vector3i & o) const { return p0 != o.p0 || p1 != o.p1 || p2 != o.p2; } QVector3D toQVector3D() const { return QVector3D(p0, p1, p2); } }; inline Vector3i operator+(const Vector3i & f, const Vector3i & s) { return Vector3i(f.p0 + s.p0, f.p1 + s.p1, f.p2 + s.p2); } inline Vector3i operator-(const Vector3i & f, const Vector3i & s) { return Vector3i(f.p0 - s.p0, f.p1 - s.p1, f.p2 - s.p2); } inline Vector3i operator/(const Vector3i & f, const int & s) { return Vector3i(f.p0 / s, f.p1 / s, f.p2 / s); } inline uint qHash(const Vector3i & v) { return v.p0 + v.p1 * 1024 + v.p2 * 1024 * 1024; } inline QDebug operator<<(QDebug d, const Vector3d & v) { d.nospace() << "{" << v.x << ", " << v.y << ", " << v.z << "}"; return d.space(); } inline QDebug operator<<(QDebug d, const Vector3i & v) { d.nospace() << "{" << v.p0 << ", " << v.p1 << ", " << v.p2 << "}"; return d.space(); } inline QDataStream & operator<<(QDataStream & s, const Vector3d & v) { s << v.x << v.y << v.z; return s; } inline QDataStream & operator>>(QDataStream & s, Vector3d & v) { s >> v.x >> v.y >> v.z; return s; } inline QDataStream & operator<<(QDataStream & s, const Vector3i & v) { s << v.p0 << v.p1 << v.p2; return s; } inline QDataStream & operator>>(QDataStream & s, Vector3i & v) { s >> v.p0 >> v.p1 >> v.p2; return s; } QColor colorFromString(const QString & str); inline float cosABV(const QVector3D & v0, const QVector3D & v1) { float l = v0.length() * v1.length(); if (l == 0.f) return 0.; return (QVector3D::dotProduct(v0, v1)) / l; } inline QVector3D projection(const QVector3D & v, const QVector3D & to) { return to.normalized() * v.length() * cosABV(v, to); } QVector3D orthToVector(const QVector3D & v, const float & scale = 1.); QVector3D rotateVector(const QVector3D & v, const QVector3D & a); void setVectorLength(QVector3D & v, const float & l); void lengthenVector(QVector3D & v, const float & l); inline float squareLength(const QVector3D & from, const QVector3D & to) { return (to.x() - from.x()) * (to.x() - from.x()) + (to.y() - from.y()) * (to.y() - from.y()) + (to.z() - from.z()) * (to.z() - from.z()); } inline QVector3D directionFromAngles(const QVector3D & a) { return rotateVector(QVector3D(1., 0., 0.), a); } inline float frac(const float & x, const float & b) { return x - int(x / b) * b; } class GLObjectBase; class QGLView; class Light; class Camera; class GLTextureManagerBase; class QGLViewBase { friend class GLObjectBase; public: QGLViewBase(); virtual ~QGLViewBase(); Camera * camera(); const Camera * camera() const; void setCamera(Camera * camera); GLTextureManagerBase * textureManager(); protected: virtual void collectLights() = 0; Camera * camera_; GLTextureManagerBase * textures_manager; }; #endif // GLTYPES_H