This repository has been archived on 2020-09-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
libs/qglengine/qglview.cpp

517 lines
14 KiB
C++

/*
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 <http://www.gnu.org/licenses/>.
*/
#include "qglview.h"
#include "glmesh.h"
#include "gltexture_manager.h"
#include <chunkstream.h>
#include <qad_types.h>
#include <QApplication>
#include <QOpenGLTexture>
#include <QKeyEvent>
using namespace QGLEngineShaders;
QGLView::QGLView(): OpenGLWindow(), renderer_(this) {
setIcon(QIcon(":/icons/qglview.png"));
deleting_ = false;
timer = 0;
app_scale = 1;
cur_handle = RendererService::htNoHandle;
need_init_ = is_first_draw = true;
backColor_ = Qt::darkGray;
hoverHaloColor_ = QColor(195, 140, 255);
selectionHaloColor_ = QColor(175, 255, 140);
ambientColor_ = QColor(10, 10, 10);
lastPos = QPoint(-1, -1);
lineWidth_ = 1.;
max_anisotropic = 1;
max_texture_chanels = 8;
cameraOrbit_ = lightEnabled_ = canSelect_ = true;
shaders_supported = selecting_ = customMouseMove_ = false;
sel_button = Qt::LeftButton;
sel_mod = Qt::ControlModifier;
fps_cnt = 0;
fps_tm = fps_ = 0.;
fogDensity_ = fogEnd_ = 1.;
fogStart_ = 0.;
hoverHaloFill_ = selectionHaloFill_ = 0.15f;
//lmode = Simple;
setFeature(qglFXAA, false);
setFeature(qglAnisotropicLevel, 8);
setFeature(qglEyeAccomodationEnabled, false);
setFeature(qglEyeAccomodationTime, 16.);
setFeature(qglEyeAccomodationMaxSpeed, 0.2);
setFeature(qglBloomEnabled, false);
setFeature(qglBloomThreshold, 0.9);
setFeature(qglBloomFactor, 1.);
setFeature(qglBloomRadius, 8);
setFeature(qglMotionBlurEnabled, false);
setFeature(qglMotionBlurFactor, 1.);
setFeature(qglMotionBlurSteps, 8);
setFeature(qglShadowsEnabled, false);
setFeature(qglShadowsMapSize, 512);
setFeature(qglShadowsSoftEnabled, true);
setFeature(qglReflectionsEnabled, false);
setFeature(qglReflectionsBlur, true);
setFeature(qglSSAOEnabled, false);
setFeature(qglSSAORadius, 5);
setFeature(qglDepthOfFieldEnabled, false);
setFeature(qglDepthOfFieldAutoFocusEnabled, true);
setFeature(qglDepthOfFieldAutoFocusSpeed, 0.1);
setFeature(qglDepthOfFieldFocus, 1.);
setFeature(qglDepthOfFieldDiaphragm, 8.);
mouse_first = mouseSelect_ = hoverHalo_ = selectionHalo_ = true;
mouseRotate_ = true;
fogEnabled_ = is_init = grabMouse_ = shaders_bind = changed_ = false;
rmode = ObjectBase::Fill;
// sel_pen = QPen(Qt::black, 1, Qt::DashLine);
// sel_brush = QBrush(QColor(170, 100, 255, 120));
scene_ = new Scene();
connect(scene_, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
connect(scene_, SIGNAL(__destroyed()), this, SLOT(__destroyed()));
camera_ = new Camera();
camera_->setAim(QVector3D());
camera_->setPos(QVector3D(2, 2, 2));
camera_->setName("Camera");
emit cameraPosChanged(camera_->pos());
//camera().aim_ = camera().pos_;
ktm_.restart();
Mesh * m = Primitive::torus(30, 12, 1., 0.1);
ObjectBase * o = new ObjectBase(m);
o->setColor(Qt::cyan);
scene()->addObject(o);
delete m;
}
QGLView::~QGLView() {
deleting_ = true;
stop();
scene_->destroy();
delete scene_;
}
void QGLView::stop() {
if (timer) killTimer(timer);
}
void QGLView::start(float freq) {
timer = startTimer(freq <= 0.f ? 0 : int(1000.f / freq));
}
Scene::SelectionMode QGLView::selectionMode() const {
return scene_->selectionMode();
}
void QGLView::setSelectionMode(Scene::SelectionMode m) {
scene_->setSelectionMode(m);
}
void QGLView::selectObject(ObjectBase * o, bool add_to_selection) {
scene_->selectObject(o, add_to_selection);
}
void QGLView::clearSelection() {
scene_->clearSelection();
}
QList<ObjectBase * > QGLView::selectedObjects() const {
return scene_->selectedObjects();
}
ObjectBase * QGLView::selectedObject() const {
return scene_->selectedObject();
}
void QGLView::resizeEvent(QResizeEvent * e) {
renderLater();
app_scale = appScale();
}
void QGLView::timerEvent(QTimerEvent *) {
renderNow();
//if (ktm_.elapsed() < QApplication::keyboardInputInterval()) return;
Qt::KeyboardModifiers km = QApplication::keyboardModifiers();
foreach (int i, keys_)
emit keyEvent((Qt::Key)i, km);
}
void QGLView::render() {
resizeGL(width(), height());
emit glBeginPaint();
renderer_.mouse_pos = mapFromGlobal(QCursor::pos());
renderer_.renderScene();
emit glPainting();
emit glEndPaint();
fps_tm += time.elapsed();
time.restart();
fps_cnt++;
if (fps_tm < 1000.) return;
fps_ = fps_cnt / fps_tm * 1000.;
fps_tm = 0.;
fps_cnt = 0;
}
void QGLView::initialize() {
checkCaps();
renderer_.reloadShaders();
renderer_.init(width(), height());
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_MULTISAMPLE);
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_MAX_ANISOTROPY_EXT);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
is_init = true;
need_init_ = false;
emit glInitializeDone();
}
void QGLView::checkCaps() {
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropic);
shaders_supported = QOpenGLShaderProgram::hasOpenGLShaderPrograms();
}
void QGLView::__destroyed() {
renderer_.rend_mat.mat_thumbnails.clear();
hov_objects.clear();
}
void QGLView::resizeGL(int width, int height) {
if (!is_init) return;
if (width <= 0 || height <= 0) return;
if (prev_size == QSize(width, height)) return;
prev_size = QSize(width, height);
aspect = float(width) / float(height);
renderer_.resize(width, height);
mouse_first = true;
//qDebug() << "resize" << width << height;
iaspect = (aspect == 0.f) ? 0. : 1 / aspect;
glViewport(0, 0, width, height);
emit glResize(width, height);
}
void QGLView::mouseReleaseEvent(QMouseEvent * e) {
if (cur_handle != RendererService::htNoHandle) {
mouseMoveEvent(e);
return;
}
bool add_ts = e->modifiers().testFlag(sel_mod);
if (selecting_) {
selecting_ = false;
canSelect_ = true;
renderer_.mouse_rect = QRect();
scene_->selectObjects(hov_objects.toList(), add_ts);
return;
}
if (canSelect_ && mouseSelect_ && e->button() == Qt::LeftButton) {
if ((lastPos - downPos).manhattanLength() < QApplication::startDragDistance() && !hov_objects.isEmpty()) {
scene_->selectObject(hov_objects[0], add_ts);
}
}
canSelect_ = e->buttons() == 0;
emit glMouseReleaseEvent(e);
}
void QGLView::mousePressEvent(QMouseEvent * e) {
if (cur_handle != RendererService::htNoHandle && e->buttons() == Qt::LeftButton) {
return;
}
if (selecting_) {
downPos = e->pos();
selecting_ = false;
renderer_.mouse_rect = QRect();
return;
}
if (!QRect(QPoint(), size()).contains(e->pos())) return;
lastPos = e->pos();
downPos = lastPos;
emit glMousePressEvent(e);
}
void QGLView::mouseMoveEvent(QMouseEvent * e) {
QPoint cpos = e->pos();
if (cur_handle != RendererService::htNoHandle && (e->buttons() == Qt::LeftButton)) {
RendererService & rs(renderer_.rend_service);
QList<ObjectBase*> objects = scene()->selectedObjects(true);
int axis = cur_handle;
if (cur_handle >= RendererService::htMoveX && cur_handle <= RendererService::htMoveZ ) axis -= RendererService::htMoveX;
if (cur_handle >= RendererService::htRotateX && cur_handle <= RendererService::htRotateZ) axis -= RendererService::htRotateX;
if (cur_handle >= RendererService::htScaleX && cur_handle <= RendererService::htScaleZ ) axis -= RendererService::htScaleX;
QVector3D axe_vector; axe_vector[axis] = 1.;
QMatrix4x4 axis_mat = camera()->fullViewMatrix() * rs.axis_mat;
QVector3D center_screen = axis_mat * rs.selection_center;
QVector3D axe_screen = ((axis_mat * (rs.selection_center + axe_vector)) - center_screen).normalized();
QVector3D mouse_vector(cpos - lastPos);
mouse_vector[1] *= -1.;
if (cur_handle >= RendererService::htMoveX && cur_handle <= RendererService::htMoveZ) {
double len_scl = 1. / QVector3D(axe_screen.x(), axe_screen.y(), 1.E-6).length();
mouse_vector /= QVector3D(width(), height(), 1);
mouse_vector *= -center_screen.z() * len_scl;
axe_vector *= QVector3D::dotProduct(axe_screen, mouse_vector);
foreach (ObjectBase * o, objects)
o->move(axe_vector);
}
if (cur_handle >= RendererService::htRotateX && cur_handle <= RendererService::htRotateZ) {
axe_screen.setZ(0.);
axe_screen.normalize();
QVector3D norm = QVector3D(axe_screen.y(), -axe_screen.x(), 0.);
axe_vector *= QVector3D::dotProduct(mouse_vector, norm) / 2. / app_scale;
foreach (ObjectBase * o, objects)
o->setRotation(o->rotation() + axe_vector);
}
if (cur_handle >= RendererService::htScaleX && cur_handle <= RendererService::htScaleZ) {
mouse_vector /= QVector3D(width(), height(), 1);
mouse_vector *= 3. / app_scale;
axe_vector *= QVector3D::dotProduct(axe_screen, mouse_vector);
foreach (ObjectBase * o, objects)
o->scale(QVector3D(1,1,1) + axe_vector);
}
//if (cur_handle >= RendererService::htScaleX && cur_handle <= RendererService::htScaleZ ) cs = Qt::SplitHCursor;
lastPos = e->pos();
return;
}
if (selecting_) {
renderer_.mouse_rect = QRect(downPos, cpos).normalized();
return;
}
if (e->buttons().testFlag(Qt::LeftButton)) {
if ((cpos - downPos).manhattanLength() >= QApplication::startDragDistance()) {
selecting_ = true;
canSelect_ = false;
}
return;
}
QRect g_rect(QPoint(), size());
if (mouseRotate_) {
float dx = e->x() - lastPos.x();
float dy = e->y() - lastPos.y();
if (e->buttons().testFlag(Qt::MidButton)) {
if (cameraOrbit_) {
camera()->orbitZ(dx / 4.f);
camera()->orbitXY(dy / 4.f);
} else {
camera()->rotateZ(dx / 4.f);
camera()->rotateXY(dy / 4.f);
}
emit cameraPosChanged(camera()->pos());
} else if (e->buttons().testFlag(Qt::RightButton)) {
float ad = camera()->distance();
camera()->moveLeft(dx / 1000.f * ad);
camera()->moveUp(dy / 1000.f * ad);
emit cameraPosChanged(camera()->pos());
}
}
lastPos = e->pos();
if (customMouseMove_) emit customMouseMoveEvent(e->pos(), lastPos, e->buttons());
if (e->buttons() == 0) {
cur_handle = RendererService::htNoHandle;
Qt::CursorShape cs = Qt::CrossCursor;
if (renderer_.edit_mode) {
uint hid = renderer_.rend_selection.id_hover;
if (hid >= RendererService::htMoveX && hid <= RendererService::htScaleZ) {
cur_handle = (RendererService::HandleType)hid;
if (hid >= RendererService::htMoveX && hid <= RendererService::htMoveZ ) cs = Qt::SizeAllCursor;
if (hid >= RendererService::htRotateX && hid <= RendererService::htRotateZ) cs = Qt::PointingHandCursor;
if (hid >= RendererService::htScaleX && hid <= RendererService::htScaleZ ) cs = Qt::SplitHCursor;
}
}
setCursor(cs);
}
if (grabMouse_) {
QCursor::setPos(mapToGlobal(QRect(QPoint(), size()).center()));
static bool mouse_sec = false;
if (mouse_sec) {
mouse_sec = false;
return;
}
if (mouse_first) {
mouse_first = false;
mouse_sec = true;
return;
}
lastPos = g_rect.center();
int dx = e->x() - lastPos.x();
int dy = e->y() - lastPos.y();
emit glMouseMoveEvent(new QMouseEvent(QEvent::MouseMove, QPoint(dx, dy), e->button(), e->buttons(), e->modifiers()));
return;
}
emit glMouseMoveEvent(e);
}
void QGLView::wheelEvent(QWheelEvent * e) {
if (mouseRotate_) {
if (e->delta() > 0) camera()->flyCloser(0.1f);
if (e->delta() < 0) camera()->flyFarer(0.1f);
emit cameraPosChanged(camera()->pos());
}
emit glWheelEvent(e);
}
void QGLView::leaveEvent(QEvent * ) {
lastPos = QPoint(-1, -1);
//qDebug() << lastPos;
}
void QGLView::keyPressEvent(QKeyEvent * e) {
emit glKeyPressEvent(e);
if (e->key() > 0) keys_.insert(e->key());
if (e->key() == Qt::Key_F11) {
emit doubleClick();
}
}
void QGLView::keyReleaseEvent(QKeyEvent * e) {
emit glKeyReleaseEvent(e);
keys_.remove(e->key());
}
void QGLView::focusOutEvent(QFocusEvent *) {
keys_.clear();
}
void QGLView::mouseDoubleClickEvent(QMouseEvent * e) {
if (e->buttons().testFlag(Qt::MidButton))
emit doubleClick();
}
Camera * QGLView::camera() {
return camera_;
}
const Camera * QGLView::camera() const {
return camera_;
}
void QGLView::setCamera(Camera * camera) {
camera_ = camera;
}
TextureManager * QGLView::textureManager() {
return renderer_.textures_manager;
}
void QGLView::reloadTextures() {
renderer_.markReloadTextures();
}
void QGLView::focusOn(const Box3D & bb) {
if (bb.isEmpty() || !camera()) return;
double size = qMax(qMax(bb.width, bb.length), bb.height);
camera()->setAim(bb.center());
camera()->flyToDistance(size * 1.25);
}
void QGLView::setCameraLightOn(bool on) {
renderer_.setCameraLightOn(on);
}
bool QGLView::isCameraLightOn() const {
return renderer_.isCameraLightOn();
}
QByteArray QGLView::saveCamera() {
ChunkStream cs;
const Camera * c = camera();
cs.add(1, c->pos()).add(2, c->aim()).add(3, c->angles()).add(4, c->FOV());
return cs.data();
}
void QGLView::restoreCamera(const QByteArray & ba) {
if (ba.isEmpty()) return;
Camera * c = camera();
QVector3D pos(c->pos()), aim(c->aim()), ang(c->angles());
float fov(c->FOV());
ChunkStream cs(ba);
cs.readAll();
cs.get(1, pos).get(2, aim).get(3, ang).get(4, fov);
camera()->setPos(pos);
camera()->setAim(aim);
camera()->setAngles(ang);
camera()->setFOV(fov);
}
QByteArray QGLView::saveFeatures() {
QByteArray ba;
QDataStream ds(&ba, QIODevice::WriteOnly);
ds << features_;
return ba;
}
void QGLView::restoreFeatures(const QByteArray & ba) {
QHash<int, QVariant> f;
QDataStream ds(ba);
ds >> f;
features_ = f;
}
QImage QGLView::materialThumbnail(Material * m) {
return renderer_.materialThumbnail(m);
}
void QGLView::setCurrentHadle(RendererService::HandleType ht) {
renderer_.rend_service.setCurrentHadle(ht);
}