/* 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 . */ #define GL_GLEXT_PROTOTYPES #include #include "renderer_service.h" #include "renderer.h" #include "qglview.h" #include "glmesh.h" #include using namespace QGLEngineShaders; RendererService::RendererService(Renderer * r_): r(r_) { line_width = 1; current_action = haNoAction; current_handle = 0; 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) { 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 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 & lv (line_mesh->vertices ()); QVector & ln (line_mesh->normals ()); QVector & 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 & mats, const QVector & 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]->selected_aim) 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 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 mv; mv.resize(1); QVector 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 & 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)) { //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 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); //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } 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; }