187 lines
4.6 KiB
C++
187 lines
4.6 KiB
C++
/*
|
|
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 <QOpenGLExtraFunctions>
|
|
#include "tonemapping_proc.h"
|
|
#include "qglview.h"
|
|
#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::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() {
|
|
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;
|
|
}
|