/* 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; GLTextureManager * currentGLTextureManager; 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; } 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, 4, 4).transposed(); } 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 glTexImage2D(target, 0, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 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(); } bool loadShaders(QGLShaderProgram * prog, const QString & name, const QString & dir) { prog->removeAllShaders(); QDir d(dir); QFileInfoList sl = d.entryInfoList(QStringList(name + ".geom"), QDir::Files | QDir::NoDotAndDotDot); #if QT_VERSION >= 0x040700 foreach (const QFileInfo & i, sl) prog->addShaderFromSourceFile(QGLShader::Geometry, i.absoluteFilePath()); #endif sl = d.entryInfoList(QStringList(name + ".vert"), QDir::Files | QDir::NoDotAndDotDot); foreach (const QFileInfo & i, sl) prog->addShaderFromSourceFile(QGLShader::Vertex, i.absoluteFilePath()); sl = d.entryInfoList(QStringList(name + ".frag"), QDir::Files | QDir::NoDotAndDotDot); foreach (const QFileInfo & i, sl) prog->addShaderFromSourceFile(QGLShader::Fragment, i.absoluteFilePath()); if (!prog->link()) { qDebug() << "[QGLView] Shader \"" + name + "\" link error: " + prog->log(); return false; } return true; } 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; } bool GLCubeTexture::create() { //qDebug("create"); destroy(); glGenTextures(1, &id_); glBindTexture(GL_TEXTURE_CUBE_MAP, id_); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*_MIPMAP_LINEAR*/); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); //glClearError(); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); //qDebug() << glGetError(); changed_ = false; return id_ > 0; } void GLCubeTexture::load() { if (isEmpty()) return; create(); if (!path(0).isEmpty()) loadFront(path(0)); if (!path(1).isEmpty()) loadBack(path(1)); if (!path(2).isEmpty()) loadLeft(path(2)); if (!path(3).isEmpty()) loadRight(path(3)); if (!path(4).isEmpty()) loadTop(path(4)); if (!path(5).isEmpty()) loadBottom(path(5)); } void GLCubeTexture::loadFromDirectory(const QString & dir) { QDir d(dir); QFileInfoList sl; sl = d.entryInfoList(QStringList("front.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadFront(sl[0].absoluteFilePath()); sl = d.entryInfoList(QStringList("back.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadBack(sl[0].absoluteFilePath()); sl = d.entryInfoList(QStringList("left.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadLeft(sl[0].absoluteFilePath()); sl = d.entryInfoList(QStringList("right.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadRight(sl[0].absoluteFilePath()); sl = d.entryInfoList(QStringList("top.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadTop(sl[0].absoluteFilePath()); sl = d.entryInfoList(QStringList("bottom.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadBottom(sl[0].absoluteFilePath()); } void GLCubeTexture::loadPathesFromDirectory(const QString & dir) { QDir d(dir); QFileInfoList sl; sl = d.entryInfoList(QStringList("front.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[0] = sl[0].absoluteFilePath(); sl = d.entryInfoList(QStringList("back.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[1] = sl[0].absoluteFilePath(); sl = d.entryInfoList(QStringList("left.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[2] = sl[0].absoluteFilePath(); sl = d.entryInfoList(QStringList("right.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[3] = sl[0].absoluteFilePath(); sl = d.entryInfoList(QStringList("top.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[4] = sl[0].absoluteFilePath(); sl = d.entryInfoList(QStringList("bottom.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[5] = sl[0].absoluteFilePath(); } GLuint GLTextureManagerBase::loadTexture(const QString & path, bool ownership) { int tid = ((GLTextureManagerBase*)currentGLTextureManager)->textureID(path); if (tid > 0) { //qDebug() << "[TextureManager] Found" << path << "as" << tid; return tid; } tid = currentQGLView->bindTexture(QImage(path), GL_TEXTURE_2D/*, GL_RGBA, QGLContext::MipmapBindOption*/); if (tid == 0) { qDebug() << "[TextureManager] Can`t load" << path; return tid; } qDebug() << "[TextureManager] Loaded" << path << "as" << tid; if (ownership) ((GLTextureManagerBase*)currentGLTextureManager)->tex_ids.insert(path, tid); /*GLenum err(0); im = currentQGLView->convertToGLFormat(im); glClearError(); glGenTextures(1, &tid); err = glGetError(); if (err != GL_NO_ERROR) { qDebug() << "can`t generate texture," << err; return false; } //glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST); glClearError(); glBindTexture(GL_TEXTURE_2D, tid); qDebug() << "load" << im.width() << "x" << im.height(); glClearError(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, im.width(), im.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, im.bits()); //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //glBindTexture(GL_TEXTURE_2D, 0); err = glGetError(); if (err != GL_NO_ERROR) { glDeleteTextures(1, &tid); qDebug() << "can`t load" << path << "," << err; return false; } currentGLTextureManager->tex_ids << tid; qDebug() << "loaded" << path << "as" << tid;*/ return tid; } GLuint GLTextureManagerBase::loadTexture(const QImage & image, bool ownership) { GLuint tid = currentQGLView->bindTexture(image); if (tid == 0) { qDebug() << "[TextureManager] Can`t load image"; return tid; } //qDebug() << "[TextureManager] Loaded image as" << tid; if (ownership) ((GLTextureManagerBase*)currentGLTextureManager)->tex_ids.insert(QString(), tid); return tid; } 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.); gluPerspective(fov_, aspect, depth_start, depth_end); 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); } Material::Material(): reflection(512) { color_diffuse = color_specular = Qt::white; color_self_illumination = Qt::black; glass = false; transparency = reflectivity = 0.f; bump_scale = relief_scale = iof = 1.f; dispersion = 0.05f; shine = shine_strength = 0.f; light_model = Phong; } void Material::apply() { GLfloat mat_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat mat_specular[4] = {0.9f, 0.9f, 0.9f, 1.0f}; GLfloat mat_emission[4] = {0.f, 0.f, 0.f, 1.0f}; mat_diffuse[0] = color_diffuse.redF(); mat_diffuse[1] = color_diffuse.greenF(); mat_diffuse[2] = color_diffuse.blueF(); mat_diffuse[3] = color_diffuse.alphaF() * (1.f - transparency); mat_specular[0] = shine_strength * color_specular.redF(); mat_specular[1] = shine_strength * color_specular.greenF(); mat_specular[2] = shine_strength * color_specular.blueF(); mat_emission[0] = color_self_illumination.redF(); mat_emission[1] = color_self_illumination.greenF(); mat_emission[2] = color_self_illumination.blueF(); glColor4f(mat_diffuse[0], mat_diffuse[1], mat_diffuse[2], mat_diffuse[3]); //qDebug() << color_diffuse.alphaF() * (1.f - transparency); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialf(GL_FRONT, GL_SHININESS, shine); glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_diffuse); } void Material::loadTextures(GLTextureManagerBase * tm) { if (tm == 0) tm = (GLTextureManagerBase*)currentGLTextureManager; if (!diffuse.bitmap_path.isEmpty()) diffuse.bitmap_id = tm->loadTexture(diffuse.bitmap_path); if (!bump.bitmap_path.isEmpty()) bump.bitmap_id = tm->loadTexture(bump.bitmap_path); if (!relief.bitmap_path.isEmpty()) relief.bitmap_id = tm->loadTexture(relief.bitmap_path); if (!diffuse_2.bitmap_path.isEmpty()) diffuse_2.bitmap_id = tm->loadTexture(diffuse_2.bitmap_path); //qDebug() << "load" << reflection.path(0); reflection.load(); } 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 GLRendererBase::setupLight(const Light & l, int inpass_index, int gl_index) { QVector3D lp = l.worldPos(), ld = (l.itransform_ * QVector4D(l.direction, 0.)).toVector3D().normalized(); GLfloat pos[] = {0.f, 0.f, 0.f, 0.f}; GLfloat dir[] = {0.f, 0.f, 0.f}; GLfloat col[] = {0.f, 0.f, 0.f}; pos[0] = l.light_type == Light::Directional ? -l.direction.x() : lp.x(); pos[1] = l.light_type == Light::Directional ? -l.direction.y() : lp.y(); pos[2] = l.light_type == Light::Directional ? -l.direction.z() : lp.z(); pos[3] = l.light_type == Light::Directional ? 0. : 1.; dir[0] = ld.x(); dir[1] = ld.y(); dir[2] = ld.z(); col[0] = l.visible_ ? l.color().redF() * l.intensity : 0.; col[1] = l.visible_ ? l.color().greenF() * l.intensity : 0.; col[2] = l.visible_ ? l.color().blueF() * l.intensity : 0.; glEnable(gl_index); //glLightfv(gl_index, GL_AMBIENT, ambient); glLightfv(gl_index, GL_DIFFUSE, col); glLightfv(gl_index, GL_SPECULAR, col); glLightfv(gl_index, GL_POSITION, pos); glLightf(gl_index, GL_CONSTANT_ATTENUATION, l.decay_const); glLightf(gl_index, GL_LINEAR_ATTENUATION, l.decay_linear); glLightf(gl_index, GL_QUADRATIC_ATTENUATION, l.decay_quadratic); if (l.light_type == Light::Cone) { glLightfv(gl_index, GL_SPOT_DIRECTION, dir); glLightf(gl_index, GL_SPOT_CUTOFF, l.angle_spread); glLightf(gl_index, GL_SPOT_EXPONENT, l.angle_decay_exp); } else { glLightf(gl_index, GL_SPOT_CUTOFF, 180.); } } void GLRendererBase::setupAmbientLight(const QColor & a, bool first_pass) { GLfloat ambient[] = {0.0f, 0.0f, 0.0f, 1.f}; if (first_pass) { ambient[0] = view.ambientColor_.redF(); ambient[1] = view.ambientColor_.greenF(); ambient[2] = view.ambientColor_.blueF(); } glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); } void GLRendererBase::setupShadersLights(int lights_count) { /*foreach (QGLShaderProgram * i, view.shaders_ppl) { i->bind(); i->setUniformValue("lightsCount", lights_count); i->setUniformValue("acc_light", lights_count > 0); //i->setUniformValue("mat", mvm); }*/ } void GLRendererBase::setupTextures(GLObjectBase & o, GLRendererBase::RenderingParameters & rp, bool first_object) { if (first_object) { glReleaseTextures(); return; } setupShadersTextures(o, rp); Material & mat(o.material_); if (rp.light) { if (o.accept_light) {if (!rp.prev_light) {glSetLightEnabled(true); rp.prev_light = true;}} else {if (rp.prev_light) {glSetLightEnabled(false); rp.prev_light = false;}} } if (rp.fog) { if (o.accept_fog) {if (!rp.prev_fog) {glSetFogEnabled(true); rp.prev_fog = true;}} else {if (rp.prev_fog) {glSetFogEnabled(false); rp.prev_fog = false;}} } if (rp.textures) { if (rp.prev_tex[0] != mat.diffuse.bitmap_id) { rp.prev_tex[0] = mat.diffuse.bitmap_id; glActiveTextureChannel(0); glBindTexture(GL_TEXTURE_2D, mat.diffuse.bitmap_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, view.anisotropicLevel_); } if (rp.prev_tex[1] != mat.bump.bitmap_id) { rp.prev_tex[1] = mat.bump.bitmap_id; glActiveTextureChannel(1); glBindTexture(GL_TEXTURE_2D, mat.bump.bitmap_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, view.anisotropicLevel_); } if (rp.prev_tex[2] != mat.relief.bitmap_id) { rp.prev_tex[2] = mat.relief.bitmap_id; glActiveTextureChannel(2); glBindTexture(GL_TEXTURE_2D, mat.relief.bitmap_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, view.anisotropicLevel_); } glActiveTextureChannel(0); } } void GLRendererBase::setupLights(int pass, int lights_per_pass) { int light_start, light_end, lmax; light_start = pass * lights_per_pass; light_end = qMin((pass + 1) * lights_per_pass, view.lights_.size()); setupAmbientLight(view.ambientColor_, pass == 0); if (!view.lights_.isEmpty()) { setupShadersLights(light_end - light_start); for (int i = light_start; i < light_end; ++i) setupLight(*view.lights_[i], i - light_start, GL_LIGHT0 + i - light_start); lmax = light_start + 8; for (int i = light_end; i < lmax; ++i) glDisable(GL_LIGHT0 + i - light_start); } else { setupShadersLights(0); for (int i = 0; i < 8; ++i) glDisable(GL_LIGHT0 + i); } } void GLRendererBase::applyFilteringParameters() { if (view.linearFiltering_) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, view.anisotropicLevel_); } void GLRendererBase::renderObjects(int pass, int light_pass, void * shaders, bool textures, bool light, bool fog) { RenderingParameters rp; rp.pass = pass; rp.light_pass = light_pass; rp.shaders = shaders; rp.textures = textures; rp.light = rp.prev_light = light; rp.fog = rp.prev_fog = fog; for (int i = 0; i < 32; ++i) rp.prev_tex[i] = 0; rp.prev_light_model = Material::Phong; setupTextures(view.objects_, rp, true); glSetLightEnabled(rp.prev_light); glSetFogEnabled(rp.prev_fog); glSetCapEnabled(GL_TEXTURE_2D, rp.textures); glSetCapEnabled(GL_BLEND, pass == GLObjectBase::Transparent); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_TEXTURE_CUBE_MAP); renderSingleObject(view.objects_, rp); } void GLRendererBase::renderSingleObject(GLObjectBase & o, RenderingParameters & rp) { if (!o.isInit()) o.init(); if (!o.isTexturesLoaded()) o.loadTextures(); if (!o.visible_) return; Material & mat(o.material_); glPushMatrix(); if (o.pos_.x() != 0. || o.pos_.y() != 0. || o.pos_.z() != 0.) qglTranslate(o.pos_); if (o.angles_.z() != 0.) glRotated(o.angles_.z(), 0., 0., 1.); if (o.angles_.y() != 0.) glRotated(o.angles_.y(), 0., 1., 0.); if (o.angles_.x() != 0.) glRotated(o.angles_.x(), 1., 0., 0.); if (o.scale_.x() != 1. || o.scale_.y() != 1. || o.scale_.z() != 1.) qglScale(o.scale_); if (rp.pass == o.pass_) { setupTextures(o, rp, false); mat.apply(); glSetPolygonMode(o.render_mode != GLObjectBase::View ? o.render_mode : (view.rmode != GLObjectBase::View ? view.rmode : GL_FILL)); glLineWidth(o.line_width > 0. ? o.line_width : view.lineWidth_); glPointSize(o.line_width > 0. ? o.line_width : view.lineWidth_); o.update(); if (o.pass_ == GLObjectBase::Transparent) { glActiveTextureChannel(3); if (mat.reflectivity > 0.) { glEnable(GL_TEXTURE_CUBE_MAP); if (!mat.reflection.isEmpty()) mat.reflection.bind(); else glDisable(GL_TEXTURE_CUBE_MAP); } else glDisable(GL_TEXTURE_CUBE_MAP); if (rp.light_pass > 0) glDisable(GL_TEXTURE_CUBE_MAP); GLfloat gm[16], bc[4] = {mat.reflectivity, mat.reflectivity, mat.reflectivity, mat.reflectivity}; glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, bc); glGetFloatv(GL_MODELVIEW_MATRIX, gm); glMatrixMode(GL_TEXTURE); glLoadTransposeMatrixf(gm); glScalef(-1., -1., -1.); glMatrixMode(GL_MODELVIEW); glActiveTextureChannel(0); } o.draw(); } foreach (GLObjectBase * i, o.children_) renderSingleObject(*i, rp); glPopMatrix(); }