/* 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 . */ #define GL_GLEXT_PROTOTYPES #include "renderer_selection.h" #include "glmesh.h" #include "qglview.h" #include #include 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 passes = scene.geometries_used.keys(); foreach(int p, passes) { QMapIterator 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> 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 points = fbo_selection.getPointsByte(); QSet 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() << 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(); } } }