source-tree refactoring
This commit is contained in:
209
src/core/render/gltexture_manager.cpp
Normal file
209
src/core/render/gltexture_manager.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
QGL TextureManager
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gltexture_manager.h"
|
||||
|
||||
#include "gltypes.h"
|
||||
|
||||
QStringList TextureManager::search_pathes(".");
|
||||
|
||||
|
||||
QVector3D colorVector(QRgb c) {
|
||||
return QVector3D(((uchar *)(&c))[0] / 255.f, ((uchar *)(&c))[1] / 255.f, ((uchar *)(&c))[2] / 255.f);
|
||||
}
|
||||
|
||||
|
||||
QString TextureManager::findFile(const QString & path) {
|
||||
return ::findFile(path, search_pathes);
|
||||
}
|
||||
|
||||
|
||||
GLuint TextureManager::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;
|
||||
GLuint tid_ = tid;
|
||||
createGLTexture(f, tid_, image);
|
||||
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);
|
||||
tex_im[bump ? 1 : 0].insert(p, image);
|
||||
}
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
GLuint TextureManager::loadTexture(const QImage & im, bool ownership, bool bump) {
|
||||
if (im.isNull()) return 0;
|
||||
QImage image(im);
|
||||
if (bump) convertToNormal(image);
|
||||
GLuint tid = 0;
|
||||
createGLTexture(f, tid, im);
|
||||
if (tid == 0) {
|
||||
qDebug() << "[TextureManager] Can`t load image";
|
||||
return tid;
|
||||
}
|
||||
// qDebug() << "[TextureManager] Loaded image as" << tid;
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
QImage TextureManager::loadTextureImage(const QString & path, bool bump) {
|
||||
QString p = findFile(path);
|
||||
if (p.isEmpty()) return QImage();
|
||||
QImage ret = tex_im[bump ? 1 : 0].value(p);
|
||||
if (!ret.isNull()) return ret;
|
||||
ret = QImage(p);
|
||||
if (bump) convertToNormal(ret);
|
||||
tex_im[bump ? 1 : 0].insert(p, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void TextureManager::reloadTexture(GLuint tid, const QString & path) {
|
||||
QString p = findFile(path);
|
||||
if (p.isEmpty() || (tid == 0)) return;
|
||||
QImage image(p);
|
||||
createGLTexture(f, tid, image);
|
||||
if (tid == 0) {
|
||||
qDebug() << "[TextureManager] Can`t load" << p;
|
||||
return;
|
||||
}
|
||||
qDebug() << "[TextureManager] Reloaded" << p << "as" << tid;
|
||||
}
|
||||
|
||||
|
||||
void TextureManager::reloadTexture(GLuint tid, const QImage & im) {
|
||||
if (im.isNull() || (tid == 0)) return;
|
||||
QImage image(im);
|
||||
createGLTexture(f, tid, image);
|
||||
qDebug() << "[TextureManager] Reloaded" << tid;
|
||||
}
|
||||
|
||||
|
||||
void TextureManager::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 normal";
|
||||
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;
|
||||
QVector3D 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.setY(piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f));
|
||||
res.setX(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.setY(piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f));
|
||||
res.setX(piClamp(0.5f - (p[0].length() - p[2].length()) / 2.f, 0.f, 1.f));
|
||||
res.setZ(1.f);
|
||||
dd[a] = res.z() * 255;
|
||||
++a;
|
||||
dd[a] = res.y() * 255;
|
||||
++a;
|
||||
dd[a] = res.x() * 255;
|
||||
++a;
|
||||
dd[a] = 255;
|
||||
++a;
|
||||
}
|
||||
}
|
||||
im = dim;
|
||||
// im.save("_normal.png");
|
||||
}
|
||||
|
||||
|
||||
bool TextureManager::loadTextures() {
|
||||
QFileInfoList fil;
|
||||
foreach(const QString & i, tex_pathes)
|
||||
loadTexture(i, true);
|
||||
tex_pathes.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void TextureManager::deleteTextures() {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
QList<GLuint> texs = tex_ids[i].values();
|
||||
qDebug() << "[TextureManager] Delete" << texs.size() << "textures";
|
||||
if (!texs.isEmpty()) f->glDeleteTextures(texs.size(), &texs[0]);
|
||||
tex_ids[i].clear();
|
||||
tex_im[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TextureManager::deleteTexture(const QString & name) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (tex_ids[i].contains(name)) {
|
||||
GLuint id = tex_ids[i][name];
|
||||
f->glDeleteTextures(1, &id);
|
||||
tex_ids[i].remove(name);
|
||||
tex_im[i].remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TextureManager::clearImageCache() {
|
||||
tex_im[0].clear();
|
||||
tex_im[1].clear();
|
||||
}
|
||||
67
src/core/render/gltexture_manager.h
Normal file
67
src/core/render/gltexture_manager.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
QGL TextureManager
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLTEXTUREMANAGER_H
|
||||
#define GLTEXTUREMANAGER_H
|
||||
|
||||
#include "qglengine_core_export.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QImage>
|
||||
#include <QMap>
|
||||
#include <QOpenGLExtraFunctions>
|
||||
|
||||
|
||||
class QGLENGINE_CORE_EXPORT TextureManager {
|
||||
public:
|
||||
TextureManager(QOpenGLExtraFunctions * f_): f(f_) {}
|
||||
virtual ~TextureManager() {}
|
||||
|
||||
static void addSearchPath(const QString & path) {
|
||||
if (!search_pathes.contains(path)) search_pathes << path;
|
||||
}
|
||||
static void clearSearchPathes() { search_pathes.clear(); }
|
||||
static QStringList searchPathes() { return search_pathes; }
|
||||
static QString findFile(const QString & path);
|
||||
GLuint loadTexture(const QString & path, bool ownership = true, bool bump = false);
|
||||
GLuint loadTexture(const QImage & image, bool ownership = true, bool bump = false);
|
||||
QImage loadTextureImage(const QString & path, bool bump = false);
|
||||
void reloadTexture(GLuint tid, const QString & path);
|
||||
void reloadTexture(GLuint tid, const QImage & image);
|
||||
int textureID(const QString & path, bool bump = false) { return tex_ids[bump ? 1 : 0][path]; }
|
||||
QImage textureImage(const QString & path, bool bump = false) { return tex_im[bump ? 1 : 0][path]; }
|
||||
void addTexture(const QString & path) { tex_pathes << path; }
|
||||
bool loadTextures();
|
||||
void deleteTextures();
|
||||
void deleteTexture(const QString & name);
|
||||
void clearImageCache();
|
||||
|
||||
protected:
|
||||
static void convertToNormal(QImage & im);
|
||||
|
||||
static QStringList search_pathes;
|
||||
|
||||
QMap<QString, GLuint> tex_ids[2];
|
||||
QMap<QString, QImage> tex_im[2];
|
||||
QStringList tex_pathes;
|
||||
QOpenGLExtraFunctions * f;
|
||||
};
|
||||
|
||||
|
||||
#endif // GLTEXTUREMANAGER_H
|
||||
450
src/core/render/renderer.cpp
Normal file
450
src/core/render/renderer.cpp
Normal file
@@ -0,0 +1,450 @@
|
||||
/*
|
||||
QGL Renderer
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include "renderer.h"
|
||||
|
||||
#include "glmesh.h"
|
||||
#include "glshaders.h"
|
||||
#include "gltexture_manager.h"
|
||||
#include "qglview.h"
|
||||
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <qad_types.h>
|
||||
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
|
||||
Renderer::Renderer(QGLView * view_)
|
||||
: RendererBase(view_)
|
||||
, fbo_ds(view_, QVector<GLenum>() << GL_RGBA16F << GL_RGBA32F << GL_RGBA16F << GL_RGBA16F << GL_RGBA16F << GL_RGBA32F << GL_RGBA16F)
|
||||
, fbo_out(view_, obrBuffersCount, false, GL_RGBA16F)
|
||||
, 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;
|
||||
cam_light->setName("Camera_Light");
|
||||
|
||||
shader_files[srSelectionFill] = "selection.glsl";
|
||||
shader_files[srSelectionHalo] = "selection_halo.glsl";
|
||||
shader_files[srSelectionApply] = "selection_apply.glsl";
|
||||
shader_files[srSelectionFrame] = "selection_frame.glsl";
|
||||
|
||||
shader_files[srServiceFill] = "service_fill.glsl";
|
||||
shader_files[srServiceFrame] = "service_frame.glsl";
|
||||
shader_files[srServiceLine] = "service_line.glsl";
|
||||
|
||||
shader_files[srGeometryPass] = "ds_geom.glsl";
|
||||
shader_files[srLightOmniPass] = "ds_light.glsl";
|
||||
shader_files[srLightSpotPass] = "ds_light.glsl";
|
||||
shader_defines[srLightSpotPass] << "SPOT";
|
||||
shader_files[srFinalPass] = "ds_final.glsl";
|
||||
shader_files[srTonemapPass] = "ds_tonemap.glsl";
|
||||
|
||||
edit_mode = need_init_shaders = true;
|
||||
camera_light_mode = QGLView::clmAuto;
|
||||
}
|
||||
|
||||
|
||||
Renderer::~Renderer() {
|
||||
delete quad;
|
||||
delete cam_light;
|
||||
qDeleteAll(shaders.values());
|
||||
if (shader_fxaa) delete shader_fxaa;
|
||||
}
|
||||
|
||||
|
||||
void Renderer::init(int width, int height) {
|
||||
fbo_ds.reinit();
|
||||
fbo_out.reinit();
|
||||
quad->reinit();
|
||||
buffer_materials.reinit();
|
||||
buffer_lights.reinit();
|
||||
buffer_lights_pos.reinit();
|
||||
textures_maps.reinit();
|
||||
textures_empty.reinit();
|
||||
resize(width, height);
|
||||
rend_mat.init(width, height);
|
||||
rend_service.init(width, height);
|
||||
rend_selection.init(width, height);
|
||||
tone_proc.init();
|
||||
initQuad(quad);
|
||||
initTextureArrays();
|
||||
initCoeffTextures();
|
||||
markReloadTextures();
|
||||
tex_env.init();
|
||||
if (is_grabbing) fbo_out.enablePixelBuffer();
|
||||
need_init_shaders = true;
|
||||
}
|
||||
|
||||
|
||||
void Renderer::resize(int width, int height) {
|
||||
rend_mat.resize(width, height);
|
||||
rend_service.resize(width, height);
|
||||
rend_selection.resize(width, height);
|
||||
fbo_ds.resize(width, height);
|
||||
fbo_out.resize(width, height);
|
||||
tone_proc.resize();
|
||||
}
|
||||
|
||||
|
||||
void Renderer::reloadShaders() {
|
||||
QMapIterator<ShaderRole, QString> it(shader_files);
|
||||
qDeleteAll(shaders.values());
|
||||
shaders.clear();
|
||||
if (shader_fxaa) delete shader_fxaa;
|
||||
shader_fxaa = nullptr;
|
||||
if (tone_proc.shader_sum) delete tone_proc.shader_sum;
|
||||
tone_proc.shader_sum = nullptr;
|
||||
QString dir = ":shaders/";
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
loadShadersMulti(shaders[it.key()], dir + it.value(), true, shader_defines.value(it.key()));
|
||||
}
|
||||
loadShadersMulti(tone_proc.shader_sum, dir + "sum.glsl", false);
|
||||
QStringList fxaa_defs;
|
||||
fxaa_defs << "FXAA_PC 1"
|
||||
<< "FXAA_GLSL_130 1"
|
||||
<< "FXAA_QUALITY__PRESET 15";
|
||||
loadShaders(shader_fxaa, QStringList() << (dir + "fxaa.vert") << (dir + "fxaa.frag"), true, fxaa_defs);
|
||||
for (auto * e: fb_effects) {
|
||||
e->reloadShaders();
|
||||
e->is_loaded = true;
|
||||
}
|
||||
need_init_shaders = true;
|
||||
view->scene()->setLightsChanged();
|
||||
view->scene()->setTreeStructChanged();
|
||||
view->scene()->setMaterialsChanged();
|
||||
}
|
||||
|
||||
|
||||
bool Renderer::bindShader(Renderer::ShaderRole role, QOpenGLShaderProgram ** ret) {
|
||||
QOpenGLShaderProgram * prog = shaders.value(role);
|
||||
if (ret) *ret = prog;
|
||||
if (!prog) return false;
|
||||
if (!prog->isLinked()) return false;
|
||||
prog->bind();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Renderer::bindShader(QOpenGLShaderProgram * sp) {
|
||||
if (!sp) return true;
|
||||
if (!sp->isLinked()) return true;
|
||||
if (!sp->bind()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Renderer::initShaders() {
|
||||
if (!need_init_shaders) return;
|
||||
need_init_shaders = false;
|
||||
initUniformBuffer(shaders.value(srGeometryPass), &buffer_materials, bpMaterials, "QGLMaterialData");
|
||||
initUniformBuffer(shaders.value(srLightOmniPass), &buffer_materials, bpMaterials, "QGLMaterialData");
|
||||
initUniformBuffer(shaders.value(srLightOmniPass), &buffer_lights, bpLightParameters, "QGLLightParameterData");
|
||||
initUniformBuffer(shaders.value(srLightOmniPass), &buffer_lights_pos, bpLightPositions, "QGLLightPositionData");
|
||||
initUniformBuffer(shaders.value(srLightSpotPass), &buffer_materials, bpMaterials, "QGLMaterialData");
|
||||
initUniformBuffer(shaders.value(srLightSpotPass), &buffer_lights, bpLightParameters, "QGLLightParameterData");
|
||||
initUniformBuffer(shaders.value(srLightSpotPass), &buffer_lights_pos, bpLightPositions, "QGLLightPositionData");
|
||||
ShaderRole roles[] = {srLightOmniPass, srLightSpotPass};
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
for (int p = 0; p < 2; ++p) {
|
||||
if (!bindShader(roles[p], &prog)) continue;
|
||||
for (int i = 0; i < 5; ++i)
|
||||
prog->setUniformValue(QString("tex_%1").arg(i).toLatin1().constData(), i);
|
||||
prog->setUniformValue("tex_coeffs[0]", (int)Renderer::dbrBuffersCount);
|
||||
prog->setUniformValue("tex_env", (int)Renderer::dbrBuffersCount + 1);
|
||||
}
|
||||
if (bindShader(srFinalPass, &prog)) {
|
||||
prog->setUniformValue("tex_g1", 0);
|
||||
prog->setUniformValue("tex_s_0", 1);
|
||||
prog->setUniformValue("tex_s_1", 2);
|
||||
prog->setUniformValue("tex_t_0", 3);
|
||||
prog->setUniformValue("tex_t_1", 4);
|
||||
}
|
||||
if (bindShader(srGeometryPass, &prog)) {
|
||||
setUniformMaps(prog);
|
||||
}
|
||||
if (bindShader(srTonemapPass, &prog)) {
|
||||
prog->setUniformValue("tex_0", 0);
|
||||
prog->setUniformValue("tex_sum", 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::releaseShader() {
|
||||
view->glUseProgram(0);
|
||||
}
|
||||
|
||||
|
||||
QVector<int> Renderer::getFreePlanes(int count) {
|
||||
prev_write_plane = cur_write_plane;
|
||||
QVector<int> ret;
|
||||
bool output_done = false;
|
||||
const int total_count = 4;
|
||||
for (int i = 0; i < total_count; ++i) {
|
||||
int plane = obrGeneral0 + i;
|
||||
if (prev_write_plane == plane) continue;
|
||||
if (!output_done) {
|
||||
fbo_out.setWriteBuffer(plane);
|
||||
cur_write_plane = plane;
|
||||
output_done = true;
|
||||
continue;
|
||||
}
|
||||
ret << plane;
|
||||
if (ret.size() == count) break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void Renderer::fillObjectsBuffer(const ObjectBaseList & ol, RenderPass pass) {
|
||||
cur_objects_.resize(ol.size());
|
||||
for (int i = 0; i < ol.size(); ++i) {
|
||||
Object & so(cur_objects_[i]);
|
||||
ObjectBase * o = ol[i];
|
||||
if (o->material()) {
|
||||
so.material = o->material()->_index;
|
||||
so.color = QVector4D(1, 1, 1, 1);
|
||||
} else {
|
||||
so.material = 0;
|
||||
so.color = QColor2QVector(o->color());
|
||||
}
|
||||
so.object_id = o->id();
|
||||
o->worldTransform().transposed().copyDataTo(so.modelmatrix);
|
||||
// qDebug() << "load obj" << o->name() << o->worldTransform();
|
||||
}
|
||||
// qDebug() << "fillObjectsBuffer" << ol.size();
|
||||
}
|
||||
|
||||
|
||||
void Renderer::renderObjects(Scene & scene, RenderPass pass) {
|
||||
QOpenGLExtraFunctions * f = view;
|
||||
QMapIterator<Mesh *, ObjectBaseList> it(scene.geometries_used[pass]);
|
||||
bool emit_pos_change = false;
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
Mesh * mesh = it.key();
|
||||
if (mesh->isObjectsChanged(pass)) {
|
||||
mesh->setObjectsChanged(pass, false);
|
||||
emit_pos_change = true;
|
||||
fillObjectsBuffer(it.value(), pass);
|
||||
// qDebug() << "loadObjects" << pass << cur_objects_.size();
|
||||
mesh->loadObjects(f, cur_objects_, pass);
|
||||
}
|
||||
if (mesh->isSelectionChanged(pass) && edit_mode) {
|
||||
mesh->setSelectionChanged(pass, false);
|
||||
fillSelectionsBuffer(rend_selection.cur_selections_, it.value());
|
||||
// qDebug() << "fillSelectionsBuffer" << pass << rend_selection.cur_selections_.size();
|
||||
mesh->loadSelections(f, rend_selection.cur_selections_, pass);
|
||||
}
|
||||
// qDebug() << "draw" << pass << it.value().size();
|
||||
mesh->draw(f, it.value().size(), pass);
|
||||
}
|
||||
if (emit_pos_change) emit view->objectsPositionChanged();
|
||||
}
|
||||
|
||||
|
||||
void Renderer::renderLight(int first_wr_buff, bool clear_only) {
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
Camera * cam = view->camera();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
view->glActiveTexture(GL_TEXTURE0 + Renderer::dbrBuffersCount + i);
|
||||
view->glBindTexture(GL_TEXTURE_2D, tex_coeff[i]);
|
||||
}
|
||||
fbo_ds.bindColorTextures();
|
||||
fbo_out.bind();
|
||||
tex_env.bind((int)Renderer::dbrBuffersCount + 1);
|
||||
typedef QPair<Renderer::ShaderRole, Light::Type> PassPair;
|
||||
QVector<PassPair> passes;
|
||||
passes << PassPair(srLightOmniPass, Light::Omni) << PassPair(srLightSpotPass, Light::Cone);
|
||||
QColor back = view->fogColor();
|
||||
back.setAlpha(0);
|
||||
foreach(PassPair pass, passes) {
|
||||
if (bindShader(pass.first, &prog)) {
|
||||
fbo_out.setWriteBuffer(first_wr_buff + pass.second);
|
||||
glClearFramebuffer(back, false);
|
||||
if (clear_only) continue;
|
||||
setUniformCamera(prog, cam);
|
||||
setUniformViewCorners(prog, cam);
|
||||
prog->setUniformValue("lights_start", lights_start[pass.second]);
|
||||
prog->setUniformValue("lights_count", (int)cur_lights[pass.second].size());
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::renderScene() {
|
||||
initShaders();
|
||||
tex_env.load();
|
||||
QOpenGLExtraFunctions * f = view;
|
||||
Scene & scene(*(view->scene()));
|
||||
Camera * cam = view->camera();
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
bool scene_changed = scene.prepare();
|
||||
scene.destroyUnused(f);
|
||||
|
||||
/// reload materials on change
|
||||
if (scene_changed || scene.need_reload_materials) {
|
||||
rend_selection.generateObjectsID(scene);
|
||||
reloadMaterials(scene);
|
||||
if (edit_mode) recreateMaterialThumbnails();
|
||||
emit view->materialsChanged();
|
||||
}
|
||||
|
||||
/// material thumbnails
|
||||
if (edit_mode && !scene_changed) {
|
||||
rend_mat.procQueue();
|
||||
}
|
||||
|
||||
/// lights
|
||||
cur_lights = scene.lights_used;
|
||||
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());
|
||||
}
|
||||
if (scene.lights_changed) {
|
||||
scene.lights_changed = false;
|
||||
reloadLightsParameters(cur_lights);
|
||||
}
|
||||
reloadLightsPositions(cam);
|
||||
|
||||
/// selection
|
||||
if (edit_mode) {
|
||||
rend_selection.renderSelection(scene);
|
||||
}
|
||||
|
||||
/// solid geometry pass
|
||||
fbo_ds.bind();
|
||||
glEnableDepth();
|
||||
glClearFramebuffer();
|
||||
if (bindShader(srGeometryPass, &prog)) {
|
||||
setUniformCamera(prog, cam);
|
||||
textures_empty.bind(f, tarEmpty);
|
||||
textures_maps.bind(f, tarMaps);
|
||||
renderObjects(scene, rpSolid);
|
||||
}
|
||||
fbo_ds.blit(dbrNormalZ, fbo_ds.id(), dbrNormalZSolid, fbo_ds.rect(), fbo_ds.rect());
|
||||
fbo_ds.blit(dbrSpecularReflect, fbo_ds.id(), dbrSpecularReflectSolid, fbo_ds.rect(), fbo_ds.rect());
|
||||
fbo_ds.release();
|
||||
|
||||
/// lighting passes
|
||||
renderLight(obrSolidOmni, scene.geometries_used[rpSolid].isEmpty());
|
||||
|
||||
/// transparent geometry pass
|
||||
fbo_ds.bind();
|
||||
glEnableDepth();
|
||||
fbo_ds.setWriteBuffers({0, 1, 2, 3, 4});
|
||||
glClearFramebuffer(Qt::black, false);
|
||||
fbo_ds.setWriteBuffers();
|
||||
if (bindShader(srGeometryPass, &prog)) {
|
||||
renderObjects(scene, rpTransparent);
|
||||
}
|
||||
fbo_ds.release();
|
||||
|
||||
/// lighting passes
|
||||
renderLight(obrTransparentOmni, scene.geometries_used[rpTransparent].isEmpty());
|
||||
|
||||
/// blending layers
|
||||
if (bindShader(srFinalPass, &prog)) {
|
||||
fbo_out.bindColorTexture(obrSolidOmni, 1);
|
||||
fbo_out.bindColorTexture(obrSolidSpot, 2);
|
||||
fbo_out.bindColorTexture(obrTransparentOmni, 3);
|
||||
fbo_out.bindColorTexture(obrTransparentSpot, 4);
|
||||
fbo_out.setWriteBuffer(obrGeneral0);
|
||||
renderQuad(prog, quad);
|
||||
}
|
||||
|
||||
cur_write_plane = obrGeneral0;
|
||||
|
||||
/// tonemapping
|
||||
tone_proc.process();
|
||||
auto free = getFreePlanes(0);
|
||||
if (bindShader(srTonemapPass, &prog)) {
|
||||
fbo_out.bind();
|
||||
prog->setUniformValue("gamma", gamma_);
|
||||
prog->setUniformValue("frame_max", tone_proc.frameMax());
|
||||
fbo_out.bindColorTexture(prev_write_plane, 0);
|
||||
renderQuad(prog, quad);
|
||||
} else {
|
||||
fbo_out.blit(prev_write_plane, fbo_out.id(), cur_write_plane, fbo_out.rect(), fbo_out.rect());
|
||||
}
|
||||
|
||||
/// FXAA
|
||||
if (view->isFeatureEnabled(QGLView::qglFXAA)) {
|
||||
prog = shader_fxaa;
|
||||
if (bindShader(prog)) {
|
||||
auto free = getFreePlanes(0);
|
||||
setUniformCamera(prog, 0, true, fbo_out.size());
|
||||
fbo_out.bindColorTexture(prev_write_plane);
|
||||
renderQuad(prog, quad, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// custom effects
|
||||
for (auto * e: fb_effects) {
|
||||
e->reloadShadersInternal();
|
||||
e->drawInternal();
|
||||
}
|
||||
|
||||
fbo_out.release();
|
||||
|
||||
/// apply hovers and selection frame
|
||||
if (edit_mode) {
|
||||
rend_selection.drawSelection(fbo_out, cur_write_plane);
|
||||
rend_service.renderService();
|
||||
} else {
|
||||
fbo_out.blit(cur_write_plane, 0, 0, fbo_out.rect(), QRect(QPoint(), view->size()));
|
||||
}
|
||||
if (is_grabbing) {
|
||||
fbo_out.queryImage(0);
|
||||
last_img = fbo_out.getImage().mirrored();
|
||||
// qDebug() << last_img.size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::setCameraLightMode(int m) {
|
||||
camera_light_mode = m;
|
||||
view->scene()->setLightsChanged();
|
||||
}
|
||||
|
||||
void Renderer::setGrabImage(bool on) {
|
||||
is_grabbing = on;
|
||||
// fbo_out.enablePixelBuffer();
|
||||
}
|
||||
|
||||
|
||||
void Renderer::addFramebufferEffect(FramebufferEffectBase * e) {
|
||||
e->r = this;
|
||||
fb_effects << e;
|
||||
}
|
||||
150
src/core/render/renderer.h
Normal file
150
src/core/render/renderer.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
QGL Renderer
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RENDERER_H
|
||||
#define RENDERER_H
|
||||
|
||||
#include "glcubemap.h"
|
||||
#include "glframebuffereffectbase.h"
|
||||
#include "renderer_base.h"
|
||||
#include "renderer_material.h"
|
||||
#include "renderer_selection.h"
|
||||
#include "renderer_service.h"
|
||||
#include "tonemapping_proc.h"
|
||||
|
||||
#include <QQueue>
|
||||
|
||||
|
||||
class QGLENGINE_CORE_EXPORT Renderer: public RendererBase {
|
||||
friend class QGLView;
|
||||
friend class MouseController;
|
||||
friend class RendererMaterial;
|
||||
friend class RendererService;
|
||||
friend class RendererSelection;
|
||||
friend class FramebufferEffectBase;
|
||||
friend class TonemappingProc;
|
||||
enum ShaderRole {
|
||||
// Selection
|
||||
srSelectionFill,
|
||||
srSelectionHalo,
|
||||
srSelectionApply,
|
||||
srSelectionFrame,
|
||||
|
||||
// Service
|
||||
srServiceFill,
|
||||
srServiceFrame,
|
||||
srServiceLine,
|
||||
|
||||
// Deferred shading
|
||||
srGeometryPass,
|
||||
srLightOmniPass,
|
||||
srLightSpotPass,
|
||||
srFinalPass,
|
||||
srTonemapPass,
|
||||
};
|
||||
enum OutBufferRole {
|
||||
obrSolidOmni,
|
||||
obrSolidSpot,
|
||||
obrTransparentOmni,
|
||||
obrTransparentSpot,
|
||||
|
||||
obrGeneral0,
|
||||
obrGeneral1,
|
||||
obrGeneral2,
|
||||
obrGeneral3,
|
||||
|
||||
obrBuffersCount,
|
||||
};
|
||||
|
||||
public:
|
||||
Renderer(QGLView * view_);
|
||||
virtual ~Renderer();
|
||||
|
||||
enum DeferredBufferRole {
|
||||
dbrDiffuse,
|
||||
dbrNormalZ,
|
||||
dbrSpecularReflect,
|
||||
dbrEmissionRough,
|
||||
dbrSpeedBitangXY,
|
||||
|
||||
dbrNormalZSolid,
|
||||
dbrSpecularReflectSolid,
|
||||
|
||||
dbrBuffersCount,
|
||||
};
|
||||
|
||||
void init(int width, int height);
|
||||
void resize(int width, int height);
|
||||
void reloadShaders();
|
||||
void renderScene();
|
||||
void setCameraLightMode(int m);
|
||||
int cameraLightMode() const { return camera_light_mode; }
|
||||
void setGrabImage(bool on);
|
||||
bool isGrabImage() const { return is_grabbing; }
|
||||
QImage getImage() const { return last_img; }
|
||||
void addFramebufferEffect(FramebufferEffectBase * e);
|
||||
void clearFramebufferEffects() { fb_effects.clear(); }
|
||||
|
||||
QImage materialThumbnail(Material * m) { return rend_mat.materialThumbnail(m); }
|
||||
void recreateMaterialThumbnails(bool force_all = false) { rend_mat.recreateMaterialThumbnails(force_all); }
|
||||
|
||||
protected:
|
||||
void fillObjectsBuffer(const ObjectBaseList & ol, RenderPass pass);
|
||||
void reloadObjects();
|
||||
void renderObjects(Scene & scene, RenderPass pass);
|
||||
void renderLight(int first_wr_buff, bool clear_only);
|
||||
|
||||
bool bindShader(ShaderRole role, QOpenGLShaderProgram ** ret = 0);
|
||||
bool bindShader(QOpenGLShaderProgram * sp);
|
||||
void initShaders();
|
||||
void releaseShader();
|
||||
|
||||
QVector<int> getFreePlanes(int count);
|
||||
|
||||
private:
|
||||
float gamma_ = 1.f;
|
||||
int camera_light_mode, cur_write_plane = 0, prev_write_plane = 0;
|
||||
bool edit_mode, need_init_shaders, need_render_sum;
|
||||
Framebuffer fbo_ds, fbo_out;
|
||||
QMap<ShaderRole, QString> shader_files;
|
||||
QMap<ShaderRole, QStringList> shader_defines;
|
||||
QMap<ShaderRole, QOpenGLShaderProgram *> shaders;
|
||||
QOpenGLShaderProgram * shader_fxaa = nullptr;
|
||||
|
||||
RendererMaterial rend_mat;
|
||||
RendererService rend_service;
|
||||
RendererSelection rend_selection;
|
||||
TonemappingProc tone_proc;
|
||||
|
||||
Mesh * quad;
|
||||
Light * cam_light;
|
||||
CubeTexture tex_env;
|
||||
|
||||
QPoint mouse_pos;
|
||||
QRect mouse_rect;
|
||||
QMatrix4x4 prev_view, prev_proj;
|
||||
QMatrix3x3 nm;
|
||||
QVector4D corner_dirs[4];
|
||||
QVector<QVector3D> hcontent;
|
||||
QMap<int, QList<Light *>> cur_lights;
|
||||
QVector<FramebufferEffectBase *> fb_effects;
|
||||
QImage last_img;
|
||||
bool is_grabbing = false;
|
||||
};
|
||||
|
||||
#endif // RENDERER_H
|
||||
422
src/core/render/renderer_base.cpp
Normal file
422
src/core/render/renderer_base.cpp
Normal file
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
QGL RendererBase
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include "renderer_base.h"
|
||||
|
||||
#include "glmesh.h"
|
||||
#include "glshaders_headers.h"
|
||||
#include "gltexture_manager.h"
|
||||
#include "qglview.h"
|
||||
#include "renderer.h"
|
||||
|
||||
#include <QOpenGLExtraFunctions>
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
|
||||
RendererBase::RendererBase(QGLView * view_)
|
||||
: view(view_)
|
||||
, buffer_materials(GL_UNIFORM_BUFFER, GL_STREAM_DRAW)
|
||||
, buffer_lights(GL_UNIFORM_BUFFER, GL_STREAM_DRAW)
|
||||
, buffer_lights_pos(GL_UNIFORM_BUFFER, GL_STREAM_DRAW)
|
||||
, textures_empty(false)
|
||||
, textures_maps(true) {
|
||||
textures_manager = new TextureManager(view);
|
||||
maps_size = QSize(512, 512);
|
||||
maps_hash = 0;
|
||||
tex_coeff[0] = tex_coeff[1] = 0;
|
||||
}
|
||||
|
||||
|
||||
RendererBase::~RendererBase() {
|
||||
delete textures_manager;
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::initTextureArrays() {
|
||||
QOpenGLExtraFunctions * f = view;
|
||||
textures_maps.init(f);
|
||||
textures_empty.init(f);
|
||||
textures_empty.resize(f, QSize(1, 1), 2);
|
||||
textures_empty.bind(f);
|
||||
QImage im(1, 1, QImage::Format_RGBA8888);
|
||||
im.fill(0xFFFFFFFF);
|
||||
textures_empty.load(f, im, emrWhite);
|
||||
im.fill(0xFF8080);
|
||||
textures_empty.load(f, im, emrBlue);
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::initUniformBuffer(QOpenGLShaderProgram * prog, Buffer * buffer, int bind_point, const char * blockName) {
|
||||
if (!prog || !buffer) return;
|
||||
if (!prog->isLinked()) return;
|
||||
QOpenGLExtraFunctions * f = view;
|
||||
buffer->init(f);
|
||||
// glClearError();
|
||||
GLint ubo_ind = f->glGetUniformBlockIndex(prog->programId(), blockName);
|
||||
f->glUniformBlockBinding(prog->programId(), ubo_ind, bind_point);
|
||||
f->glBindBufferBase(GL_UNIFORM_BUFFER, bind_point, buffer->ID());
|
||||
// qDebug() << "initUBO" << QString::number(f->glGetError(), 16);
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::setUniformHalo(QOpenGLShaderProgram * prog, const char * type, QColor color, float fill) {
|
||||
prog->setUniformValue((QString(type) + "_color").toLatin1().constData(), color);
|
||||
prog->setUniformValue((QString(type) + "_fill").toLatin1().constData(), fill);
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::setUniformMaps(QOpenGLShaderProgram * prog) {
|
||||
prog->setUniformValue("qgl_texture_array[0]", (int)tarEmpty);
|
||||
prog->setUniformValue("qgl_texture_array[1]", (int)tarMaps);
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::setUniformCamera(QOpenGLShaderProgram * prog, Camera * cam, bool matrices, QSize viewport) {
|
||||
double w = view->width(), h = view->height();
|
||||
if (viewport.isValid()) {
|
||||
w = viewport.width();
|
||||
h = viewport.height();
|
||||
}
|
||||
QMatrix4x4 mat_view, mat_proj;
|
||||
if (cam) {
|
||||
if (matrices) {
|
||||
mat_view = cam->fullViewMatrix();
|
||||
mat_proj = cam->projectionMatrix(w / h);
|
||||
}
|
||||
prog->setUniformValue("z_near", cam->depthStart());
|
||||
}
|
||||
prog->setUniformValue("dt", QVector2D(1. / w, 1. / h));
|
||||
prog->setUniformValue("qgl_ViewSize", QVector2D(w, h));
|
||||
prog->setUniformValue("qgl_ViewMatrix", mat_view);
|
||||
prog->setUniformValue("qgl_ViewProjMatrix", mat_proj * mat_view);
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::setUniformViewCorners(QOpenGLShaderProgram * prog, Camera * cam, QSize viewport) {
|
||||
double w = view->width(), h = view->height();
|
||||
if (viewport.isValid()) {
|
||||
w = viewport.width();
|
||||
h = viewport.height();
|
||||
}
|
||||
QMatrix4x4 mproji = cam->projectionMatrix(w / h).inverted();
|
||||
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) {
|
||||
world_dirs[i] = QVector4D(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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::fillSelectionsBuffer(QVector<uchar> & buffer, const ObjectBaseList & ol) {
|
||||
buffer.resize(ol.size());
|
||||
for (int i = 0; i < ol.size(); ++i) {
|
||||
buffer[i] = (ol[i]->isSelected(true) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::fillSelectionsBuffer(QVector<uchar> & buffer, bool yes, int size) {
|
||||
buffer.resize(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
buffer[i] = (yes ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::reloadMaterials(Scene & scene) {
|
||||
// qDebug() << "reloadMaterias";
|
||||
QList<Map *> maps[2];
|
||||
QMap<QString, int> tex_layers[2];
|
||||
foreach(Material * m, scene.materials) {
|
||||
if (m->map_diffuse.hasBitmap()) maps[0] << &(m->map_diffuse);
|
||||
if (m->map_normal.hasBitmap()) maps[1] << &(m->map_normal);
|
||||
if (m->map_metalness.hasBitmap()) maps[0] << &(m->map_metalness);
|
||||
if (m->map_roughness.hasBitmap()) maps[0] << &(m->map_roughness);
|
||||
if (m->map_emission.hasBitmap()) maps[0] << &(m->map_emission);
|
||||
if (m->map_relief.hasBitmap()) maps[0] << &(m->map_relief);
|
||||
}
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
foreach(Map * m, maps[i])
|
||||
tex_layers[i][m->bitmap_path] = 0;
|
||||
}
|
||||
int layers_count = tex_layers[0].size() + tex_layers[1].size(), cl = -1;
|
||||
uint cur_maps_hash = qHash(tex_layers[0].keys()) ^ (qHash(tex_layers[1].keys()) + 0xF00FF00F);
|
||||
if (maps_hash != cur_maps_hash) {
|
||||
maps_hash = cur_maps_hash;
|
||||
textures_maps.resize(view, maps_size, layers_count);
|
||||
textures_maps.bind(view);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
QMutableMapIterator<QString, int> it(tex_layers[i]);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
QImage im = textures_manager->loadTextureImage(it.key(), i == 1);
|
||||
textures_maps.load(view, im, ++cl);
|
||||
it.value() = cl;
|
||||
}
|
||||
foreach(Map * m, maps[i]) {
|
||||
m->_layer = tex_layers[i].value(m->bitmap_path);
|
||||
// qDebug() << "assign" << m->bitmap_path << "layer" << m->_layer;
|
||||
}
|
||||
}
|
||||
textures_maps.mipmaps(view);
|
||||
// qDebug() << "load" << (cl+1) << "bitmaps";
|
||||
}
|
||||
|
||||
QGLMaterial glm;
|
||||
cur_materials_.clear();
|
||||
cur_materials_ << glm;
|
||||
foreach(Material * m, scene.materials) {
|
||||
if (cur_materials_.size() >= max_materials) {
|
||||
qDebug() << "[QGLEngine] Warning: Too many materials! Maximum" << max_materials;
|
||||
break;
|
||||
}
|
||||
m->_index = cur_materials_.size();
|
||||
m->_changed = false;
|
||||
glm.color_diffuse = QColor2QVector(m->color_diffuse);
|
||||
glm.color_emission = QColor2QVector(m->color_emission);
|
||||
glm.transparency = m->transparency;
|
||||
glm.reflectivity = m->reflectivity;
|
||||
glm.iof = m->iof;
|
||||
glm.dispersion = m->dispersion;
|
||||
m->map_diffuse.copyToQGLMap(glm.map[mtDiffuse]);
|
||||
m->map_normal.copyToQGLMap(glm.map[mtNormal]);
|
||||
m->map_metalness.copyToQGLMap(glm.map[mtMetalness]);
|
||||
m->map_roughness.copyToQGLMap(glm.map[mtRoughness]);
|
||||
m->map_emission.copyToQGLMap(glm.map[mtEmission]);
|
||||
m->map_relief.copyToQGLMap(glm.map[mtRelief]);
|
||||
cur_materials_ << glm;
|
||||
}
|
||||
// qDebug() << "load" << cur_materials_.size() << "materials";
|
||||
buffer_materials.bind(view);
|
||||
buffer_materials.resize(view, cur_materials_.size() * sizeof(QGLMaterial));
|
||||
buffer_materials.load(view, cur_materials_.constData(), cur_materials_.size() * sizeof(QGLMaterial));
|
||||
scene.need_reload_materials = false;
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::reloadLightsParameters(const QMap<int, QList<Light *>> & lights) {
|
||||
lights_start.clear();
|
||||
lights_start[Light::Omni] = 0;
|
||||
QMapIterator<int, QList<Light *>> it(lights);
|
||||
current_lights.clear();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
lights_start[it.key()] = current_lights.size();
|
||||
current_lights.append(it.value());
|
||||
}
|
||||
cur_lights_params_.resize(qMin(current_lights.size(), max_lights));
|
||||
// qDebug() << "reloadLightsParameters" << cur_lights_params_.size();
|
||||
for (int i = 0; i < cur_lights_params_.size(); ++i) {
|
||||
QGLLightParameter & so(cur_lights_params_[i]);
|
||||
Light * l = current_lights[i];
|
||||
double ang_start = l->angle_start / 2.f, ang_end = l->angle_end / 2.f;
|
||||
if (l->light_type == Light::Omni) ang_start = ang_end = 180.;
|
||||
// qDebug() << "light" << light->name() << ulightn << pos;
|
||||
so.color = QColor2QVector(l->color_);
|
||||
so.angles[0] = ang_start;
|
||||
so.angles[1] = cos(ang_start * deg2rad);
|
||||
so.angles[2] = ang_end;
|
||||
so.angles[3] = cos(ang_end * deg2rad);
|
||||
so.decay_intensity[0] = l->decay_const;
|
||||
so.decay_intensity[1] = l->decay_linear;
|
||||
so.decay_intensity[2] = l->decay_quadratic;
|
||||
so.decay_intensity[3] = l->intensity;
|
||||
}
|
||||
buffer_lights.bind(view);
|
||||
buffer_lights.resize(view, cur_lights_params_.size() * sizeof(QGLLightParameter));
|
||||
buffer_lights.load(view, cur_lights_params_.constData(), cur_lights_params_.size() * sizeof(QGLLightParameter));
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::reloadLightsPositions(Camera * cam) {
|
||||
cur_lights_pos_.resize(qMin(current_lights.size(), max_lights));
|
||||
QMatrix4x4 mat = cam->viewMatrix() * cam->offsetMatrix();
|
||||
for (int i = 0; i < cur_lights_pos_.size(); ++i) {
|
||||
QGLLightPosition & so(cur_lights_pos_[i]);
|
||||
Light * l = current_lights[i];
|
||||
QMatrix4x4 m = mat * l->worldTransform();
|
||||
QVector4D pos(0, 0, 0, 1.), dir(QVector3D(0, 0, -1), 1);
|
||||
pos = m * pos;
|
||||
dir = (m * QVector4D(QVector3D(0, 0, -1), 0)).normalized();
|
||||
so.position = pos;
|
||||
so.direction = dir;
|
||||
}
|
||||
buffer_lights_pos.bind(view);
|
||||
buffer_lights_pos.resize(view, cur_lights_pos_.size() * sizeof(QGLLightPosition));
|
||||
buffer_lights_pos.load(view, cur_lights_pos_.constData(), cur_lights_pos_.size() * sizeof(QGLLightPosition));
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::markReloadTextures() {
|
||||
maps_hash = 0;
|
||||
textures_manager->clearImageCache();
|
||||
view->scene()->need_reload_materials = true;
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::setMapsSize(QSize sz) {
|
||||
maps_size = sz;
|
||||
markReloadTextures();
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::initQuad(Mesh * mesh, QMatrix4x4 mat) {
|
||||
QGLEngineShaders::Object quab_object;
|
||||
mat.transposed().copyDataTo(quab_object.modelmatrix);
|
||||
mesh->init(view);
|
||||
mesh->loadObject(view, quab_object);
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::renderQuad(QOpenGLShaderProgram * prog, Mesh * mesh, Camera * cam, bool uniforms) {
|
||||
glDisableDepth();
|
||||
if (uniforms) setUniformCamera(prog, cam, false);
|
||||
mesh->draw(view, 1);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
float RadicalInverse_VdC(uint bits) {
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
|
||||
|
||||
QVector2D Hammersley(uint i, uint N) {
|
||||
return QVector2D(float(i) / float(N), RadicalInverse_VdC(i));
|
||||
}
|
||||
|
||||
|
||||
QVector3D ImportanceSampleGGX(QVector2D Xi, QVector3D N, float roughness) {
|
||||
float a = roughness * roughness;
|
||||
float phi = 2.0 * M_PI * Xi[0];
|
||||
float cosTheta = sqrt((1.0 - Xi[1]) / (1.0 + (a * a - 1.0) * Xi[1]));
|
||||
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
|
||||
// преобразование из сферических в декартовы координаты
|
||||
QVector3D H;
|
||||
H[0] = cos(phi) * sinTheta;
|
||||
H[1] = sin(phi) * sinTheta;
|
||||
H[2] = cosTheta;
|
||||
// преобразование из касательного пространства в мировые координаты
|
||||
QVector3D up = qAbs(N[2]) < 0.999 ? QVector3D(0.0, 0.0, 1.0) : QVector3D(1.0, 0.0, 0.0);
|
||||
QVector3D tangent = QVector3D::crossProduct(up, N).normalized();
|
||||
QVector3D bitangent = QVector3D::crossProduct(N, tangent);
|
||||
QVector3D sampleVec = tangent * H[0] + bitangent * H[1] + N * H[2];
|
||||
return sampleVec.normalized();
|
||||
}
|
||||
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness) {
|
||||
float k = (roughness * roughness) / 2.0;
|
||||
float nom = NdotV;
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
return nom / denom;
|
||||
}
|
||||
|
||||
|
||||
float GeometrySmith(QVector3D N, QVector3D V, QVector3D L, float roughness) {
|
||||
float NdotV = piMax(QVector3D::dotProduct(N, V), 0.f);
|
||||
float NdotL = piMax(QVector3D::dotProduct(N, L), 0.f);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
|
||||
QVector2D IntegrateBRDF(float NdotV, float roughness) {
|
||||
QVector3D V;
|
||||
V[0] = sqrt(1.f - NdotV * NdotV);
|
||||
V[1] = 0.f;
|
||||
V[2] = NdotV;
|
||||
float A = 0.f;
|
||||
float B = 0.f;
|
||||
QVector3D N = QVector3D(0.f, 0.f, 1.f);
|
||||
const uint SAMPLE_COUNT = 256u;
|
||||
for (uint i = 0u; i < SAMPLE_COUNT; ++i) {
|
||||
QVector2D Xi = Hammersley(i, SAMPLE_COUNT);
|
||||
QVector3D H = ImportanceSampleGGX(Xi, N, roughness);
|
||||
QVector3D L = (2.f * QVector3D::dotProduct(V, H) * H - V).normalized();
|
||||
float NdotL = piMax(L[2], 0.f);
|
||||
float NdotH = piMax(H[2], 0.f);
|
||||
float VdotH = piMax(QVector3D::dotProduct(V, H), 0.f);
|
||||
if (NdotL > 0.f) {
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
float G_Vis = (G * VdotH) / (NdotH * NdotV);
|
||||
float Fc = pow(1.f - VdotH, 5.f);
|
||||
A += (1.f - Fc) * G_Vis;
|
||||
B += Fc * G_Vis;
|
||||
}
|
||||
}
|
||||
A /= float(SAMPLE_COUNT);
|
||||
B /= float(SAMPLE_COUNT);
|
||||
return QVector2D(A, B);
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::initCoeffTextures() {
|
||||
QImage im = QImage(":/coeffs_brdf.png").mirrored();
|
||||
int size = im.width();
|
||||
QVector<QVector2D> data(size * size);
|
||||
int ind = -1;
|
||||
for (int x = 0; x < size; ++x) {
|
||||
for (int y = 0; y < size; ++y) {
|
||||
QColor p = im.pixelColor(x, y);
|
||||
data[++ind] = QVector2D(p.redF(), p.greenF());
|
||||
}
|
||||
}
|
||||
createCoeffTexture(tex_coeff[0], data.constData(), size, 2);
|
||||
}
|
||||
|
||||
|
||||
void RendererBase::createCoeffTexture(GLuint & id, const void * data, int size, int channels) {
|
||||
QOpenGLExtraFunctions * f = view;
|
||||
deleteGLTexture(f, id);
|
||||
f->glGenTextures(1, &id);
|
||||
f->glBindTexture(GL_TEXTURE_2D, id);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
GLenum iformat = GL_R16F, format = GL_RED;
|
||||
if (channels == 2) {
|
||||
iformat = GL_RG16F;
|
||||
format = GL_RG;
|
||||
}
|
||||
if (channels == 3) {
|
||||
iformat = GL_RGB16F;
|
||||
format = GL_RGB;
|
||||
}
|
||||
if (channels == 4) {
|
||||
iformat = GL_RGBA16F;
|
||||
format = GL_RGBA;
|
||||
}
|
||||
f->glTexImage2D(GL_TEXTURE_2D, 0, iformat, size, size, 0, format, GL_FLOAT, data);
|
||||
}
|
||||
67
src/core/render/renderer_base.h
Normal file
67
src/core/render/renderer_base.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
QGL RendererBase
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RENDERER_BASE_H
|
||||
#define RENDERER_BASE_H
|
||||
|
||||
#include "glbuffer.h"
|
||||
#include "glshaders_types.h"
|
||||
#include "gltexturearray.h"
|
||||
|
||||
|
||||
class QGLENGINE_CORE_EXPORT RendererBase {
|
||||
public:
|
||||
RendererBase(QGLView * view_);
|
||||
~RendererBase();
|
||||
|
||||
protected:
|
||||
void initTextureArrays();
|
||||
void initUniformBuffer(QOpenGLShaderProgram * prog, Buffer * buffer, int bind_point, const char * blockName);
|
||||
void setUniformHalo(QOpenGLShaderProgram * prog, const char * type, QColor color, float fill);
|
||||
void setUniformMaps(QOpenGLShaderProgram * prog);
|
||||
void setUniformCamera(QOpenGLShaderProgram * prog, Camera * cam, bool matrices = true, QSize viewport = QSize());
|
||||
void setUniformViewCorners(QOpenGLShaderProgram * prog, Camera * cam, QSize viewport = QSize());
|
||||
void fillSelectionsBuffer(QVector<uchar> & buffer, const ObjectBaseList & ol);
|
||||
void fillSelectionsBuffer(QVector<uchar> & buffer, bool yes, int size);
|
||||
void reloadMaterials(Scene & scene);
|
||||
void reloadLightsParameters(const QMap<int, QList<Light *>> & lights);
|
||||
void reloadLightsPositions(Camera * cam);
|
||||
void markReloadTextures();
|
||||
void setMapsSize(QSize sz);
|
||||
void initQuad(Mesh * mesh, QMatrix4x4 mat = QMatrix4x4());
|
||||
void renderQuad(QOpenGLShaderProgram * prog, Mesh * mesh, Camera * cam = 0, bool uniforms = true);
|
||||
void initCoeffTextures();
|
||||
void createCoeffTexture(GLuint & id, const void * data, int size, int channels = 1);
|
||||
|
||||
QGLView * view;
|
||||
TextureManager * textures_manager;
|
||||
QVector<QGLEngineShaders::Object> cur_objects_;
|
||||
QVector<QGLEngineShaders::QGLMaterial> cur_materials_;
|
||||
QVector<QGLEngineShaders::QGLLightParameter> cur_lights_params_;
|
||||
QVector<QGLEngineShaders::QGLLightPosition> cur_lights_pos_;
|
||||
Buffer buffer_materials;
|
||||
Buffer buffer_lights, buffer_lights_pos;
|
||||
Texture2DArray textures_empty, textures_maps;
|
||||
QSize maps_size;
|
||||
uint maps_hash;
|
||||
GLuint tex_coeff[2];
|
||||
QMap<int, int> lights_start;
|
||||
QList<Light *> current_lights;
|
||||
};
|
||||
|
||||
#endif // RENDERER_BASE_H
|
||||
133
src/core/render/renderer_material.cpp
Normal file
133
src/core/render/renderer_material.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
QGL RendererMaterial
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include "renderer_material.h"
|
||||
|
||||
#include "glmesh.h"
|
||||
#include "gltexture_manager.h"
|
||||
#include "qglview.h"
|
||||
#include "renderer.h"
|
||||
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <qad_types.h>
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
|
||||
RendererMaterial::RendererMaterial(Renderer * r_): r(r_), fbo_mat_thumb(r->view, 6, true, GL_RGBA16F) {
|
||||
mat_sphere = Primitive::ellipsoid(16, 16);
|
||||
mat_camera = new Camera();
|
||||
mat_camera->setPos(QVector3D(2, 2, 2));
|
||||
mat_camera->setAim(QVector3D());
|
||||
mat_camera->setFOV(45.);
|
||||
mat_light = new Light();
|
||||
mat_light->setPos(QVector3D(50, 100, 25));
|
||||
last_thumb_material = 0;
|
||||
}
|
||||
|
||||
|
||||
RendererMaterial::~RendererMaterial() {
|
||||
delete mat_sphere;
|
||||
delete mat_camera;
|
||||
delete mat_light;
|
||||
}
|
||||
|
||||
|
||||
void RendererMaterial::init(int width, int height) {
|
||||
fbo_mat_thumb.reinit();
|
||||
mat_sphere->reinit();
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
|
||||
void RendererMaterial::resize(int width, int height) {
|
||||
fbo_mat_thumb.enablePixelBuffer();
|
||||
fbo_mat_thumb.resize(256, 256);
|
||||
}
|
||||
|
||||
|
||||
void RendererMaterial::renderMaterial(Material * m) {
|
||||
// qDebug() << "renderMaterial" << m;
|
||||
last_thumb_material = m;
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
QOpenGLExtraFunctions * f = r->view;
|
||||
fbo_mat_thumb.bind();
|
||||
glEnableDepth();
|
||||
glClearFramebuffer(QColor(0, 0, 0, 0));
|
||||
if (r->bindShader(Renderer::srGeometryPass, &prog)) {
|
||||
r->setUniformMaps(prog);
|
||||
r->setUniformCamera(prog, mat_camera, true, fbo_mat_thumb.size());
|
||||
// qDebug() << mat_camera->viewMatrix();
|
||||
r->textures_empty.bind(f, tarEmpty);
|
||||
r->textures_maps.bind(f, tarMaps);
|
||||
Object o;
|
||||
o.material = m->_index;
|
||||
mat_sphere->loadObject(f, o);
|
||||
mat_sphere->draw(f, 1);
|
||||
}
|
||||
fbo_mat_thumb.bindColorTextures();
|
||||
fbo_mat_thumb.bindDepthTexture(5);
|
||||
fbo_mat_thumb.setWriteBuffer(5);
|
||||
if (r->bindShader(Renderer::srLightOmniPass, &prog)) {
|
||||
r->setUniformCamera(prog, mat_camera, true, fbo_mat_thumb.size());
|
||||
r->setUniformViewCorners(prog, mat_camera, fbo_mat_thumb.size());
|
||||
for (int i = 0; i < 5; ++i)
|
||||
prog->setUniformValue(QString("tex_%1").arg(i).toLatin1().constData(), i);
|
||||
prog->setUniformValue("tex_d", 5);
|
||||
prog->setUniformValue("lights_start", 0);
|
||||
prog->setUniformValue("lights_count", 1);
|
||||
QMap<int, QList<Light *>> mat_l;
|
||||
mat_l[Light::Omni] << mat_light;
|
||||
r->reloadLightsParameters(mat_l);
|
||||
r->reloadLightsPositions(mat_camera);
|
||||
glClearFramebuffer(Qt::black, false);
|
||||
r->renderQuad(prog, r->quad, mat_camera);
|
||||
r->view->scene()->setLightsChanged();
|
||||
}
|
||||
fbo_mat_thumb.queryImage(5);
|
||||
fbo_mat_thumb.release();
|
||||
}
|
||||
|
||||
|
||||
void RendererMaterial::procQueue() {
|
||||
if (last_thumb_material) {
|
||||
mat_thumbnails[last_thumb_material] = fbo_mat_thumb.getImage();
|
||||
emit r->view->materialThumbnailCreated(last_thumb_material);
|
||||
last_thumb_material = 0;
|
||||
}
|
||||
if (!mat_thumb_queue.isEmpty()) renderMaterial(mat_thumb_queue.dequeue());
|
||||
}
|
||||
|
||||
|
||||
QImage RendererMaterial::materialThumbnail(Material * m) {
|
||||
return mat_thumbnails.value(m);
|
||||
}
|
||||
|
||||
|
||||
void RendererMaterial::recreateMaterialThumbnails(bool force_all) {
|
||||
if (force_all) {
|
||||
mat_thumb_queue.clear();
|
||||
// qDebug() << "recreateMaterialThumbnails" << view->scene_->materials;
|
||||
foreach(Material * m, r->view->scene()->materials)
|
||||
mat_thumb_queue.enqueue(m);
|
||||
} else {
|
||||
foreach(Material * m, r->view->scene()->changed_materials)
|
||||
if (!mat_thumb_queue.contains(m)) mat_thumb_queue.enqueue(m);
|
||||
}
|
||||
}
|
||||
53
src/core/render/renderer_material.h
Normal file
53
src/core/render/renderer_material.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
QGL RendererMaterial
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RENDERER_MATERIAL_H
|
||||
#define RENDERER_MATERIAL_H
|
||||
|
||||
#include "glframebuffer.h"
|
||||
|
||||
#include <QQueue>
|
||||
|
||||
|
||||
class QGLENGINE_CORE_EXPORT RendererMaterial {
|
||||
friend class QGLView;
|
||||
|
||||
public:
|
||||
RendererMaterial(Renderer * r_);
|
||||
virtual ~RendererMaterial();
|
||||
|
||||
void init(int width, int height);
|
||||
void resize(int width, int height);
|
||||
|
||||
QImage materialThumbnail(Material * m);
|
||||
void recreateMaterialThumbnails(bool force_all = false);
|
||||
void renderMaterial(Material * m);
|
||||
void procQueue();
|
||||
|
||||
private:
|
||||
Renderer * r;
|
||||
Framebuffer fbo_mat_thumb;
|
||||
Mesh * mat_sphere;
|
||||
Camera * mat_camera;
|
||||
Light * mat_light;
|
||||
QMap<Material *, QImage> mat_thumbnails;
|
||||
Material * last_thumb_material;
|
||||
QQueue<Material *> mat_thumb_queue;
|
||||
};
|
||||
|
||||
#endif // RENDERER_MATERIAL_H
|
||||
215
src/core/render/renderer_selection.cpp
Normal file
215
src/core/render/renderer_selection.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
QGL RendererSelection
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include "renderer_selection.h"
|
||||
|
||||
#include "glmesh.h"
|
||||
#include "qglview.h"
|
||||
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <qad_types.h>
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
|
||||
RendererSelection::RendererSelection(Renderer * r_): r(r_), fbo_selection(r->view, 6) {
|
||||
sel_frame = Primitive::plane(2., 2.);
|
||||
id_hover = 0;
|
||||
line_thick_ = 2.;
|
||||
scale_ = 0.5;
|
||||
}
|
||||
|
||||
|
||||
RendererSelection::~RendererSelection() {
|
||||
delete sel_frame;
|
||||
}
|
||||
|
||||
|
||||
void RendererSelection::init(int width, int height) {
|
||||
fbo_selection.reinit();
|
||||
sel_frame->reinit();
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
|
||||
void RendererSelection::resize(int width, int height) {
|
||||
line_thick_ = lineThickness() + 1.;
|
||||
scale_ = 0.5 / appScale();
|
||||
fbo_selection.enablePixelBuffer();
|
||||
fbo_selection.resize(width * scale_, height * scale_);
|
||||
}
|
||||
|
||||
|
||||
void RendererSelection::generateObjectsID(Scene & scene) {
|
||||
ids.clear();
|
||||
aim_ids.clear();
|
||||
QList<int> passes = scene.geometries_used.keys();
|
||||
foreach(int p, passes) {
|
||||
QMapIterator<Mesh *, ObjectBaseList> it(scene.geometries_used[p]);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
foreach(ObjectBase * o, it.value()) {
|
||||
uint id = qHash(o);
|
||||
ids[id] = o;
|
||||
o->id_ = id;
|
||||
}
|
||||
}
|
||||
QMapIterator<int, QList<Light *>> lit(scene.lights_used);
|
||||
while (lit.hasNext()) {
|
||||
lit.next();
|
||||
foreach(ObjectBase * o, lit.value()) {
|
||||
uint id = qHash(o);
|
||||
ids[id] = o;
|
||||
aim_ids[id + 1] = o;
|
||||
o->id_ = id;
|
||||
}
|
||||
}
|
||||
foreach(Camera * o, scene.cameras_used) {
|
||||
uint id = qHash(o);
|
||||
ids[id] = o;
|
||||
aim_ids[id + 1] = o;
|
||||
o->id_ = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererSelection::renderSelection(Scene & scene) {
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
QGLView * view = r->view;
|
||||
MouseController & mc(view->mouse);
|
||||
if (r->bindShader(Renderer::srSelectionFill, &prog)) {
|
||||
mc.hov_objects.clear();
|
||||
mc.hov_aims.clear();
|
||||
id_hover = 0;
|
||||
if (fbo_selection.queriedPoints() > 0) {
|
||||
if (fbo_selection.queriedPoints() == 1) {
|
||||
id_hover = fbo_selection.getPoint();
|
||||
ObjectBase * o = ids.value(id_hover);
|
||||
if (o)
|
||||
mc.hov_objects << o;
|
||||
else {
|
||||
o = aim_ids.value(id_hover);
|
||||
if (o) mc.hov_aims << o;
|
||||
}
|
||||
// qDebug() << id_hover;
|
||||
} else {
|
||||
QVector<uint> points = fbo_selection.getPointsByte();
|
||||
QSet<uint> ids_hover;
|
||||
foreach(uint i, points)
|
||||
ids_hover << i;
|
||||
foreach(uint i, ids_hover) {
|
||||
ObjectBase * o = ids.value(i);
|
||||
if (o) mc.hov_objects << o;
|
||||
o = aim_ids.value(i);
|
||||
if (o) mc.hov_aims << o;
|
||||
}
|
||||
// qDebug() << ids_hover;
|
||||
}
|
||||
}
|
||||
|
||||
fbo_selection.bind();
|
||||
|
||||
fbo_selection.setWriteBuffers();
|
||||
glEnableDepth();
|
||||
glClearFramebuffer(QColor(0, 0, 0, 0));
|
||||
r->setUniformCamera(prog, view->camera());
|
||||
r->renderObjects(scene, rpSolid);
|
||||
r->renderObjects(scene, rpTransparent);
|
||||
view->glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
RendererService & rs(r->rend_service);
|
||||
rs.drawLights();
|
||||
rs.drawCameras();
|
||||
rs.drawCurrentHandleObjects();
|
||||
if (r->mouse_rect.isNull())
|
||||
fbo_selection.queryPoint(0, r->mouse_pos * scale_);
|
||||
else
|
||||
fbo_selection.queryPoints(0, QRect(r->mouse_rect.topLeft() * scale_, r->mouse_rect.size() * scale_));
|
||||
|
||||
// qDebug() << id_hover;
|
||||
fbo_selection.bindColorTexture(sbrSrcHover, sbrSrcHover);
|
||||
fbo_selection.bindColorTexture(sbrSrcSelect, sbrSrcSelect);
|
||||
fbo_selection.setWriteBuffers(QVector<int>() << sbrHovered << sbrSelected);
|
||||
if (!view->isHoverHaloEnabled() && !view->isSelectionHaloEnabled())
|
||||
glClearFramebuffer(QColor(0, 0, 0, 0), false);
|
||||
else {
|
||||
r->bindShader(Renderer::srSelectionHalo, &prog);
|
||||
r->setUniformHalo(prog, "hover", view->hoverHaloColor(), view->hoverHaloFillAlpha());
|
||||
r->setUniformHalo(prog, "selection", view->selectionHaloColor(), view->selectionHaloFillAlpha());
|
||||
prog->setUniformValue("has_hover", view->isHoverHaloEnabled() && (id_hover > 0) ? 1.f : 0.f);
|
||||
prog->setUniformValue("has_selection", view->isSelectionHaloEnabled() ? 1.f : 0.f);
|
||||
prog->setUniformValue("fb_hover", (int)sbrSrcHover);
|
||||
prog->setUniformValue("fb_selection", (int)sbrSrcSelect);
|
||||
prog->setUniformValue("hover_id",
|
||||
QVector4D(float(id_hover & 0xFF) / 255.f,
|
||||
float((id_hover >> 8) & 0xFF) / 255.f,
|
||||
float((id_hover >> 16) & 0xFF) / 255.f,
|
||||
float((id_hover >> 24) & 0xFF) / 255.f));
|
||||
r->renderQuad(prog, r->quad, view->camera());
|
||||
}
|
||||
|
||||
prog = r->shader_fxaa;
|
||||
if (r->bindShader(prog)) {
|
||||
r->setUniformCamera(prog, 0, true, fbo_selection.size());
|
||||
fbo_selection.bindColorTexture(sbrHovered);
|
||||
fbo_selection.setWriteBuffer(sbrHoveredFXAA);
|
||||
r->renderQuad(prog, r->quad, 0, false);
|
||||
fbo_selection.bindColorTexture(sbrSelected);
|
||||
fbo_selection.setWriteBuffer(sbrSelectedFXAA);
|
||||
r->renderQuad(prog, r->quad, 0, false);
|
||||
}
|
||||
fbo_selection.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererSelection::renderSelectionFrame() {
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
if (r->bindShader(Renderer::srSelectionFrame, &prog)) {
|
||||
QMatrix4x4 mat;
|
||||
double mrx = r->mouse_rect.x(), mrw = r->mouse_rect.width(), vw = r->view->width();
|
||||
double mry = r->mouse_rect.y(), mrh = r->mouse_rect.height(), vh = r->view->height();
|
||||
mat.translate(-1. + (mrw + mrx * 2) / vw, 1. - (mrh + mry * 2) / vh, 0.);
|
||||
mat.scale(mrw / vw, mrh / vh, 0.);
|
||||
r->initQuad(sel_frame, mat);
|
||||
prog->setUniformValue("size", QVector2D(mrw / vw, mrh / vh));
|
||||
prog->setUniformValue("thickness", line_thick_);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
r->renderQuad(prog, sel_frame);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererSelection::drawSelection(Framebuffer & fbo_out, int index_out) {
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
if (r->bindShader(Renderer::srSelectionApply, &prog)) {
|
||||
fbo_selection.bindColorTextures();
|
||||
fbo_out.bindColorTexture(index_out);
|
||||
prog->setUniformValue("fb_out", 0);
|
||||
prog->setUniformValue("fb_hover", (int)sbrHoveredFXAA);
|
||||
prog->setUniformValue("fb_select", (int)sbrSelectedFXAA);
|
||||
r->renderQuad(prog, r->quad, r->view->camera());
|
||||
if (!r->mouse_rect.isNull()) {
|
||||
renderSelectionFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/core/render/renderer_selection.h
Normal file
66
src/core/render/renderer_selection.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
QGL RendererSelection
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RENDERER_SELECTION_H
|
||||
#define RENDERER_SELECTION_H
|
||||
|
||||
#include "renderer_service.h"
|
||||
|
||||
#include <QHash>
|
||||
|
||||
|
||||
class QGLENGINE_CORE_EXPORT RendererSelection {
|
||||
friend class QGLView;
|
||||
friend class MouseController;
|
||||
friend class Renderer;
|
||||
friend class RendererService;
|
||||
|
||||
public:
|
||||
RendererSelection(Renderer * r_);
|
||||
virtual ~RendererSelection();
|
||||
|
||||
void init(int width, int height);
|
||||
void resize(int width, int height);
|
||||
|
||||
protected:
|
||||
enum SelectionBufferRole {
|
||||
sbrSrcHover,
|
||||
sbrSrcSelect,
|
||||
sbrHovered,
|
||||
sbrSelected,
|
||||
sbrHoveredFXAA,
|
||||
sbrSelectedFXAA,
|
||||
};
|
||||
|
||||
void generateObjectsID(Scene & scene);
|
||||
void renderSelection(Scene & scene);
|
||||
void renderSelectionFrame();
|
||||
void drawSelection(Framebuffer & fbo_out, int index_out = 0);
|
||||
|
||||
private:
|
||||
Renderer * r;
|
||||
Framebuffer fbo_selection;
|
||||
Mesh * sel_frame;
|
||||
float line_thick_, scale_;
|
||||
QVector<uchar> cur_selections_;
|
||||
QHash<uint, ObjectBase *> ids;
|
||||
QHash<uint, ObjectBase *> aim_ids;
|
||||
uint id_hover;
|
||||
};
|
||||
|
||||
#endif // RENDERER_selection_H
|
||||
528
src/core/render/renderer_service.cpp
Normal file
528
src/core/render/renderer_service.cpp
Normal file
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
QGL RendererService
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include "renderer_service.h"
|
||||
|
||||
#include "glmesh.h"
|
||||
#include "qglview.h"
|
||||
#include "renderer.h"
|
||||
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <qad_types.h>
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
|
||||
RendererService::RendererService(Renderer * r_): r(r_) {
|
||||
line_width = 1;
|
||||
current_action = haNoAction;
|
||||
current_handle = QFlags<HandleMesh>();
|
||||
mat_xyz.resize(3);
|
||||
mat_ms2.resize(3);
|
||||
color_xyz.resize(3);
|
||||
color_ms2.resize(3);
|
||||
const QVector3D _rot[3] = {QVector3D(0, 1, 0), QVector3D(-1, 0, 0), QVector3D(0, 0, 1)};
|
||||
const QVector3D _rot2[3] = {QVector3D(0, 0, 0), QVector3D(1, 0, 0), QVector3D(0, -1, 0)};
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
QMatrix4x4 m;
|
||||
m.rotate(90., _rot[i]);
|
||||
mat_xyz[i] = m;
|
||||
m.setToIdentity();
|
||||
if (!_rot2[i].isNull()) m.rotate(90., _rot2[i]);
|
||||
mat_ms2[i] = m;
|
||||
color_xyz[i] = color_ms2[i] = QVector4D(0, 0, 0, 0.8);
|
||||
color_xyz[i][i] = 1.;
|
||||
}
|
||||
color_ms2[0] = (color_xyz[0] + color_xyz[1]) / 2.;
|
||||
color_ms2[1] = (color_xyz[0] + color_xyz[2]) / 2.;
|
||||
color_ms2[2] = (color_xyz[1] + color_xyz[2]) / 2.;
|
||||
axis_camera = new Camera();
|
||||
axis_camera->setAim(QVector3D());
|
||||
axis_camera->setFOV(45.);
|
||||
axis_mesh = Primitive::arrow(12);
|
||||
size_vp_scale = size_full_scale = 1.;
|
||||
|
||||
box_mesh = Primitive::cube(0.8, 0.8, 0.8);
|
||||
box_mesh_f = Primitive::cubeFrame(0.8, 0.8, 0.8);
|
||||
omni_mesh = Primitive::ellipsoid(2, 1, 0.5);
|
||||
omni_mesh_f = Primitive::ellipsoidFrame(2, 1, 0.5);
|
||||
omni_mesh->scalePoints(1.5);
|
||||
omni_mesh_f->scalePoints(1.5);
|
||||
cone_mesh = Primitive::cone(8, 0.5, 1.);
|
||||
cone_mesh_f = Primitive::coneFrame(8, 0.5, 1.);
|
||||
QMatrix4x4 mat;
|
||||
mat.translate(0, 0, -1);
|
||||
cone_mesh->transformPoints(mat);
|
||||
cone_mesh_f->transformPoints(mat);
|
||||
cone_mesh_f->scalePoints(1.5);
|
||||
|
||||
box_mesh->scalePoints(1.3);
|
||||
omni_mesh->scalePoints(1.3);
|
||||
cone_mesh->translatePoints(0, 0, 0.5);
|
||||
cone_mesh->scalePoints(1.4);
|
||||
cone_mesh->translatePoints(0, 0, -0.5);
|
||||
cone_mesh->scalePoints(1.5);
|
||||
|
||||
camera_mesh = Primitive::cube(1.2, 1.2, 1.2);
|
||||
mat.translate(0, 0, -0.5);
|
||||
Mesh * m = Primitive::cone(6, 0.6, 1.);
|
||||
m->scalePoints(1.4);
|
||||
m->transformPoints(mat);
|
||||
camera_mesh->append(m);
|
||||
camera_mesh_f = Primitive::cubeFrame(1., 1., 1.);
|
||||
camera_mesh_f->append(Primitive::cubeFrame(0.5, 0.5, 0.5));
|
||||
m = Primitive::coneFrame(6, 0.6, 1.);
|
||||
m->transformPoints(mat);
|
||||
camera_mesh_f->append(m);
|
||||
|
||||
line_spot_f = Primitive::lineFrame(QVector3D(), QVector3D(0, 0, -1));
|
||||
line_camera_f = Primitive::lineFrame(QVector3D(), QVector3D(0, 0, -1));
|
||||
|
||||
handle_move_mesh = Primitive::arrow(12, 0.06);
|
||||
handle_ms_2_mesh = Primitive::torus(8, 12, 0.5, 0.02, 90);
|
||||
m = Primitive::disc(8, 0.5, 90);
|
||||
handle_ms_2_mesh->append(m);
|
||||
m->flipNormals();
|
||||
handle_ms_2_mesh->append(m);
|
||||
delete m;
|
||||
|
||||
handle_rotate_mesh = Primitive::arrow(12, 0.03);
|
||||
m = Primitive::torus(30, 12, 0.5, 0.06);
|
||||
m->translatePoints(QVector3D(0., 0., 0.75));
|
||||
handle_rotate_mesh->append(m);
|
||||
delete m;
|
||||
|
||||
handle_scale_mesh = Primitive::cylinder(12, 0.03, 0.85);
|
||||
m = Primitive::ellipsoid(12, 12, 0.15);
|
||||
m->translatePoints(QVector3D(0., 0., 0.85));
|
||||
handle_scale_mesh->append(m);
|
||||
delete m;
|
||||
handle_scale_3_mesh = Primitive::ellipsoid(12, 12, 0.2);
|
||||
|
||||
handle_move_mesh->scalePoints(7.5);
|
||||
handle_ms_2_mesh->scalePoints(7.5);
|
||||
handle_rotate_mesh->scalePoints(7.5);
|
||||
handle_scale_mesh->scalePoints(7.5);
|
||||
handle_scale_3_mesh->scalePoints(7.5);
|
||||
}
|
||||
|
||||
|
||||
RendererService::~RendererService() {
|
||||
delete box_mesh;
|
||||
delete box_mesh_f;
|
||||
delete omni_mesh;
|
||||
delete omni_mesh_f;
|
||||
delete cone_mesh;
|
||||
delete cone_mesh_f;
|
||||
delete camera_mesh;
|
||||
delete camera_mesh_f;
|
||||
delete line_spot_f;
|
||||
delete line_camera_f;
|
||||
delete axis_camera;
|
||||
delete axis_mesh;
|
||||
delete handle_move_mesh;
|
||||
delete handle_ms_2_mesh;
|
||||
delete handle_rotate_mesh;
|
||||
delete handle_scale_mesh;
|
||||
delete handle_scale_3_mesh;
|
||||
}
|
||||
|
||||
|
||||
void RendererService::init(int width, int height) {
|
||||
box_mesh->reinit();
|
||||
box_mesh_f->reinit();
|
||||
omni_mesh->reinit();
|
||||
omni_mesh_f->reinit();
|
||||
cone_mesh->reinit();
|
||||
cone_mesh_f->reinit();
|
||||
camera_mesh->reinit();
|
||||
camera_mesh_f->reinit();
|
||||
line_spot_f->reinit();
|
||||
line_camera_f->reinit();
|
||||
axis_mesh->reinit();
|
||||
handle_move_mesh->reinit();
|
||||
handle_ms_2_mesh->reinit();
|
||||
handle_rotate_mesh->reinit();
|
||||
handle_scale_mesh->reinit();
|
||||
handle_scale_3_mesh->reinit();
|
||||
axis_mesh->reinit();
|
||||
fillXYZObjects();
|
||||
axis_mesh->loadObjects(r->view, cur_objects);
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
|
||||
void RendererService::resize(int width, int height) {
|
||||
axis_viewport = preferredIconSize(10.);
|
||||
line_width = lineThickness();
|
||||
size_vp_scale = 25. * appScale() / qMax(qMin(width, height), 1);
|
||||
// qDebug() << axis_viewport;
|
||||
}
|
||||
|
||||
|
||||
QMatrix4x4 RendererService::invariantSizeMatrix(QVector3D p, double * ret_scale) {
|
||||
QVector4D pos = QVector4D(p, 1.);
|
||||
double dist = -(v_mat * pos).z();
|
||||
QMatrix4x4 m;
|
||||
m.translate(pos.toVector3D());
|
||||
m.scale(dist * size_full_scale);
|
||||
if (ret_scale) *ret_scale = dist * size_full_scale;
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
QMatrix4x4 RendererService::parentRotationMatrix(ObjectBase * o, bool self_rotation) {
|
||||
QMatrix4x4 ret;
|
||||
if (!o) return ret;
|
||||
QMatrix4x4 pmat;
|
||||
if (o->parent()) {
|
||||
pmat = o->parent()->transform().matrixRotate();
|
||||
}
|
||||
if (self_rotation) {
|
||||
ret *= o->transform().matrixRotate();
|
||||
}
|
||||
ret = pmat * ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void RendererService::fillXYZObjects() {
|
||||
cur_objects.resize(3);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
cur_objects[i].color = color_xyz[i];
|
||||
mat_xyz[i].transposed().copyDataTo(cur_objects[i].modelmatrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererService::fillOmniObjects() {
|
||||
QList<Light *> ll = r->view->scene()->lights_used.value(Light::Omni);
|
||||
Object o;
|
||||
cur_objects.clear();
|
||||
foreach(Light * l, ll) {
|
||||
QMatrix4x4 m = invariantSizeMatrix(l->worldPos());
|
||||
m.transposed().copyDataTo(o.modelmatrix);
|
||||
o.object_id = l->id();
|
||||
cur_objects << o;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererService::fillAimedObjects(const ObjectBaseList & objects, Mesh * line_mesh) {
|
||||
Object o;
|
||||
cur_objects.clear();
|
||||
cur_aims.clear();
|
||||
QVector<QVector3D> & lv(line_mesh->vertices());
|
||||
QVector<QVector3D> & ln(line_mesh->normals());
|
||||
QVector<QVector2D> & lt(line_mesh->texcoords());
|
||||
QVector<Vector2i> & lind(line_mesh->indicesLines());
|
||||
lv.clear();
|
||||
foreach(ObjectBase * go, objects) {
|
||||
AimedObject * ao = (AimedObject *)go;
|
||||
QMatrix4x4 m;
|
||||
m = invariantSizeMatrix(ao->worldPos()) * parentRotationMatrix(ao);
|
||||
m.transposed().copyDataTo(o.modelmatrix);
|
||||
o.object_id = ao->id();
|
||||
cur_objects << o;
|
||||
|
||||
lv << ao->worldPos() << ao->worldAim();
|
||||
|
||||
m = invariantSizeMatrix(ao->worldAim());
|
||||
m.transposed().copyDataTo(o.modelmatrix);
|
||||
o.object_id = ao->id() + 1;
|
||||
cur_aims << o;
|
||||
}
|
||||
ln.resize(lv.size());
|
||||
lt.resize(lv.size());
|
||||
lind.resize(lv.size() / 2);
|
||||
for (int i = 0; i < lind.size(); ++i) {
|
||||
lind[i] = Vector2i(i * 2, i * 2 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererService::fillHandleObjects(QVector3D center,
|
||||
HandleMesh ids[],
|
||||
const QVector<QMatrix4x4> & mats,
|
||||
const QVector<QVector4D> & colors,
|
||||
QMatrix4x4 add_mat,
|
||||
int count) {
|
||||
QMatrix4x4 m = invariantSizeMatrix(center) * add_mat;
|
||||
cur_objects.resize(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
cur_objects[i].color = colors[i];
|
||||
QMatrix4x4 omat = m * mats[i];
|
||||
cur_objects[i].object_id = ids[i];
|
||||
if (current_handle.testFlag(ids[i])) {
|
||||
cur_objects[i].color = QVector4D(0, 1, 1, 1);
|
||||
}
|
||||
omat.transposed().copyDataTo(cur_objects[i].modelmatrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool RendererService::calculateCenter() {
|
||||
ObjectBaseList sol = r->view->scene()->selectedObjects(true);
|
||||
if (sol.isEmpty()) return false;
|
||||
selection_center = sol[0]->worldPos();
|
||||
if (sol.size() > 1) {
|
||||
Box3D bb;
|
||||
foreach(ObjectBase * o, sol) {
|
||||
o->calculateBoundingBox();
|
||||
bb |= o->boundingBox();
|
||||
}
|
||||
if (!bb.isEmpty()) {
|
||||
selection_center = bb.center();
|
||||
}
|
||||
}
|
||||
axis_mat = QMatrix4x4();
|
||||
if ((sol.size() == 1)) {
|
||||
if (current_action == haMove) {
|
||||
if (sol[0]->isAimSelected()) selection_center = ((AimedObject *)sol[0])->worldAim();
|
||||
} else {
|
||||
axis_mat = parentRotationMatrix(sol[0]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void RendererService::drawCurrentHandleObjects() {
|
||||
if (current_action == haNoAction) return;
|
||||
if (calculateCenter()) {
|
||||
HandleMesh ids[3];
|
||||
switch (current_action) {
|
||||
case haMove:
|
||||
ids[0] = hmMoveX;
|
||||
ids[1] = hmMoveY;
|
||||
ids[2] = hmMoveZ;
|
||||
break;
|
||||
case haRotate:
|
||||
ids[0] = hmRotateX;
|
||||
ids[1] = hmRotateY;
|
||||
ids[2] = hmRotateZ;
|
||||
break;
|
||||
case haScale:
|
||||
ids[0] = hmScaleX;
|
||||
ids[1] = hmScaleY;
|
||||
ids[2] = hmScaleZ;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
fillHandleObjects(selection_center, ids, mat_xyz, color_xyz, axis_mat);
|
||||
Mesh * hm = currentHandleMesh();
|
||||
QVector<uchar> sel;
|
||||
sel.fill(0, 3);
|
||||
if (hm) {
|
||||
hm->loadObjects(r->view, cur_objects);
|
||||
hm->loadSelections(r->view, sel);
|
||||
hm->draw(r->view, 3);
|
||||
}
|
||||
if (current_action == haMove || current_action == haScale) {
|
||||
switch (current_action) {
|
||||
case haMove:
|
||||
ids[0] = hmMoveXY;
|
||||
ids[1] = hmMoveXZ;
|
||||
ids[2] = hmMoveYZ;
|
||||
break;
|
||||
case haScale:
|
||||
ids[0] = hmScaleXY;
|
||||
ids[1] = hmScaleXZ;
|
||||
ids[2] = hmScaleYZ;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
hm = handle_ms_2_mesh;
|
||||
fillHandleObjects(selection_center, ids, mat_ms2, color_ms2, axis_mat);
|
||||
hm->loadObjects(r->view, cur_objects);
|
||||
hm->loadSelections(r->view, sel);
|
||||
hm->draw(r->view, 3);
|
||||
if (current_action == haScale) {
|
||||
hm = handle_scale_3_mesh;
|
||||
QVector<QMatrix4x4> mv;
|
||||
mv.resize(1);
|
||||
QVector<QVector4D> cv;
|
||||
cv.fill(QVector4D(1, 1, 0.5, 1), 1);
|
||||
ids[0] = hmMaxScale;
|
||||
fillHandleObjects(selection_center, ids, mv, cv, axis_mat, 1);
|
||||
hm->loadObjects(r->view, cur_objects);
|
||||
hm->loadSelections(r->view, sel);
|
||||
hm->draw(r->view, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererService::drawLights() {
|
||||
QGLView * v = r->view;
|
||||
RendererSelection & rs(r->rend_selection);
|
||||
|
||||
fillOmniObjects();
|
||||
omni_mesh->loadObjects(v, cur_objects);
|
||||
r->fillSelectionsBuffer(rs.cur_selections_, lights2objectList(v->scene()->lights_used.value(Light::Omni)));
|
||||
omni_mesh->loadSelections(v, rs.cur_selections_);
|
||||
omni_mesh->draw(v, cur_objects.size());
|
||||
|
||||
ObjectBaseList ll = lights2objectList(r->view->scene()->lights_used.value(Light::Cone));
|
||||
fillAimedObjects(ll, line_spot_f);
|
||||
cone_mesh->loadObjects(v, cur_objects);
|
||||
r->fillSelectionsBuffer(rs.cur_selections_, ll);
|
||||
cone_mesh->loadSelections(v, rs.cur_selections_);
|
||||
cone_mesh->draw(v, cur_objects.size());
|
||||
box_mesh->loadObjects(v, cur_aims);
|
||||
box_mesh->loadSelections(v, rs.cur_selections_);
|
||||
box_mesh->draw(v, cur_aims.size());
|
||||
}
|
||||
|
||||
|
||||
void RendererService::drawLightsFrame(QColor color) {
|
||||
QGLView * v = r->view;
|
||||
RendererSelection & rs(r->rend_selection);
|
||||
|
||||
fillOmniObjects();
|
||||
setObjectsColor(cur_objects, color);
|
||||
omni_mesh_f->loadObjects(v, cur_objects);
|
||||
r->fillSelectionsBuffer(rs.cur_selections_, lights2objectList(v->scene()->lights_used.value(Light::Omni)));
|
||||
omni_mesh_f->loadSelections(v, rs.cur_selections_);
|
||||
omni_mesh_f->draw(v, cur_objects.size());
|
||||
|
||||
ObjectBaseList ll = lights2objectList(r->view->scene()->lights_used.value(Light::Cone));
|
||||
fillAimedObjects(ll, line_spot_f);
|
||||
setObjectsColor(cur_objects, color);
|
||||
cone_mesh_f->loadObjects(v, cur_objects);
|
||||
r->fillSelectionsBuffer(rs.cur_selections_, ll);
|
||||
cone_mesh_f->loadSelections(v, rs.cur_selections_);
|
||||
cone_mesh_f->draw(v, cur_objects.size());
|
||||
|
||||
setObjectsColor(cur_aims, color);
|
||||
box_mesh_f->loadObjects(v, cur_aims);
|
||||
box_mesh_f->loadSelections(v, rs.cur_selections_);
|
||||
box_mesh_f->draw(v, cur_aims.size());
|
||||
}
|
||||
|
||||
|
||||
void RendererService::drawCameras() {
|
||||
QGLView * v = r->view;
|
||||
RendererSelection & rs(r->rend_selection);
|
||||
|
||||
ObjectBaseList cl = cameras2objectList(r->view->scene()->cameras_used);
|
||||
cl.removeOne(r->view->camera());
|
||||
fillAimedObjects(cl, line_camera_f);
|
||||
camera_mesh->loadObjects(v, cur_objects);
|
||||
r->fillSelectionsBuffer(rs.cur_selections_, cl);
|
||||
camera_mesh->loadSelections(v, rs.cur_selections_);
|
||||
camera_mesh->draw(v, cur_objects.size());
|
||||
box_mesh->loadObjects(v, cur_aims);
|
||||
box_mesh->loadSelections(v, rs.cur_selections_);
|
||||
box_mesh->draw(v, cur_aims.size());
|
||||
}
|
||||
|
||||
|
||||
void RendererService::drawCamerasFrame(QColor color) {
|
||||
QGLView * v = r->view;
|
||||
RendererSelection & rs(r->rend_selection);
|
||||
|
||||
ObjectBaseList cl = cameras2objectList(r->view->scene()->cameras_used);
|
||||
cl.removeOne(r->view->camera());
|
||||
fillAimedObjects(cl, line_camera_f);
|
||||
setObjectsColor(cur_objects, color);
|
||||
camera_mesh_f->loadObjects(v, cur_objects);
|
||||
r->fillSelectionsBuffer(rs.cur_selections_, cl);
|
||||
camera_mesh_f->loadSelections(v, rs.cur_selections_);
|
||||
camera_mesh_f->draw(v, cur_objects.size());
|
||||
|
||||
setObjectsColor(cur_aims, color);
|
||||
box_mesh_f->loadObjects(v, cur_aims);
|
||||
box_mesh_f->loadSelections(v, rs.cur_selections_);
|
||||
box_mesh_f->draw(v, cur_aims.size());
|
||||
}
|
||||
|
||||
|
||||
void RendererService::setObjectsColor(QVector<Object> & ol, QColor col) {
|
||||
QVector4D cv = QColor2QVector(col);
|
||||
for (int i = 0; i < ol.size(); ++i)
|
||||
ol[i].color = cv;
|
||||
}
|
||||
|
||||
|
||||
void RendererService::renderService() {
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
QOpenGLExtraFunctions * f = r->view;
|
||||
size_full_scale = tan(r->view->camera()->FOV() / 2. * deg2rad) * size_vp_scale;
|
||||
v_mat = r->view->camera()->fullViewMatrix();
|
||||
f->glEnable(GL_MULTISAMPLE);
|
||||
glEnableDepth();
|
||||
f->glClear(GL_DEPTH_BUFFER_BIT);
|
||||
glDisable(GL_CULL_FACE);
|
||||
if (r->bindShader(Renderer::srServiceFrame, &prog)) {
|
||||
prog->setUniformValue("qgl_ProjMatrix", r->view->camera()->projectionMatrix(r->view->aspect));
|
||||
|
||||
/// lights
|
||||
r->setUniformCamera(prog, r->view->camera());
|
||||
|
||||
prog->setUniformValue("line_width", 2.f);
|
||||
prog->setUniformValue("z_offset", 0.f);
|
||||
drawLightsFrame(Qt::white);
|
||||
drawCamerasFrame(Qt::white);
|
||||
prog->setUniformValue("line_width", 1.f);
|
||||
prog->setUniformValue("z_offset", -1.E-2f);
|
||||
drawLightsFrame(Qt::black);
|
||||
drawCamerasFrame(Qt::black);
|
||||
}
|
||||
if (r->bindShader(Renderer::srServiceLine, &prog)) {
|
||||
r->setUniformCamera(prog, r->view->camera());
|
||||
line_object.color = QColor2QVector(Qt::white);
|
||||
line_spot_f->loadObject(f, line_object);
|
||||
line_camera_f->loadObject(f, line_object);
|
||||
line_spot_f->draw(f, 1);
|
||||
line_camera_f->draw(f, 1);
|
||||
}
|
||||
glEnable(GL_CULL_FACE);
|
||||
if (r->bindShader(Renderer::srServiceFill, &prog)) {
|
||||
r->setUniformCamera(prog, r->view->camera());
|
||||
|
||||
/// handles
|
||||
f->glEnable(GL_BLEND);
|
||||
f->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
drawCurrentHandleObjects();
|
||||
f->glDisable(GL_BLEND);
|
||||
|
||||
/// axis
|
||||
f->glViewport(0, 0, axis_viewport.width(), axis_viewport.height());
|
||||
axis_camera->setPos(-r->view->camera()->direction() * 3.);
|
||||
axis_camera->setAim(QVector3D());
|
||||
axis_camera->setRotation(r->view->camera()->rotation());
|
||||
r->setUniformCamera(prog, axis_camera, true, axis_viewport);
|
||||
axis_mesh->draw(f, 3);
|
||||
f->glViewport(0, 0, r->view->width(), r->view->height());
|
||||
}
|
||||
f->glDisable(GL_MULTISAMPLE);
|
||||
}
|
||||
|
||||
|
||||
Mesh * RendererService::currentHandleMesh() {
|
||||
switch (current_action) {
|
||||
case haMove: return handle_move_mesh;
|
||||
case haRotate: return handle_rotate_mesh;
|
||||
case haScale: return handle_scale_mesh;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
112
src/core/render/renderer_service.h
Normal file
112
src/core/render/renderer_service.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
QGL RendererService
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RENDERER_SERVICE_H
|
||||
#define RENDERER_SERVICE_H
|
||||
|
||||
#include "glframebuffer.h"
|
||||
#include "glshaders_types.h"
|
||||
|
||||
#include <QQueue>
|
||||
|
||||
|
||||
class QGLENGINE_CORE_EXPORT RendererService {
|
||||
friend class QGLView;
|
||||
friend class MouseController;
|
||||
friend class Renderer;
|
||||
friend class RendererSelection;
|
||||
|
||||
public:
|
||||
RendererService(Renderer * r_);
|
||||
virtual ~RendererService();
|
||||
|
||||
enum HandleAction {
|
||||
haNoAction,
|
||||
haMove,
|
||||
haRotate,
|
||||
haScale,
|
||||
};
|
||||
|
||||
enum HandleMesh {
|
||||
hmMoveX = 0x01,
|
||||
hmMoveY = 0x02,
|
||||
hmMoveZ = 0x04,
|
||||
hmMoveXY = hmMoveX | hmMoveY,
|
||||
hmMoveXZ = hmMoveX | hmMoveZ,
|
||||
hmMoveYZ = hmMoveY | hmMoveZ,
|
||||
hmMaxMove = hmMoveX | hmMoveY | hmMoveZ,
|
||||
hmRotateX = 0x08,
|
||||
hmRotateY = 0x10,
|
||||
hmRotateZ = 0x20,
|
||||
hmMaxRotate = hmRotateX | hmRotateY | hmRotateZ,
|
||||
hmScaleX = 0x40,
|
||||
hmScaleY = 0x80,
|
||||
hmScaleZ = 0x100,
|
||||
hmScaleXY = hmScaleX | hmScaleY,
|
||||
hmScaleXZ = hmScaleX | hmScaleZ,
|
||||
hmScaleYZ = hmScaleY | hmScaleZ,
|
||||
hmMaxScale = hmScaleX | hmScaleY | hmScaleZ,
|
||||
};
|
||||
|
||||
void init(int width, int height);
|
||||
void resize(int width, int height);
|
||||
|
||||
QMatrix4x4 invariantSizeMatrix(QVector3D p, double * ret_scale = 0);
|
||||
QMatrix4x4 parentRotationMatrix(ObjectBase * o, bool self_rotation = true);
|
||||
void fillXYZObjects();
|
||||
void fillOmniObjects();
|
||||
void fillAimedObjects(const ObjectBaseList & objects, Mesh * line_mesh);
|
||||
void fillHandleObjects(QVector3D center,
|
||||
HandleMesh ids[],
|
||||
const QVector<QMatrix4x4> & mats,
|
||||
const QVector<QVector4D> & colors,
|
||||
QMatrix4x4 add_mat,
|
||||
int count = 3);
|
||||
bool calculateCenter();
|
||||
void drawCurrentHandleObjects();
|
||||
void drawLights();
|
||||
void drawLightsFrame(QColor color);
|
||||
void drawCameras();
|
||||
void drawCamerasFrame(QColor color);
|
||||
void setObjectsColor(QVector<QGLEngineShaders::Object> & ol, QColor col);
|
||||
void renderService();
|
||||
void setCurrentAction(HandleAction ha) { current_action = ha; }
|
||||
Mesh * currentHandleMesh();
|
||||
|
||||
private:
|
||||
Renderer * r;
|
||||
Mesh *axis_mesh, *handle_move_mesh, *handle_rotate_mesh, *handle_scale_mesh;
|
||||
Mesh *handle_ms_2_mesh, *handle_scale_3_mesh;
|
||||
Mesh *box_mesh_f, *omni_mesh_f, *cone_mesh_f, *camera_mesh_f;
|
||||
Mesh *box_mesh, *omni_mesh, *cone_mesh, *camera_mesh;
|
||||
Mesh *line_spot_f, *line_camera_f;
|
||||
QMatrix4x4 v_mat, axis_mat;
|
||||
QVector3D selection_center;
|
||||
QVector<QMatrix4x4> mat_xyz, mat_ms2;
|
||||
QVector<QVector4D> color_xyz, color_ms2;
|
||||
QVector<QGLEngineShaders::Object> cur_objects, cur_aims;
|
||||
QGLEngineShaders::Object line_object;
|
||||
Camera * axis_camera;
|
||||
QSize axis_viewport;
|
||||
HandleAction current_action;
|
||||
QFlags<HandleMesh> current_handle;
|
||||
int line_width;
|
||||
double size_vp_scale, size_full_scale;
|
||||
};
|
||||
|
||||
#endif // RENDERER_SERVICE_H
|
||||
187
src/core/render/tonemapping_proc.cpp
Normal file
187
src/core/render/tonemapping_proc.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
QGL TonemappingProc
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include "tonemapping_proc.h"
|
||||
|
||||
#include "qglview.h"
|
||||
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <qad_types.h>
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
|
||||
TonemappingProc::TonemappingProc(Renderer * rend)
|
||||
: QThread()
|
||||
, r(rend)
|
||||
, fbo_1x1(r->view, 1, false, GL_RGB32F)
|
||||
, fbomm(r->fbo_out, Renderer::obrGeneral1, 3)
|
||||
, buffer_vbo(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW) {
|
||||
shader_sum = 0;
|
||||
timer_delim = 0;
|
||||
frame_max = cur_max = 1.;
|
||||
need_render_sum = exit_ = false;
|
||||
enabled = false;
|
||||
timer_tone = startTimer(10);
|
||||
}
|
||||
|
||||
|
||||
TonemappingProc::~TonemappingProc() {
|
||||
exit_ = true;
|
||||
if (!wait(1000)) terminate();
|
||||
killTimer(timer_tone);
|
||||
if (shader_sum) delete shader_sum;
|
||||
}
|
||||
|
||||
|
||||
void TonemappingProc::init() {
|
||||
buffer_vbo.reinit();
|
||||
fbo_1x1.reinit();
|
||||
fbomm.reinit();
|
||||
QOpenGLExtraFunctions * f = r->view;
|
||||
buffer_vbo.init(f);
|
||||
f->glGenVertexArrays(1, &vbo_vao);
|
||||
f->glBindVertexArray(vbo_vao);
|
||||
buffer_vbo.bind(f);
|
||||
f->glEnableVertexAttribArray(1);
|
||||
f->glVertexAttribIPointer(1, 2, GL_UNSIGNED_INT, 0, 0);
|
||||
buffer_vbo.release(f);
|
||||
f->glBindVertexArray(0);
|
||||
fbomm.lastPlane().enablePixelBuffer();
|
||||
fbo_1x1.resize(1, 1);
|
||||
resize();
|
||||
if (!isRunning()) start();
|
||||
}
|
||||
|
||||
|
||||
void TonemappingProc::resize() {
|
||||
QOpenGLExtraFunctions * f = r->view;
|
||||
fbomm.resize();
|
||||
int pcnt = fbomm.width(fbomm.lastLevel()) * fbomm.height(fbomm.lastLevel());
|
||||
QVector<Vector2i> _data;
|
||||
_data.resize(pcnt);
|
||||
pcnt = -1;
|
||||
for (int x = 0; x < fbomm.width(fbomm.lastLevel()); ++x)
|
||||
for (int y = 0; y < fbomm.height(fbomm.lastLevel()); ++y)
|
||||
_data[++pcnt] = Vector2i(x, y);
|
||||
buffer_vbo.bind(f);
|
||||
buffer_vbo.resize(f, _data.size() * sizeof(Vector2i));
|
||||
buffer_vbo.load(f, _data.constData(), _data.size() * sizeof(Vector2i));
|
||||
}
|
||||
|
||||
|
||||
void TonemappingProc::timerEvent(QTimerEvent * e) {
|
||||
if (!fbo_1x1.isInit() || !enabled) return;
|
||||
if (timer_delim == 0) need_render_sum = true;
|
||||
timer_delim = (timer_delim + 1) % 10;
|
||||
mutex.lock();
|
||||
float fmax = frame_max;
|
||||
mutex.unlock();
|
||||
float dt = 0.01f, a = dt * 5.f, b = 1.f - a;
|
||||
cur_max = fmax * a + cur_max * b;
|
||||
}
|
||||
|
||||
|
||||
void TonemappingProc::renderSum(Framebuffer & fbo_src, int index) {
|
||||
QOpenGLExtraFunctions * f = r->view;
|
||||
int pcnt = fbo_src.width() * fbo_src.height();
|
||||
fbo_src.bindColorTexture(index);
|
||||
fbo_1x1.bind();
|
||||
glClearFramebuffer();
|
||||
if (shader_sum) {
|
||||
if (shader_sum->isLinked()) {
|
||||
if (shader_sum->bind()) {
|
||||
shader_sum->setUniformValue("tex", 0);
|
||||
shader_sum->setUniformValue("pcnt", float(pcnt));
|
||||
f->glBindVertexArray(vbo_vao);
|
||||
f->glEnable(GL_BLEND);
|
||||
f->glBlendFunc(GL_ONE, GL_ONE);
|
||||
f->glBlendEquation(GL_MAX);
|
||||
f->glDrawArrays(GL_POINTS, 0, pcnt);
|
||||
f->glBlendEquation(GL_FUNC_ADD);
|
||||
f->glDisable(GL_BLEND);
|
||||
f->glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
fbo_1x1.release();
|
||||
}
|
||||
|
||||
|
||||
void TonemappingProc::run() {
|
||||
while (!exit_) {
|
||||
if (!enabled) {
|
||||
msleep(100);
|
||||
continue;
|
||||
}
|
||||
mutex.lock();
|
||||
if (last_data.isEmpty()) {
|
||||
mutex.unlock();
|
||||
msleep(10);
|
||||
continue;
|
||||
}
|
||||
QVector<QVector4D> data = last_data;
|
||||
last_data.clear();
|
||||
mutex.unlock();
|
||||
float max = calcHistogram(data);
|
||||
last_max << max;
|
||||
if (last_max.size() > 5) last_max.removeAt(0);
|
||||
float cm = last_max[0];
|
||||
for (int i = 1; i < last_max.size(); ++i)
|
||||
cm += last_max[i];
|
||||
cm /= last_max.size();
|
||||
mutex.lock();
|
||||
frame_max = cm;
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float TonemappingProc::calcHistogram(const QVector<QVector4D> & data) {
|
||||
if (data.isEmpty()) return 1.f;
|
||||
float max = 0.;
|
||||
QVector3D luma(0.299, 0.587, 0.114);
|
||||
foreach(const QVector4D & p, data) {
|
||||
float l = QVector3D::dotProduct(p.toVector3D(), luma);
|
||||
max = qMax(max, l);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
bool TonemappingProc::process() {
|
||||
if (!need_render_sum || !enabled) return false;
|
||||
need_render_sum = false;
|
||||
Framebuffer & fbo(fbomm.lastPlane());
|
||||
if (fbo.queriedPoints() > 0) {
|
||||
QVector<QVector4D> data = fbo.getPointsFloat();
|
||||
mutex.lock();
|
||||
last_data = data;
|
||||
mutex.unlock();
|
||||
}
|
||||
fbomm.create();
|
||||
fbo.queryPoints(0, fbo.rect(), GL_FLOAT);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
float TonemappingProc::frameMax() {
|
||||
if (!enabled) return 1.f;
|
||||
return cur_max;
|
||||
}
|
||||
64
src/core/render/tonemapping_proc.h
Normal file
64
src/core/render/tonemapping_proc.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
QGL TonemappingProc
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TONEMAPPING_PROC_H
|
||||
#define TONEMAPPING_PROC_H
|
||||
|
||||
#include "glframebuffer_mipmap.h"
|
||||
|
||||
#include <QThread>
|
||||
|
||||
|
||||
class QGLENGINE_CORE_EXPORT TonemappingProc: public QThread {
|
||||
friend class Renderer;
|
||||
friend class QGLView;
|
||||
|
||||
public:
|
||||
TonemappingProc(Renderer * rend);
|
||||
virtual ~TonemappingProc();
|
||||
|
||||
void init();
|
||||
void resize();
|
||||
void prepareSum();
|
||||
void renderSum(Framebuffer & fbo_src, int index);
|
||||
|
||||
bool process();
|
||||
float frameMax();
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent * e) override;
|
||||
void run() override;
|
||||
float calcHistogram(const QVector<QVector4D> & data);
|
||||
|
||||
private:
|
||||
Renderer * r;
|
||||
QMutex mutex;
|
||||
QVector<QVector4D> last_data;
|
||||
QVector<float> last_max;
|
||||
float frame_max, cur_max;
|
||||
bool need_render_sum, enabled;
|
||||
std::atomic_bool exit_;
|
||||
int timer_tone, timer_delim;
|
||||
Framebuffer fbo_1x1;
|
||||
FramebufferMipmap fbomm;
|
||||
QOpenGLShaderProgram * shader_sum;
|
||||
Buffer buffer_vbo;
|
||||
GLenum vbo_vao;
|
||||
};
|
||||
|
||||
#endif // RENDERER_H
|
||||
Reference in New Issue
Block a user