/* 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 "gltypes.h" #include "qglview.h" QStringList GLTextureManagerBase::search_pathes("."); 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, nullptr); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); // 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(); } QString GLTextureManagerBase::findFile(const QString & path) { return ::findFile(path, search_pathes); } GLuint GLTextureManagerBase::loadTexture(const QString & path, bool ownership, bool bump) { QString p = findFile(path); if (p.isEmpty()) return 0; int tid = textureID(p, bump); if (tid > 0) { // qDebug() << "[TextureManager] Found" << path << "as" << tid; return tid; } QImage image(p); if (bump) convertToNormal(image); // qDebug() << p << image.width() << image.height() << image.format() << bump; /// tid = currentQGLView->bindTexture(image, GL_TEXTURE_2D/*, GL_RGBA, __GLContext__::MipmapBindOption*/); // GLuint tid = 0; GLuint _tid = tid; createGLTexture(_tid, image); /// currentQGLView->bindTexture(image, GL_TEXTURE_2D); tid = _tid; if (tid == 0) { qDebug() << "[TextureManager] Can`t load" << p; return tid; } qDebug() << "[TextureManager] Loaded" << p << "as" << tid; if (ownership) tex_ids[bump ? 1 : 0].insert(p, tid); return tid; } GLuint GLTextureManagerBase::loadTexture(const QImage & im, bool ownership, bool bump) { if (im.isNull()) return 0; QImage image(im); if (bump) convertToNormal(image); GLuint tid = 0; createGLTexture(tid, im); /// currentQGLView->bindTexture(image, GL_TEXTURE_2D); if (tid == 0) { qDebug() << "[TextureManager] Can`t load image"; return tid; } // qDebug() << "[TextureManager] Loaded image as" << tid; if (ownership) tex_ids[bump ? 1 : 0].insert(QString(), tid); return tid; } void GLTextureManagerBase::reloadTexture(GLuint tid, const QString & path) { QString p = findFile(path); if (p.isEmpty() || (tid == 0)) return; QImage image(p); createGLTexture(tid, image); if (tid == 0) { qDebug() << "[TextureManager] Can`t load" << p; return; } qDebug() << "[TextureManager] Reloaded" << p << "as" << tid; } void GLTextureManagerBase::reloadTexture(GLuint tid, const QImage & im) { if (im.isNull() || (tid == 0)) return; QImage image(im); createGLTexture(tid, image); qDebug() << "[TextureManager] Reloaded" << tid; } Vector3d colorVector(QRgb c) { return Vector3d(((uchar *)(&c))[0] / 255., ((uchar *)(&c))[1] / 255., ((uchar *)(&c))[2] / 255.); } void GLTextureManagerBase::convertToNormal(QImage & im) { if (im.isNull()) return; QImage sim = im.convertToFormat(QImage::Format_ARGB32); float sum[3] = {0., 0., 0.}; llong a = 0; const uchar * sd = sim.constBits(); for (int i = 0; i < sim.height(); i++) { for (int j = 0; j < sim.width(); j++) { sum[2] += sd[a] / 255.f - 0.5f; ++a; sum[1] += sd[a] / 255.f - 0.5f; ++a; sum[0] += sd[a] / 255.f - 0.5f; ++a; ++a; } } float wh = sim.width() * sim.height(); sum[0] /= wh; sum[1] /= wh; sum[2] /= wh; qDebug() << sum[0] << sum[1] << sum[2]; if ((qAbs(sum[0]) <= 0.05f) && (qAbs(sum[1]) <= 0.05f) && (sum[2] >= 0.25f)) /// already normal return; qDebug() << "convert to bump"; QImage dim = QImage(sim.width(), sim.height(), QImage::Format_ARGB32); int tx, ty, w = sim.width(), h = sim.height(); a = 0; uchar * dd = dim.bits(); for (int i = 0; i < sim.height(); i++) { for (int j = 0; j < sim.width(); j++) { tx = j - 1; tx = tx < 0 ? w + tx : tx % w; ty = i - 1; ty = ty < 0 ? h + ty : ty % h; Vector3d p[3], res; p[0] = colorVector(sim.pixel(j, i)); p[1] = colorVector(sim.pixel(j, ty)); p[2] = colorVector(sim.pixel(tx, i)); res.y = piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f); res.x = piClamp(0.5f + (p[0].length() - p[2].length()) / 2.f, 0.f, 1.f); tx = (j + 1) % w; ty = (i + 1) % h; p[1] = colorVector(sim.pixel(j, ty)); p[2] = colorVector(sim.pixel(tx, i)); res.y = piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f); res.x = piClamp(0.5f + (p[0].length() - p[2].length()) / 2.f, 0.f, 1.f); res.z = 1.; dd[a] = res.z * 255; ++a; dd[a] = res.x * 255; ++a; dd[a] = res.y * 255; ++a; dd[a] = 255; ++a; } } im = dim; // im.save("_bump.png"); } Material::Material(): map_reflection(512) { color_diffuse = color_specular = Qt::white; color_self_illumination = Qt::black; glass = false; transparency = reflectivity = 0.f; map_specularity.color_amount = 0.5f; map_specular.color_amount = 1.f; iof = 1.f; dispersion = 0.05f; } void Material::apply(QOpenGLShaderProgram * prog) { if (prog) { setUniformMaterial(prog, *this); } else { 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] = map_diffuse.color_amount * color_diffuse.redF(); mat_diffuse[1] = map_diffuse.color_amount * color_diffuse.greenF(); mat_diffuse[2] = map_diffuse.color_amount * color_diffuse.blueF(); mat_diffuse[3] = map_diffuse.color_amount * color_diffuse.alphaF() * (1.f - transparency); mat_specular[0] = map_specular.color_amount * color_specular.redF(); mat_specular[1] = map_specular.color_amount * color_specular.greenF(); mat_specular[2] = map_specular.color_amount * color_specular.blueF(); mat_emission[0] = map_self_illumination.color_amount * color_self_illumination.redF(); mat_emission[1] = map_self_illumination.color_amount * color_self_illumination.greenF(); mat_emission[2] = map_self_illumination.color_amount * color_self_illumination.blueF(); glColor4f(mat_diffuse[0], mat_diffuse[1], mat_diffuse[2], mat_diffuse[3]); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); // qDebug() << (map_specularity.color_amount)*128.; glMaterialf(GL_FRONT, GL_SHININESS, (map_specularity.color_amount) * 128.f); glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_diffuse); } } void Material::loadTextures(GLTextureManagerBase * tm) { // qDebug() << "load textures"; if (!tm) return; if (!map_diffuse.bitmap_path.isEmpty()) map_diffuse.bitmap_id = tm->loadTexture(map_diffuse.bitmap_path); if (!map_normal.bitmap_path.isEmpty()) map_normal.bitmap_id = tm->loadTexture(map_normal.bitmap_path, true, true); if (!map_relief.bitmap_path.isEmpty()) map_relief.bitmap_id = tm->loadTexture(map_relief.bitmap_path); if (!map_specularity.bitmap_path.isEmpty()) map_specularity.bitmap_id = tm->loadTexture(map_specularity.bitmap_path); if (!map_specular.bitmap_path.isEmpty()) map_specular.bitmap_id = tm->loadTexture(map_specular.bitmap_path); if (!map_self_illumination.bitmap_path.isEmpty()) map_self_illumination.bitmap_id = tm->loadTexture(map_self_illumination.bitmap_path); // if (!map_diffuse_2.bitmap_path.isEmpty()) map_diffuse_2.bitmap_id = tm->loadTexture(map_diffuse_2.bitmap_path); map_reflection.load(); }