git-svn-id: svn://db.shs.com.ru/libs@703 a8b55f48-bf90-11e4-a774-851b48703e85
This commit is contained in:
274
qglengine/core/glcubemap.cpp
Normal file
274
qglengine/core/glcubemap.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
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 "gltypes.h"
|
||||
#include "glcubemap.h"
|
||||
#include "hdr_p.h"
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
|
||||
QVector<QVector3D> loadFileHDR(const QString & path, QSize * size) {
|
||||
if (size) *size = QSize();
|
||||
QVector<QVector3D> 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<float> 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<QVector3D> faceHDR(const QVector<QVector3D> & data, QSize sz, QSize & fsz, int face) {
|
||||
QVector<QVector3D> 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<QVector3D> & data, QSize sz) {
|
||||
bind();
|
||||
QSize fsz;
|
||||
QVector<QVector3D> 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<QVector3D> data = loadFileHDR(hdr_path, &sz);
|
||||
loadHDR(data, sz);
|
||||
}
|
||||
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();
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user