From b8f2ee0dfb929c33470027761140b1ed6ac9ed07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B5=D0=BB=D0=B8=D0=BF=D0=B5=D0=BD=D0=BA=D0=BE=20?= =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Sun, 15 Dec 2019 10:38:43 +0000 Subject: [PATCH] git-svn-id: svn://db.shs.com.ru/libs@703 a8b55f48-bf90-11e4-a774-851b48703e85 --- qglengine/CMakeLists.txt | 2 + qglengine/core/glcubemap.cpp | 274 ++++++++++++++++++++++ qglengine/core/glcubemap.h | 67 ++++++ qglengine/core/glmaterial.cpp | 10 + qglengine/core/glmaterial.h | 1 + qglengine/core/hdr.cpp | 125 ++++++++++ qglengine/core/hdr_p.h | 26 ++ qglengine/formats/loader_assimp.cpp | 1 + qglengine/qglview.cpp | 11 +- qglengine/qglview.h | 13 +- qglengine/qglview_test/qglview_window.cpp | 7 + qglengine/qglview_test/qglview_window.h | 2 + qglengine/qglview_test/qglview_window.ui | 13 +- qglengine/renderer.cpp | 19 +- qglengine/renderer.h | 9 +- qglengine/renderer_base.cpp | 8 +- qglengine/shaders/ds_light.glsl | 27 ++- qglengine/tonemapping_proc.cpp | 2 +- qglengine/widgets/view_editor.cpp | 36 ++- qglengine/widgets/view_editor.h | 4 +- qglengine/widgets/view_editor.ui | 266 ++++++++++++--------- 21 files changed, 772 insertions(+), 151 deletions(-) create mode 100644 qglengine/core/glcubemap.cpp create mode 100644 qglengine/core/glcubemap.h create mode 100644 qglengine/core/hdr.cpp create mode 100644 qglengine/core/hdr_p.h diff --git a/qglengine/CMakeLists.txt b/qglengine/CMakeLists.txt index 45080bf..a84d4fc 100644 --- a/qglengine/CMakeLists.txt +++ b/qglengine/CMakeLists.txt @@ -30,6 +30,8 @@ list(APPEND SRC ${FSRC}) qt_sources(FSRC DIR "core") list(APPEND SRC ${FSRC}) qt_wrap(${SRC} HDRS out_HDR CPPS out_CPP QMS out_QM) +file(GLOB PHS "*_p.h" "formats/*_p.h" "core/*_p.h") +list(REMOVE_ITEM out_HDR "${PHS}") qt_add_library(qglengine_core SHARED out_CPP) qt_target_link_libraries(qglengine_core qad_utils qad_widgets assimp ${OPENGL_LIBRARIES}) message(STATUS "Building qglengine_core") diff --git a/qglengine/core/glcubemap.cpp b/qglengine/core/glcubemap.cpp new file mode 100644 index 0000000..49bfee3 --- /dev/null +++ b/qglengine/core/glcubemap.cpp @@ -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 . +*/ + +#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); + } + 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(); +} +*/ diff --git a/qglengine/core/glcubemap.h b/qglengine/core/glcubemap.h new file mode 100644 index 0000000..65d6042 --- /dev/null +++ b/qglengine/core/glcubemap.h @@ -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 . +*/ + +#ifndef GLCUBEMAP_H +#define GLCUBEMAP_H + +#include "glshaders_types.h" +#include "chunkstream.h" + +QVector 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 & 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 pathes; +}; + + +#endif // GLCUBEMAP_H diff --git a/qglengine/core/glmaterial.cpp b/qglengine/core/glmaterial.cpp index b2c28ee..86caa69 100644 --- a/qglengine/core/glmaterial.cpp +++ b/qglengine/core/glmaterial.cpp @@ -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(); +} diff --git a/qglengine/core/glmaterial.h b/qglengine/core/glmaterial.h index 90a3143..2e6d311 100644 --- a/qglengine/core/glmaterial.h +++ b/qglengine/core/glmaterial.h @@ -104,6 +104,7 @@ public: void load(TextureManager * tm); void setMapsChanged(); void setTypes(); + void detectMaps(); QString name; QColor color_diffuse; QColor color_emission; diff --git a/qglengine/core/hdr.cpp b/qglengine/core/hdr.cpp new file mode 100644 index 0000000..f2b01d6 --- /dev/null +++ b/qglengine/core/hdr.cpp @@ -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 . +*/ + +#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(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. +*/ + +#ifndef HDR_P_H +#define HDR_P_H + +#include + +bool RGBE_ReadPixels_RLE(QDataStream * fp, float * data, int scanline_width, int num_scanlines); + +#endif // HDR_P_H diff --git a/qglengine/formats/loader_assimp.cpp b/qglengine/formats/loader_assimp.cpp index d848a06..9a07077 100644 --- a/qglengine/formats/loader_assimp.cpp +++ b/qglengine/formats/loader_assimp.cpp @@ -124,6 +124,7 @@ Material * assimpMaterial(const aiMaterial * m) { ret->map_roughness.bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_SHININESS(0)); ret->map_emission .bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_EMISSIVE(0)); ret->transparency = 1.f - aiMatFloat(m, AI_MATKEY_OPACITY, 1.f); + ret->detectMaps(); ret->setTypes(); return ret; } diff --git a/qglengine/qglview.cpp b/qglengine/qglview.cpp index efcb5f6..f4c05dc 100644 --- a/qglengine/qglview.cpp +++ b/qglengine/qglview.cpp @@ -90,8 +90,9 @@ QGLView::QGLView(): OpenGLWindow(), renderer_(this), mouse(this) { //camera().aim_ = camera().pos_; ktm_.restart(); - Mesh * m = Primitive::torus(100, 40, 1., 0.4, 360); - //Mesh * m = Primitive::coneFrame(10, 1, 1., 2.); + //Mesh * m = Primitive::torus(100, 40, 1., 0.4, 360); + Mesh * m = Primitive::cube(10, 10, 10); + m->flipNormals(); //QMatrix4x4 mat; //mat.rotate(90, 0,1,0); //mat.translate(0, 0, 2); @@ -178,17 +179,19 @@ void QGLView::render() { void QGLView::initialize() { checkCaps(); - renderer_.reloadShaders(); - renderer_.init(width(), height()); glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_MULTISAMPLE); glDisable(GL_BLEND); glEnable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_CUBE_MAP); glEnable(GL_TEXTURE_MAX_ANISOTROPY_EXT); glEnable(GL_CULL_FACE); + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); glCullFace(GL_BACK); + renderer_.reloadShaders(); + renderer_.init(width(), height()); is_init = true; need_init_ = false; emit glInitializeDone(); diff --git a/qglengine/qglview.h b/qglengine/qglview.h index 45c31b1..8f5f014 100644 --- a/qglengine/qglview.h +++ b/qglengine/qglview.h @@ -75,6 +75,12 @@ public: QGLView(); virtual ~QGLView(); + enum CameraLightMode { + clmOff, + clmAuto, + clmOn, + }; + enum Feature { qglFXAA, qglAnisotropicLevel, @@ -102,6 +108,7 @@ public: qglDepthOfFieldDiaphragm }; + Q_ENUM(CameraLightMode) void stop(); void start(float freq = 60.); @@ -114,6 +121,7 @@ public: float gamma() const {return renderer_.gamma_;} bool autoExposure() const {return renderer_.tone_proc.enabled;} int maxAnisotropicLevel() const {return max_anisotropic;} + QString environmentMapFile() const {return renderer_.tex_env.fileHDR();} QColor ambientColor() const {return ambientColor_;} QColor fogColor() const {return fogColor_;} @@ -164,8 +172,8 @@ public: Scene * scene() {return scene_;} void focusOn(const Box3D & bb); - void setCameraLightOn(bool on) {renderer_.setCameraLightOn(on);} - bool isCameraLightOn() const {return renderer_.isCameraLightOn();} + void setCameraLightMode(CameraLightMode m) {renderer_.setCameraLightMode(m);} + CameraLightMode cameraLightMode() const {return (CameraLightMode)renderer_.cameraLightMode();} Camera * camera() {return camera_;} const Camera * camera() const {return camera_;} @@ -238,6 +246,7 @@ public slots: void setGamma(const float & arg) {renderer_.gamma_ = arg;} void setAutoExposure(bool arg) {renderer_.tone_proc.enabled = arg;} void setAmbientColor(const QColor & arg) {ambientColor_ = arg;} + void setEnvironmentMapFile(QString file) {renderer_.tex_env.setFileHDR(file);} void setFogColor(const QColor & arg) {fogColor_ = arg;} void setFogDensity(const float & arg) {fogDensity_ = arg;} void setFogDecay(const float & arg) {fogDecay_ = arg;} diff --git a/qglengine/qglview_test/qglview_window.cpp b/qglengine/qglview_test/qglview_window.cpp index 5d9291a..5d9d37e 100644 --- a/qglengine/qglview_test/qglview_window.cpp +++ b/qglengine/qglview_test/qglview_window.cpp @@ -242,3 +242,10 @@ void QGLViewWindow::on_actionScale_triggered(bool on) { actionScale ->setChecked(true); view->view()->setCurrentAction(RendererService::haScale); } + + +#include "glcubemap.h" +void QGLViewWindow::on_pushButton_3_clicked() { + QString f = QFileDialog::getOpenFileName(this, "Select file", "", "*"); + if (f.isEmpty()) return; +} diff --git a/qglengine/qglview_test/qglview_window.h b/qglengine/qglview_test/qglview_window.h index c96687c..aebb7c3 100644 --- a/qglengine/qglview_test/qglview_window.h +++ b/qglengine/qglview_test/qglview_window.h @@ -105,6 +105,8 @@ private slots: void on_spinFogDensity_valueChanged(double v) {view->view()->setFogDensity(v);} void on_spinFogDecay_valueChanged(double v) {view->view()->setFogDecay(v);} + void on_pushButton_3_clicked(); + public slots: signals: diff --git a/qglengine/qglview_test/qglview_window.ui b/qglengine/qglview_test/qglview_window.ui index 91eaaa2..a9bde08 100644 --- a/qglengine/qglview_test/qglview_window.ui +++ b/qglengine/qglview_test/qglview_window.ui @@ -80,8 +80,8 @@ 0 0 - 945 - 636 + 934 + 737 @@ -635,6 +635,13 @@ + + + + load HDR + + + @@ -741,7 +748,7 @@ 0 0 1107 - 21 + 24 diff --git a/qglengine/renderer.cpp b/qglengine/renderer.cpp index 3d2221d..4aab809 100644 --- a/qglengine/renderer.cpp +++ b/qglengine/renderer.cpp @@ -30,7 +30,7 @@ using namespace QGLEngineShaders; Renderer::Renderer(QGLView * view_): RendererBase(view_), fbo_ds (view_, QVector() << GL_RGBA16F << GL_RGBA32F << GL_RGBA16F << GL_RGBA16F << GL_RGBA16F), fbo_out (view_, obrBuffersCount, false, GL_RGBA16F), - rend_mat(this), rend_service(this), rend_selection(this), tone_proc(this) { + rend_mat(this), rend_service(this), rend_selection(this), tone_proc(this), tex_env(view_, 512) { quad = Primitive::plane(2., 2.); cam_light = new Light(); cam_light->intensity = 0.75; @@ -69,7 +69,8 @@ Renderer::Renderer(QGLView * view_): RendererBase(view_), << ShaderPair("dof", &shader_dof);*/ shader_fxaa = 0; gamma_ = 1.; - edit_mode = need_init_shaders = is_camera_light = true; + edit_mode = need_init_shaders = true; + camera_light_mode = QGLView::clmAuto; } @@ -90,6 +91,7 @@ void Renderer::init(int width, int height) { initQuad(quad); initTextureArrays(); initCoeffTextures(); + tex_env.init(); need_init_shaders = true; } @@ -158,6 +160,7 @@ void Renderer::initShaders() { prog->setUniformValue(QString("tex_%1").arg(i).toLatin1().constData(), i); prog->setUniformValue("tex_coeffs[0]", (int)Renderer::dbrBuffersCount); //prog->setUniformValue("tex_coeffs[1]", (int)Renderer::dbrBuffersCount+1); + prog->setUniformValue("tex_env", (int)Renderer::dbrBuffersCount+1); } if (bindShader(srFinalPass, &prog)) { prog->setUniformValue("tex_g1" , 0); @@ -238,6 +241,7 @@ void Renderer::renderLight(int first_wr_buff, bool clear_only) { } fbo_ds.bindColorTextures(); fbo_out.bind(); + tex_env.bind((int)Renderer::dbrBuffersCount+1); //int ri = 1, wi = 0; typedef QPair PassPair; QVector passes; @@ -256,6 +260,7 @@ void Renderer::renderLight(int first_wr_buff, bool clear_only) { prog->setUniformValue("fog_color", view->fogColor_); prog->setUniformValue("fog_decay", qMax(view->fogDecay_, 0.001f)); prog->setUniformValue("fog_density", view->fogDensity_); + prog->setUniformValue("view_mat", cam->viewMatrix().inverted().toGenericMatrix<3,3>()); renderQuad(prog, quad, cam); } } @@ -264,6 +269,7 @@ void Renderer::renderLight(int first_wr_buff, bool clear_only) { void Renderer::renderScene() { initShaders(); + tex_env.load(); QOpenGLExtraFunctions * f = view; Scene & scene(*(view->scene_)); Camera * cam = view->camera(); @@ -289,7 +295,10 @@ void Renderer::renderScene() { /// lights cur_lights = scene.lights_used; - if (is_camera_light) { + bool use_camlight = (camera_light_mode == QGLView::clmOn); + if ((camera_light_mode == QGLView::clmAuto) && cur_lights.isEmpty()) + use_camlight = true; + if (use_camlight) { cur_lights[Light::Omni] << cam_light; cam_light->setPos(cam->pos()); } @@ -367,7 +376,7 @@ void Renderer::renderScene() { } -void Renderer::setCameraLightOn(bool on) { - is_camera_light = on; +void Renderer::setCameraLightMode(int m) { + camera_light_mode = m; view->scene()->setLightsChanged(); } diff --git a/qglengine/renderer.h b/qglengine/renderer.h index 4e1595f..1b583b0 100644 --- a/qglengine/renderer.h +++ b/qglengine/renderer.h @@ -24,6 +24,7 @@ #include "renderer_service.h" #include "renderer_selection.h" #include "tonemapping_proc.h" +#include "glcubemap.h" #include @@ -82,8 +83,8 @@ public: void resize(int width, int height); void reloadShaders(); void renderScene(); - void setCameraLightOn(bool on); - bool isCameraLightOn() const {return is_camera_light;} + void setCameraLightMode(int m); + int cameraLightMode() const {return camera_light_mode;} QImage materialThumbnail(Material * m) {return rend_mat.materialThumbnail(m);} void recreateMaterialThumbnails(bool force_all = false) {rend_mat.recreateMaterialThumbnails(force_all);} @@ -101,7 +102,8 @@ protected: private: float gamma_; - bool edit_mode, need_init_shaders, is_camera_light, need_render_sum; + int camera_light_mode; + bool edit_mode, need_init_shaders, need_render_sum; Framebuffer fbo_ds, fbo_out; /*QOpenGLShaderProgram * shader_fxaa, * shader_ds_0, * shader_ds_1, * shader_hdr, * shader_small; QOpenGLShaderProgram * shader_bloom_0, * shader_bloom_1, * shader_motion_blur, * shader_fbo_add; @@ -119,6 +121,7 @@ private: Mesh * quad; Light * cam_light; + CubeTexture tex_env; QPoint mouse_pos; QRect mouse_rect; diff --git a/qglengine/renderer_base.cpp b/qglengine/renderer_base.cpp index 5d0782b..a9f91d8 100644 --- a/qglengine/renderer_base.cpp +++ b/qglengine/renderer_base.cpp @@ -115,13 +115,17 @@ void RendererBase::setUniformViewCorners(QOpenGLShaderProgram * prog, Camera * c h = viewport.height(); } QMatrix4x4 mproji = cam->projectionMatrix(w / h).inverted(); - QVector4D corner_dirs[4]; + QMatrix4x4 mviewi = cam->viewMatrix().inverted(); + QVector4D corner_dirs[4], world_dirs[4]; corner_dirs[0] = (mproji * QVector4D(-1, -1, 0, 1)); corner_dirs[1] = (mproji * QVector4D(-1, 1, 0, 1)); corner_dirs[2] = (mproji * QVector4D( 1, 1, 0, 1)); corner_dirs[3] = (mproji * QVector4D( 1, -1, 0, 1)); - for (int i = 0; i < 4; ++i) + for (int i = 0; i < 4; ++i) { + world_dirs[i] = mviewi.mapVector(corner_dirs[i].toVector3D()); prog->setUniformValue(QString("view_corners[%1]").arg(i).toLatin1().constData(), corner_dirs[i]); + prog->setUniformValue(QString("world_corners[%1]").arg(i).toLatin1().constData(), world_dirs[i]); + } } diff --git a/qglengine/shaders/ds_light.glsl b/qglengine/shaders/ds_light.glsl index e072de0..7f8c132 100644 --- a/qglengine/shaders/ds_light.glsl +++ b/qglengine/shaders/ds_light.glsl @@ -1,31 +1,34 @@ // vert // -out vec3 view_dir; +out vec3 view_dir, world_dir; -uniform vec4 view_corners[4]; +uniform vec4 view_corners[4], world_corners[4]; void main(void) { qgl_FragTexture = qgl_Texture; gl_Position = qgl_ftransform(); - view_dir = view_corners[gl_VertexID].xyz; + view_dir = view_corners [gl_VertexID].xyz; + world_dir = world_corners[gl_VertexID].xyz; } // frag // -in vec3 view_dir; +in vec3 view_dir, world_dir; uniform vec2 dt; uniform float z_near; uniform sampler2D tex_coeffs[2]; uniform sampler2D tex_0, tex_1, tex_2, tex_3, tex_4; +uniform samplerCube tex_env; uniform int lights_start, lights_count; uniform vec4 fog_color = vec4(0.5, 0.5, 0.5, 1); uniform float fog_decay = 10, fog_density = 0; +uniform mat3 view_mat; const vec3 luma = vec3(0.299, 0.587, 0.114); -const float _min_rough = 1.e-8; +const float _min_rough = 1.e-8, max_lod = 8; vec4 pos, lpos, shp; vec3 li, si, ldir, halfV, bn, bn2, lwdir; @@ -154,11 +157,14 @@ void main(void) { li *= (1 - shlick); alpha = min(1, alpha * (1 + shlick)); - vec2 brdf = texture(tex_coeffs[0], vec2(NdotV*0.99, roughness3*0.995)).rg; + vec2 brdf = texture(tex_coeffs[0], vec2(NdotV*0.99, roughness*0.995)).rg; float env_spec = shlick * brdf.x + brdf.y; + vec3 spec_col = mix(vec3(1), diffuse, metalness); + vec3 env_dir = view_mat * reflect(-v, normal); + vec3 env_col = textureLod(tex_env, env_dir, sqrt(roughness) * max_lod).rgb * spec_col; - vec3 res_col = max(vec3(0), li * diffuse + si * mix(vec3(1), diffuse, metalness) + emission); - res_col = mix(res_col, fog_color.rgb, env_spec); + vec3 res_col = max(vec3(0), li * diffuse + si * spec_col + emission); + res_col = mix(res_col, env_col, env_spec * reflectivity); float plen = length(pos.xyz); float fog = 1 - exp(-plen / fog_decay); @@ -169,6 +175,7 @@ void main(void) { //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); //qgl_FragColor.rgb = vec3(shlick * brdf.x + brdf.y); - //qgl_FragColor.rgb = vec3(env_spec); - //qgl_FragColor.rgb = vec3(1-GeometrySchlickGGX(dot(normal, v),roughness)); + //qgl_FragColor.rgb = vec3(alpha); + //qgl_FragColor.rgb = vec3(textureLod(tex_env, world_dir, 0).rgb); + //qgl_FragColor.a = 1.; } diff --git a/qglengine/tonemapping_proc.cpp b/qglengine/tonemapping_proc.cpp index fedcedc..0c2b8c7 100644 --- a/qglengine/tonemapping_proc.cpp +++ b/qglengine/tonemapping_proc.cpp @@ -33,7 +33,7 @@ TonemappingProc::TonemappingProc(Renderer * rend): QThread(), r(rend), timer_delim = 0; frame_max = cur_max = 1.; need_render_sum = exit_ = false; - enabled = true; + enabled = false; timer_tone = startTimer(10); } diff --git a/qglengine/widgets/view_editor.cpp b/qglengine/widgets/view_editor.cpp index 49b8725..894950c 100644 --- a/qglengine/widgets/view_editor.cpp +++ b/qglengine/widgets/view_editor.cpp @@ -18,6 +18,7 @@ #include "view_editor.h" #include "ui_view_editor.h" +#include #include #include @@ -27,6 +28,7 @@ ViewEditor::ViewEditor(QWidget * parent): QWidget(parent) { ui->setupUi(this); view = 0; active = true; + ui->checkCameraLight->setCheckState(Qt::PartiallyChecked); } @@ -44,7 +46,10 @@ void ViewEditor::assignQGLView(QGLView * v) { ui->colorSelectionHalo->setColor(view->selectionHaloColor()); ui->checkFXAA->setChecked(view->isFeatureEnabled(QGLView::qglFXAA)); ui->checkCameraOrbit->setChecked(view->isCameraOrbit()); + ui->checkCameraLight->setCheckState((Qt::CheckState)view->cameraLightMode()); ui->checkService->setChecked(view->isServiceMode()); + ui->lineHDR->setProperty("GLpath", view->environmentMapFile()); + ui->lineHDR->setText(QFileInfo(view->environmentMapFile()).fileName()); active = true; } @@ -140,13 +145,32 @@ void ViewEditor::on_checkCameraOrbit_clicked(bool val) { } -void ViewEditor::on_checkCameraLight_clicked(bool val) { - if (!view || !active) return; - view->setCameraLightOn(val); -} - - void ViewEditor::on_checkService_clicked(bool val) { if (!view || !active) return; view->setServiceMode(val); } + + +void ViewEditor::on_checkCameraLight_stateChanged(int s) { + if (!view || !active) return; + view->setCameraLightMode((QGLView::CameraLightMode)s); + +} + + +void ViewEditor::on_buttonHDRClear_clicked() { + if (!view || !active) return; + ui->lineHDR->setText(""); + ui->lineHDR->setProperty("GLpath", ""); + view->setEnvironmentMapFile(""); +} + + +void ViewEditor::on_buttonHDRSelect_clicked() { + if (!view || !active) return; + QString str = QFileDialog::getOpenFileName(this, "Select image", ui->lineHDR->property("GLpath").toString(), "Radiance HDR(*.hdr)"); + if (str.isEmpty()) return; + ui->lineHDR->setText(QFileInfo(str).fileName()); + ui->lineHDR->setProperty("GLpath", str); + view->setEnvironmentMapFile(str); +} diff --git a/qglengine/widgets/view_editor.h b/qglengine/widgets/view_editor.h index b6d1472..d4663e0 100644 --- a/qglengine/widgets/view_editor.h +++ b/qglengine/widgets/view_editor.h @@ -55,8 +55,10 @@ private slots: void on_checkAutoExposure_toggled(bool val); void on_checkFXAA_clicked(bool val); void on_checkCameraOrbit_clicked(bool val); - void on_checkCameraLight_clicked(bool val); void on_checkService_clicked(bool val); + void on_checkCameraLight_stateChanged(int s); + void on_buttonHDRClear_clicked(); + void on_buttonHDRSelect_clicked(); signals: diff --git a/qglengine/widgets/view_editor.ui b/qglengine/widgets/view_editor.ui index 1a711b7..2ff5423 100644 --- a/qglengine/widgets/view_editor.ui +++ b/qglengine/widgets/view_editor.ui @@ -73,6 +73,65 @@ + + + + Gamma: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 0.010000000000000 + + + 5.000000000000000 + + + 1.000000000000000 + + + 2 + + + + + + + Env HDR: + + + + + + + 2 + + + + + + + + + :/icons/edit-delete.png:/icons/edit-delete.png + + + + + + + + :/icons/document-open.png:/icons/document-open.png + + + + + @@ -90,9 +149,6 @@ Auto exposure - - true - @@ -105,6 +161,16 @@ + + + + Camera light + + + true + + + @@ -112,117 +178,86 @@ Camera - - - - - Gamma: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + + + + + + Orbit + + + true + + + + + + + Qt::Horizontal + + + + 40 + 1 + + + + + + + + FOV: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 0.100000000000000 + + + 179.900000000000006 + + + 60.000000000000000 + + + + - - - - 0.010000000000000 - - - 5.000000000000000 - - - 1.000000000000000 - - - 2 - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 20 - 1 - - - - - - - - FOV: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - CamLight - - - true - - - - - - - 0.100000000000000 - - - 179.900000000000006 - - - 60.000000000000000 - - - - - - - Orbit - - - true - - - - - - - Depth start: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 3 - - - 999999999.000000000000000 - - - QAbstractSpinBox::AdaptiveDecimalStepType - - - 1.000000000000000 - - + + + + + + Depth start: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 3 + + + 999999999.000000000000000 + + + QAbstractSpinBox::AdaptiveDecimalStepType + + + 1.000000000000000 + + + + @@ -468,6 +503,9 @@
colorbutton.h
- + + + +