/* QGLView Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU 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_handle = htNoHandle; mat_xyz.resize(3); color_xyz.resize(3); const QVector3D _rot[3] = {QVector3D(0,1,0), QVector3D(-1,0,0), QVector3D(0,0,1)}; for (int i = 0; i < 3; ++i) { QMatrix4x4 m; m.rotate(90., _rot[i]); mat_xyz[i] = m; color_xyz[i] = QVector4D(0,0,0,1); color_xyz[i][i] = 1.; } 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(); box_mesh_f = Primitive::cubeFrame(); omni_mesh = Primitive::ellipsoid(2, 1); omni_mesh_f = Primitive::ellipsoidFrame(2, 1); omni_mesh ->scalePoints(1.5); omni_mesh_f->scalePoints(1.5); box_mesh ->scalePoints(1.3); omni_mesh ->scalePoints(1.3); handle_move_mesh = Primitive::arrow(12, 0.06); handle_rotate_mesh = Primitive::arrow(12, 0.03); Mesh * 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.06, 0.06, 0.85); m = Primitive::ellipsoid(12, 12, 0.3, 0.3, 0.3); m->translatePoints(QVector3D(0., 0., 0.85)); handle_scale_mesh->append(m); delete m; handle_move_mesh ->scalePoints(7.5); handle_rotate_mesh->scalePoints(7.5); handle_scale_mesh ->scalePoints(7.5); } RendererService::~RendererService() { delete box_mesh; delete box_mesh_f; delete omni_mesh; delete omni_mesh_f; delete axis_camera; delete axis_mesh; delete handle_move_mesh; delete handle_rotate_mesh; delete handle_scale_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) { QVector4D pos = QVector4D(p, 1.); double dist = -(v_mat * pos).z(); QMatrix4x4 m; m.translate(pos.toVector3D()); m.scale(dist * size_full_scale); return m; } 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; 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::fillHandleObjects(QVector3D center, HandleType first, QMatrix4x4 add_mat) { cur_objects.resize(3); for (int i = 0; i < 3; ++i) { cur_objects[i].color = color_xyz[i]; QMatrix4x4 m = invariantSizeMatrix(center); m = m * add_mat * mat_xyz[i]; cur_objects[i].object_id = first + i; m.transposed().copyDataTo(cur_objects[i].modelmatrix); } } bool RendererService::fillCurrentHandleObjects() { QList sol = r->view->scene()->selectedObjects(true); if (sol.isEmpty()) return false; selection_center = QVector3D(); Box3D bb; foreach (ObjectBase * o, sol) { o->calculateBoundingBox(); bb |= o->boundingBox(); } if (bb.isEmpty()) selection_center = sol[0]->worldPos(); else selection_center = bb.center(); QMatrix4x4 rm; if ((sol.size() == 1) && (current_handle >= htRotateX)) { rm.rotate(sol[0]->angles_.z(), 0., 0., 1.); rm.rotate(sol[0]->angles_.y(), 0., 1., 0.); rm.rotate(sol[0]->angles_.x(), 1., 0., 0.); } fillHandleObjects(selection_center, current_handle, rm); return true; } 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); if (r->bindShader(Renderer::srServiceFrame, &prog)) { prog->setUniformValue("qgl_ProjMatrix", r->view->camera()->projectionMatrix(r->view->aspect)); /// lights //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_CULL_FACE); r->setUniformCamera(prog, r->view->camera()); fillOmniObjects(); setObjectsColor(cur_objects, Qt::white); prog->setUniformValue("line_width", 2.f); prog->setUniformValue("z_offset", 0.f); omni_mesh_f->loadObjects(f, cur_objects); omni_mesh_f->draw(f, cur_objects.size()); setObjectsColor(cur_objects, Qt::black); prog->setUniformValue("line_width", 1.f); prog->setUniformValue("z_offset", -1.E-3f); omni_mesh_f->loadObjects(f, cur_objects); omni_mesh_f->draw(f, cur_objects.size()); glEnable(GL_CULL_FACE); //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } if (r->bindShader(Renderer::srServiceFill, &prog)) { r->setUniformCamera(prog, r->view->camera()); /// handles if (fillCurrentHandleObjects()) { Mesh * hm = currentHandleMesh(); if (hm) { hm->loadObjects(r->view, cur_objects); hm->draw(f, 3); } } /// axis f->glViewport(0, 0, axis_viewport.width(), axis_viewport.height()); axis_camera->setPos(-r->view->camera()->direction() * 3.); 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_handle) { case htMoveX : case htMoveY : case htMoveZ : return handle_move_mesh; case htRotateX: case htRotateY: case htRotateZ: return handle_rotate_mesh; case htScaleX : case htScaleY : case htScaleZ : return handle_scale_mesh; default: break; } return 0; }