git-svn-id: svn://db.shs.com.ru/libs@703 a8b55f48-bf90-11e4-a774-851b48703e85

This commit is contained in:
2019-12-15 10:38:43 +00:00
parent 64209212a9
commit b8f2ee0dfb
21 changed files with 772 additions and 151 deletions

View 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();
}
*/

View File

@@ -0,0 +1,67 @@
/*
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/>.
*/
#ifndef GLCUBEMAP_H
#define GLCUBEMAP_H
#include "glshaders_types.h"
#include "chunkstream.h"
QVector<QVector3D> loadFileHDR(const QString & path, QSize * size = 0);
class CubeTexture {
public:
CubeTexture(QOpenGLExtraFunctions * f_, int _size, const GLenum & _format = GL_RGB16F);
bool init();
void destroy();
void bind(int channel = 0);
void release();
void resize(int _size) {size = _size; changed_ = true;}
void loadHDR(const QVector<QVector3D> & data, QSize sz);
void setFileHDR(const QString & path);
QString fileHDR() const {return hdr_path;}
//void loadFromDirectory(const QString & dir);
//void loadFront(const QString & path) {bind(); pathes[0] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_X);}
//void loadBack(const QString & path) {bind(); pathes[1] = path; createGLTexture(id_, rotateQImageRight(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_X);}
//void loadLeft(const QString & path) {bind(); pathes[2] = path; createGLTexture(id_, QImage(path).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y);}
//void loadRight(const QString & path) {bind(); pathes[3] = path; createGLTexture(id_, rotateQImage180(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_Y);}
//void loadTop(const QString & path) {bind(); pathes[4] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);}
//void loadBottom(const QString & path) {bind(); pathes[5] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_Z);}
//void load();
//bool isEmpty() const {foreach (const QString & i, pathes) if (!i.isEmpty()) return false; return true;}
GLenum format() const {return format_;}
void setFormat(GLenum f) {format_ = f; changed_ = true;}
GLuint id() const {return id_;}
bool isInit() const {return id_ != 0;}
//const QString & path(int side) const {return pathes[side];}
//void setPath(int side, const QString & p) {pathes[side] = p;}
//void loadPathesFromDirectory(const QString & dir);
void load();
private:
QOpenGLExtraFunctions * f;
bool changed_;
int size;
GLenum format_;
GLuint id_;
QString hdr_path;
//QVector<QString> pathes;
};
#endif // GLCUBEMAP_H

View File

@@ -199,3 +199,13 @@ void Material::setTypes() {
map_emission ._type = mtEmission ;
map_relief ._type = mtRelief ;
}
void Material::detectMaps() {
map_diffuse .use_bitmap = !map_diffuse .bitmap_path.isEmpty();
map_normal .use_bitmap = !map_normal .bitmap_path.isEmpty();
map_metalness.use_bitmap = !map_metalness.bitmap_path.isEmpty();
map_roughness.use_bitmap = !map_roughness.bitmap_path.isEmpty();
map_emission .use_bitmap = !map_emission .bitmap_path.isEmpty();
map_relief .use_bitmap = !map_relief .bitmap_path.isEmpty();
}

View File

@@ -104,6 +104,7 @@ public:
void load(TextureManager * tm);
void setMapsChanged();
void setTypes();
void detectMaps();
QString name;
QColor color_diffuse;
QColor color_emission;

125
qglengine/core/hdr.cpp Normal file
View File

@@ -0,0 +1,125 @@
/*
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 "hdr_p.h"
#include "qmath.h"
#define RGBE_DATA_RED 2
#define RGBE_DATA_GREEN 1
#define RGBE_DATA_BLUE 0
/* number of floats per pixel */
#define RGBE_DATA_SIZE 3
void rgbe2float(float *red, float *green, float *blue, uchar rgbe[4]) {
float f;
if (rgbe[3]) {
f = static_cast<float>(ldexp(1.0,rgbe[3]-(int)(128+8)));
*red = rgbe[0] * f;
*green = rgbe[1] * f;
*blue = rgbe[2] * f;
}
else
*red = *green = *blue = 0.0;
}
/* simple read routine. will not correctly handle run length encoding */
bool RGBE_ReadPixels(QDataStream * fp, float * data, int numpixels) {
uchar rgbe[4];
while(numpixels-- > 0) {
if (fp->readRawData((char*)rgbe, sizeof(rgbe)) < 1)
return false;
rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE],rgbe);
data += RGBE_DATA_SIZE;
}
return true;
}
bool RGBE_ReadPixels_RLE(QDataStream * fp, float * data, int scanline_width, int num_scanlines) {
uchar rgbe[4], *ptr, *ptr_end;
int i, count;
uchar buf[2];
QByteArray scanline_buffer;
if ((scanline_width < 8)||(scanline_width > 0x7fff))
/* run length encoding is not allowed so read flat*/
return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines);
scanline_buffer.resize(4*scanline_width);
/* read in each successive scanline */
while(num_scanlines > 0) {
if (fp->readRawData((char*)rgbe,sizeof(rgbe)) < 1) {
return false;
}
if ((rgbe[0] != 2)||(rgbe[1] != 2)||(rgbe[2] & 0x80)) {
/* this file is not run length encoded */
rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],&data[RGBE_DATA_BLUE],rgbe);
data += RGBE_DATA_SIZE;
return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines-1);
}
if ((((int)rgbe[2])<<8 | rgbe[3]) != scanline_width) {
return false;
}
ptr = (uchar*)scanline_buffer.data();
/* read each of the four channels for the scanline into the buffer */
for(i=0;i<4;i++) {
ptr_end = (uchar*)scanline_buffer.data() + ((i+1)*scanline_width);
while(ptr < ptr_end) {
if (fp->readRawData((char*)buf,sizeof(buf[0])*2) < 1) {
return false;
}
if (buf[0] > 128) {
/* a run of the same value */
count = buf[0]-128;
if ((count == 0)||(count > ptr_end - ptr)) {
return false;
}
while(count-- > 0)
*ptr++ = buf[1];
}
else {
/* a non-run */
count = buf[0];
if ((count == 0)||(count > ptr_end - ptr)) {
return false;
}
*ptr++ = buf[1];
if (--count > 0) {
if (fp->readRawData((char*)ptr,sizeof(*ptr)*count) < 1) {
return false;
}
ptr += count;
}
}
}
}
/* now convert data from buffer into floats */
for(i=0;i<scanline_width;i++) {
rgbe[0] = scanline_buffer[i];
rgbe[1] = scanline_buffer[i+scanline_width];
rgbe[2] = scanline_buffer[i+2*scanline_width];
rgbe[3] = scanline_buffer[i+3*scanline_width];
rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],
&data[RGBE_DATA_BLUE],rgbe);
data += RGBE_DATA_SIZE;
}
num_scanlines--;
}
return true;
}

26
qglengine/core/hdr_p.h Normal file
View File

@@ -0,0 +1,26 @@
/*
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/>.
*/
#ifndef HDR_P_H
#define HDR_P_H
#include <QDataStream>
bool RGBE_ReadPixels_RLE(QDataStream * fp, float * data, int scanline_width, int num_scanlines);
#endif // HDR_P_H