128
void GLViewer::mouseMovesCamera(){
129
camera()->frame()->setWheelSensitivity(-1.0f);
131
setMouseBinding(Qt::SHIFT + Qt::LeftButton, SELECT);
132
//setMouseBinding(Qt::RightButton, NO_CLICK_ACTION);
133
setMouseBinding(Qt::SHIFT + Qt::LeftButton + Qt::RightButton, FRAME, ZOOM);
134
setMouseBinding(Qt::SHIFT + Qt::MidButton, FRAME, TRANSLATE);
135
setMouseBinding(Qt::SHIFT + Qt::RightButton, FRAME, ROTATE);
136
setWheelBinding(Qt::ShiftModifier , FRAME, ZOOM);
138
setMouseBinding(Qt::LeftButton + Qt::RightButton, CAMERA, ZOOM);
139
setMouseBinding(Qt::MidButton, CAMERA, ZOOM);
140
setMouseBinding(Qt::LeftButton, CAMERA, ROTATE);
141
setMouseBinding(Qt::RightButton, CAMERA, TRANSLATE);
142
setWheelBinding(Qt::NoModifier, CAMERA, ZOOM);
145
void GLViewer::mouseMovesManipulatedFrame(qglviewer::Constraint* c){
146
setMouseBinding(Qt::LeftButton + Qt::RightButton, FRAME, ZOOM);
147
setMouseBinding(Qt::MidButton, FRAME, ZOOM);
148
setMouseBinding(Qt::LeftButton, FRAME, ROTATE);
149
setMouseBinding(Qt::RightButton, FRAME, TRANSLATE);
150
setWheelBinding(Qt::NoModifier , FRAME, ZOOM);
151
manipulatedFrame()->setConstraint(c);
154
130
bool GLViewer::isManipulating(){
155
131
return isMoving || manipulatedClipPlane>=0;
173
149
displayMessage("Manipulating clip plane #"+lexical_cast<string>(planeNo+1)+(grp.empty()?grp:" (bound planes:"+grp+")"));
176
void GLViewer::useDisplayParameters(size_t n){
177
LOG_DEBUG("Loading display parameters from #"<<n);
178
vector<shared_ptr<DisplayParameters> >& dispParams=Omega::instance().getScene()->dispParams;
179
if(dispParams.size()<=(size_t)n){ throw std::invalid_argument(("Display parameters #"+lexical_cast<string>(n)+" don't exist (number of entries "+lexical_cast<string>(dispParams.size())+")").c_str());; return;}
180
const shared_ptr<DisplayParameters>& dp=dispParams[n];
182
if(dp->getValue("OpenGLRenderer",val)){ istringstream oglre(val);
183
yade::ObjectIO::load<typeof(renderer),boost::archive::xml_iarchive>(oglre,"renderer",renderer);
185
else { LOG_WARN("OpenGLRenderer configuration not found in display parameters, skipped.");}
186
if(dp->getValue("GLViewer",val)){ GLViewer::setState(val); displayMessage("Loaded view configuration #"+lexical_cast<string>(n)); }
187
else { LOG_WARN("GLViewer configuration not found in display parameters, skipped."); }
190
void GLViewer::saveDisplayParameters(size_t n){
191
LOG_DEBUG("Saving display parameters to #"<<n);
192
vector<shared_ptr<DisplayParameters> >& dispParams=Omega::instance().getScene()->dispParams;
193
if(dispParams.size()<=n){while(dispParams.size()<=n) dispParams.push_back(shared_ptr<DisplayParameters>(new DisplayParameters));} assert(n<dispParams.size());
194
shared_ptr<DisplayParameters>& dp=dispParams[n];
196
yade::ObjectIO::save<typeof(renderer),boost::archive::xml_oarchive>(oglre,"renderer",renderer);
197
dp->setValue("OpenGLRenderer",oglre.str());
198
dp->setValue("GLViewer",GLViewer::getState());
199
displayMessage("Saved view configuration ot #"+lexical_cast<string>(n));
202
152
string GLViewer::getState(){
203
153
QString origStateFileName=stateFileName();
204
154
string tmpFile=Omega::instance().tmpFilename();
426
376
showEntireScene();
429
void GLViewer::draw()
432
if(!nextFrameSnapshotFilename.empty() && boost::algorithm::ends_with(nextFrameSnapshotFilename,".pdf")){
433
gl2psStream=fopen(nextFrameSnapshotFilename.c_str(),"wb");
434
if(!gl2psStream){ int err=errno; throw runtime_error(string("Error opening file ")+nextFrameSnapshotFilename+": "+strerror(err)); }
435
LOG_DEBUG("Start saving snapshot to "<<nextFrameSnapshotFilename);
436
size_t nBodies=Omega::instance().getScene()->bodies->size();
437
int sortAlgo=(nBodies<100 ? GL2PS_BSP_SORT : GL2PS_SIMPLE_SORT);
438
gl2psBeginPage(/*const char *title*/"Some title", /*const char *producer*/ "Yade",
439
/*GLint viewport[4]*/ NULL,
440
/*GLint format*/ GL2PS_PDF, /*GLint sort*/ sortAlgo, /*GLint options*/GL2PS_SIMPLE_LINE_OFFSET|GL2PS_USE_CURRENT_VIEWPORT|GL2PS_TIGHT_BOUNDING_BOX|GL2PS_COMPRESS|GL2PS_OCCLUSION_CULL|GL2PS_NO_BLENDING,
441
/*GLint colormode*/ GL_RGBA, /*GLint colorsize*/0,
442
/*GL2PSrgba *colortable*/NULL,
443
/*GLint nr*/0, /*GLint ng*/0, /*GLint nb*/0,
444
/*GLint buffersize*/4096*4096 /* 16MB */, /*FILE *stream*/ gl2psStream,
445
/*const char *filename*/NULL);
449
qglviewer::Vec vd=camera()->viewDirection(); renderer->viewDirection=Vector3r(vd[0],vd[1],vd[2]);
450
if(Omega::instance().getScene()){
451
const shared_ptr<Scene>& scene=Omega::instance().getScene();
452
int selection = selectedName();
453
if(selection!=-1 && (*(Omega::instance().getScene()->bodies)).exists(selection) && isMoving){
454
static Real lastTimeMoved(0);
455
static Real initv0(0); static Real initv1(0); static Real initv2(0);
456
float v0,v1,v2; manipulatedFrame()->getPosition(v0,v1,v2);
457
if(last == selection) // delay by one redraw, so the body will not jump into 0,0,0 coords
459
Quaternionr& q = (*(Omega::instance().getScene()->bodies))[selection]->state->ori;
460
Vector3r& v = (*(Omega::instance().getScene()->bodies))[selection]->state->pos;
461
Vector3r& vel = (*(Omega::instance().getScene()->bodies))[selection]->state->vel;
462
Vector3r& angVel = (*(Omega::instance().getScene()->bodies))[selection]->state->angVel;
463
angVel=Vector3r::Zero();
464
if (!initv0 && !initv1 && !initv2){initv0=v0;initv1=v1;initv2=v2;}
465
if (initv0!=v0 || initv1!=v1 || initv2!=v2) {
466
Real dt=(scene->time-lastTimeMoved); lastTimeMoved=scene->time;
468
vel[0]=-(v[0]-v0)/dt; vel[1]=-(v[1]-v1)/dt; vel[2]=-(v[2]-v2)/dt;
469
vel[0]=-(initv0-v0)/dt; vel[1]=-(initv1-v1)/dt; vel[2]=-(initv2-v2)/dt;
470
initv0=v0;initv1=v1;initv2=v2;
473
else {vel[0]=vel[1]=vel[2]=0; /*v[0]=v0;v[1]=v1;v[2]=v2;*/}
474
v[0]=v0;v[1]=v1;v[2]=v2;
475
//FIXME: should update spin like velocity above, when the body is rotated:
476
double q0,q1,q2,q3; manipulatedFrame()->getOrientation(q0,q1,q2,q3); q.x()=q0;q.y()=q1;q.z()=q2;q.w()=q3;
478
(*(Omega::instance().getScene()->bodies))[selection]->userForcedDisplacementRedrawHook();
481
if(manipulatedClipPlane>=0){
482
assert(manipulatedClipPlane<renderer->numClipPlanes);
483
float v0,v1,v2; manipulatedFrame()->getPosition(v0,v1,v2);
484
double q0,q1,q2,q3; manipulatedFrame()->getOrientation(q0,q1,q2,q3);
485
Se3r newSe3(Vector3r(v0,v1,v2),Quaternionr(q0,q1,q2,q3)); newSe3.orientation.normalize();
486
const Se3r& oldSe3=renderer->clipPlaneSe3[manipulatedClipPlane];
487
FOREACH(int planeId, boundClipPlanes){
488
if(planeId>=renderer->numClipPlanes || !renderer->clipPlaneActive[planeId] || planeId==manipulatedClipPlane) continue;
489
Se3r& boundSe3=renderer->clipPlaneSe3[planeId];
490
Quaternionr relOrient=oldSe3.orientation.conjugate()*boundSe3.orientation; relOrient.normalize();
491
Vector3r relPos=oldSe3.orientation.conjugate()*(boundSe3.position-oldSe3.position);
492
boundSe3.position=newSe3.position+newSe3.orientation*relPos;
493
boundSe3.orientation=newSe3.orientation*relOrient;
494
boundSe3.orientation.normalize();
496
renderer->clipPlaneSe3[manipulatedClipPlane]=newSe3;
498
scene->renderer=renderer;
499
renderer->render(scene, selectedName());
503
void GLViewer::drawWithNames(){
504
qglviewer::Vec vd=camera()->viewDirection(); renderer->viewDirection=Vector3r(vd[0],vd[1],vd[2]);
505
const shared_ptr<Scene> scene(Omega::instance().getScene());
506
scene->renderer=renderer;
507
renderer->scene=scene;
508
renderer->renderShape();
511
379
// new object selected.
512
380
// set frame coordinates, and isDynamic=false;
513
381
void GLViewer::postSelection(const QPoint& point)
561
429
QGLViewer::endSelection(point);
564
qglviewer::Vec GLViewer::displayedSceneCenter(){
565
return camera()->unprojectedCoordinatesOf(qglviewer::Vec(width()/2 /* pixels */ ,height()/2 /* pixels */, /*middle between near plane and far plane*/ .5));
568
float GLViewer::displayedSceneRadius(){
569
return (camera()->unprojectedCoordinatesOf(qglviewer::Vec(width()/2,height()/2,.5))-camera()->unprojectedCoordinatesOf(qglviewer::Vec(0,0,.5))).norm();
572
void GLViewer::postDraw(){
573
Real wholeDiameter=QGLViewer::camera()->sceneRadius()*2;
575
renderer->viewInfo.sceneRadius=QGLViewer::camera()->sceneRadius();
576
qglviewer::Vec c=QGLViewer::camera()->sceneCenter();
577
renderer->viewInfo.sceneCenter=Vector3r(c[0],c[1],c[2]);
579
Real dispDiameter=min(wholeDiameter,max((Real)displayedSceneRadius()*2,wholeDiameter/1e3)); // limit to avoid drawing 1e5 lines with big zoom level
580
//qglviewer::Vec center=QGLViewer::camera()->sceneCenter();
581
Real gridStep=pow(10,(floor(log10(dispDiameter)-.7)));
582
Real scaleStep=pow(10,(floor(log10(displayedSceneRadius()*2)-.7))); // unconstrained
583
int nSegments=((int)(wholeDiameter/gridStep))+1;
584
Real realSize=nSegments*gridStep;
585
//LOG_TRACE("nSegments="<<nSegments<<",gridStep="<<gridStep<<",realSize="<<realSize);
588
nSegments *= 2; // there's an error in QGLViewer::drawGrid(), so we need to mitigate it by '* 2'
591
if(drawGrid & 1) {glColor3f(0.6,0.3,0.3); glPushMatrix(); glRotated(90.,0.,1.,0.); QGLViewer::drawGrid(realSize,nSegments); glPopMatrix();}
592
if(drawGrid & 2) {glColor3f(0.3,0.6,0.3); glPushMatrix(); glRotated(90.,1.,0.,0.); QGLViewer::drawGrid(realSize,nSegments); glPopMatrix();}
593
if(drawGrid & 4) {glColor3f(0.3,0.3,0.6); glPushMatrix(); /*glRotated(90.,0.,1.,0.);*/ QGLViewer::drawGrid(realSize,nSegments); glPopMatrix();}
595
if(drawGrid & 1) {glColor3f(0.4,0.1,0.1); glPushMatrix(); glRotated(90.,0.,1.,0.); QGLViewer::drawGrid(realSize,nSegments*10); glPopMatrix();}
596
if(drawGrid & 2) {glColor3f(0.1,0.4,0.1); glPushMatrix(); glRotated(90.,1.,0.,0.); QGLViewer::drawGrid(realSize,nSegments*10); glPopMatrix();}
597
if(drawGrid & 4) {glColor3f(0.1,0.1,0.4); glPushMatrix(); /*glRotated(90.,0.,1.,0.);*/ QGLViewer::drawGrid(realSize,nSegments*10); glPopMatrix();}
602
Real segmentSize=scaleStep;
603
qglviewer::Vec screenDxDy[3]; // dx,dy for x,y,z scale segments
604
int extremalDxDy[2]={0,0};
605
for(int axis=0; axis<3; axis++){
606
qglviewer::Vec delta(0,0,0); delta[axis]=segmentSize;
607
qglviewer::Vec center=displayedSceneCenter();
608
screenDxDy[axis]=camera()->projectedCoordinatesOf(center+delta)-camera()->projectedCoordinatesOf(center);
609
for(int xy=0;xy<2;xy++)extremalDxDy[xy]=(axis>0 ? min(extremalDxDy[xy],(int)screenDxDy[axis][xy]) : screenDxDy[axis][xy]);
611
//LOG_DEBUG("Screen offsets for axes: "<<" x("<<screenDxDy[0][0]<<","<<screenDxDy[0][1]<<") y("<<screenDxDy[1][0]<<","<<screenDxDy[1][1]<<") z("<<screenDxDy[2][0]<<","<<screenDxDy[2][1]<<")");
612
int margin=10; // screen pixels
613
int scaleCenter[2]; scaleCenter[0]=abs(extremalDxDy[0])+margin; scaleCenter[1]=abs(extremalDxDy[1])+margin;
614
//LOG_DEBUG("Center of scale "<<scaleCenter[0]<<","<<scaleCenter[1]);
615
//displayMessage(QString().sprintf("displayed scene radius %g",displayedSceneRadius()));
616
startScreenCoordinatesSystem();
617
glDisable(GL_LIGHTING);
618
glDisable(GL_DEPTH_TEST);
620
for(int axis=0; axis<3; axis++){
621
Vector3r color(.4,.4,.4); color[axis]=.9;
624
glVertex2f(scaleCenter[0],scaleCenter[1]);
625
glVertex2f(scaleCenter[0]+screenDxDy[axis][0],scaleCenter[1]+screenDxDy[axis][1]);
629
glEnable(GL_DEPTH_TEST);
630
QGLViewer::drawText(scaleCenter[0],scaleCenter[1],QString().sprintf("%.3g",(double)scaleStep));
631
stopScreenCoordinatesSystem();
634
// cutting planes (should be moved to OpenGLRenderer perhaps?)
635
// only painted if one of those is being manipulated
636
if(manipulatedClipPlane>=0){
637
for(int planeId=0; planeId<renderer->numClipPlanes; planeId++){
638
if(!renderer->clipPlaneActive[planeId] && planeId!=manipulatedClipPlane) continue;
640
const Se3r& se3=renderer->clipPlaneSe3[planeId];
641
AngleAxisr aa(se3.orientation);
642
glTranslatef(se3.position[0],se3.position[1],se3.position[2]);
643
glRotated(aa.angle()*Mathr::RAD_TO_DEG,aa.axis()[0],aa.axis()[1],aa.axis()[2]);
645
if(!renderer->clipPlaneActive[planeId]) cff=.4;
646
glColor3f(max((Real)0.,cff*cos(planeId)),max((Real)0.,cff*sin(planeId)),planeId==manipulatedClipPlane); // variable colors
647
QGLViewer::drawGrid(realSize,2*nSegments);
648
drawArrow(wholeDiameter/6);
653
Scene* rb=Omega::instance().getScene().get();
654
#define _W3 setw(3)<<setfill('0')
655
#define _W2 setw(2)<<setfill('0')
658
unsigned x=10,y=height()-3-lineHt*2;
659
glColor3v(Vector3r(1,1,1));
660
if(timeDispMask & GLViewer::TIME_VIRT){
662
const Real& t=Omega::instance().getScene()->time;
663
unsigned min=((unsigned)t/60),sec=(((unsigned)t)%60),msec=((unsigned)(1e3*t))%1000,usec=((unsigned long)(1e6*t))%1000,nsec=((unsigned long)(1e9*t))%1000;
664
if(min>0) oss<<_W2<<min<<":"<<_W2<<sec<<"."<<_W3<<msec<<"m"<<_W3<<usec<<"u"<<_W3<<nsec<<"n";
665
else if (sec>0) oss<<_W2<<sec<<"."<<_W3<<msec<<"m"<<_W3<<usec<<"u"<<_W3<<nsec<<"n";
666
else if (msec>0) oss<<_W3<<msec<<"m"<<_W3<<usec<<"u"<<_W3<<nsec<<"n";
667
else if (usec>0) oss<<_W3<<usec<<"u"<<_W3<<nsec<<"n";
668
else oss<<_W3<<nsec<<"ns";
669
QGLViewer::drawText(x,y,oss.str().c_str());
672
glColor3v(Vector3r(0,.5,.5));
673
if(timeDispMask & GLViewer::TIME_REAL){
674
QGLViewer::drawText(x,y,getRealTimeString().c_str() /* virtual, since player gets that from db */);
677
if(timeDispMask & GLViewer::TIME_ITER){
680
if(rb->stopAtIter>rb->iter) oss<<" ("<<setiosflags(ios::fixed)<<setw(3)<<setprecision(1)<<setfill('0')<<(100.*rb->iter)/rb->stopAtIter<<"%)";
681
QGLViewer::drawText(x,y,oss.str().c_str());
685
glColor3v(Vector3r(1,1,0));
687
oss<<"grid: "<<setprecision(4)<<gridStep;
688
if(gridSubdivide) oss<<" (minor "<<setprecision(3)<<gridStep*.1<<")";
689
QGLViewer::drawText(x,y,oss.str().c_str());
693
QGLViewer::postDraw();
694
if(!nextFrameSnapshotFilename.empty()){
696
if(boost::algorithm::ends_with(nextFrameSnapshotFilename,".pdf")){
698
LOG_DEBUG("Finished saving snapshot to "<<nextFrameSnapshotFilename);
704
saveSnapshot(QString(nextFrameSnapshotFilename.c_str()),/*overwrite*/ true);
706
// notify the caller that it is done already (probably not an atomic op :-|, though)
707
nextFrameSnapshotFilename.clear();
711
432
string GLViewer::getRealTimeString(){
712
433
ostringstream oss;
713
434
time_duration t=Omega::instance().getRealTime_duration();
724
void GLViewer::mouseMoveEvent(QMouseEvent *e){
725
last_user_event = boost::posix_time::second_clock::local_time();
726
QGLViewer::mouseMoveEvent(e);
729
void GLViewer::mousePressEvent(QMouseEvent *e){
730
last_user_event = boost::posix_time::second_clock::local_time();
731
QGLViewer::mousePressEvent(e);
734
/* Handle double-click event; if clipping plane is manipulated, align it with the global coordinate system.
735
* Otherwise pass the event to QGLViewer to handle it normally.
737
* mostly copied over from ManipulatedFrame::mouseDoubleClickEvent
739
void GLViewer::mouseDoubleClickEvent(QMouseEvent *event){
740
last_user_event = boost::posix_time::second_clock::local_time();
742
if(manipulatedClipPlane<0) { /* LOG_DEBUG("Double click not on clipping plane"); */ QGLViewer::mouseDoubleClickEvent(event); return; }
743
#if QT_VERSION >= 0x040000
744
if (event->modifiers() == Qt::NoModifier)
746
if (event->state() == Qt::NoButton)
748
switch (event->button()){
749
case Qt::LeftButton: manipulatedFrame()->alignWithFrame(NULL,true); LOG_DEBUG("Aligning cutting plane"); break;
750
// case Qt::RightButton: projectOnLine(camera->position(), camera->viewDirection()); break;
751
default: break; // avoid warning
755
void GLViewer::wheelEvent(QWheelEvent* event){
756
last_user_event = boost::posix_time::second_clock::local_time();
758
if(manipulatedClipPlane<0){ QGLViewer::wheelEvent(event); return; }
759
assert(manipulatedClipPlane<renderer->numClipPlanes);
760
float distStep=1e-3*sceneRadius();
761
//const float wheelSensitivityCoef = 8E-4f;
762
//Vec trans(0.0, 0.0, -event->delta()*wheelSensitivity()*wheelSensitivityCoef*(camera->position()-position()).norm());
763
float dist=event->delta()*manipulatedFrame()->wheelSensitivity()*distStep;
764
Vector3r normal=renderer->clipPlaneSe3[manipulatedClipPlane].orientation*Vector3r(0,0,1);
765
qglviewer::Vec newPos=manipulatedFrame()->position()+qglviewer::Vec(normal[0],normal[1],normal[2])*dist;
766
manipulatedFrame()->setPosition(newPos);
767
renderer->clipPlaneSe3[manipulatedClipPlane].position=Vector3r(newPos[0],newPos[1],newPos[2]);
769
/* in draw, bound cutting planes will be moved as well */
772
445
// cut&paste from QGLViewer::domElement documentation
773
446
QDomElement GLViewer::domElement(const QString& name, QDomDocument& document) const{
774
447
QDomElement de=document.createElement("grid");