/*
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 "renderer_service.h"
#include "glmesh.h"
#include "qglview.h"
#include "renderer.h"
#include
#include
using namespace QGLEngineShaders;
RendererService::RendererService(Renderer * r_): r(r_) {
line_width = 1;
current_action = haNoAction;
current_handle = QFlags();
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) {
box_mesh->reinit();
box_mesh_f->reinit();
omni_mesh->reinit();
omni_mesh_f->reinit();
cone_mesh->reinit();
cone_mesh_f->reinit();
camera_mesh->reinit();
camera_mesh_f->reinit();
line_spot_f->reinit();
line_camera_f->reinit();
axis_mesh->reinit();
handle_move_mesh->reinit();
handle_ms_2_mesh->reinit();
handle_rotate_mesh->reinit();
handle_scale_mesh->reinit();
handle_scale_3_mesh->reinit();
axis_mesh->reinit();
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 & 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]->isAimSelected()) 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