/* QGL CubeTexture 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 "glcubemap.h" #include "hdr_p.h" using namespace QGLEngineShaders; QVector loadFileHDR(const QString & path, QSize * size) { if (size) *size = QSize(); QVector ret; QFile f(path); if (!f.open(QIODevice::ReadOnly)) { qDebug() << "[QGLEngine] Can`t open" << path; return ret; } QTextStream ts(&f); QString line = ts.readLine(256); if (line != "#?RADIANCE") return ret; QSize sz; while (!ts.atEnd()) { line = ts.readLine(256); if (line.startsWith("FORMAT")) { line.remove(0, 7); if (!line.startsWith("32-bit")) { qDebug() << "[QGLEngine] File" << path << "has unknown format!"; return ret; } } if (line.mid(1, 2) == "Y ") { QStringList sl = line.trimmed().split(" "); sl.removeAll(""); if (sl.size() != 4) { qDebug() << "[QGLEngine] File" << path << "has unknown size!"; return ret; } sz.setWidth (sl[3].toInt()); sz.setHeight(sl[1].toInt()); //qDebug() << "found size" << sz; break; } } if (sz.isEmpty()) return ret; f.seek(ts.pos()); QDataStream ds(&f); int count = sz.width() * sz.height(); QVector data(count*3); if (!RGBE_ReadPixels_RLE(&ds, data.data(), sz.width(), sz.height())) return ret; if (size) *size = sz; ret.resize(count); //QColor col; //QImage im(sz, QImage::Format_ARGB32); //QRgb * imdata = (QRgb*)im.bits(); for (int i = 0; i < count; ++i) { QVector3D p(pow(data[i*3 + 2], 1. / 2.2), pow(data[i*3 + 1], 1. / 2.2), pow(data[i*3 + 0], 1. / 2.2)); ret[i] = p; //col = QColor::fromRgbF(piClamp(p[0], 0.f, 1.f), // piClamp(p[1], 0.f, 1.f), // piClamp(p[2], 0.f, 1.f)); //imdata[i] = col.rgb(); } //im.save("_hdr.png"); return ret; } //#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 //#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 //#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 //#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 //#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 //#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A QVector faceHDR(const QVector & data, QSize sz, QSize & fsz, int face) { QVector ret; if (data.isEmpty() || sz.isNull()) return ret; QRect fr; int fw = sz.width () / 4; int fh = sz.height() / 3; fsz = QSize(fw, fh); ret.reserve(fw * fh); switch (face) { case GL_TEXTURE_CUBE_MAP_POSITIVE_X: fr.setRect(fw, fh, fw, fh); for (int x = fr.left(); x <= fr.right(); ++x) { for (int y = fr.top(); y <= fr.bottom(); ++y) { ret << data[y*sz.width() + x]; } } break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: fr.setRect(fw*3, fh, fw, fh); for (int x = fr.right(); x >= fr.left(); --x) { for (int y = fr.bottom(); y >= fr.top(); --y) { ret << data[y*sz.width() + x]; } } break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: fr.setRect( 0, fh, fw, fh); for (int y = fr.bottom(); y >= fr.top(); --y) { for (int x = fr.left(); x <= fr.right(); ++x) { ret << data[y*sz.width() + x]; } } break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: fr.setRect(fw*2, fh, fw, fh); for (int y = fr.top(); y <= fr.bottom(); ++y) { for (int x = fr.right(); x >= fr.left(); --x) { ret << data[y*sz.width() + x]; } } break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: fr.setRect(fw, 0, fw, fh); for (int x = fr.left(); x <= fr.right(); ++x) { for (int y = fr.top(); y <= fr.bottom(); ++y) { ret << data[y*sz.width() + x]; } } break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: fr.setRect(fw, fh*2, fw, fh); for (int x = fr.left(); x <= fr.right(); ++x) { for (int y = fr.top(); y <= fr.bottom(); ++y) { ret << data[y*sz.width() + x]; } } break; default: break; } if (fr.isEmpty()) return ret; //qDebug() << ret.size() << fr; return ret; } CubeTexture::CubeTexture(QOpenGLExtraFunctions * f_, int _size, const GLenum & _format): f(f_) { size = _size; format_ = _format; id_ = 0; changed_ = false; } bool CubeTexture::init() { if (isInit()) return true; f->glGenTextures(1, &id_); f->glBindTexture(GL_TEXTURE_CUBE_MAP, id_); f->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); f->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); f->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); f->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); f->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); //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); changed_ = false; return id_ > 0; } void CubeTexture::destroy() { if (!isInit()) return; f->glDeleteTextures(1, &id_); id_ = 0; } void CubeTexture::bind(int channel) { init(); f->glActiveTexture(GL_TEXTURE0 + channel); f->glBindTexture(GL_TEXTURE_CUBE_MAP, id_); } void CubeTexture::release() { f->glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } void CubeTexture::loadHDR(const QVector & data, QSize sz) { bind(); QSize fsz; QVector fd; for (int i = 0; i < 6; ++i) { fd = faceHDR(data, sz, fsz, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i); //qDebug() << "load cube" << fd[0]; //f->glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); f->glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format_, fsz.width(), fsz.height(), 0, GL_RGB, GL_FLOAT, fd.isEmpty() ? 0 : fd.constData()); //qDebug() << QString::number(GetLastError(), 16); } f->glGenerateMipmap(GL_TEXTURE_CUBE_MAP); } void CubeTexture::setFileHDR(const QString & path) { hdr_path = path; changed_ = true; } void CubeTexture::load() { if (!changed_) return; init(); if (!hdr_path.isEmpty()) { QSize sz; QVector data = loadFileHDR(hdr_path, &sz); loadHDR(data, sz); } else { destroy(); bind(); for (int i = 0; i < 6; ++i) { f->glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format_, 1, 1, 0, GL_RGB, GL_FLOAT, 0); } f->glGenerateMipmap(GL_TEXTURE_CUBE_MAP); } changed_ = false; } /* void CubeTexture::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 CubeTexture::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 CubeTexture::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(); } */