/* QGLView 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 . */ #include "qglview.h" #include #include QGLView::QGLView(): OpenGLWindow(), fbo_selection(3) { // setFrameShape(QFrame::NoFrame); // setViewportUpdateMode(FullViewportUpdate); // setCacheMode(CacheNone); // setMouseTracking(true); // setFocusPolicy(Qt::WheelFocus); // setScene(new QGraphicsScene()); // setInteractive(true); setIcon(QIcon("://icons/qglview.png")); deleting_ = false; timer = 0; need_init_ = is_first_draw = true; objects_.is_root = true; objects_.view_ = this; backColor_ = Qt::darkGray; hoverHaloColor_ = QColor(195, 140, 255, 96); 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_ = true; shaders_supported = selecting_ = customMouseMove_ = false; sel_button = Qt::LeftButton; sel_mod = Qt::NoModifier; renderer_ = nullptr; fps_cnt = 0; fps_tm = fps_ = 0.; sel_obj = hov_obj = nullptr; fogDensity_ = fogEnd_ = 1.; fogStart_ = 0.; fogMode_ = Exp; hoverHaloFill_ = 0.333f; selectionHaloFill_ = 0.5f; //lmode = Simple; shader_select = shader_halo = nullptr; setFeature(qglMSAA, false); setFeature(qglFXAA, false); setFeature(qglLinearFiltering, true); setFeature(qglAnisotropicLevel, 8); setFeature(qglHDR, false); 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 = GLObjectBase::Fill; sel_mode = QGLView::SingleSelection; // sel_pen = QPen(Qt::black, 1, Qt::DashLine); // sel_brush = QBrush(QColor(170, 100, 255, 120)); camera()->setAim(QVector3D()); camera()->setPos(QVector3D(2, 2, 2)); camera()->setName("Camera"); addObject(camera()); emit cameraPosChanged(camera()->pos()); //camera().aim_ = camera().pos_; ktm_.restart(); } QGLView::~QGLView() { stop(); if (shader_select) delete shader_select; if (shader_halo) delete shader_halo; deleting_ = true; } void QGLView::stop() { if (timer) killTimer(timer); timer = 0; } void QGLView::start(float freq) { stop(); timer = startTimer(freq <= 0.f ? 0 : int(1000.f / freq)); } GLRendererBase * QGLView::renderer() { return renderer_; } void QGLView::setRenderer(GLRendererBase * r, GLRendererBase ** prev) { if (prev != nullptr) *prev = renderer_; renderer_ = r; } void QGLView::addObject(GLObjectBase * o) { objects_.addChild(o); o->setView(this); collectLights(); QList cl = o->children(true); cl << o; foreach (GLObjectBase * i, cl) { emit objectAdded(i); } if (is_init) { o->init(); } } int QGLView::objectsCount(bool all) { if (!all) return objects_.childCount(); int cnt = 0; objectsCountInternal(&cnt, &objects_); return cnt; } void QGLView::removeObject(GLObjectBase * o, bool inChildren) { o->setView(nullptr); if (inChildren) removeObjectInternal(o, &objects_); else objects_.removeChild(o); objectDeleted(o); } void QGLView::removeObject(GLObjectBase & o, bool inChildren) { removeObject(&o, inChildren); } void QGLView::clearObjects(bool deleteAll) { removeObject(camera_); objects_.clearChildren(deleteAll); addObject(camera()); selectObject(nullptr); hov_obj = nullptr; } QList QGLView::objects(bool all) { return objects_.children(all); } int QGLView::lightsCount() const { return lights_.size(); } void QGLView::removeLight(int index) { removeObject(lights_.at(index)); lights_.removeAt(index); } void QGLView::removeLight(Light * l) { foreach (Light * i, lights_) if (i == l) removeObject(i); lights_.removeAll(l); } void QGLView::clearLights(bool deleteAll) { if (deleteAll) foreach (Light * i, lights_) delete i; lights_.clear(); } void QGLView::addTexture(const QString & path) { textures_manager->addTexture(path); } void QGLView::addAnimation(const QString & dir, const QString & name) { textures_manager->addAnimation(dir, name); } Light * QGLView::light(int index) { return lights_[index]; } Light * QGLView::light(const QString & name) { foreach (Light * i, lights_) if (i->name_ == name) return i; return nullptr; } void QGLView::selectObject(GLObjectBase * o) { if (o == sel_obj) return; GLObjectBase * pso = sel_obj; sel_obj = o; emit selectionChanged(sel_obj, pso); } void QGLView::resizeEvent(QResizeEvent * e) { renderLater(); } 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() { if (!isVisible()) return; resizeGL(width(), height()); QRect g_rect(QPoint(), size()); emit glBeforePaint(); //qDebug() << "paintGL"; //QMutexLocker ml_v(&v_mutex); glEnable(GL_CULL_FACE); //glDisable(GL_CULL_FACE); camera()->apply(aspect); //objects_.preparePos(camera()); start_rp.cam_offset_matrix = camera()->offsetMatrix(); start_rp.proj_matrix = getGLMatrix(GL_PROJECTION_MATRIX); start_rp.view_matrix = getGLMatrix(GL_MODELVIEW_MATRIX); //objects_.buildTransform(); /// Selection detect //glClearFramebuffer(QColor(100, 0, 0, 0)); if (mouseSelect_) { glReleaseTextures(); glEnableDepth(); glDisable(GL_TEXTURE_1D); glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_CUBE_MAP); glDisable(GL_MULTISAMPLE); glDisable(GL_LIGHTING); glDisable(GL_BLEND); glDisable(GL_ALPHA_TEST); glDisable(GL_RESCALE_NORMAL); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); fbo_selection.bind(); fbo_selection.setWriteBuffer(0); glClearFramebuffer(QColor(0, 0, 0, 0)); if (shaders_supported && shader_select->isLinked()) shader_select->bind(); renderSelection(); if (shaders_supported && shader_select->isLinked()) shader_select->release(); uchar cgid[4] = {0, 0, 0, 0}; uint iid = 0; GLObjectBase * so = nullptr; if (!g_rect.contains(lastPos)) { if (hov_obj != nullptr) { hov_obj = nullptr; emit hoverChanged(nullptr, hov_obj); } } else { glReadPixels(lastPos.x(), height() - lastPos.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, cgid); iid = uint(cgid[0] << 24) | uint(cgid[1] << 16) | uint(cgid[2] << 8) | cgid[3]; so = ids.value(iid, nullptr); //qDebug() <name() << cgid[3]; } if (selectionHalo_ && sel_obj) { fbo_selection.setWriteBuffer(2); renderHalo(sel_obj, qHash((quint64)sel_obj), selectionHaloColor_, selectionHaloFill_); } if (hoverHalo_ && hov_obj) { fbo_selection.setWriteBuffer(1); renderHalo(hov_obj, iid, hoverHaloColor_, hoverHaloFill_); } fbo_selection.release(); glEnableDepth(); /*glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY);*/ } camera()->apply(aspect); start_rp.cam_offset_matrix = camera()->offsetMatrix(); cur_mvpm = start_rp.proj_matrix * start_rp.view_matrix * start_rp.cam_offset_matrix; //objects_.preparePos(camera()); static GLRendererBase * prev_rend = nullptr; glShadeModel(GL_SMOOTH); if (prev_rend != renderer_) { prev_rend = renderer_; if (renderer_ != nullptr) { renderer_->init(width(), height()); renderer_->resize(width(), height()); renderer_->reloadShaders(); } } emit glBeginPaint(); if (renderer_ != nullptr) { renderer_->rp.prepare(); renderer_->prepareScene(); renderer_->renderScene(); } emit glPainting(); glUseProgram(0); if (selectionHalo_ || hoverHalo_) { glReleaseTextures(); glBindFramebuffer(GL_FRAMEBUFFER, 0); //glClearFramebuffer(Qt::black, false); glActiveTexture(GL_TEXTURE0); glEnable(GL_BLEND); glDisable(GL_TEXTURE_CUBE_MAP); glDisable(GL_LIGHTING); glDisableDepth(); glBlendFunc(GL_SRC_ALPHA, GL_ONE); if (selectionHalo_ && sel_obj) { glBindTexture(GL_TEXTURE_2D, fbo_selection.colorTexture(2)); //qDebug() << "draw sel"; glDrawQuad(); } if (hoverHalo_ && hov_obj) { glBindTexture(GL_TEXTURE_2D, fbo_selection.colorTexture(1)); //qDebug() << "draw hover"; //glBindTexture(GL_TEXTURE_2D, textures_manager->loadTexture("batt_pn.jpg")); glDrawQuad(); } } glResetAllTransforms(); glBindFramebuffer(GL_FRAMEBUFFER, 0); glUseProgram(0); //glDisable(GL_BLEND); //glDisable(GL_LIGHTING); //glActiveTexture(GL_TEXTURE0); //glBindTexture(GL_TEXTURE_2D, textures_manager->loadTexture("batt_pn.jpg")); //glDrawQuad(); emit glEndPaint(); /*releaseShaders(); glActiveTextureChannel(0); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.3, 0.5, 0.8, 0.5); glResetAllTransforms(); glBegin(GL_QUADS); glTexCoord2f(0.f, 0.f); glVertex2f(-1.f, -1.f); glTexCoord2f(1.f, 0.f); glVertex2f(1.f, -1.); glTexCoord2f(1.f, 1.f); glVertex2f(1.f, 1.f); glTexCoord2f(0.f, 1.f); glVertex2f(-1.f, 1.f); glEnd();*/ /* glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_LIGHTING); glActiveTextureChannel(0); glBindTexture(GL_TEXTURE_2D, fbo->texture()); glDisable(GL_DEPTH_TEST); glBegin(GL_QUADS); glColor3f(1.f, 1.f, 1.f); glTexCoord2f(0.f, 0.f); glVertex2f(-1.f, -1.f); glTexCoord2f(0.f, 1.f); glVertex2f(-1.f, 1.f); glTexCoord2f(1.f, 1.f); glVertex2f(1.f, 1.f); glTexCoord2f(1.f, 0.f); glVertex2f(1.f, -1.); glEnd(); glEnable(GL_DEPTH_TEST);*/ 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() { //initializeOpenGLFunctions(); glEnable(GL_TEXTURE_MAX_ANISOTROPY_EXT); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glEnableDepth(); glEnable(GL_CULL_FACE); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); glActiveTexture(GL_TEXTURE0 + 3); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glActiveTexture(GL_TEXTURE0); glShadeModel(GL_SMOOTH); glCullFace(GL_BACK); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_DIFFUSE); textures_manager->loadTextures(); objects_.initInternal(); checkCaps(); shader_select = new QOpenGLShaderProgram(context()); shader_halo = new QOpenGLShaderProgram(context()); reloadThisShaders(); is_init = true; //resizeGL(width(), height()); need_init_ = false; emit glInitializeDone(); } void QGLView::renderHalo(const GLObjectBase * obj, const uint iid, const QColor & color, const float & fill) { if (!shaders_supported) return; if (!shader_halo) return; if (!shader_halo->isLinked()) return; if (obj) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, fbo_selection.colorTexture()); shader_halo->bind(); shader_halo->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4()); shader_halo->setUniformValue("t0", 0); shader_halo->setUniformValue("dt", QVector2D(1.f / width(), 1.f / height())); shader_halo->setUniformValue("selected", QVector4D(float((iid >> 24) & 0xFF) / 255.f, float((iid >> 16) & 0xFF) / 255.f, float((iid >> 8) & 0xFF) / 255.f, float( iid & 0xFF) / 255.f)); shader_halo->setUniformValue("color", color); shader_halo->setUniformValue("fill", GLfloat(fill)); //qDebug() << "render halo" << iid << shader_halo->log() << shader_halo->programId(); glDisableDepth(); //glClearFramebuffer(color); glDrawQuad(shader_halo); glDepthMask(GL_TRUE); //glFlush(); shader_halo->release(); } else { glClearFramebuffer(Qt::black, false); } } void QGLView::renderSelection() { // cid = 1; ids.clear(); if (shaders_supported) { if (shader_select) { if (shader_select->isLinked()) { sh_id_loc = shader_select->uniformLocation("id"); shader_select->setUniformValue("z_far", GLfloat(depthEnd())); shader_select->setUniformValue("z_near", GLfloat(depthStart())); } } } //qDebug() << sh_id_loc; start_rp.view_matrix = getGLMatrix(GL_MODELVIEW_MATRIX); glPushMatrix(); renderSingleSelection(objects_); glPopMatrix(); } void QGLView::renderSingleSelection(GLObjectBase & o) { if (!o.isInit()) { o.init(); o.loadTextures(); } if (!o.visible_ || !o.select_) return; QMatrix4x4 curview = start_rp.view_matrix * start_rp.cam_offset_matrix * o.itransform_; uint id = qHash((quint64)&o); ids.insert(id, &o); glLineWidth(o.line_width > 0.f ? o.line_width : lineWidth_); glPointSize(o.line_width > 0.f ? o.line_width : lineWidth_); if (shaders_supported){ if (shader_select) { if (shader_select->isLinked()) { setUniformMatrices(shader_select, start_rp.proj_matrix, curview); shader_select->setUniformValue(sh_id_loc, QVector4D(float((id >> 24) & 0xFF) / 255.f, float((id >> 16) & 0xFF) / 255.f, float((id >> 8) & 0xFF) / 255.f, float(id & 0xFF) / 255.f)); } } } else { setGLMatrix(curview); glColor4f(float((id >> 24) & 0xFF) / 255.f, float((id >> 16) & 0xFF) / 255.f, float((id >> 8) & 0xFF) / 255.f, float(id & 0xFF) / 255.f); } //qDebug() << o.name() << "assign to" << sh_id_loc << cid; //glColor4f(float((cid >> 24) & 0xFF) / 255.f, float((cid >> 16) & 0xFF) / 255.f, float((cid >> 8) & 0xFF) / 255.f, float(cid & 0xFF) / 255.f); // ++cid; o.draw(nullptr, true); foreach (GLObjectBase * i, o.children_) renderSingleSelection(*i); } void QGLView::collectLights() { lights_.clear(); collectObjectLights(&objects_); } void QGLView::objectDeleted(GLObjectBase * o) { if (deleting_) return; //qDebug() << "del" << o; if (sel_obj == o) selectObject(nullptr); if (hov_obj == o) hov_obj = nullptr; collectLights(); } void QGLView::collectObjectLights(GLObjectBase * o) { if (o->type_ == GLObjectBase::glLight) { lights_ << globject_cast(o); o->view_ = this; } foreach (GLObjectBase * i, o->children()) collectObjectLights(i); } void QGLView::objectsCountInternal(int * cnt, GLObjectBase * where) { ++(*cnt); foreach (GLObjectBase * i, where->children_) objectsCountInternal(cnt, i); } void QGLView::removeObjectInternal(GLObjectBase * o, GLObjectBase * where) { foreach (GLObjectBase * i, where->children_) { if (o == i) where->removeChild(i); else removeObjectInternal(o, i); objectDeleted(i); } } void QGLView::checkCaps() { glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropic); //glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_chanels); //qDebug() << max_texture_chanels; //qDebug() << max_texture_chanels; shaders_supported = QOpenGLShaderProgram::hasOpenGLShaderPrograms(); } void QGLView::reloadThisShaders() { if (!shaders_supported) return; loadShaders(shader_select, "selection", "://shaders"); loadShaders(shader_halo, "selection_halo", "://shaders"); //loadShaders(shader_rope, "rope", "://shaders"); } void QGLView::glReleaseTextures(int channels) { for (int i = channels - 1; i >= 0; --i) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } } void QGLView::applyFog() { GLfloat fog_col[4] = {float(fogColor_.redF()), float(fogColor_.greenF()), float(fogColor_.blueF()), .0f}; if (fogEnabled_) { glEnable(GL_FOG); glFogf(GL_FOG_DENSITY, fogDensity_); glFogf(GL_FOG_START, fogStart_); glFogf(GL_FOG_END, fogEnd_); glFogi(GL_FOG_MODE, fogMode_); fog_col[0] = fogColor_.redF(); fog_col[1] = fogColor_.greenF(); fog_col[2] = fogColor_.blueF(); glFogfv(GL_FOG_COLOR, fog_col); } else glDisable(GL_FOG); } 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); if (renderer_) renderer_->resize(width, height); mouse_first = true; //qDebug() << "resize" << width << height; fbo_selection.resize(width, height); iaspect = (aspect == 0.f) ? 0. : 1 / aspect; glViewport(0, 0, width, height); emit glResize(width, height); } void QGLView::mouseReleaseEvent(QMouseEvent * e) { // qDebug() << "mouseReleaseEvent" << e << isActive(); // QGraphicsView::mouseReleaseEvent(e); //setCursor(QCursor(Qt::ArrowCursor)); selecting_ = false; if (mouseSelect_ && e->button() == Qt::LeftButton) { if ((lastPos - downPos).manhattanLength() < 8) { if (sel_obj != hov_obj) selectObject(hov_obj); } } emit glMouseReleaseEvent(e); } void QGLView::mousePressEvent(QMouseEvent * e) { // qDebug() << "mousePressEvent" << e << isActive(); // QGraphicsView::mousePressEvent(e); // mouseThis_ = (scene()->itemAt(mapToScene(e->pos()) , QTransform() ) == 0); selecting_ = false; if (!QRect(QPoint(), size()).contains(e->pos())) return; /// TODO select by rect //if (e->button() == sel_button && e->modifiers() == sel_mod) // selecting_ = true; lastPos = e->pos(); downPos = lastPos; //qDebug() << mouseThis_; emit glMousePressEvent(e); } void QGLView::mouseMoveEvent(QMouseEvent * e) { // qDebug() << "mouseMoveEvent" << e << isActive(); // QGraphicsView::mouseMoveEvent(e); //lastPos = e->pos(); if (selecting_) { return; } // if (!QRect(QPoint(), size()).contains(e->pos())) return; //if (scene()->itemAt(mapToScene(e->pos())) != 0) return; ///qDebug() << e->x() << e->y(); QRect g_rect(QPoint(), size()); if (mouseRotate_) { float dx = e->x() - lastPos.x(); float dy = e->y() - lastPos.y(); if (e->buttons() & Qt::LeftButton) { //camera().angle_z += dx / 4.; //camera().angle_xy += dy / 4.; 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() & Qt::RightButton) { float ad = camera()->distance(); camera()->moveLeft(dx / 1000.f * ad); camera()->moveUp(dy / 1000.f * ad); //camera().pos.setX(camera().pos.x() + camera().pos.z() * dx / 500.); //camera().pos.setY(camera().pos.y() - camera().pos.z() * dy / 500.); emit cameraPosChanged(camera()->pos()); } //lights[0]->pos_ = camera().pos(); } if (customMouseMove_) emit customMouseMoveEvent(e->pos(), lastPos, e->buttons()); lastPos = e->pos(); if (grabMouse_) { //if (!isrunning) return; 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; //qDebug() << "first" << e->pos(); 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); //camera().pos.setZ(camera().pos.z() - 0.1 * camera().pos.z()); if (e->delta() < 0) camera()->flyFarer(0.1f); //camera().pos.setZ(camera().pos.z() + 0.1 * camera().pos.z()); 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(); } QByteArray QGLView::saveCamera() { ChunkStream cs; const Camera * c = camera(); cs.add(1, c->posX()); cs.add(2, c->posY()); cs.add(3, c->posZ()); cs.add(4, c->aim().x()); cs.add(5, c->aim().y()); cs.add(6, c->aim().z()); cs.add(7, c->angleZ()); cs.add(8, c->angleXY()); cs.add(9, c->angleRoll()); cs.add(10, c->FOV()); return cs.data(); } void QGLView::restoreCamera(const QByteArray &ba) { if (ba.isEmpty()) return; ChunkStream cs(ba); QVector3D pos, aim, ang; while (!cs.atEnd()) { switch (cs.read()) { case 1: pos.setX(cs.getData()); break; case 2: pos.setY(cs.getData()); break; case 3: pos.setZ(cs.getData()); break; case 4: aim.setX(cs.getData()); break; case 5: aim.setY(cs.getData()); break; case 6: aim.setZ(cs.getData()); break; case 7: ang.setZ(cs.getData()); break; case 8: ang.setY(cs.getData()); break; case 9: ang.setX(cs.getData()); break; case 10: setFOV(cs.getData()); break; default: break; } } camera()->setPos(pos); camera()->setAim(aim); camera()->setAngles(ang); } QByteArray QGLView::saveFeatures() { QByteArray ba; QDataStream ds(&ba, QIODevice::WriteOnly); ds << features_; return ba; } void QGLView::restoreFeatures(const QByteArray & ba) { QHash f; QDataStream ds(ba); ds >> f; features_ = f; }