//=============================================================================
//
// OpenFlipper
// Copyright (C) 2008 by Computer Graphics Group, RWTH Aachen
// www.openflipper.org
//
//-----------------------------------------------------------------------------
//
// License
//
// OpenFlipper 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.
//
// OpenFlipper 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 OpenFlipper. If not, see .
//
//-----------------------------------------------------------------------------
//
// $Revision: 4430 $
// $Author: moebius $
// $Date: 2009-01-23 17:14:32 +0100 (Fr, 23. Jan 2009) $
//
//=============================================================================
//=============================================================================
//
// CLASS QtBaseViewer - IMPLEMENTATION
//
//=============================================================================
//== INCLUDES =================================================================
#include "QtBaseViewer.hh"
#include "QtGLGraphicsScene.hh"
#include "QtGLGraphicsView.hh"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "move.xpm"
#include "light.xpm"
#include "info.xpm"
#include "home.xpm"
#include "set_home.xpm"
#include "viewall.xpm"
#include "pick.xpm"
#include "persp.xpm"
#include "ortho.xpm"
#include "scenegraph.xpm"
#include "mono.xpm"
#include "stereo.xpm"
#define homeIcon home_xpm
#define sethomeIcon set_home_xpm
#define moveIcon move_xpm
#define lightIcon light_xpm
#define questionIcon info_xpm
#define viewallIcon viewall_xpm
#define pickIcon pick_xpm
#define perspectiveIcon persp_xpm
#define orthoIcon ortho_xpm
#define sceneGraphIcon scenegraph_xpm
#define monoIcon mono_xpm
#define stereoIcon stereo_xpm
#ifdef max
# undef max
#endif
#ifdef min
# undef min
#endif
//== NAMESPACES ===============================================================
//== IMPLEMENTATION ==========================================================
static const char VIEW_MAGIC[] =
"ACG::QtWidgets::QGLViewerWidget encoded view";
//== IMPLEMENTATION ==========================================================
QtBaseViewer::QtBaseViewer( QWidget* _parent,
const char* /* _name */ ,
QStatusBar *_statusBar,
const QGLFormat* _format,
const QtBaseViewer* _share,
Options _options ) :
QWidget(_parent),
statusbar_(0),
glareaGrabbed_(false),
updateLocked_(false),
projectionUpdateLocked_(false),
blending_(true),
sceneGraphDialog_(0),
options_(_options),
privateStatusBar_(0),
disableKeyHandling_(false),
externalDrag_(false),
snapshotName_("snap.png"),
snapshotCounter_(0),
snapshot_(0),
pick_mode_name_(""),
pick_mode_idx_(-1),
renderPicking_(false),
pickRendererMode_(ACG::SceneGraph::PICK_ANYTHING)
{
// check for OpenGL support
if ( !QGLFormat::hasOpenGL() )
{
std::cerr << "This system has no OpenGL support.\n";
exit(1);
}
// widget stuff
createWidgets(_format,_statusBar,_share);
// bind GL context to GL state class
glstate_ = new ACG::GLState();
// state
orthoWidth_ = 2.0;
isRotating_ = false;
near_ = 0.1;
far_ = 100.0;
fovy_ = 45.0;
focalDist_ = 3.0;
eyeDist_ = 0.01;
sceneGraphRoot_ = 0;
curDrawMode_ = ACG::SceneGraph::DrawModes::NONE;
availDrawModes_ = ACG::SceneGraph::DrawModes::NONE;
normalsMode_ = DONT_TOUCH_NORMALS;
faceOrientation_ = CCW_ORIENTATION;
projectionMode_ = PERSPECTIVE_PROJECTION;
backFaceCulling_ = false;
twoSidedLighting_ = true;
animation_ = false;
light_matrix_.identity();
snapshot_=new QImage;
trackMouse_ = false;
popupEnabled_ = true;
// stereo
stereo_ = false;
pickMenu_ = 0;
funcMenu_ = 0;
drawMenu_ = 0;
// init action modes: Examine & Pick
actionMode_ = PickingMode;
lastActionMode_ = PickingMode;
examineMode();
// clipboard sync stuff
synchronized_ = false;
skipNextSync_ = false;
socket_ = new QUdpSocket();
for (int i=6666; i<6676; ++i)
if ( socket_->bind( i ) )
{
std::cout << "listen on port " << i << "\n";
break;
}
add_sync_host("127.0.0.1");
// Note: we start locked (initialization of updateLocked_)
// will be unlocked in initializeGL()
// Actions
action_.insert( "Background", new QAction( "Background color", this ) );
action_.insert( "Snapshot", new QAction( "Snapshot", this ) );
action_.insert( "SnapshotName", new QAction( "Set snapshot name", this ) );
action_.insert( "SnapshotSavesView", new QAction( "Snapshot saves view", this ) );
action_.insert( "CopyView", new QAction( "Copy view", this ) );
action_.insert( "PasteView", new QAction( "Paste view", this ) );
action_.insert( "PasteDropSize", new QAction( "Paste/Drop effects size", this ) );
action_.insert( "Synchronize", new QAction( "Synchronize", this ) );
action_.insert( "Animation", new QAction( "Animation", this ) );
action_.insert( "BackfaceCulling", new QAction( "Backface culling", this ) );
action_.insert( "TwoSidedLighting", new QAction( "Two-sided lighting", this ) );
connect( action_["Background"], SIGNAL( triggered() ),
this, SLOT( actionBackground() ) );
connect( action_["Snapshot"], SIGNAL( triggered() ),
this, SLOT( actionSnapshot() ) );
connect( action_["SnapshotName"], SIGNAL( triggered() ),
this, SLOT( actionSnapshotName() ) );
connect( action_["SnapshotSavesView"], SIGNAL( triggered() ),
this, SLOT( actionSnapshotSavesView() ) );
connect( action_["CopyView"], SIGNAL( triggered() ),
this, SLOT( actionCopyView() ) );
connect( action_["PasteView"], SIGNAL( triggered() ),
this, SLOT( actionPasteView() ) );
connect( action_["PasteDropSize"], SIGNAL( triggered() ),
this, SLOT( actionPasteDropSize() ) );
connect( action_["Synchronize"], SIGNAL( triggered() ),
this, SLOT( actionSynchronize() ) );
connect( action_["Animation"], SIGNAL( triggered() ),
this, SLOT( actionAnimation() ) );
connect( action_["BackfaceCulling"], SIGNAL( triggered() ),
this, SLOT( actionBackfaceCulling() ) );
connect( action_["TwoSidedLighting"], SIGNAL( triggered() ),
this, SLOT( actionTwoSidedLighting() ) );
action_["SnapshotSavesView"]->setCheckable( true );
action_["PasteDropSize"]->setCheckable( true );
action_["Synchronize"]->setCheckable( true );
action_["Animation"]->setCheckable( true );
action_["BackfaceCulling"]->setCheckable( true );
action_["TwoSidedLighting"]->setCheckable( true );
QSizePolicy sp = sizePolicy();
sp.setHorizontalPolicy( QSizePolicy::Expanding );
sp.setVerticalPolicy( QSizePolicy::Expanding );
sp.setHorizontalStretch( 1 );
sp.setVerticalStretch( 1 );
setSizePolicy( sp );
redrawTime_.start ();
}
//-----------------------------------------------------------------------------
QtBaseViewer::~QtBaseViewer()
{
delete privateStatusBar_;
delete snapshot_;
delete glstate_;
delete sceneGraphDialog_;
delete socket_;
// delete socket_notifier_;
}
//-----------------------------------------------------------------------------
QSize
QtBaseViewer::sizeHint() const
{
return QSize( 600, 600 );
}
//-----------------------------------------------------------------------------
void QtBaseViewer::setStatusBar(QStatusBar* _sb)
{
if (_sb==0)
{
if (privateStatusBar_==0)
privateStatusBar_=new QStatusBar(this);
statusbar_=privateStatusBar_;
if (options_ & ShowPrivateStatusBar)
privateStatusBar_->show();
else
privateStatusBar_->hide();
}
else {
statusbar_ = _sb;
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::applyOptions(int _options)
{
if (_options&ShowPrivateStatusBar)
setStatusBar(0);
else if (privateStatusBar_!=0)
privateStatusBar_->hide();
if (_options&ShowToolBar) buttonBar_->show();
else buttonBar_->hide();
if (_options&ShowPickButton) pickButton_->show();
else pickButton_->hide();
if (_options&ShowQuestionButton) questionButton_->show();
else questionButton_->hide();
if (_options&ShowWheelX) wheelX_->show();
else wheelX_->hide();
if (_options&ShowWheelY) wheelY_->show();
else wheelY_->hide();
if (_options&ShowWheelZ) wheelZ_->show();
else wheelZ_->hide();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::makeCurrent() {
glWidget_->makeCurrent();
}
void QtBaseViewer::swapBuffers() {
glWidget_->swapBuffers();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::sceneGraph(ACG::SceneGraph::BaseNode* _root)
{
sceneGraphRoot_ = _root;
if (sceneGraphRoot_)
{
// get draw modes
ACG::SceneGraph::CollectDrawModesAction action;
ACG::SceneGraph::traverse(sceneGraphRoot_, action);
availDrawModes_ = action.drawModes();
updatePopupMenu();
// get scene size
ACG::SceneGraph::BoundingBoxAction act;
ACG::SceneGraph::traverse(sceneGraphRoot_, act);
ACG::Vec3d bbmin = (ACG::Vec3d) act.bbMin();
ACG::Vec3d bbmax = (ACG::Vec3d) act.bbMax();
if ( ( bbmin[0] > bbmax[0] ) ||
( bbmin[1] > bbmax[1] ) ||
( bbmin[2] > bbmax[2] ) )
setScenePos( ACG::Vec3d( 0.0,0.0,0.0 ) , 1.0 );
else
setScenePos( ( bbmin + bbmax ) * 0.5,
( bbmax - bbmin ).norm() * 0.5 );
}
updateGL();
emit(signalSceneGraphChanged(sceneGraphRoot_));
}
//-----------------------------------------------------------------------------
void QtBaseViewer::lockUpdate()
{
updateLocked_ = true;
// QToolTip::add(moveButton_, "Switch to move mode (display locked)");
}
void QtBaseViewer::unlockUpdate()
{
// QToolTip::add(moveButton_,"Switch to move mode");
updateLocked_ = false;
}
void QtBaseViewer::unlockAndUpdate()
{
unlockUpdate();
updateGL();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::trackMouse(bool _track)
{
trackMouse_ = _track;
}
//-----------------------------------------------------------------------------
void QtBaseViewer::enablePopupMenu(bool _enable)
{
popupEnabled_ = _enable;
if ( popupEnabled_ ) {
glView_->setContextMenuPolicy( Qt::DefaultContextMenu );
} else {
glView_->setContextMenuPolicy( Qt::CustomContextMenu );
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::perspectiveProjection()
{
projectionMode(PERSPECTIVE_PROJECTION);
updateGL();
}
void QtBaseViewer::orthographicProjection()
{
projectionMode(ORTHOGRAPHIC_PROJECTION);
updateGL();
}
void QtBaseViewer::toggleProjectionMode()
{
if (projectionMode_ == ORTHOGRAPHIC_PROJECTION)
projectionMode(PERSPECTIVE_PROJECTION);
else
projectionMode(ORTHOGRAPHIC_PROJECTION);
// sync
emit(signalSetView(glstate_->modelview(), glstate_->inverse_modelview()));
updateGL();
}
void QtBaseViewer::projectionMode(ProjectionMode _p)
{
if ((projectionMode_ = _p) == ORTHOGRAPHIC_PROJECTION)
projectionButton_->setIcon( QPixmap(orthoIcon) );
else
projectionButton_->setIcon( QPixmap(perspectiveIcon) );
updateProjectionMatrix();
}
void QtBaseViewer::updateProjectionMatrix()
{
if( projectionUpdateLocked_ )
return;
makeCurrent();
glstate_->reset_projection();
switch (projectionMode_)
{
case ORTHOGRAPHIC_PROJECTION:
{
double aspect = (double) glWidth() / (double) glHeight();
glstate_->ortho( -orthoWidth_, orthoWidth_,
-orthoWidth_/aspect, orthoWidth_/aspect,
near_, far_ );
break;
}
case PERSPECTIVE_PROJECTION:
{
glstate_->perspective(fovy_,
(GLdouble) glWidth() / (GLdouble) glHeight(),
near_, far_);
break;
}
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::setScenePos(const ACG::Vec3d& _center, double _radius)
{
scene_center_ = trackball_center_ = _center;
scene_radius_ = trackball_radius_ = _radius;
orthoWidth_ = 2.0 * scene_radius_;
near_ = 0.001 * scene_radius_;
far_ = 10.0 * scene_radius_;
updateProjectionMatrix();
updateGL();
}
//----------------------------------------------------------------------------
void QtBaseViewer::viewingDirection( const ACG::Vec3d& _dir, const ACG::Vec3d& _up )
{
// calc eye point for this direction
ACG::Vec3d eye = scene_center_ - _dir*(3.0*scene_radius_);
glstate_->reset_modelview();
glstate_->lookAt((ACG::Vec3d)eye, (ACG::Vec3d)scene_center_, (ACG::Vec3d)_up);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionMode(ActionMode _am)
{
moveButton_->setDown(false);
lightButton_->setDown(false);
pickButton_->setDown(false);
questionButton_->setDown(false);
trackMouse(false);
if (_am != actionMode_)
{
lastActionMode_ = actionMode_;
actionMode_ = _am;
}
switch (actionMode_)
{
case ExamineMode:
{
glView_->setCursor(Qt::PointingHandCursor);
glBase_->setCursor(Qt::PointingHandCursor);
moveButton_->setDown(true);
break;
}
case LightMode:
{
glView_->setCursor(Qt::PointingHandCursor);
glBase_->setCursor(Qt::PointingHandCursor);
lightButton_->setDown(true);
break;
}
case PickingMode:
{
glView_->setCursor(Qt::ArrowCursor);
glBase_->setCursor(Qt::ArrowCursor);
pickButton_->setDown(true);
if (pick_mode_idx_ != -1) {
trackMouse(pick_modes_[pick_mode_idx_].tracking);
glView_->setCursor(pick_modes_[pick_mode_idx_].cursor);
glBase_->setCursor(pick_modes_[pick_mode_idx_].cursor);
}
break;
}
case QuestionMode:
{
glView_->setCursor(Qt::WhatsThisCursor);
glBase_->setCursor(Qt::WhatsThisCursor);
questionButton_->setDown(true);
break;
}
}
emit(signalActionModeChanged(actionMode_));
//emit pickmodeChanged with either the name of the current pickmode or an empty string
if(actionMode_ == PickingMode)
emit(signalPickModeChanged(pick_mode_name_));
else
emit(signalPickModeChanged(""));
}
//-----------------------------------------------------------------------------
void QtBaseViewer::faceOrientation(FaceOrientation _ori)
{
makeCurrent();
switch ( faceOrientation_ = _ori ) {
case CCW_ORIENTATION:
glFrontFace( GL_CCW );
break;
case CW_ORIENTATION:
glFrontFace( GL_CW );
break;
}
updateGL();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::backFaceCulling(bool _b)
{
makeCurrent();
if (funcMenu_==0) updatePopupMenu();
if ( (backFaceCulling_ = _b) )
glEnable( GL_CULL_FACE );
else
glDisable( GL_CULL_FACE );
action_["BackfaceCulling"]->setChecked( backFaceCulling_ );
updateGL();
}
void QtBaseViewer::twoSidedLighting(bool _b)
{
makeCurrent();
if (funcMenu_==0) updatePopupMenu();
glstate_->set_twosided_lighting(twoSidedLighting_=_b);
action_["TwoSidedLighting"]->setChecked(twoSidedLighting_);
updateGL();
}
void QtBaseViewer::animation(bool _b)
{
makeCurrent();
if (funcMenu_==0) updatePopupMenu();
animation_ = _b;
action_["Animation"]->setChecked( animation_ );
updateGL();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::normalsMode(NormalsMode _mode)
{
makeCurrent();
switch(normalsMode_ = _mode)
{
case DONT_TOUCH_NORMALS:
glDisable(GL_NORMALIZE);
break;
case NORMALIZE_NORMALS:
glEnable(GL_NORMALIZE);
break;
}
updateGL();
}
//-----------------------------------------------------------------------------
void
QtBaseViewer::copyToImage( QImage& _image,
unsigned int /* _l */ , unsigned int /* _t */ ,
unsigned int /* _w */ , unsigned int /* _h */ ,
GLenum /* _buffer */ )
{
makeCurrent();
_image = glWidget_->grabFrameBuffer(true);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::drawNow()
{
makeCurrent();
paintGL();
swapBuffers();
glView_->repaint();
}
void QtBaseViewer::updateGL()
{
if (!isUpdateLocked() && !isHidden() )
{
glScene_->update();
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::drawScene()
{
QTime timer;
timer.start();
// adjust clipping planes
ACG::Vec3d c = glstate_->modelview().transform_point(scene_center_);
near_ = std::max(0.0001f * scene_radius_, -(c[2] + scene_radius_));
far_ = std::max(0.0002f * scene_radius_, -(c[2] - scene_radius_));
updateProjectionMatrix();
// store time since last repaint in gl state and restart timer
glstate_->set_msSinceLastRedraw (redrawTime_.restart ());
// draw mono or stereo
makeCurrent();
if (stereo_) drawScene_stereo();
else drawScene_mono();
glFinish();
frame_time_ = timer.elapsed();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::drawScene_mono()
{
emit(signalDrawScene(glstate_));
if (sceneGraphRoot_)
{
if (! renderPicking_ ) {
ACG::SceneGraph::DrawAction action(curDrawMode_, false);
ACG::SceneGraph::traverse(sceneGraphRoot_, action, *glstate_, curDrawMode_);
if( blending_ )
{
ACG::SceneGraph::DrawAction action(curDrawMode_, true);
ACG::SceneGraph::traverse(sceneGraphRoot_, action, *glstate_, curDrawMode_);
}
} else {
// prepare GL state
makeCurrent();
glDisable(GL_LIGHTING);
glClear(GL_DEPTH_BUFFER_BIT);
glInitNames();
glPushName((GLuint) 0);
// do the picking
ACG::SceneGraph::PickAction action(pickRendererMode_);
ACG::SceneGraph::traverse(sceneGraphRoot_, action, *glstate_);
glEnable(GL_LIGHTING);
}
}
}
//-----------------------------------------------------------------------------
void
QtBaseViewer::drawScene_stereo()
{
double l, r, t, b, w, h, a, radians, wd2, ndfl;
w = glWidth();
h = glHeight();
a = w / h;
radians = fovy_ * 0.5 / 180.0 * M_PI;
wd2 = near_ * tan(radians);
ndfl = near_ / focalDist_ * scene_radius_;
l = -a*wd2;
r = a*wd2;
t = wd2;
b = -wd2;
double offset = 0.5 * eyeDist_;
double offset2 = offset * ndfl;
// left eye
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(l+offset2, r+offset2, b, t, near_, far_);
glTranslatef(-offset, 0.0, 0.0);
glMatrixMode(GL_MODELVIEW);
glDrawBuffer(GL_BACK_LEFT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawScene_mono();
// right eye
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(l-offset2, r-offset2, b, t, near_, far_);
glTranslatef(offset, 0.0, 0.0);
glMatrixMode(GL_MODELVIEW);
glDrawBuffer(GL_BACK_RIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawScene_mono();
glDrawBuffer(GL_BACK);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::setHome()
{
home_modelview_ = glstate_->modelview();
home_inverse_modelview_ = glstate_->inverse_modelview();
homeOrthoWidth_ = orthoWidth_;
home_center_ = trackball_center_;
home_radius_ = trackball_radius_;
}
void QtBaseViewer::home()
{
makeCurrent();
glstate_->set_modelview(home_modelview_, home_inverse_modelview_);
orthoWidth_ = homeOrthoWidth_;
trackball_center_ = home_center_;
trackball_radius_ = home_radius_;
updateProjectionMatrix();
updateGL();
// sync
emit(signalSetView(glstate_->modelview(), glstate_->inverse_modelview()));
}
//-----------------------------------------------------------------------------
void QtBaseViewer::viewAll()
{
makeCurrent();
// move center (in camera coords) to origin and translate in -z dir
translate(-(glstate_->modelview().transform_point(scene_center_))
- ACG::Vec3d(0.0, 0.0, 3.0*scene_radius_ ));
orthoWidth_ = 1.1*scene_radius_;
double aspect = (double) glWidth() / (double) glHeight();
if (aspect > 1.0) orthoWidth_ *= aspect;
updateProjectionMatrix();
updateGL();
// sync
emit(signalSetView(glstate_->modelview(), glstate_->inverse_modelview()));
}
//-----------------------------------------------------------------------------
void QtBaseViewer::flyTo(const QPoint& _pos, bool _move_back)
{
makeCurrent();
unsigned int nodeIdx, targetIdx;
ACG::Vec3d hitPoint;
if (pick( ACG::SceneGraph::PICK_ANYTHING, _pos, nodeIdx, targetIdx, &hitPoint))
{
if (projectionMode_ == PERSPECTIVE_PROJECTION)
{
ACG::Vec3d eye(glState().eye());
ACG::Vec3d t = hitPoint - eye;
ACG::Vec3d e = eye + t * (_move_back ? -0.5f : 0.5f);
flyTo(e, hitPoint, 300);
}
else
{
// Zoom in or out?
orthoWidth_ *= _move_back ? 2.0 : 0.5;
// Set the double click point as the new trackball center
// Rotations will use this point as the center.
trackball_center_ = hitPoint;
/// @todo : Translate view such that hitpoint is in center of viewport
// Update the projection matrix
updateProjectionMatrix();
// Redraw scene
updateGL();
}
// sync with external viewer
emit(signalSetView(glstate_->modelview(), glstate_->inverse_modelview()));
}
}
void QtBaseViewer::flyTo(const ACG::Vec3d& _position,
const ACG::Vec3d& _center,
double _time)
{
makeCurrent();
// compute rotation
ACG::Vec3d c = glstate_->modelview().transform_point(_center);
ACG::Vec3d p = glstate_->modelview().transform_point(_position);
ACG::Vec3d view =(p-c).normalize();
ACG::Vec3d z(0,0,1);
ACG::Vec3d axis = (z % -view).normalize();
double angle = acos(std::max(-1.0,
std::min(1.0,
(z | view)))) / M_PI * 180.0;
if (angle > 175)
axis = ACG::Vec3d(0,1,0);
// compute translation
ACG::Vec3d target = glstate_->modelview().transform_point(_center);
ACG::Vec3d trans ( -target[0],
-target[1],
-target[2] - (_position-_center).norm() );
// how many frames in _time ms ?
unsigned int frames = (unsigned int)(_time / frame_time_);
if (frames > 1000) frames=1000;
// animate it
if (frames > 10)
{
ACG::Vec3d t = trans / (double)frames;
double a = angle / (double)frames;
for (unsigned int i=0; i FLT_MIN)
rotate(axis, a, _center);
drawNow();
}
}
// no animation
else
{
translate(trans);
if (fabs(angle) > FLT_MIN)
rotate(axis, angle, _center);
updateGL();
}
trackball_center_ = _center;
trackball_radius_ = std::max(scene_radius_,
(_center-_position).norm()*0.9f);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::setView(const ACG::GLMatrixd& _modelview,
const ACG::GLMatrixd& _inverse_modelview)
{
makeCurrent();
glstate_->set_modelview(_modelview, _inverse_modelview);
updateGL();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::initializeGL()
{
// we use GLEW to manage extensions
// initialize it first
glewInit();
// lock update
lockUpdate();
// init GL state
glstate_->initialize();
// OpenGL state
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glDisable(GL_DITHER);
glShadeModel( GL_FLAT );
projectionMode( projectionMode_ );
normalsMode( normalsMode_ );
faceOrientation( faceOrientation_ );
backFaceCulling( backFaceCulling_ );
twoSidedLighting( twoSidedLighting_ );
// light sources
light_matrix_.identity();
update_lights();
// scene pos and size
scene_center_ = trackball_center_ = ACG::Vec3d( 0.0, 0.0, 0.0 );
scene_radius_ = trackball_radius_ = 1.0;
orthoWidth_ = 2.0;
// modelview
glstate_->translate(0.0, 0.0, -3.0);
setHome();
// pixel transfer
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
// emit initialization signal
emit(signalInitializeGL());
// unlock update (we started locked)
unlockUpdate();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::update_lights()
{
makeCurrent();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMultMatrixd(light_matrix_.data());
GLfloat pos[4], col[4];
col[0] = col[1] = col[2] = 0.7;
pos[3] = col[3] = 0.0;
#define SET_LIGHT(i,x,y,z) { \
pos[0]=x; pos[1]=y; pos[2]=z; \
glLightfv(GL_LIGHT##i, GL_POSITION, pos); \
glLightfv(GL_LIGHT##i, GL_DIFFUSE, col); \
glLightfv(GL_LIGHT##i, GL_SPECULAR, col); \
glEnable(GL_LIGHT##i); \
}
SET_LIGHT(0, 0.0, 0.0, 1.0);
SET_LIGHT(1, -1.0, 1.0, 0.7);
SET_LIGHT(2, 1.0, 1.0, 0.7);
col[0] = col[1] = col[2] = 0.3; col[3] = 1.0;
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
glPopMatrix();
}
void QtBaseViewer::rotate_lights(ACG::Vec3d& _axis, double _angle)
{
light_matrix_.rotate(_angle, _axis[0], _axis[1], _axis[2], ACG::MULT_FROM_LEFT);
update_lights();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::paintGL()
{
static bool initialized = false;
if (!initialized)
{
// we use GLEW to manage extensions
// initialize it first
glewInit();
// lock update
lockUpdate();
// init GL state
glstate_->initialize();
// initialize lights
light_matrix_.identity();
// scene pos and size
scene_center_ = trackball_center_ = ACG::Vec3d( 0.0, 0.0, 0.0 );
scene_radius_ = trackball_radius_ = 1.0;
orthoWidth_ = 2.0;
// modelview
glstate_->translate(0.0, 0.0, -3.0);
setHome();
// pixel transfer
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
// emit initialization signal
emit(signalInitializeGL());
// unlock update (we started locked)
unlockUpdate();
initialized = true;
}
if (!isUpdateLocked())
{
lockUpdate();
glPushAttrib (GL_ALL_ATTRIB_BITS);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glDisable(GL_DITHER);
glShadeModel( GL_FLAT );
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
normalsMode( normalsMode_ );
faceOrientation( faceOrientation_ );
backFaceCulling( backFaceCulling_ );
// light sources
update_lights();
glstate_->setState ();
glColor4f(1.0,0.0,0.0,1.0);
// clear (stereo mode clears buffers on its own)
if (!stereo_)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
unlockUpdate();
// draw scene
drawScene();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib ();
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::resizeGL(int _w, int _h)
{
updateProjectionMatrix();
glstate_->viewport(0, 0, _w, _h);
updateGL();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::encodeView(QString& _view)
{
const ACG::GLMatrixd m = glstate_->modelview();
const ACG::GLMatrixd p = glstate_->projection();
_view.sprintf("%s\n"
"%lf %lf %lf %lf\n%lf %lf %lf %lf\n"
"%lf %lf %lf %lf\n%lf %lf %lf %lf\n"
"%lf %lf %lf %lf\n%lf %lf %lf %lf\n"
"%lf %lf %lf %lf\n%lf %lf %lf %lf\n"
"%d %d %d %lf\n",
VIEW_MAGIC,
m(0,0), m(0,1), m(0,2), m(0,3),
m(1,0), m(1,1), m(1,2), m(1,3),
m(2,0), m(2,1), m(2,2), m(2,3),
m(3,0), m(3,1), m(3,2), m(3,3),
p(0,0), p(0,1), p(0,2), p(0,3),
p(1,0), p(1,1), p(1,2), p(1,3),
p(2,0), p(2,1), p(2,2), p(2,3),
p(3,0), p(3,1), p(3,2), p(3,3),
glWidth(), glHeight(),
projectionMode_,
orthoWidth_ );
}
//----------------------------------------------------------------------------
bool QtBaseViewer::decodeView(const QString& _view)
{
if (_view.left(sizeof(VIEW_MAGIC)-1) != QString(VIEW_MAGIC))
return false;
ACG::GLMatrixd m, p;
int w, h, pMode;
sscanf( (_view.toAscii().data())+sizeof(VIEW_MAGIC)-1,
"%lf %lf %lf %lf\n%lf %lf %lf %lf\n"
"%lf %lf %lf %lf\n%lf %lf %lf %lf\n"
"%lf %lf %lf %lf\n%lf %lf %lf %lf\n"
"%lf %lf %lf %lf\n%lf %lf %lf %lf\n"
"%d %d %d %lf\n",
&m(0,0), &m(0,1), &m(0,2), &m(0,3),
&m(1,0), &m(1,1), &m(1,2), &m(1,3),
&m(2,0), &m(2,1), &m(2,2), &m(2,3),
&m(3,0), &m(3,1), &m(3,2), &m(3,3),
&p(0,0), &p(0,1), &p(0,2), &p(0,3),
&p(1,0), &p(1,1), &p(1,2), &p(1,3),
&p(2,0), &p(2,1), &p(2,2), &p(2,3),
&p(3,0), &p(3,1), &p(3,2), &p(3,3),
&w, &h,
&pMode,
&orthoWidth_ );
makeCurrent();
if (projectionMode_ != (ProjectionMode)pMode)
projectionMode((ProjectionMode)pMode);
glstate_->set_modelview(m);
if (w>0 && h>0 &&
action_["PasteDropSize"]->isChecked() )
{
glstate_->set_projection(p);
glView_->setFixedSize(w,h);
updateGeometry();
}
updateGL();
return true;
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionDrawMenu( QAction * _action )
{
unsigned int mode( _action->data().toUInt() );
// combine draw modes
if (qApp->keyboardModifiers() & Qt::ShiftModifier)
{
if (drawMode() & mode)
drawMode(drawMode() & ~mode);
else
drawMode(drawMode() | mode);
}
// simply switch draw mode
else
{
// clear all other checked items
std::vector< QAction * >::iterator aIter, aEnd;
aEnd = drawMenuActions_.end();
for( aIter = drawMenuActions_.begin();
aIter != aEnd;
++aIter )
{
if( (*aIter)->data().toUInt() != mode )
(*aIter)->setChecked( false );
}
drawMode(mode);
}
hidePopupMenus();
updateGL();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionBackground()
{
const ACG::Vec4f bc = glstate_->clear_color() * 255.0;
QColor backCol((int)bc[0], (int)bc[1], (int)bc[2]);
QColor c = QColorDialog::getColor(backCol,this);
if (c != backCol && c.isValid())
backgroundColor(ACG::Vec4f(((double) c.red()) / 255.0,
((double) c.green()) / 255.0,
((double) c.blue()) / 255.0,
1.0));
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionCopyView()
{
QString view; encodeView(view);
QApplication::clipboard()->setText(view);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionPasteView()
{
QString view; view=QApplication::clipboard()->text();
decodeView(view);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionPasteDropSize()
{
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionSynchronize()
{
setSynchronization( action_["Synchronize"]->isChecked() );
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionSynchronize(bool _enable)
{
setSynchronization( _enable );
}
bool QtBaseViewer::synchronization(){
return synchronized_;
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionAnimation()
{
animation(!animation());
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionAnimation(bool _enable)
{
animation(_enable);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionBackfaceCulling()
{
backFaceCulling(!backFaceCulling());
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionBackfaceCulling(bool _enable)
{
backFaceCulling(_enable);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionTwoSidedLighting()
{
twoSidedLighting(!twoSidedLighting());
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionTwoSidedLighting(bool _enable)
{
twoSidedLighting(_enable);
}
//-----------------------------------------------------------------------------
void
QtBaseViewer::createWidgets(const QGLFormat* _format,
QStatusBar* _sb,
const QtBaseViewer* _share)
{
statusbar_=privateStatusBar_=0;
setStatusBar(_sb);
drawMenu_=0;
funcMenu_=0;
pickMenu_=0;
// contains splitter and eventually status bar
// QT3: Q3VBoxLayout* layout=new Q3VBoxLayout(this,0,0,"toplevel layout");
QVBoxLayout* layout=new QVBoxLayout(this);
layout->setSpacing( 0 );
layout->setMargin( 0 );
// contains glarea and buttons
// QT3: Q3Frame* work=new Q3Frame(this,"box-glarea-buttons");
QFrame* work=new QFrame(this);
layout->addWidget(work,1); // gets all stretch
// private status bar
assert(statusbar_!=0);
if (privateStatusBar_!=0)
layout->addWidget(privateStatusBar_,0); // no stretch
// Construct GL context & widget
QGLWidget* share = 0;
if (_share) share = _share->glWidget_;
QGLFormat format;
format.setAlpha(true);
if (_format!=0) format = *_format;
glWidget_ = new QGLWidget(format, 0, share);
glView_ = new QtGLGraphicsView(this, work);
glScene_ = new QtGLGraphicsScene (this);
glView_->setViewport(glWidget_);
glView_->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
glView_->setScene(glScene_);
wheelZ_=new ACG::QtWidgets::QtWheel( 0,"wheel-z",ACG::QtWidgets::QtWheel::Vertical);
wheelZ_->setMinimumSize(wheelZ_->sizeHint());
wheelZ_->setMaximumSize(wheelZ_->sizeHint());
connect(wheelZ_,SIGNAL(angleChangedBy(double)),
this,SLOT(slotWheelZ(double)));
wheelZ_->setToolTip( "Translate along z-axis.");
wheelZ_->setWhatsThis( "Translate along z-axis.");
if ((options_&ShowWheelZ)==0)
wheelZ_->hide();
wheelY_=new ACG::QtWidgets::QtWheel( 0,"wheel-y",ACG::QtWidgets::QtWheel::Horizontal);
wheelY_->setMinimumSize(wheelY_->sizeHint());
wheelY_->setMaximumSize(wheelY_->sizeHint());
connect(wheelY_,SIGNAL(angleChangedBy(double)),
this,SLOT(slotWheelY(double)));
wheelY_->setToolTip("Rotate around y-axis.");
wheelY_->setWhatsThis( "Rotate around y-axis.");
if ((options_&ShowWheelY)==0)
wheelY_->hide();
wheelX_=new ACG::QtWidgets::QtWheel( 0,"wheel-x",ACG::QtWidgets::QtWheel::Vertical);
wheelX_->setMinimumSize(wheelX_->sizeHint());
wheelX_->setMaximumSize(wheelX_->sizeHint());
connect(wheelX_,SIGNAL(angleChangedBy(double)),
this,SLOT(slotWheelX(double)));
wheelX_->setToolTip("Rotate around x-axis.");
wheelX_->setWhatsThis( "Rotate around x-axis.");
if ((options_&ShowWheelX)==0)
wheelX_->hide();
QGraphicsWidget *wheelX = glScene_->addWidget (wheelX_);
QGraphicsWidget *wheelY = glScene_->addWidget (wheelY_);
QGraphicsWidget *wheelZ = glScene_->addWidget (wheelZ_);
wheelX_->setWindowOpacity (0.5);
wheelY_->setWindowOpacity (0.5);
wheelZ_->setWindowOpacity (0.5);
wheelX->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
wheelY->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
wheelZ->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
glBaseLayout_ = new QGraphicsGridLayout;
glBaseLayout_->addItem(wheelX, 1, 0);
glBaseLayout_->addItem(wheelY, 2, 1);
glBaseLayout_->addItem(wheelZ, 1, 3);
glBaseLayout_->setColumnStretchFactor(0,0);
glBaseLayout_->setColumnStretchFactor(1,0);
glBaseLayout_->setColumnStretchFactor(2,1);
glBaseLayout_->setColumnStretchFactor(3,0);
glBaseLayout_->setRowStretchFactor(0,1);
glBaseLayout_->setRowStretchFactor(1,0);
glBaseLayout_->setRowStretchFactor(2,0);
glBase_ = new QGraphicsWidget;
glBase_->setLayout(glBaseLayout_);
glScene_->addItem(glBase_);
glBase_->setGeometry (glScene_->sceneRect ());
QRectF r = glScene_->sceneRect ();
connect ( glScene_, SIGNAL( sceneRectChanged( const QRectF & ) ),
this, SLOT( sceneRectChanged( const QRectF & ) ) );
// If popupEnabled_ this signal will not be emitted!
// If popupEnabled_ is set to false the Contextmenu Mode will be set to customContextMenuRequested
// and this signal will be emitted on right click
connect( glView_ , SIGNAL( customContextMenuRequested( const QPoint& ) ) ,
this , SIGNAL( signalCustomContextMenuRequested( const QPoint& ) ) );
// is stereo possible ?
if (format.stereo())
std::cerr << "Stereo buffer requested: "
<< (glWidget_->format().stereo() ? "ok\n" : "failed\n");
// toolbar
buttonBar_= new QToolBar( "Viewer Toolbar", work );
buttonBar_->setOrientation(Qt::Vertical);
moveButton_ = new QToolButton( buttonBar_ );
moveButton_->setIcon( QPixmap(moveIcon) );
moveButton_->setMinimumSize( 16, 16 );
moveButton_->setMaximumSize( 32, 32 );
moveButton_->setToolTip( "Switch to move mode." );
moveButton_->setWhatsThis(
"Switch to move mode.
"
"- Rotate using left mouse button.
"
"- Translate using middle mouse button.
"
"- Zoom using left+middle mouse buttons.
" );
QObject::connect( moveButton_, SIGNAL( clicked() ),
this, SLOT( examineMode() ) );
buttonBar_->addWidget( moveButton_)->setText("Move");
lightButton_ = new QToolButton( buttonBar_ );
lightButton_->setIcon( QPixmap(lightIcon) );
lightButton_->setMinimumSize( 16, 16 );
lightButton_->setMaximumSize( 32, 32 );
lightButton_->setToolTip("Switch to light mode.");
lightButton_->setWhatsThis(
"Switch to light mode.
"
"Rotate lights using left mouse button.");
QObject::connect( lightButton_, SIGNAL( clicked() ),
this, SLOT( lightMode() ) );
buttonBar_->addWidget( lightButton_)->setText("Light");
pickButton_ = new QToolButton( buttonBar_ );
pickButton_->setIcon( QPixmap(pickIcon) );
pickButton_->setMinimumSize( 16, 16 );
pickButton_->setMaximumSize( 32, 32 );
pickButton_->setToolTip("Switch to picking mode.");
pickButton_->setWhatsThis(
"Switch to picking mode.
"
"Use picking functions like flipping edges.
"
"To change the mode use the right click
"
"context menu in the viewer.");
QObject::connect( pickButton_, SIGNAL( clicked() ),
this, SLOT( pickingMode() ) );
buttonBar_->addWidget( pickButton_)->setText("Pick");
questionButton_ = new QToolButton( buttonBar_ );
questionButton_->setIcon( QPixmap(questionIcon) );
questionButton_->setMinimumSize( 16, 16 );
questionButton_->setMaximumSize( 32, 32 );
questionButton_->setToolTip("Switch to identification mode.");
questionButton_->setWhatsThis(
"Switch to identification mode.
"
"Use identification mode to get information "
"about objects. Click on an object and see "
"the log output for information about the "
"object.");
QObject::connect( questionButton_, SIGNAL( clicked() ),
this, SLOT( questionMode() ) );
buttonBar_->addWidget( questionButton_)->setText("Question");
buttonBar_->addSeparator();
homeButton_ = new QToolButton( buttonBar_ );
homeButton_->setIcon( QPixmap(homeIcon) );
homeButton_->setMinimumSize( 16, 16 );
homeButton_->setMaximumSize( 32, 32 );
homeButton_->setCheckable( false );
homeButton_->setToolTip("Restore home view.");
homeButton_->setWhatsThis(
"Restore home view
"
"Resets the view to the home view");
QObject::connect( homeButton_, SIGNAL( clicked() ),
this, SLOT( home() ) );
buttonBar_->addWidget( homeButton_)->setText("Home");
setHomeButton_ = new QToolButton( buttonBar_ );
setHomeButton_->setIcon( QPixmap(sethomeIcon) );
setHomeButton_->setMinimumSize( 16, 16 );
setHomeButton_->setMaximumSize( 32, 32 );
setHomeButton_->setCheckable( false );
setHomeButton_->setToolTip("Set home view");
setHomeButton_->setWhatsThis(
"Store home view
"
"Stores the current view as the home view");
QObject::connect( setHomeButton_, SIGNAL( clicked() ),
this, SLOT( setHome() ) );
buttonBar_->addWidget( setHomeButton_)->setText("Set Home");
viewAllButton_ = new QToolButton( buttonBar_ );
viewAllButton_->setIcon( QPixmap(viewallIcon) );
viewAllButton_->setMinimumSize( 16, 16 );
viewAllButton_->setMaximumSize( 32, 32 );
viewAllButton_->setCheckable( false );
viewAllButton_->setToolTip("View all.");
viewAllButton_->setWhatsThis(
"View all
"
"Move the objects in the scene so that"
" the whole scene is visible.");
QObject::connect( viewAllButton_, SIGNAL( clicked() ),
this, SLOT( viewAll() ) );
buttonBar_->addWidget( viewAllButton_)->setText("View all");
projectionButton_ = new QToolButton( buttonBar_ );
projectionButton_->setIcon( QPixmap(perspectiveIcon) );
projectionButton_->setMinimumSize( 16, 16 );
projectionButton_->setMaximumSize( 32, 32 );
projectionButton_->setCheckable( false );
projectionButton_->setToolTip(
"Switch between perspective and "
"parrallel projection mode.");
projectionButton_->setWhatsThis(
"Switch projection modes
"
"Switch between perspective and "
"parrallel projection mode.");
QObject::connect( projectionButton_, SIGNAL( clicked() ),
this, SLOT( toggleProjectionMode() ) );
buttonBar_->addWidget( projectionButton_)->setText( "Projection" );
if (glWidget_->format().stereo())
{
stereoButton_ = new QToolButton( buttonBar_ );
stereoButton_->setIcon( QPixmap(monoIcon) );
stereoButton_->setMinimumSize( 16, 16 );
stereoButton_->setMaximumSize( 32, 32 );
stereoButton_->setCheckable( true );
stereoButton_->setToolTip( "Toggle stereo viewing");
stereoButton_->setWhatsThis(
"Toggle stereo mode
"
"Use this button to switch between stereo "
"and mono view. To use this feature you need "
"a stereo capable graphics card and a stereo "
"display/projection system.");
QObject::connect( stereoButton_, SIGNAL( clicked() ),
this, SLOT( toggleStereoMode() ) );
buttonBar_->addWidget( stereoButton_)->setText( "Stereo");
}
buttonBar_->addSeparator();
sceneGraphButton_ = new QToolButton( buttonBar_ );
sceneGraphButton_->setIcon( QPixmap(sceneGraphIcon) );
sceneGraphButton_->setMinimumSize( 16, 16 );
sceneGraphButton_->setMaximumSize( 32, 32 );
sceneGraphButton_->setCheckable( false );
sceneGraphButton_->setToolTip("Toggle scene graph viewer.");
sceneGraphButton_->setWhatsThis(
"Toggle scene graph viewer
"
"The scene graph viewer enables you to examine the "
"displayed scene graph and to modify certain nodes.
"
"There are three modi for the scene graph viewer:"
"- hidden
"
"- split: share space
"
"- dialog: own dialog window
"
"This button toggles between these modi.");
QObject::connect( sceneGraphButton_, SIGNAL( clicked() ),
this, SLOT( showSceneGraphDialog() ) );
buttonBar_->addWidget( sceneGraphButton_)->setText( "SceneGraph" );
glLayout_ = new QGridLayout(work);
glLayout_->setSpacing( 0 );
glLayout_->setMargin( 0 );
glLayout_->addWidget(glView_, 0,0);
glLayout_->addWidget(buttonBar_, 0,1);
glLayout_->setColumnStretch(0,1);
glLayout_->setColumnStretch(1,0);
if (!(options_ & ShowToolBar))
buttonBar_->hide();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::updatePopupMenu()
{
//
// Draw mode menu
//
if ( ! drawMenu_ )
{
drawMenu_ = new QMenu( this );
connect( drawMenu_, SIGNAL( aboutToHide() ),
this, SLOT( hidePopupMenus() ) );
}
QActionGroup * drawGroup = new QActionGroup( this );
drawGroup->setExclusive( false );
connect( drawGroup, SIGNAL( triggered( QAction * ) ),
this, SLOT( actionDrawMenu( QAction * ) ) );
drawMenuActions_.clear();
std::vector< unsigned int > draw_mode_id;
draw_mode_id = ACG::SceneGraph::DrawModes::getDrawModeIDs( availDrawModes_ );
for ( unsigned int i = 0; i < draw_mode_id.size(); ++i )
{
unsigned int id = draw_mode_id[i];
std::string descr = ACG::SceneGraph::DrawModes::description( id );
QAction * action = new QAction( descr.c_str(), drawGroup );
action->setData( QVariant( id ) );
action->setCheckable( true );
action->setChecked( ACG::SceneGraph::DrawModes::containsId( curDrawMode_, id ) );
drawMenuActions_.push_back( action );
}
drawMenu_->clear();
drawMenu_->addActions( drawGroup->actions() );
// function menu
if (!funcMenu_)
{
funcMenu_=new QMenu( this );
funcMenu_->addAction( action_[ "Background" ] );
funcMenu_->addSeparator();
funcMenu_->addAction( action_[ "Snapshot" ] );
funcMenu_->addAction( action_[ "SnapshotName" ] );
funcMenu_->addAction( action_[ "SnapshotSavesView" ] );
funcMenu_->addSeparator();
funcMenu_->addAction( action_[ "CopyView" ] );
funcMenu_->addAction( action_[ "PasteView" ] );
funcMenu_->addAction( action_[ "PasteDropSize" ] );
funcMenu_->addSeparator();
funcMenu_->addAction( action_[ "Synchronize" ] );
funcMenu_->addSeparator();
funcMenu_->addAction( action_[ "Animation" ] );
funcMenu_->addAction( action_[ "BackfaceCulling" ] );
funcMenu_->addAction( action_[ "TwoSidedLighting" ] );
connect( funcMenu_, SIGNAL( aboutToHide() ),
this, SLOT( hidePopupMenus() ) );
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::hidePopupMenus()
{
if ( drawMenu_ )
{
drawMenu_->blockSignals(true);
drawMenu_->hide();
drawMenu_->blockSignals(false);
}
if ( funcMenu_ )
{
funcMenu_->blockSignals(true);
funcMenu_->hide();
funcMenu_->blockSignals(false);
}
if ( pickMenu_ )
{
pickMenu_->blockSignals(true);
pickMenu_->hide();
pickMenu_->blockSignals(false);
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::translate(const ACG::Vec3d& _trans)
{
makeCurrent();
glstate_->translate(_trans[0], _trans[1], _trans[2], ACG::MULT_FROM_LEFT);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::initModelviewMatrix()
{
makeCurrent();
glstate_->reset_modelview();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::rotate(const ACG::Vec3d& _axis,
double _angle,
const ACG::Vec3d& _center)
{
makeCurrent();
ACG::Vec3d t = glstate_->modelview().transform_point(_center);
glstate_->translate(-t[0], -t[1], -t[2], ACG::MULT_FROM_LEFT);
glstate_->rotate(_angle, _axis[0], _axis[1], _axis[2], ACG::MULT_FROM_LEFT);
glstate_->translate( t[0], t[1], t[2], ACG::MULT_FROM_LEFT);
sync_send( glstate_->modelview(), glstate_->inverse_modelview() );
}
//-----------------------------------------------------------------------------
unsigned int QtBaseViewer::glWidth() const {
return glView_->width();
}
unsigned int QtBaseViewer::glHeight() const {
return glView_->height();
}
QSize QtBaseViewer::glSize() const {
return glView_->size();
}
QPoint QtBaseViewer::glMapFromGlobal( const QPoint& _pos ) const {
return glView_->mapFromGlobal(_pos);
}
QPoint QtBaseViewer::glMapToGlobal( const QPoint& _pos ) const {
return glView_->mapToGlobal(_pos);
}
//-----------------------------------------------------------------------------
void
QtBaseViewer::showSceneGraphDialog()
{
if (sceneGraphRoot_)
{
if (!sceneGraphDialog_)
{
sceneGraphDialog_ = new ACG::QtWidgets::QtSceneGraphDialog( this, sceneGraphRoot_ );
connect(this,
SIGNAL(signalSceneGraphChanged(ACG::SceneGraph::BaseNode*)),
sceneGraphDialog_,
SLOT(update(ACG::SceneGraph::BaseNode*)));
connect(sceneGraphDialog_,
SIGNAL(signalNodeChanged(ACG::SceneGraph::BaseNode*)),
this,
SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
}
sceneGraphDialog_->show();
}
}
//-----------------------------------------------------------------------------
void
QtBaseViewer::slotNodeChanged(ACG::SceneGraph::BaseNode* _node)
{
emit(signalNodeChanged(_node));
updateGL();
}
//-----------------------------------------------------------------------------
void QtBaseViewer::slotWheelX(double _dAngle)
{
rotate(ACG::Vec3d(1,0,0),ACG::QtWidgets::QtWheel::deg(ACG::QtWidgets::QtWheel::clip(_dAngle)));
updateGL();
// sync
emit(signalSetView(glstate_->modelview(), glstate_->inverse_modelview()));
}
void QtBaseViewer::slotWheelY(double _dAngle)
{
rotate(ACG::Vec3d(0,1,0),ACG::QtWidgets::QtWheel::deg(ACG::QtWidgets::QtWheel::clip(_dAngle)));
updateGL();
// sync
emit(signalSetView(glstate_->modelview(), glstate_->inverse_modelview()));
}
void QtBaseViewer::slotWheelZ(double _dist)
{
double dz=_dist*0.5/M_PI*scene_radius_*2.0;
translate(ACG::Vec3d(0,0,dz));
updateGL();
// sync
emit(signalSetView(glstate_->modelview(), glstate_->inverse_modelview()));
}
//-----------------------------------------------------------------------------
void QtBaseViewer::sceneRectChanged(const QRectF &rect)
{
glBase_->setGeometry (rect);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::grabGLArea()
{
glareaGrabbed_ = true;
glView_->setCursor(Qt::BlankCursor);
glBase_->setCursor(Qt::BlankCursor);
glView_->grabMouse();
glView_->grabKeyboard();
}
void QtBaseViewer::releaseGLArea()
{
glareaGrabbed_ = false;
glView_->releaseMouse();
glView_->releaseKeyboard();
glView_->setCursor(Qt::ArrowCursor);
glBase_->setCursor(Qt::ArrowCursor);
}
//-----------------------------------------------------------------------------
void QtBaseViewer::glContextMenuEvent(QContextMenuEvent* _event)
{
if (popupEnabled_)
{
QPoint cpos(QCursor::pos()), dpos, fpos, ppos;
int offset = 10, dw, dh, fw, fh, pw, ph;
int minx, maxx, miny, maxy;
int dx(0), dy(0);
#ifdef ARCH_DARWIN
# define WIDTH width()
# define HEIGHT height()
#else
# define WIDTH sizeHint().width()
# define HEIGHT sizeHint().height()
#endif
// drawing mode menu
if (drawMenu_)//TODO: && drawMenu_->count()>0)
{
dw = drawMenu_->WIDTH;
dh = drawMenu_->HEIGHT;
dpos = cpos + QPoint(offset, offset);
}
else
{
dpos = cpos; dw=dh=0;
}
// function menu
///@todo: if (funcMenu_ && funcMenu_->count()>0)
if (funcMenu_)
{
fw = funcMenu_->WIDTH;
fh = funcMenu_->HEIGHT;
fpos = cpos + QPoint(offset, -offset-fh);
}
else
{
fpos = cpos; fw=fh=0;
}
// pick mode menu
///@todo: if (pickMenu_ && pickMenu_->count()>0)
if (pickMenu_)
{
pw = pickMenu_->WIDTH;
ph = pickMenu_->HEIGHT;
ppos = cpos + QPoint(-offset-pw, -ph/2);
}
else
{
ppos = cpos; pw=ph=0;
}
// handle screen boundaries
minx = std::min(dpos.x(), std::min(fpos.x(), ppos.x()));
maxx = std::max(dpos.x()+dw, std::max(fpos.x()+fw, ppos.x()+pw));
miny = std::min(dpos.y(), std::min(fpos.y(), ppos.y()));
maxy = std::max(dpos.y()+dh, std::max(fpos.y()+fh, ppos.y()+ph));
if (minx < 0)
{
dx = -minx;
}
else if (maxx >= qApp->desktop()->width())
{
dx = qApp->desktop()->width() - maxx;
}
if (miny < 0)
{
dy = -miny;
}
else if (maxy >= qApp->desktop()->height())
{
dy = qApp->desktop()->height() - maxy;
}
dpos += QPoint(dx, dy);
fpos += QPoint(dx, dy);
ppos += QPoint(dx, dy);
// popping up 3 menus only works w/o Qt menu fade/animate effects
bool animate_menu = qApp->isEffectEnabled(Qt::UI_AnimateMenu);
bool fade_menu = qApp->isEffectEnabled(Qt::UI_FadeMenu);
if (animate_menu) qApp->setEffectEnabled(Qt::UI_AnimateMenu, false);
if (fade_menu) qApp->setEffectEnabled(Qt::UI_FadeMenu, false);
// popup the 3 menus
if (drawMenu_) ///@todo: && drawMenu_->count()>0)
{
// SceneGraph::DrawModes::setQPopupMenuChecked(drawMenu_, curDrawMode_);
drawMenu_->popup(dpos);
}
if (funcMenu_) ///@todo: && funcMenu_->count()>0)
funcMenu_->popup(fpos);
if (pickMenu_) ///@todo: && pickMenu_->count()>0)
pickMenu_->popup(ppos);
// restore effect state
if (animate_menu) qApp->setEffectEnabled(Qt::UI_AnimateMenu, true);
if (fade_menu) qApp->setEffectEnabled(Qt::UI_FadeMenu, true);
_event->accept();
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::glMousePressEvent(QMouseEvent* _event)
{
// right button pressed => popup menu (ignore here)
if (_event->button() == Qt::RightButton && popupEnabled_)
{
return;
}
else
{
switch (actionMode_)
{
case ExamineMode:
if ((_event->modifiers() & Qt::ControlModifier)) // drag&drop
if ( externalDrag_ ) {
emit startDragEvent( _event );
} else {
startDrag();
}
else
viewMouseEvent(_event); // examine
break;
case LightMode:
lightMouseEvent(_event);
break;
case PickingMode: // give event to application
emit(signalMouseEvent(_event, pick_mode_name_));
emit(signalMouseEvent(_event));
break;
case QuestionMode: // give event to application
emit(signalMouseEventIdentify(_event));
break;
}
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::glMouseDoubleClickEvent(QMouseEvent* _event)
{
switch (actionMode_)
{
case ExamineMode:
viewMouseEvent(_event);
break;
case LightMode:
lightMouseEvent(_event);
break;
case PickingMode: // give event to application
emit(signalMouseEvent(_event, pick_mode_name_));
emit(signalMouseEvent(_event));
break;
case QuestionMode: // give event to application
emit(signalMouseEventIdentify(_event));
break;
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::glMouseMoveEvent(QMouseEvent* _event)
{
switch ( actionMode_ )
{
case ExamineMode:
viewMouseEvent(_event);
break;
case LightMode:
lightMouseEvent(_event);
break;
case PickingMode:
// give event to application
// deliver mouse moves with no button down, if tracking is enabled,
if ((_event->buttons() & (Qt::LeftButton | Qt::MidButton | Qt::RightButton))
|| trackMouse_)
{
emit(signalMouseEvent(_event, pick_mode_name_));
emit(signalMouseEvent(_event));
}
break;
case QuestionMode: // give event to application
emit(signalMouseEventIdentify(_event));
break;
default: // avoid warning
break;
}
}
//-----------------------------------------------------------------------------
void QtBaseViewer::glMouseReleaseEvent(QMouseEvent* _event)
{
// if (_event->button() == Qt::RightButton )
// hidePopupMenus();
if (_event->button() != Qt::RightButton ||
(actionMode_ == PickingMode && !popupEnabled_) )
{
switch ( actionMode_ )
{
case ExamineMode:
viewMouseEvent(_event);
break;
case LightMode:
lightMouseEvent(_event);
break;
case PickingMode: // give event to application
emit(signalMouseEvent(_event, pick_mode_name_));
emit(signalMouseEvent(_event));
break;
case QuestionMode: // give event to application
emit(signalMouseEventIdentify(_event));
break;
default: // avoid warning
break;
}
}
isRotating_ = false;
}
//-----------------------------------------------------------------------------
void QtBaseViewer::glMouseWheelEvent(QWheelEvent* _event)
{
switch ( actionMode_ )
{
case ExamineMode:
viewWheelEvent(_event);
break;
case PickingMode: // give event to application
emit(signalWheelEvent(_event, pick_mode_name_));
break;
default: // avoid warning
break;
}
isRotating_ = false;
}
//-----------------------------------------------------------------------------
void QtBaseViewer::updatePickMenu()
{
delete pickMenu_;
pickMenu_ = new QMenu( 0 );
connect( pickMenu_, SIGNAL( aboutToHide() ),
this, SLOT( hidePopupMenus() ) );
QActionGroup * ag = new QActionGroup( pickMenu_ );
ag->setExclusive( true );
for (unsigned int i=0; i 0) && (iaddSeparator();
}
else
{
QAction * ac = new QAction( pick_modes_[i].name.c_str(), ag );
ac->setData( QVariant( i ) );
ac->setCheckable( true );
if ((int)i == pick_mode_idx_)
ac->setChecked( true );
pickMenu_->addAction( ac );
}
}
connect( ag, SIGNAL( triggered( QAction * ) ),
this, SLOT( actionPickMenu( QAction * ) ));
}
//-----------------------------------------------------------------------------
void QtBaseViewer::actionPickMenu( QAction * _action )
{
int _id = _action->data().toInt();
if (_id < (int) pick_modes_.size() )
{
pickMode( _id );
}
actionMode( PickingMode );
hidePopupMenus();
}
//-----------------------------------------------------------------------------
QToolBar* QtBaseViewer::getToolBar() {
return buttonBar_;
}
QToolBar* QtBaseViewer::removeToolBar() {
glLayout_->removeWidget( buttonBar_ );
return buttonBar_;
}
//=============================================================================
//=============================================================================