/* 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 . */ #define GL_GLEXT_PROTOTYPES #include #include "tonemapping_proc.h" #include "qglview.h" #include using namespace QGLEngineShaders; TonemappingProc::TonemappingProc(Renderer * rend): QThread(), r(rend), fbo_1x1(r->view, 1, false, GL_RGB32F), fbomm(r->fbo_out, Renderer::obrSum, 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() { 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 _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(Qt::white, false); 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(); //fbo_src.bind(); } void TonemappingProc::run() { while (!exit_) { if (!enabled) { msleep(100); continue; } mutex.lock(); if (last_data.isEmpty()) { mutex.unlock(); msleep(10); continue; } QVector 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 & 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 data = fbo.getPointsFloat(); mutex.lock(); last_data = data; mutex.unlock(); } fbomm.create(); fbo.queryPoints(0, fbo.rect(), GL_FLOAT); //renderSum(fbomm.plane(fbomm.lastLevel()), 0); return true; } float TonemappingProc::frameMax() { if (!enabled) return 1.f; return cur_max; }