1 /****************************************************************************
2 * MeshLab o o *
3 * An extendible mesh processor o o *
4 * _ O _ *
5 * Copyright(C) 2005, 2006 \/)\/ *
6 * Visual Computing Lab /\/| *
7 * ISTI - Italian National Research Council | *
8 * \ *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20 * for more details. *
21 * *
22 ****************************************************************************/
23
24
25
26 #include <common/interfaces.h>
27 #include <common/GLExtensionsManager.h>
28
29 #include "glarea.h"
30 #include "mainwindow.h"
31 #include "multiViewer_Container.h"
32 #include "ml_default_decorators.h"
33
34 #include <QFileDialog>
35 #include <QClipboard>
36 #include <QLocale>
37 #include <QPainterPath>
38
39 #include <wrap/gl/picking.h>
40 #include <wrap/qt/trackball.h>
41 #include <wrap/qt/col_qt_convert.h>
42 #include <wrap/qt/shot_qt.h>
43 #include <wrap/qt/checkGLError.h>
44 #include <wrap/qt/gl_label.h>
45 #include <wrap/io_trimesh/export_ply.h>
46 #include <wrap/io_trimesh/import_ply.h>
47 #include<QOpenGLContext>
48
49
50 using namespace std;
51 using namespace vcg;
52
GLArea(QWidget * parent,MultiViewer_Container * mvcont,RichParameterSet * current)53 GLArea::GLArea(QWidget *parent, MultiViewer_Container *mvcont, RichParameterSet *current)
54 : QGLWidget(parent,mvcont->sharedDataContext()),interrbutshow(false)
55 {
56 makeCurrent();
57 parentmultiview = mvcont;
58 this->updateCustomSettingValues(*current);
59 animMode=AnimNone;
60 iRenderer=0; //Shader support
61 iEdit=0;
62 currentEditor=0;
63 suspendedEditor=false;
64 lastModelEdited = 0;
65 cfps=0;
66 lastTime=0;
67 hasToPick=false;
68 hasToSelectMesh=false;
69 hasToGetPickPos=false;
70 //hasToUpdateTexture=false;
71 helpVisible=false;
72 takeSnapTile=false;
73 activeDefaultTrackball=true;
74 infoAreaVisible = true;
75 trackBallVisible = true;
76 currentShader = NULL;
77 lastFilterRef = NULL;
78 //lastEditRef = NULL;
79 setAttribute(Qt::WA_DeleteOnClose,true);
80 fov = fovDefault();
81 clipRatioFar = 5;
82 clipRatioNear = clipRatioNearDefault();
83 nearPlane = .2f;
84 farPlane = 5.f;
85
86 //if (mvcont != NULL)
87 // shared = mvcont->sharedDataContext();
88
89 id = mvcont->getNextViewerId();
90
91 updateMeshSetVisibilities();
92 updateRasterSetVisibilities();
93 setAutoFillBackground(false);
94
95 //Raster support
96 _isRaster =false;
97 opacity = 0.5;
98 zoom = false;
99 targetTex = 0;
100
101 connect(this->md(), SIGNAL(currentMeshChanged(int)), this, SLOT(manageCurrentMeshChange()),Qt::QueuedConnection);
102 //connect(this->md(), SIGNAL(meshDocumentModified()), this, SLOT(updateAllPerMeshDecorators()),Qt::QueuedConnection);
103 connect(this->md(), SIGNAL(meshSetChanged()), this, SLOT(updateMeshSetVisibilities()));
104 connect(this->md(), SIGNAL(rasterSetChanged()), this, SLOT(updateRasterSetVisibilities()));
105 connect(this->md(), SIGNAL(documentUpdated()),this,SLOT(completeUpdateRequested()));
106 connect(this->md(), SIGNAL(updateDecorators(int)),this,SLOT(updatePerMeshDecorators(int)));
107 connect(this, SIGNAL(updateLayerTable()), this->mw(), SIGNAL(updateLayerTable()));
108 connect(md(),SIGNAL(meshRemoved(int)),this,SLOT(meshRemoved(int)));
109
110 QShortcut *copyViewSC = new QShortcut(QKeySequence::Copy, (QWidget*)this);
111 QObject::connect(copyViewSC, SIGNAL(activated()), (QWidget*)this, SLOT(copyToClip()));
112 QShortcut *pasteViewSC = new QShortcut(QKeySequence::Paste, (QWidget*)this);
113 QObject::connect(pasteViewSC, SIGNAL(activated()), (QWidget*)this, SLOT(pasteFromClip()));
114
115 /*getting the meshlab MainWindow from parent, which is QWorkspace.
116 *note as soon as the GLArea is added as Window to the QWorkspace the parent of GLArea is a QWidget,
117 *which takes care about the window frame (its parent is the QWorkspace again).
118 */
119 MainWindow* mainwindow = this->mw();
120 //connecting the MainWindow Slots to GLArea signal (simple passthrough)
121 if(mainwindow != NULL){
122 connect(this,SIGNAL(updateMainWindowMenus()),mainwindow,SLOT(updateMenus()));
123 connect(mainwindow,SIGNAL(dispatchCustomSettings(RichParameterSet&)),this,SLOT(updateCustomSettingValues(RichParameterSet&)));
124 }else{
125 qDebug("The parent of the GLArea parent is not a pointer to the meshlab MainWindow.");
126 }
127 lastloadedraster = -1;
128 }
129
~GLArea()130 GLArea::~GLArea()
131 {
132 }
133
134 /*
135 This member returns the information of the Mesh in terms of VC,VQ,FC,FQ,WT
136 where:
137 VC = VertColor,VQ = VertQuality,FC = FaceColor,FQ = FaceQuality,WT = WedgTexCoord
138 */
GetMeshInfoString()139 QString GLArea::GetMeshInfoString()
140 {
141 QString info;
142 if(mm()->hasDataMask(MeshModel::MM_VERTQUALITY) ) {info.append("VQ ");}
143 if(mm()->hasDataMask(MeshModel::MM_VERTCOLOR) ) {info.append("VC ");}
144 if(mm()->hasDataMask(MeshModel::MM_VERTRADIUS) ) {info.append("VR ");}
145 if(mm()->hasDataMask(MeshModel::MM_VERTTEXCOORD)) {info.append("VT ");}
146 if(mm()->hasDataMask(MeshModel::MM_VERTCURV) ) {info.append("VK ");}
147 if(mm()->hasDataMask(MeshModel::MM_VERTCURVDIR) ) {info.append("VD ");}
148 if(mm()->hasDataMask(MeshModel::MM_FACECOLOR) ) {info.append("FC ");}
149 if(mm()->hasDataMask(MeshModel::MM_FACEQUALITY) ) {info.append("FQ ");}
150 if(mm()->hasDataMask(MeshModel::MM_WEDGTEXCOORD)) {info.append("WT ");}
151 if(mm()->hasDataMask(MeshModel::MM_CAMERA) ) {info.append("MC ");}
152 if(mm()->hasDataMask(MeshModel::MM_POLYGONAL) ) {info.append("MP ");}
153
154 return info;
155 }
156
minimumSizeHint() const157 QSize GLArea::minimumSizeHint() const {return QSize(400,300);}
sizeHint() const158 QSize GLArea::sizeHint() const {return QSize(400,300);}
159
160
initializeGL()161 void GLArea::initializeGL()
162 {
163 makeCurrent();
164 glShadeModel(GL_SMOOTH);
165 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
166 glPixelStorei(GL_PACK_ALIGNMENT, 1);
167 glEnable(GL_DEPTH_TEST);
168 glEnable(GL_NORMALIZE);
169 static float diffuseColor[]={1.0,1.0,1.0,1.0};
170 glEnable(GL_LIGHT0);
171 glDisable(GL_LIGHT1);
172 glLightfv(GL_LIGHT1,GL_DIFFUSE,diffuseColor);
173 trackball.center=Point3f(0, 0, 0);
174 trackball.radius= 1;
175
176 trackball_light.center=Point3f(0, 0, 0);
177 trackball_light.radius= 1;
178 GLExtensionsManager::initializeGLextensions();
179 //doneCurrent();
180 }
181
pasteTile()182 void GLArea::pasteTile()
183 {
184 QString outfile;
185 makeCurrent();
186 glPushAttrib(GL_ENABLE_BIT);
187 bool useAlfa = ss.background==1;
188 QImage tileBuffer = grabFrameBuffer(useAlfa).mirrored(false, true);
189 if(ss.tiledSave)
190 {
191 outfile=QString("%1/%2_%3-%4.png")
192 .arg(ss.outdir)
193 .arg(ss.basename)
194 .arg(tileCol,2,10,QChar('0'))
195 .arg(tileRow,2,10,QChar('0'));
196 tileBuffer.mirrored(false,true).save(outfile,"PNG");
197 }
198 else
199 {
200 if (snapBuffer.isNull())
201 snapBuffer = QImage(tileBuffer.width() * ss.resolution, tileBuffer.height() * ss.resolution, tileBuffer.format());
202
203 uchar *snapPtr = snapBuffer.bits() + (tileBuffer.bytesPerLine() * tileCol) + ((totalCols * tileRow) * tileBuffer.byteCount());
204 uchar *tilePtr = tileBuffer.bits();
205
206 for (int y=0; y < tileBuffer.height(); y++)
207 {
208 memcpy((void*) snapPtr, (void*) tilePtr, tileBuffer.bytesPerLine());
209 snapPtr+=tileBuffer.bytesPerLine() * totalCols;
210 tilePtr+=tileBuffer.bytesPerLine();
211 }
212 }
213 tileCol++;
214
215 if (tileCol >= totalCols)
216 {
217 tileCol=0;
218 tileRow++;
219
220 if (tileRow >= totalRows)
221 {
222 if(ss.snapAllLayers)
223 {
224 outfile=QString("%1/%2%3_L%4.png")
225 .arg(ss.outdir).arg(ss.basename)
226 .arg(ss.counter,2,10,QChar('0'))
227 .arg(currSnapLayer,2,10,QChar('0'));
228 } else {
229 outfile=QString("%1/%2%3.png")
230 .arg(ss.outdir).arg(ss.basename)
231 .arg(ss.counter++,2,10,QChar('0'));
232 }
233
234 if(!ss.tiledSave)
235 {
236 bool ret = (snapBuffer.mirrored(false,true)).save(outfile,"PNG");
237 if (ret)
238 {
239 this->Logf(GLLogStream::SYSTEM, "Snapshot saved to %s",outfile.toLocal8Bit().constData());
240 if(ss.addToRasters)
241 {
242 // get current transform, before is reset by the following importRaster
243 Shotm shot_tmp = shotFromTrackball().first;
244 float tmp_sca = trackball.track.sca;
245 mw()->importRaster(outfile);
246
247 RasterModel *rastm = md()->rm();
248 rastm->shot = shot_tmp;
249 float ratio=(float)rastm->currentPlane->image.height()/(float)rastm->shot.Intrinsics.ViewportPx[1];
250 rastm->shot.Intrinsics.ViewportPx[0]=rastm->currentPlane->image.width();
251 rastm->shot.Intrinsics.ViewportPx[1]=rastm->currentPlane->image.height();
252 rastm->shot.Intrinsics.PixelSizeMm[1]/=ratio;
253 rastm->shot.Intrinsics.PixelSizeMm[0]/=ratio;
254 rastm->shot.Intrinsics.CenterPx[0]= rastm->shot.Intrinsics.ViewportPx[0]/2.0;
255 rastm->shot.Intrinsics.CenterPx[1]= rastm->shot.Intrinsics.ViewportPx[1]/2.0;
256
257 //importRaster has destroyed the original trackball state, now we restore it
258 trackball.track.sca = tmp_sca;
259 loadShot(QPair<Shotm, float>(shot_tmp, trackball.track.sca));
260 }
261 }
262 else
263 {
264 Logf(GLLogStream::WARNING,"Error saving %s",outfile.toLocal8Bit().constData());
265 }
266 }
267 takeSnapTile=false;
268 snapBuffer=QImage();
269 }
270 }
271 update();
272 glPopAttrib();
273 }
274
275
276
drawGradient()277 void GLArea::drawGradient()
278 {
279 makeCurrent();
280 glMatrixMode(GL_PROJECTION);
281 glPushMatrix();
282 glLoadIdentity();
283 glOrtho(-1,1,-1,1,-1,1);
284 glMatrixMode(GL_MODELVIEW);
285 glPushMatrix();
286 glLoadIdentity();
287 glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
288 glDisable(GL_DEPTH_TEST);
289 glDisable(GL_LIGHTING);
290 glDisable(GL_TEXTURE_2D);
291
292 if (!takeSnapTile)
293 {
294 glBegin(GL_TRIANGLE_STRIP);
295 glColor(glas.backgroundTopColor); glVertex2f(-1, 1);
296 glColor(glas.backgroundBotColor); glVertex2f(-1, -1);
297 glColor(glas.backgroundTopColor); glVertex2f(1, 1);
298 glColor(glas.backgroundBotColor); glVertex2f(1, -1);
299 glEnd();
300 }
301 else
302 {
303 float xb = (-tileCol * 2) - 1;
304 float yb = (-tileRow * 2) - 1;
305 float xt = ((totalCols - tileCol) * 2) - 1;
306 float yt = ((totalRows - tileRow) * 2) - 1;
307
308 glBegin(GL_TRIANGLE_STRIP);
309 glColor(glas.backgroundTopColor); glVertex2f(xb, yt);
310 glColor(glas.backgroundBotColor); glVertex2f(xb, yb);
311 glColor(glas.backgroundTopColor); glVertex2f(xt, yt);
312 glColor(glas.backgroundBotColor); glVertex2f(xt, yb);
313 glEnd();
314 }
315
316 glPopAttrib();
317 glPopMatrix(); // restore modelview
318 glMatrixMode(GL_PROJECTION);
319 glPopMatrix();
320 glMatrixMode(GL_MODELVIEW);
321 //doneCurrent();
322 }
323
drawLight()324 void GLArea::drawLight()
325 {
326 makeCurrent();
327 // ============== LIGHT TRACKBALL ==============
328 // Apply the trackball for the light direction
329 glPushMatrix();
330 trackball_light.GetView();
331 trackball_light.Apply();
332
333 static float lightPosF[]={0.0,0.0,1.0,0.0};
334 glLightfv(GL_LIGHT0,GL_POSITION,lightPosF);
335 static float lightPosB[]={0.0,0.0,-1.0,0.0};
336 glLightfv(GL_LIGHT1,GL_POSITION,lightPosB);
337
338 if (!(isDefaultTrackBall()))
339 {
340 glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
341 glColor3f(1,1,0);
342 glDisable(GL_LIGHTING);
343 const unsigned int lineNum=3;
344 glBegin(GL_LINES);
345 for(unsigned int i=0;i<=lineNum;++i)
346 for(unsigned int j=0;j<=lineNum;++j) {
347 glVertex3f(-1.0f+i*2.0/lineNum,-1.0f+j*2.0/lineNum,-2);
348 glVertex3f(-1.0f+i*2.0/lineNum,-1.0f+j*2.0/lineNum, 2);
349 }
350 glEnd();
351 glPopAttrib();
352 }
353 glPopMatrix();
354 if(!isDefaultTrackBall()) trackball_light.DrawPostApply();
355
356 }
RenderForSelection(int pickX,int pickY)357 int GLArea::RenderForSelection(int pickX, int pickY)
358 {
359 makeCurrent();
360 if (mvc() == NULL)
361 return -1;
362
363 MLSceneGLSharedDataContext* datacont = mvc()->sharedDataContext();
364 if (datacont == NULL)
365 return -1;
366
367 int sz = int( md()->meshList.size())*5;
368 GLuint *selectBuf =new GLuint[sz];
369 glSelectBuffer(sz, selectBuf);
370 glRenderMode(GL_SELECT);
371 glInitNames();
372
373 /* Because LoadName() won't work with no names on the stack */
374 glPushName(-1);
375 double mp[16];
376
377 GLint viewport[4];
378 glGetIntegerv(GL_VIEWPORT,viewport);
379 glPushAttrib(GL_TRANSFORM_BIT);
380 glMatrixMode(GL_PROJECTION);
381 glGetDoublev(GL_PROJECTION_MATRIX ,mp);
382 glPushMatrix();
383 glLoadIdentity();
384 gluPickMatrix(pickX, pickY, 4, 4, viewport);
385 glMultMatrixd(mp);
386
387 glMatrixMode(GL_MODELVIEW);
388 glPushMatrix();
389
390 /*if (shared->highPrecisionRendering())
391 glTranslate(-shared->globalSceneCenter());*/
392
393 foreach(MeshModel * mp, this->md()->meshList)
394 {
395 glLoadName(mp->id());
396
397 datacont->setMeshTransformationMatrix(mp->id(), mp->cm.Tr);
398 datacont->draw(mp->id(), context());
399 }
400
401 long hits;
402 glPopMatrix();
403 glMatrixMode(GL_PROJECTION);
404 glPopMatrix();
405 glMatrixMode(GL_MODELVIEW);
406 hits = glRenderMode(GL_RENDER);
407 glPopAttrib();
408
409 std::vector< std::pair<double,unsigned int> > H;
410 for(long ii=0;ii<hits;ii++){
411 H.push_back( std::pair<double,unsigned int>(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3]));
412 }
413 std::sort(H.begin(),H.end());
414 delete [] selectBuf;
415 if(hits==0) return -1;
416 return H.front().second;
417 }
418
paintEvent(QPaintEvent *)419 void GLArea::paintEvent(QPaintEvent* /*event*/)
420 {
421 if (mvc() == NULL)
422 return;
423 QPainter painter(this);
424 painter.beginNativePainting();
425 #ifdef Q_OS_MAC
426 glGetError(); // This seems required because on osx painter.beginNativePainting() trashes the err state of opengl
427 #endif
428
429 makeCurrent();
430
431 if(!isValid())
432 return;
433
434 QElapsedTimer time;
435 time.start();
436
437 /*if(!this->md()->isBusy())
438 {
439 initTexture(hasToUpdateTexture);
440 hasToUpdateTexture=false;
441 }*/
442
443 ::glClearColor(1.0,1.0,1.0,0.0);
444 if (takeSnapTile && (ss.background == 3))
445 ::glClearColor(0.0, 0.0, 0.0, 0.0);
446 glEnable(GL_DEPTH_TEST);
447 glDepthMask(GL_TRUE);
448 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
449
450 setView(); // Set Modelview and Projection matrix
451 if((!takeSnapTile) || (takeSnapTile && (ss.background==0)) )
452 drawGradient(); // draws the background
453
454 drawLight();
455
456 glPushMatrix();
457 // Finally apply the Trackball for the model
458 trackball.GetView();
459 trackball.Apply();
460
461 glPushMatrix();
462
463 if(!this->md()->isBusy())
464 {
465 glPushAttrib(GL_ALL_ATTRIB_BITS);
466
467
468 if ((iRenderer) && (parentmultiview != NULL))
469 {
470 MLSceneGLSharedDataContext* shared = parentmultiview->sharedDataContext();
471 if (shared != NULL)
472 {
473 MLSceneGLSharedDataContext::PerMeshRenderingDataMap dt;
474 shared->getRenderInfoPerMeshView(context(),dt);
475
476 iRenderer->Render(currentShader, *this->md(),dt,this);
477
478 MLDefaultMeshDecorators defdec(mw());
479
480 foreach(MeshModel * mp, this->md()->meshList)
481 {
482 if ((mp != NULL) && (meshVisibilityMap[mp->id()]))
483 {
484 QList<QAction *>& tmpset = iPerMeshDecoratorsListMap[mp->id()];
485 for( QList<QAction *>::iterator it = tmpset.begin(); it != tmpset.end();++it)
486 {
487 MeshDecorateInterface * decorInterface = qobject_cast<MeshDecorateInterface *>((*it)->parent());
488 decorInterface->decorateMesh(*it,*mp,this->glas.currentGlobalParamSet,this,&painter,md()->Log);
489 }
490 MLRenderingData meshdt;
491 shared->getRenderInfoPerMeshView(mp->id(),context(),meshdt);
492 defdec.decorateMesh(*mp,meshdt,&painter,md()->Log);
493 }
494 }
495 }
496 }
497 else
498 {
499 if(hasToSelectMesh) // right mouse click you have to select a mesh
500 {
501 int newId=RenderForSelection(pointToPick[0],pointToPick[1]);
502 if(newId>=0)
503 {
504 Logf(0,"Selected new Mesh %i",newId);
505 md()->setCurrentMesh(newId);
506 if (mw() != NULL)
507 mw()->updateLayerDialog();
508 //update();
509 }
510 hasToSelectMesh=false;
511 }
512 MLSceneGLSharedDataContext* datacont = mvc()->sharedDataContext();
513 if (datacont == NULL)
514 return;
515
516 foreach(MeshModel * mp, this->md()->meshList)
517 {
518 if (meshVisibilityMap[mp->id()])
519 {
520 MLRenderingData curr;
521 datacont->getRenderInfoPerMeshView(mp->id(),context(),curr);
522 MLPerViewGLOptions opts;
523 if (curr.get(opts) == false)
524 throw MLException(QString("GLArea: invalid MLPerViewGLOptions"));
525 setLightingColors(opts);
526
527
528 if(opts._back_face_cull)
529 glEnable(GL_CULL_FACE);
530 else
531 glDisable(GL_CULL_FACE);
532
533 datacont->setMeshTransformationMatrix(mp->id(),mp->cm.Tr);
534 datacont->draw(mp->id(),context());
535 }
536 }
537 foreach(MeshModel * mp, this->md()->meshList)
538 {
539 if (meshVisibilityMap[mp->id()])
540 {
541 MLRenderingData curr;
542 MLDefaultMeshDecorators defdec(mw());
543 datacont->getRenderInfoPerMeshView(mp->id(), context(), curr);
544 defdec.decorateMesh(*mp, curr, &painter, md()->Log);
545
546 QList<QAction *>& tmpset = iPerMeshDecoratorsListMap[mp->id()];
547 for (QList<QAction *>::iterator it = tmpset.begin(); it != tmpset.end(); ++it)
548 {
549 MeshDecorateInterface * decorInterface = qobject_cast<MeshDecorateInterface *>((*it)->parent());
550 decorInterface->decorateMesh(*it, *mp, this->glas.currentGlobalParamSet, this, &painter, md()->Log);
551 }
552 }
553 }
554 }
555 if (iEdit) {
556 iEdit->setLog(&md()->Log);
557 iEdit->Decorate(*mm(), this, &painter);
558 }
559
560 glPopAttrib();
561 } ///end if busy
562
563 glPopMatrix(); // We restore the state to immediately after the trackball (and before the bbox scaling/translating)
564
565 if(trackBallVisible && !takeSnapTile && !(iEdit && !suspendedEditor))
566 trackball.DrawPostApply();
567
568 foreach(QAction * p, iPerDocDecoratorlist)
569 {
570 MeshDecorateInterface * decorInterface = qobject_cast<MeshDecorateInterface *>(p->parent());
571 decorInterface->decorateDoc(p, *this->md(), this->glas.currentGlobalParamSet, this, &painter, md()->Log);
572 }
573
574 // The picking of the surface position has to be done in object space,
575 // so after trackball transformation (and before the matrix associated to each mesh);
576 if(hasToPick && hasToGetPickPos)
577 {
578 Point3f pp;
579 hasToPick=false;
580 if(Pick<Point3f>(pointToPick[0],pointToPick[1],pp))
581 {
582 emit transmitSurfacePos(nameToGetPickPos, pp);
583 hasToGetPickPos=false;
584 }
585 }
586
587 if (hasToPick && hasToGetPickCoords)
588 {
589 Point2f pp(pointToPick[0], pointToPick[1]);
590 hasToPick = false;
591 emit transmitPickedPos(nameToGetPickCoords, pp);
592 hasToGetPickCoords = false;
593 }
594
595
596
597 // we want to write scene-space the point picked with double-click in the log
598 // we have to do it now, before leaving this transformation space
599 // we hook to the same mechanism double-click will be managed later on to move trackball
600 if(hasToPick && !hasToGetPickPos)
601 {
602 Point3f pp;
603 if(Pick<Point3f>(pointToPick[0],pointToPick[1],pp))
604 {
605 // write picked point in the log
606 Logf(0,"Recentering on point [%f %f %f] [%d,%d]",pp[0],pp[1],pp[2],pointToPick[0],pointToPick[1]);
607 }
608 }
609
610 glPopMatrix(); // We restore the state to immediately before the trackball
611 //If it is a raster viewer draw the image as a texture
612 if (isRaster())
613 {
614 if ((md()->rm() != NULL) && (lastloadedraster != md()->rm()->id()))
615 loadRaster(md()->rm()->id());
616 drawTarget();
617 }
618
619 // Double click move picked point to center
620 // It has to be done in the before trackball space (we MOVE the trackball itself...)
621 if(hasToPick && !hasToGetPickPos)
622 {
623 Point3f pp;
624 hasToPick=false;
625 if(Pick<Point3f>(pointToPick[0],pointToPick[1],pp))
626 {
627 trackball.MouseUp(pointToPick[0],pointToPick[1], vcg::Trackball::BUTTON_NONE );
628 trackball.Translate(-pp);
629 trackball.Scale(1.25f);
630
631 QCursor::setPos(mapToGlobal(QPoint(width()/2+2,height()/2+2)));
632 }
633 }
634
635 // ...and take a snapshot
636 if (takeSnapTile) pasteTile();
637
638 // Finally display HELP if requested
639 if (isHelpVisible())
640 displayHelp();
641
642 //Draw highlight if it is the current viewer
643 if(mvc()->currentId==id)
644 displayViewerHighlight();
645
646 QString error = checkGLError::makeString("There are gl errors: ");
647 if(!error.isEmpty()) {
648 Log(GLLogStream::WARNING, qUtf8Printable(error));
649 }
650 //check if viewers are linked
651 MainWindow *window = qobject_cast<MainWindow *>(QApplication::activeWindow());
652 if(window && window->linkViewersAct->isChecked() && mvc()->currentId==id)
653 mvc()->updateTrackballInViewers();
654
655 // Draw the log area background
656 // on the bottom of the glArea
657 if (infoAreaVisible)
658 {
659 glPushAttrib(GL_ENABLE_BIT);
660 glDisable(GL_DEPTH_TEST);
661 renderingFacilityString();
662 displayInfo(&painter);
663 displayRealTimeLog(&painter);
664 updateFps(time.elapsed());
665 glPopAttrib();
666 }
667 //doneCurrent();
668 glFlush();
669 glFinish();
670 painter.endNativePainting();
671 }
672
displayMatrix(QPainter * painter,QRect areaRect)673 void GLArea::displayMatrix(QPainter *painter, QRect areaRect)
674 {
675 makeCurrent();
676 painter->save();
677 qFont.setFamily("Helvetica");
678 qFont.setPixelSize(10);
679 qFont.setStyleStrategy(QFont::PreferAntialias);
680 painter->setFont(qFont);
681
682 QString tableText;
683 for(int i=0;i<4;i++)
684 tableText+=QString("\t%1\t%2\t%3\t%4\n")
685 .arg(mm()->cm.Tr[i][0],5,'f',2).arg(mm()->cm.Tr[i][1],5,'f',2)
686 .arg(mm()->cm.Tr[i][2],5,'f',2).arg(mm()->cm.Tr[i][3],5,'f',2);
687
688 QTextOption TO;
689 QTextOption::Tab ttt;
690 ttt.type=QTextOption::DelimiterTab;
691 ttt.delimiter = '.';
692 const int columnSpacing = 40;
693 ttt.position=columnSpacing;
694 QList<QTextOption::Tab> TabList;
695 for(int i=0;i<4;++i){
696 TabList.push_back(ttt);
697 ttt.position+=columnSpacing;
698 }
699 TO.setTabs(TabList);
700 painter->drawText(areaRect, tableText, TO);
701 painter->restore();
702 }
displayRealTimeLog(QPainter * painter)703 void GLArea::displayRealTimeLog(QPainter *painter)
704 {
705 makeCurrent();
706 painter->endNativePainting();
707 painter->save();
708 painter->setPen(Qt::white);
709 Color4b logAreaColor = glas.logAreaColor;
710 glas.logAreaColor[3]=128;
711 if(mvc()->currentId!=id) logAreaColor /=2.0;
712
713 qFont.setStyleStrategy(QFont::PreferAntialias);
714 qFont.setFamily("Helvetica");
715 qFont.setPixelSize(11);
716 painter->setFont(qFont);
717 float margin = qFont.pixelSize();
718 QFontMetrics metrics = QFontMetrics(font());
719 int border = qMax(4, metrics.leading());
720 qreal roundness = 10.0f;
721 QTextDocument doc;
722 doc.setDefaultFont(qFont);
723 int startingpoint = border;
724 //mQMultiMap<QString,std::pair<QString,QString> >::const_iterator it = md()->Log.RealTimeLogText.constBegin();it != md()->Log.RealTimeLogText.constEnd();++it)
725 for (QString keyIt : md()->Log.realTimeLogMultiMap().uniqueKeys() )
726 {
727 QList< QPair<QString,QString> > valueList = md()->Log.realTimeLogMultiMap().values(keyIt);
728 QPair<QString,QString> itVal;
729 // the map contains pairs of meshname, text
730 // the meshname is used only to disambiguate when there are more than two boxes with the same title
731 for(const QPair<QString,QString>& itVal: valueList)
732 {
733 QString HeadName = keyIt;
734 if(md()->Log.realTimeLogMultiMap().count(keyIt)>1)
735 HeadName += " - "+itVal.first;
736 doc.clear();
737 doc.setDocumentMargin(margin*0.75);
738 QColor textColor = Qt::white;
739 QColor headColor(200,200,200);
740 doc.setHtml("<font color=\"" + headColor.name() + "\" size=\"+1\" ><p><i><b>" + HeadName + "</b></i></p></font>"
741 "<font color=\"" + textColor.name() + "\" >" + itVal.second + "</font>");
742 QRect outrect(border,startingpoint,doc.size().width(),doc.size().height());
743 QPainterPath path;
744 painter->setBrush(QBrush(ColorConverter::ToQColor(logAreaColor),Qt::SolidPattern));
745 painter->setPen(ColorConverter::ToQColor(logAreaColor));
746 path.addRoundedRect(outrect,roundness,roundness);
747 painter->drawPath(path);
748 painter->save();
749 painter->translate(border,startingpoint);
750 doc.drawContents(painter);
751 painter->restore();
752 startingpoint = startingpoint + doc.size().height() + margin*.75;
753 }
754 }
755
756 // After the rederaw we clear the RealTimeLog buffer!
757 md()->Log.clearRealTimeLog();
758 painter->restore();
759 painter->beginNativePainting();
760 }
761
displayInfo(QPainter * painter)762 void GLArea::displayInfo(QPainter *painter)
763 {
764 makeCurrent();
765 if ((mvc() == NULL) || (md() == NULL))
766 return;
767 painter->endNativePainting();
768 painter->save();
769
770 painter->setRenderHint(QPainter::HighQualityAntialiasing);
771 QPen textPen(QColor(255,255,255,200));
772 textPen.setWidthF(0.2f);
773 painter->setPen(textPen);
774
775 qFont.setStyleStrategy(QFont::PreferAntialias);
776 qFont.setFamily("Helvetica");
777 qFont.setPixelSize(12);
778 painter->setFont(qFont);
779 QFontMetrics metrics = QFontMetrics(qFont);
780 int border = qMax(4, metrics.leading()) / 2;
781 int numLines = 6;
782
783 float barHeight = ((metrics.height() + metrics.leading())*numLines) + 2 * border;
784
785 QRect Column_0(width()/10, this->height()-barHeight+border, width()/2, this->height()-border);
786 QRect Column_1(width()/2 , this->height()-barHeight+border, width()*3/4, this->height()-border);
787 QRect Column_2(width()*3/4 , this->height()-barHeight+border, width(), this->height()-border);
788
789 Color4b logAreaColor = glas.logAreaColor;
790 glas.logAreaColor[3]=128;
791 if(mvc()->currentId!=id) logAreaColor /=2.0;
792
793 painter->fillRect(QRect(0, this->height()-barHeight, width(), this->height()), ColorConverter::ToQColor(logAreaColor));
794
795 QString col1Text,col0Text;
796
797 if(this->md()->size()>0)
798 {
799 if(this->md()->size()==1)
800 {
801 QLocale engLocale(QLocale::English, QLocale::UnitedStates);
802 col1Text += QString("Mesh: %1\n").arg(mm()->label());
803 col1Text += "Vertices: " + engLocale.toString(mm()->cm.vn) + " \n";
804 col1Text += "Faces: " + engLocale.toString(mm()->cm.fn) + " \n";
805 }
806 else
807 {
808 QLocale engLocale(QLocale::English, QLocale::UnitedStates);
809 QFileInfo inf = mm()->label();
810 col1Text += QString("Current Mesh: %1\n").arg(inf.completeBaseName());
811 col1Text += "Vertices: " + engLocale.toString(mm()->cm.vn) + " (" + engLocale.toString(this->md()->vn()) + ") \n";
812 col1Text += "Faces: " + engLocale.toString(mm()->cm.fn) + " (" + engLocale.toString(this->md()->fn()) + ") \n";
813 }
814
815
816 int svn = 0;
817 int sfn = 0;
818
819 if (mm() != NULL)
820 {
821 svn = mm()->cm.svn;
822 sfn = mm()->cm.sfn;
823 }
824
825 QLocale engLocale(QLocale::English, QLocale::UnitedStates);
826 col1Text += "Selection: v: " + engLocale.toString(svn) + " f: " + engLocale.toString(sfn) + " \n";
827
828 col1Text += GetMeshInfoString();
829
830 if(fov>5) col0Text += QString("FOV: %1\n").arg(fov);
831 else col0Text += QString("FOV: Ortho\n");
832 if ((cfps>0) && (cfps<1999))
833 col0Text += QString("FPS: %1\n").arg(cfps,7,'f',1);
834
835 col0Text += renderfacility;
836
837 if (clipRatioNear!=clipRatioNearDefault())
838 col0Text += QString("\nClipping Near:%1\n").arg(clipRatioNear,7,'f',2);
839 painter->drawText(Column_1, Qt::AlignLeft | Qt::TextWordWrap, col1Text);
840 painter->drawText(Column_0, Qt::AlignLeft | Qt::TextWordWrap, col0Text);
841 if(mm()->cm.Tr != Matrix44m::Identity() ) displayMatrix(painter, Column_2);
842 }
843 painter->restore();
844 painter->beginNativePainting();
845 //glPopAttrib();
846 }
847
renderingFacilityString()848 void GLArea::renderingFacilityString()
849 {
850
851 renderfacility.clear();
852 makeCurrent();
853 if (md()->size() > 0)
854 {
855 enum RenderingType { FULL_BO, MIXED, FULL_IMMEDIATE_MODE };
856 RenderingType rendtype = FULL_IMMEDIATE_MODE;
857
858 if (parentmultiview != NULL)
859 {
860 MLSceneGLSharedDataContext* shared = parentmultiview->sharedDataContext();
861 if (shared != NULL)
862 {
863 int hh = 0;
864 foreach(MeshModel* meshmod, md()->meshList)
865 {
866 if (shared->isBORenderingAvailable(meshmod->id()))
867 {
868 rendtype = MIXED;
869 if ((rendtype == MIXED) && (hh == md()->meshList.size() - 1))
870 rendtype = FULL_BO;
871 }
872 ++hh;
873 }
874 }
875 }
876
877 switch (rendtype)
878 {
879 case(FULL_BO):
880 {
881 renderfacility += QString("BO_RENDERING");
882 break;
883 }
884 case(MIXED):
885 {
886 renderfacility += QString("MIXED_RENDERING");
887 break;
888 }
889 case(FULL_IMMEDIATE_MODE):
890 {
891 renderfacility += QString("IMMEDIATE_MODE_RENDERING");
892 break;
893 }
894 }
895 }
896 }
897
displayViewerHighlight()898 void GLArea::displayViewerHighlight()
899 {
900 makeCurrent();
901 // Enter in 2D screen Mode again
902 glPushAttrib(GL_LINE_BIT);
903
904 glMatrixMode(GL_PROJECTION);
905 glPushMatrix();
906 glLoadIdentity();
907 glOrtho(-1,1,-1,1,-1,1);
908 glMatrixMode(GL_MODELVIEW);
909 glPushMatrix();
910 glLoadIdentity();
911 glPushAttrib(GL_ENABLE_BIT);
912 glDisable(GL_DEPTH_TEST);
913 glDisable(GL_LIGHTING);
914 glDisable(GL_TEXTURE_2D);
915 glEnable(GL_BLEND);
916 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
917 glColor4f(1.0f,1.0f,1.0f,0.3f);
918 for(int width =5; width>0 ; width -= 2)
919 {
920 glLineWidth(width);
921 glBegin(GL_LINE_LOOP);
922 glVertex2f(-1.f,1.f); glVertex2f( 1.f,1.f); glVertex2f( 1.f,-1.f); glVertex2f(-1.f,-1.f);
923 glEnd();
924 }
925 // Closing 2D
926 glPopAttrib();
927 glPopMatrix(); // restore modelview
928 glMatrixMode(GL_PROJECTION);
929 glPopMatrix();
930 glMatrixMode(GL_MODELVIEW);
931 glPopAttrib();
932
933 }
934
935
displayHelp()936 void GLArea::displayHelp()
937 {
938 makeCurrent();
939 static QString tableText;
940 if(tableText.isEmpty())
941 {
942 QFile helpFile(":/images/onscreenHelp.txt");
943 if(helpFile.open(QFile::ReadOnly))
944 tableText=helpFile.readAll();
945 else assert(0);
946 #ifdef Q_OS_MAC
947 tableText.replace("Ctrl","Command");
948 #endif
949 }
950 md()->Log.RealTimeLog("Quick Help","",tableText);
951 }
952
953
saveSnapshot()954 void GLArea::saveSnapshot()
955 {
956 makeCurrent();
957 // snap all layers
958 currSnapLayer=0;
959
960 // number of subparts
961 totalCols=totalRows=ss.resolution;
962 tileRow=tileCol=0;
963
964 if(ss.snapAllLayers)
965 {
966 while(currSnapLayer<this->md()->meshList.size())
967 {
968 tileRow=tileCol=0;
969 qDebug("Snapping layer %i",currSnapLayer);
970 int mmit = 0;
971 foreach(MeshModel *mp,this->md()->meshList) {
972 if (mmit == currSnapLayer)
973 meshSetVisibility(mp, true);
974 else
975 meshSetVisibility(mp, false);
976 mmit++;
977 }
978
979 takeSnapTile=true;
980 for (int tilenum = 0; tilenum < (ss.resolution*ss.resolution); tilenum++)
981 repaint();
982 currSnapLayer++;
983 }
984
985 //cleanup
986 foreach(MeshModel *mp,this->md()->meshList) {
987 meshSetVisibility(mp,true);
988 }
989 ss.counter++;
990 }
991 else
992 {
993 takeSnapTile=true;
994 update();
995 }
996 }
997
998 // Slot called when the current mesh has changed.
manageCurrentMeshChange()999 void GLArea::manageCurrentMeshChange()
1000 {
1001 //if we have an edit tool open, notify it that the current layer has changed
1002 if(iEdit)
1003 {
1004 if(iEdit->isSingleMeshEdit())
1005 assert(lastModelEdited); // if there is an editor that works on a single mesh
1006 // last model edited should always be set when start edit is called
1007
1008 iEdit->LayerChanged(*this->md(), *lastModelEdited, this,parentmultiview->sharedDataContext());
1009
1010 //now update the last model edited
1011 //TODO this is not the best design.... iEdit should maybe keep track of the model on its own
1012 lastModelEdited = this->md()->mm();
1013 }
1014 emit this->updateMainWindowMenus();
1015 // if the layer has changed update also the decoration.
1016 // updateAllPerMeshDecorators();
1017 }
1018
1019 ///// Execute a end/start pair for all the PerMesh decorator that are active in this glarea.
1020 ///// It is used when the document is changed or when some parameter changes
1021 ///// Note that it is rather inefficient. Such work should be done only once for each decorator.
1022 //void GLArea::updateAllPerMeshDecorators()
1023 //{
1024 // MeshDocument* mdoc = md();
1025 // if (mdoc == NULL)
1026 // return;
1027 // makeCurrent();
1028 //
1029 // for (QMap<int, QList<QAction *> >::iterator i = iPerMeshDecoratorsListMap.begin(); i != iPerMeshDecoratorsListMap.end(); ++i )
1030 // {
1031 //
1032 // MeshModel *m = md()->getMesh(i.key());
1033 // foreach(QAction *p , i.value())
1034 // {
1035 // MeshDecorateInterface * decorInterface = qobject_cast<MeshDecorateInterface *>(p->parent());
1036 // decorInterface->endDecorate (p, *m,this->glas.currentGlobalParamSet,this);
1037 // decorInterface->setLog(&md()->Log);
1038 // decorInterface->startDecorate(p,*m, this->glas.currentGlobalParamSet,this);
1039 // }
1040 // }
1041 //
1042 // MultiViewer_Container* viewcont = mvc();
1043 // if (viewcont == NULL)
1044 // return;
1045 //
1046 // MLSceneGLSharedDataContext* shared = viewcont->sharedDataContext();
1047 // if (shared == NULL)
1048 // return;
1049 //
1050 // MLDefaultMeshDecorators defdec(mw());
1051 // for(MeshModel* mm = mdoc->nextMesh();mm != NULL;mm = mdoc->nextMesh(mm))
1052 // {
1053 // MLRenderingData dt;
1054 // shared->getRenderInfoPerMeshView(mm->id(),context(),dt);
1055 // defdec.cleanMeshDecorationData(*mm,dt);
1056 // defdec.initMeshDecorationData(*mm,dt);
1057 // }
1058 //}
1059
1060
updateAllDecorators()1061 void GLArea::updateAllDecorators()
1062 {
1063 updateAllPerMeshDecorators();
1064 if (md() == NULL)
1065 return;
1066 foreach(QAction * p, iPerDocDecoratorlist)
1067 {
1068 MeshDecorateInterface * decorInterface = qobject_cast<MeshDecorateInterface *>(p->parent());
1069 decorInterface->endDecorate(p, *md(), this->glas.currentGlobalParamSet, this);
1070 decorInterface->setLog(&md()->Log);
1071 decorInterface->startDecorate(p, *md(), this->glas.currentGlobalParamSet, this);
1072 }
1073 if (mvc() != NULL)
1074 mvc()->updateAllViewers();
1075 }
1076
setCurrentEditAction(QAction * editAction)1077 void GLArea::setCurrentEditAction(QAction *editAction)
1078 {
1079 if ((parentmultiview == NULL) || (parentmultiview->sharedDataContext() == NULL))
1080 return;
1081
1082 makeCurrent();
1083 assert(editAction);
1084 currentEditor = editAction;
1085
1086 iEdit = actionToMeshEditMap.value(currentEditor);
1087 if (iEdit == NULL)
1088 return;
1089
1090 lastModelEdited = this->md()->mm();
1091
1092 /*_oldvalues.clear();
1093 parentmultiview->sharedDataContext()->getRenderInfoPerMeshView(context(), _oldvalues);*/
1094
1095 MLRenderingData dt;
1096 if (iEdit->isSingleMeshEdit())
1097 {
1098 if (md()->mm() != NULL)
1099 {
1100 parentmultiview->sharedDataContext()->getRenderInfoPerMeshView(md()->mm()->id(), context(), dt);
1101 iEdit->suggestedRenderingData(*(md()->mm()), dt);
1102 MLPoliciesStandAloneFunctions::disableRedundatRenderingDataAccordingToPriorities(dt);
1103 parentmultiview->sharedDataContext()->setRenderingDataPerMeshView(md()->mm()->id(), context(), dt);
1104 parentmultiview->sharedDataContext()->manageBuffers(md()->mm()->id());
1105 }
1106 }
1107 else
1108 {
1109 foreach(MeshModel* mm, md()->meshList)
1110 {
1111 if (mm != NULL)
1112 {
1113 parentmultiview->sharedDataContext()->getRenderInfoPerMeshView(mm->id(), context(), dt);
1114 iEdit->suggestedRenderingData(*(mm), dt);
1115 MLPoliciesStandAloneFunctions::disableRedundatRenderingDataAccordingToPriorities(dt);
1116 parentmultiview->sharedDataContext()->setRenderingDataPerMeshView(mm->id(), context(), dt);
1117 parentmultiview->sharedDataContext()->manageBuffers(mm->id());
1118 }
1119 }
1120 }
1121 if (mw() != NULL)
1122 mw()->updateLayerDialog();
1123 if (!iEdit->StartEdit(*this->md(), this,parentmultiview->sharedDataContext()))
1124 {
1125 //iEdit->EndEdit(*(this->md()->mm()), this);
1126 endEdit();
1127 }
1128 else
1129 {
1130 Logf(GLLogStream::SYSTEM,"Started Mode %s", qUtf8Printable(currentEditor->text()));
1131 if(mm()!=NULL)
1132 mm()->meshModified() = true;
1133 else assert(!iEdit->isSingleMeshEdit());
1134 update();
1135 }
1136 }
1137
1138
readyToClose()1139 bool GLArea::readyToClose()
1140 {
1141 makeCurrent();
1142 // Now do the actual closing of the glArea
1143 if (getCurrentEditAction())
1144 {
1145 endEdit();
1146 md()->meshDocStateData().clear();
1147 }
1148 if (iRenderer)
1149 iRenderer->Finalize(currentShader, this->md(), this);
1150
1151 // Now manage the closing of the decorator set;
1152 foreach(QAction* act, iPerDocDecoratorlist)
1153 {
1154 MeshDecorateInterface* mdec = qobject_cast<MeshDecorateInterface*>(act->parent());
1155 mdec->endDecorate(act,*md(),glas.currentGlobalParamSet,this);
1156 mdec->setLog(NULL);
1157 }
1158 iPerDocDecoratorlist.clear();
1159 QSet<QAction *> dectobeclose;
1160 for(QMap<int, QList<QAction *> >::iterator it = iPerMeshDecoratorsListMap.begin();it != iPerMeshDecoratorsListMap.end();++it)
1161 {
1162 foreach(QAction* curract,it.value())
1163 dectobeclose.insert(curract);
1164 }
1165
1166 for(QSet<QAction *>::iterator it = dectobeclose.begin();it != dectobeclose.end();++it)
1167 {
1168 MeshDecorateInterface* mdec = qobject_cast<MeshDecorateInterface*>((*it)->parent());
1169 if (mdec != NULL)
1170 {
1171 mdec->endDecorate(*it,*md(),glas.currentGlobalParamSet,this);
1172 mdec->setLog(NULL);
1173 }
1174 }
1175 dectobeclose.clear();
1176 iPerMeshDecoratorsListMap.clear();
1177 if(targetTex) glDeleteTextures(1, &targetTex);
1178 emit glareaClosed();
1179 return true;
1180 }
1181
keyReleaseEvent(QKeyEvent * e)1182 void GLArea::keyReleaseEvent ( QKeyEvent * e )
1183 {
1184 makeCurrent();
1185 e->ignore();
1186 if(iEdit && !suspendedEditor) iEdit->keyReleaseEvent(e,*mm(),this);
1187 else{
1188 if(e->key()==Qt::Key_Control) trackball.ButtonUp(QT2VCG(Qt::NoButton, Qt::ControlModifier ) );
1189 if(e->key()==Qt::Key_Shift) trackball.ButtonUp(QT2VCG(Qt::NoButton, Qt::ShiftModifier ) );
1190 if(e->key()==Qt::Key_Alt) trackball.ButtonUp(QT2VCG(Qt::NoButton, Qt::AltModifier ) );
1191 }
1192 }
1193
keyPressEvent(QKeyEvent * e)1194 void GLArea::keyPressEvent ( QKeyEvent * e )
1195 {
1196 makeCurrent();
1197 e->ignore();
1198 if(iEdit && !suspendedEditor) iEdit->keyPressEvent(e,*mm(),this);
1199 else{
1200 if(e->key()==Qt::Key_Control) trackball.ButtonDown(QT2VCG(Qt::NoButton, Qt::ControlModifier ) );
1201 if(e->key()==Qt::Key_Shift) trackball.ButtonDown(QT2VCG(Qt::NoButton, Qt::ShiftModifier ) );
1202 if(e->key()==Qt::Key_Alt) trackball.ButtonDown(QT2VCG(Qt::NoButton, Qt::AltModifier ) );
1203 }
1204 }
1205
mousePressEvent(QMouseEvent * e)1206 void GLArea::mousePressEvent(QMouseEvent*e)
1207 {
1208 makeCurrent();
1209 e->accept();
1210 if (!this->hasFocus())
1211 {
1212 this->setFocus();
1213 }
1214
1215 {
1216 if ((iEdit != NULL) && !suspendedEditor)
1217 {
1218 iEdit->mousePressEvent(e, *mm(), this);
1219 }
1220 else
1221 {
1222 if (e->button() == Qt::RightButton) // Select a new current mesh
1223 {
1224 hasToSelectMesh = true;
1225 this->pointToPick = Point2i(QT2VCG_X(this, e), QT2VCG_Y(this, e));
1226 }
1227 else
1228 {
1229 if ((e->modifiers() & Qt::ShiftModifier) &&
1230 (e->modifiers() & Qt::ControlModifier) &&
1231 (e->button() == Qt::LeftButton))
1232 activeDefaultTrackball = false;
1233 else activeDefaultTrackball = true;
1234
1235 if (isDefaultTrackBall())
1236 {
1237 if (QApplication::keyboardModifiers() & Qt::Key_Control) trackball.ButtonDown(QT2VCG(Qt::NoButton, Qt::ControlModifier));
1238 else trackball.ButtonUp(QT2VCG(Qt::NoButton, Qt::ControlModifier));
1239 if (QApplication::keyboardModifiers() & Qt::Key_Shift) trackball.ButtonDown(QT2VCG(Qt::NoButton, Qt::ShiftModifier));
1240 else trackball.ButtonUp(QT2VCG(Qt::NoButton, Qt::ShiftModifier));
1241 if (QApplication::keyboardModifiers() & Qt::Key_Alt) trackball.ButtonDown(QT2VCG(Qt::NoButton, Qt::AltModifier));
1242 else trackball.ButtonUp(QT2VCG(Qt::NoButton, Qt::AltModifier));
1243
1244 trackball.MouseDown(QT2VCG_X(this, e), QT2VCG_Y(this, e), QT2VCG(e->button(), e->modifiers()));
1245 }
1246 else trackball_light.MouseDown(QT2VCG_X(this, e), QT2VCG_Y(this, e), QT2VCG(e->button(), Qt::NoModifier));
1247 }
1248 }
1249 }
1250 update();
1251 }
1252
mouseMoveEvent(QMouseEvent * e)1253 void GLArea::mouseMoveEvent(QMouseEvent*e)
1254 {
1255 makeCurrent();
1256 if( (iEdit && !suspendedEditor) )
1257 iEdit->mouseMoveEvent(e,*mm(),this);
1258 else {
1259 if (isDefaultTrackBall())
1260 {
1261 trackball.MouseMove(QT2VCG_X(this,e), QT2VCG_Y(this,e));
1262 setCursorTrack(trackball.current_mode);
1263 }
1264 else trackball_light.MouseMove(QT2VCG_X(this,e), QT2VCG_Y(this,e));
1265 }
1266 update();
1267 }
1268
1269 // When mouse is released we set the correct mouse cursor
mouseReleaseEvent(QMouseEvent * e)1270 void GLArea::mouseReleaseEvent(QMouseEvent*e)
1271 {
1272 makeCurrent();
1273 //clearFocus();
1274 activeDefaultTrackball=true;
1275 if( (iEdit && !suspendedEditor) )
1276 iEdit->mouseReleaseEvent(e,*mm(),this);
1277 else {
1278 if (isDefaultTrackBall()) trackball.MouseUp(QT2VCG_X(this,e), QT2VCG_Y(this,e), QT2VCG(e->button(), e->modifiers() ) );
1279 else trackball_light.MouseUp(QT2VCG_X(this,e), QT2VCG_Y(this,e), QT2VCG(e->button(),e->modifiers()) );
1280 setCursorTrack(trackball.current_mode);
1281 }
1282
1283 update();
1284 }
1285
1286 //Processing of tablet events, interesting only for painting plugins
tabletEvent(QTabletEvent * e)1287 void GLArea::tabletEvent(QTabletEvent*e)
1288 {
1289 makeCurrent();
1290 if(iEdit && !suspendedEditor) iEdit->tabletEvent(e,*mm(),this);
1291 else e->ignore();
1292 }
1293
wheelEvent(QWheelEvent * e)1294 void GLArea::wheelEvent(QWheelEvent*e)
1295 {
1296 makeCurrent();
1297 setFocus();
1298 if( (iEdit && !suspendedEditor) )
1299 {
1300 iEdit->wheelEvent(e,*mm(),this);
1301 }
1302 else
1303 {
1304 const int WHEEL_STEP = 120;
1305 float notch = e->delta()/ float(WHEEL_STEP);
1306 switch(e->modifiers())
1307 {
1308 case Qt::ControlModifier:
1309 {
1310 clipRatioNear = math::Clamp(clipRatioNear*powf(1.1f, notch),0.01f,500.0f);
1311 break;
1312 }
1313 case Qt::ShiftModifier:
1314 {
1315 fov = math::Clamp(fov+1.2f*notch,5.0f,90.0f);
1316 break;
1317 }
1318 case Qt::AltModifier:
1319 {
1320 glas.pointSize = math::Clamp(glas.pointSize*powf(1.2f, notch), MLPerViewGLOptions::minPointSize(), MLPerViewGLOptions::maxPointSize());
1321 MLSceneGLSharedDataContext* cont = mvc()->sharedDataContext();
1322 if (cont != NULL)
1323 {
1324 foreach(MeshModel * mp, this->md()->meshList)
1325 {
1326 MLRenderingData dt;
1327 cont->getRenderInfoPerMeshView(mp->id(), context(), dt);
1328 MLPerViewGLOptions opt;
1329 dt.get(opt);
1330 opt._perpoint_pointsize = glas.pointSize;
1331 opt._perpoint_pointsmooth_enabled = glas.pointSmooth;
1332 opt._perpoint_pointattenuation_enabled = glas.pointDistanceAttenuation;
1333 cont->setGLOptions(mp->id(), context(), opt);
1334 }
1335 if (mw() != NULL)
1336 mw()->updateLayerDialog();
1337 }
1338 break;
1339 }
1340 default:
1341 {
1342 if(isRaster())
1343 this->opacity = math::Clamp( opacity*powf(1.2f, notch),0.1f,1.0f);
1344 else
1345 trackball.MouseWheel( e->delta()/ float(WHEEL_STEP));
1346 break;
1347 }
1348 }
1349 }
1350 update();
1351 }
1352
1353
mouseDoubleClickEvent(QMouseEvent * e)1354 void GLArea::mouseDoubleClickEvent ( QMouseEvent * e )
1355 {
1356 makeCurrent();
1357 if ((iEdit == NULL) || suspendedEditor)
1358 {
1359 hasToPick = true;
1360 pointToPick = Point2i(QT2VCG_X(this, e), QT2VCG_Y(this, e));
1361 }
1362 update();
1363 }
1364
focusInEvent(QFocusEvent * e)1365 void GLArea::focusInEvent ( QFocusEvent * e )
1366 {
1367 makeCurrent();
1368 QWidget::focusInEvent(e);
1369 emit currentViewerChanged(id);
1370 }
1371
setCursorTrack(vcg::TrackMode * tm)1372 void GLArea::setCursorTrack(vcg::TrackMode *tm)
1373 {
1374 makeCurrent();
1375 //static QMap<QString,QCursor> curMap;
1376 if(curMap.isEmpty())
1377 {
1378 curMap[QString("")]=QCursor(Qt::ArrowCursor);
1379 curMap["SphereMode"]=QCursor(QPixmap(":/images/cursors/plain_trackball.png"),1,1);
1380 curMap["PanMode"]=QCursor(QPixmap(":/images/cursors/plain_pan.png"),1,1);
1381 curMap["ScaleMode"]=QCursor(QPixmap(":/images/cursors/plain_zoom.png"),1,1);
1382 curMap["PickMode"]=QCursor(QPixmap(":/images/cursors/plain_pick.png"),1,1);
1383 }
1384 if(tm) setCursor(curMap[tm->Name()]);
1385 else
1386 if(hasToGetPickPos) setCursor(curMap["PickMode"]);
1387 else setCursor(curMap[""]);
1388
1389 }
1390
setDecorator(QString name,bool state)1391 void GLArea::setDecorator(QString name, bool state)
1392 {
1393 makeCurrent();
1394 updateDecorator(name, false, state);
1395 }
1396
toggleDecorator(QString name)1397 void GLArea::toggleDecorator(QString name)
1398 {
1399 makeCurrent();
1400 updateDecorator(name, true, false);
1401 }
1402
1403
updateDecorator(QString name,bool toggle,bool stateToSet)1404 void GLArea::updateDecorator(QString name, bool toggle, bool stateToSet)
1405 {
1406 makeCurrent();
1407 MeshDecorateInterface *iDecorateTemp = this->mw()->PM.getDecoratorInterfaceByName(name);
1408 if (!iDecorateTemp) {
1409 this->Logf(GLLogStream::SYSTEM,"Could not get Decorate interface %s", qUtf8Printable(name));
1410 this->Log(GLLogStream::SYSTEM,"Known decorate interfaces:");
1411 for (auto tt : this->mw()->PM.meshDecoratePlugins()) {
1412 for (auto action : tt->actions()) {
1413 this->Logf(GLLogStream::SYSTEM,"- %s", qUtf8Printable(tt->decorationName(action)));
1414 }
1415 }
1416 return;
1417 }
1418 QAction *action = iDecorateTemp->action(name);
1419
1420 if(iDecorateTemp->getDecorationClass(action)== MeshDecorateInterface::PerDocument)
1421 {
1422 bool found=this->iPerDocDecoratorlist.removeOne(action);
1423 if(found)
1424 {
1425 if(toggle || stateToSet==false){
1426 iDecorateTemp->endDecorate(action,*md(),glas.currentGlobalParamSet,this);
1427 iDecorateTemp->setLog(NULL);
1428 this->Logf(GLLogStream::SYSTEM,"Disabled Decorate mode %s", qUtf8Printable(action->text()));
1429 } else
1430 this->Logf(GLLogStream::SYSTEM,"Trying to disable an already disabled Decorate mode %s", qUtf8Printable(action->text()));
1431 }
1432 else{
1433 if(toggle || stateToSet==true){
1434 iDecorateTemp->setLog(&(this->md()->Log));
1435 bool ret = iDecorateTemp->startDecorate(action,*md(), glas.currentGlobalParamSet, this);
1436 if(ret) {
1437 this->iPerDocDecoratorlist.push_back(action);
1438 this->Logf(GLLogStream::SYSTEM,"Enabled Decorate mode %s", qUtf8Printable(action->text()));
1439 }
1440 else this->Logf(GLLogStream::SYSTEM,"Failed start of Decorate mode %s", qUtf8Printable(action->text()));
1441 } else
1442 this->Logf(GLLogStream::SYSTEM,"Trying to enable an already enabled Decorate mode %s", qUtf8Printable(action->text()));
1443 }
1444 }
1445
1446 if(iDecorateTemp->getDecorationClass(action)== MeshDecorateInterface::PerMesh)
1447 {
1448 MeshModel ¤tMeshModel = *mm();
1449 bool found=this->iCurPerMeshDecoratorList().removeOne(action);
1450 if(found)
1451 {
1452 if(toggle || stateToSet==false){
1453 iDecorateTemp->endDecorate(action,currentMeshModel,glas.currentGlobalParamSet,this);
1454 iDecorateTemp->setLog(NULL);
1455 this->Logf(0,"Disabled Decorate mode %s", qUtf8Printable(action->text()));
1456 } else
1457 this->Logf(GLLogStream::SYSTEM,"Trying to disable an already disabled Decorate mode %s", qUtf8Printable(action->text()));
1458 }
1459 else{
1460 if(toggle || stateToSet==true){
1461 QString errorMessage;
1462 if (iDecorateTemp->isDecorationApplicable(action,currentMeshModel,errorMessage))
1463 {
1464 iDecorateTemp->setLog(&md()->Log);
1465 bool ret = iDecorateTemp->startDecorate(action,currentMeshModel, glas.currentGlobalParamSet, this);
1466 if(ret) {
1467 this->iCurPerMeshDecoratorList().push_back(action);
1468 this->Logf(GLLogStream::SYSTEM,"Enabled Decorate mode %s", qUtf8Printable(action->text()));
1469 }
1470 else this->Logf(GLLogStream::SYSTEM,"Failed Decorate mode %s", qUtf8Printable(action->text()));
1471 } else
1472 this->Logf(GLLogStream::SYSTEM,"Error in Decorate mode %s: %s", qUtf8Printable(action->text()), qUtf8Printable(errorMessage));
1473
1474 }
1475 }
1476 }
1477 }
1478
1479 //void GLArea::setDrawMode(vcg::GLW::DrawMode mode)
1480 //{
1481 // makeCurrent();
1482 // for(QMap<int,RenderMode>::iterator it = rendermodemap.begin();it != rendermodemap.end();++it)
1483 // it.value().drawMode = mode;
1484 // update();
1485 //}
1486 //
1487 //void GLArea::setDrawMode(RenderMode& rm,vcg::GLW::DrawMode mode )
1488 //{
1489 // makeCurrent();
1490 // rm.drawMode = mode;
1491 // update();
1492 //}
1493 //
1494 //void GLArea::setColorMode(vcg::GLW::ColorMode mode)
1495 //{
1496 // makeCurrent();
1497 // for(QMap<int,RenderMode>::iterator it = rendermodemap.begin();it != rendermodemap.end();++it)
1498 // it.value().colorMode = mode;
1499 // update();
1500 //}
1501 //
1502 //void GLArea::setColorMode( RenderMode& rm,vcg::GLW::ColorMode mode )
1503 //{
1504 // makeCurrent();
1505 // rm.colorMode = mode;
1506 // update();
1507 //}
1508 //
1509 //void GLArea::setTextureMode(vcg::GLW::TextureMode mode)
1510 //{
1511 // makeCurrent();
1512 // for(QMap<int,RenderMode>::iterator it = rendermodemap.begin();it != rendermodemap.end();++it)
1513 // it.value().textureMode = mode;
1514 // update();
1515 //}
1516 //
1517 //void GLArea::setTextureMode(RenderMode& rm,vcg::GLW::TextureMode mode)
1518 //{
1519 // makeCurrent();
1520 // rm.textureMode = mode;
1521 // update();
1522 //}
1523 //
1524 //void GLArea::setLight(bool setState)
1525 //{
1526 // makeCurrent();
1527 // for(QMap<int,RenderMode>::iterator it = rendermodemap.begin();it != rendermodemap.end();++it)
1528 // it.value().lighting = setState;
1529 // update();
1530 //}
1531 //
1532 //void GLArea::setLightMode(bool state,LightingModel lmode)
1533 //{
1534 // makeCurrent();
1535 // for(QMap<int,RenderMode>::iterator it = rendermodemap.begin();it != rendermodemap.end();++it)
1536 // {
1537 // switch(lmode)
1538 // {
1539 // case LDOUBLE: it.value().doubleSideLighting = state; break;
1540 // case LFANCY: it.value().fancyLighting = state; break;
1541 // }
1542 // }
1543 // update();
1544 //}
1545 //
1546 //void GLArea::setBackFaceCulling(bool enabled)
1547 //{
1548 // makeCurrent();
1549 // for(QMap<int,RenderMode>::iterator it = rendermodemap.begin();it != rendermodemap.end();++it)
1550 // it.value().backFaceCull = enabled;
1551 // update();
1552 //}
1553 //
setLightingColors(const MLPerViewGLOptions & opts)1554 void GLArea::setLightingColors(const MLPerViewGLOptions& opts)
1555 {
1556 makeCurrent();
1557 if (opts._double_side_lighting || opts._fancy_lighting)
1558 glEnable(GL_LIGHT1);
1559 else
1560 glDisable(GL_LIGHT1);
1561
1562 //WARNING!!!!! ALL THIS DATA SHOULD BE MOVED INSIDE THE OPTS....IN THE NEXT MESHLAB RELEASE....MAYBE.....
1563 glLightfv(GL_LIGHT0, GL_AMBIENT, Color4f::Construct(glas.baseLightAmbientColor).V());
1564 glLightfv(GL_LIGHT0, GL_DIFFUSE, Color4f::Construct(glas.baseLightDiffuseColor).V());
1565 glLightfv(GL_LIGHT0, GL_SPECULAR,Color4f::Construct(glas.baseLightSpecularColor).V());
1566
1567 glLightfv(GL_LIGHT1, GL_AMBIENT, Color4f::Construct(glas.baseLightAmbientColor).V());
1568 glLightfv(GL_LIGHT1, GL_DIFFUSE, Color4f::Construct(glas.baseLightDiffuseColor).V());
1569 glLightfv(GL_LIGHT1, GL_SPECULAR,Color4f::Construct(glas.baseLightSpecularColor).V());
1570 if(opts._fancy_lighting)
1571 {
1572 glLightfv(GL_LIGHT0, GL_DIFFUSE, Color4f::Construct(glas.fancyFLightDiffuseColor).V());
1573 glLightfv(GL_LIGHT1, GL_DIFFUSE, Color4f::Construct(glas.fancyBLightDiffuseColor).V());
1574 }
1575 //*********************************************************************************************************
1576 }
1577
setView()1578 void GLArea::setView()
1579 {
1580 makeCurrent();
1581 glViewport(0,0, (GLsizei) QTLogicalToDevice(this,width()),(GLsizei) QTLogicalToDevice(this,height()));
1582
1583 GLfloat fAspect = (GLfloat)width()/height();
1584 glMatrixMode(GL_PROJECTION);
1585 glLoadIdentity();
1586 Matrix44f mtTr; mtTr.SetTranslate( trackball.center);
1587 Matrix44f mtSc; mtSc.SetScale(4.0f,4.0f,4.0f);
1588 Matrix44f mt = mtSc * mtTr * trackball.Matrix() *(-mtTr);
1589 // Matrix44f mt = trackball.Matrix();
1590
1591 Box3m bb;
1592 bb.Add(Matrix44m::Construct(mt),this->md()->bbox());
1593 float cameraDist = this->getCameraDistance();
1594
1595 if(fov<=5) cameraDist = 8.0f; // small hack for orthographic projection where camera distance is rather meaningless...
1596
1597 nearPlane = cameraDist*clipRatioNear;
1598 farPlane = cameraDist + max(viewRatio(),float(-bb.min[2]));
1599
1600 // qDebug("tbcenter %f %f %f",trackball.center[0],trackball.center[1],trackball.center[2]);
1601 // qDebug("camera dist %f far %f",cameraDist, farPlane);
1602 // qDebug("Bb %f %f %f - %f %f %f", bb.min[0], bb.min[1], bb.min[2], bb.max[0], bb.max[1], bb.max[2]);
1603
1604 if (!takeSnapTile)
1605 {
1606 if(fov==5) glOrtho( -viewRatio()*fAspect, viewRatio()*fAspect, -viewRatio(), viewRatio(), nearPlane, farPlane);
1607 else gluPerspective(fov, fAspect, nearPlane, farPlane);
1608 }
1609 else setTiledView(fov, viewRatio(), fAspect, nearPlane, farPlane, cameraDist);
1610
1611 glMatrixMode(GL_MODELVIEW);
1612 glLoadIdentity();
1613 gluLookAt(0, 0, cameraDist, 0, 0, 0, 0, 1, 0);
1614 }
1615
setTiledView(GLdouble fovY,float viewRatio,float fAspect,GLdouble zNear,GLdouble zFar,float)1616 void GLArea::setTiledView(GLdouble fovY, float viewRatio, float fAspect, GLdouble zNear, GLdouble zFar, float /*cameraDist*/)
1617 {
1618 makeCurrent();
1619 if(fovY<=5)
1620 {
1621 GLdouble fLeft = -viewRatio*fAspect;
1622 GLdouble fRight = viewRatio*fAspect;
1623 GLdouble fBottom = -viewRatio;
1624 GLdouble fTop = viewRatio;
1625
1626 GLdouble tDimX = fabs(fRight-fLeft) / totalCols;
1627 GLdouble tDimY = fabs(fTop-fBottom) / totalRows;
1628
1629
1630 glOrtho(fLeft + tDimX * tileCol, fLeft + tDimX * (tileCol+1), /* left, right */
1631 fBottom + tDimY * tileRow, fBottom + tDimY * (tileRow+1), /* bottom, top */
1632 zNear, zFar);
1633 }
1634 else
1635 {
1636 GLdouble fTop = zNear * tan(math::ToRad(fovY/2.0));
1637 GLdouble fRight = fTop * fAspect;
1638 GLdouble fBottom = -fTop;
1639 GLdouble fLeft = -fRight;
1640
1641 // tile Dimension
1642 GLdouble tDimX = fabs(fRight-fLeft) / totalCols;
1643 GLdouble tDimY = fabs(fTop-fBottom) / totalRows;
1644
1645 glFrustum(fLeft + tDimX * tileCol, fLeft + tDimX * (tileCol+1),
1646 fBottom + tDimY * tileRow, fBottom + tDimY * (tileRow+1), zNear, zFar);
1647 }
1648 }
1649
updateFps(float deltaTime)1650 void GLArea::updateFps(float deltaTime)
1651 {
1652 const int avgSize =10;
1653 static float fpsVector[avgSize];
1654 static int j=0;
1655 float averageFps=0;
1656 if (deltaTime>0) {
1657 fpsVector[j]=deltaTime;
1658 j=(j+1) % avgSize;
1659 }
1660 for (int i=0;i<avgSize;i++) averageFps+=fpsVector[i];
1661 cfps=1000.0f/(averageFps/avgSize);
1662 lastTime=deltaTime;
1663 }
1664
resetTrackBall()1665 void GLArea::resetTrackBall()
1666 {
1667 makeCurrent();
1668 trackball.Reset();
1669 float newScale= 3.0f/this->md()->bbox().Diag();
1670 trackball.track.sca = newScale;
1671 trackball.track.tra.Import(-this->md()->bbox().Center());
1672 clipRatioNear = clipRatioNearDefault();
1673 if (!isRaster())
1674 fov=fovDefault();
1675 update();
1676 }
1677
hideEvent(QHideEvent *)1678 void GLArea::hideEvent(QHideEvent * /*event*/)
1679 {
1680 trackball.current_button=0;
1681 }
1682
sendViewPos(QString name)1683 void GLArea::sendViewPos(QString name)
1684 {
1685 #ifndef VCG_USE_EIGEN
1686 Point3f pos= trackball.track.InverseMatrix() *Inverse(trackball.camera.model) *Point3f(0,0,0);
1687 #else
1688 Point3f pos= Eigen::Transform3f(trackball.track.InverseMatrix()) * Eigen::Transform3f(Inverse(trackball.camera.model)).translation();
1689 #endif
1690 emit transmitViewPos(name, pos);
1691 }
1692
sendSurfacePos(QString name)1693 void GLArea::sendSurfacePos(QString name)
1694 {
1695 qDebug("sendSurfacePos %s", qUtf8Printable(name));
1696 nameToGetPickPos = name;
1697 hasToGetPickPos=true;
1698 }
1699
sendPickedPos(QString name)1700 void GLArea::sendPickedPos(QString name)
1701 {
1702 qDebug("sendPickedPos %s", qUtf8Printable(name));
1703 nameToGetPickCoords = name;
1704 hasToGetPickCoords = true;
1705 }
1706
sendViewDir(QString name)1707 void GLArea::sendViewDir(QString name)
1708 {
1709 Point3f dir= getViewDir();
1710 emit transmitViewDir(name,dir);
1711 }
1712
sendMeshShot(QString name)1713 void GLArea::sendMeshShot(QString name)
1714 {
1715 Shotm curShot=this->md()->mm()->cm.shot;
1716 emit transmitShot(name, curShot);
1717 }
1718
sendMeshMatrix(QString name)1719 void GLArea::sendMeshMatrix(QString name)
1720 {
1721 Matrix44m mat=this->md()->mm()->cm.Tr;
1722 emit transmitMatrix(name, mat);
1723 }
1724
sendViewerShot(QString name)1725 void GLArea::sendViewerShot(QString name)
1726 {
1727 Shotm curShot=shotFromTrackball().first;
1728 emit transmitShot(name, curShot);
1729 }
sendRasterShot(QString name)1730 void GLArea::sendRasterShot(QString name)
1731 {
1732 Shotm curShot;
1733 if (this->md()->rm() != NULL)
1734 curShot = this->md()->rm()->shot;
1735 emit transmitShot(name, curShot);
1736 }
1737
sendCameraPos(QString name)1738 void GLArea::sendCameraPos( QString name )
1739 {
1740 Point3f pos = trackball.camera.ViewPoint();
1741 emit transmitCameraPos(name, pos);
1742 }
1743
sendTrackballPos(QString name)1744 void GLArea::sendTrackballPos(QString name)
1745 {
1746 Point3f pos = -trackball.track.tra;
1747 emit transmitTrackballPos(name, pos);
1748 }
1749
getViewDir()1750 Point3f GLArea::getViewDir()
1751 {
1752 vcg::Matrix44f rotM;
1753 trackball.track.rot.ToMatrix(rotM);
1754 return vcg::Inverse(rotM)*vcg::Point3f(0,0,1);
1755 }
1756
updateCustomSettingValues(RichParameterSet & rps)1757 void GLArea::updateCustomSettingValues( RichParameterSet& rps )
1758 {
1759 makeCurrent();
1760 glas.updateGlobalParameterSet(rps);
1761
1762 this->update();
1763 }
1764
initGlobalParameterSet(RichParameterSet * defaultGlobalParamSet)1765 void GLArea::initGlobalParameterSet( RichParameterSet * defaultGlobalParamSet)
1766 {
1767 GLAreaSetting::initGlobalParameterSet(defaultGlobalParamSet);
1768 }
1769
1770 //Don't alter the state of the other elements in the visibility map
updateMeshSetVisibilities()1771 void GLArea::updateMeshSetVisibilities()
1772 {
1773 meshVisibilityMap.clear();
1774 foreach(MeshModel * mp, this->md()->meshList)
1775 {
1776 //Insert the new pair in the map; If the key is already in the map, its value will be overwritten
1777 meshVisibilityMap.insert(mp->id(),mp->visible);
1778 }
1779 }
1780
1781 //Don't alter the state of the other elements in the visibility map
updateRasterSetVisibilities()1782 void GLArea::updateRasterSetVisibilities()
1783 {
1784 //Align rasterVisibilityMap state with rasterList state
1785 //Deleting from the map the visibility of the deleted rasters
1786 QMapIterator<int, bool> i(rasterVisibilityMap);
1787 while (i.hasNext()) {
1788 i.next();
1789 bool found =false;
1790 foreach(RasterModel * rp, this->md()->rasterList)
1791 {
1792 if(rp->id() == i.key())
1793 {
1794 found = true;
1795 break;
1796 }
1797 }
1798 if(!found)
1799 rasterVisibilityMap.remove(i.key());
1800 }
1801
1802 foreach(RasterModel * rp, this->md()->rasterList)
1803 {
1804 //Insert the new pair in the map;If the key is already in the map, its value will be overwritten
1805 rasterVisibilityMap.insert(rp->id(),rp->visible);
1806 }
1807 }
1808
meshSetVisibility(MeshModel * mp,bool visibility)1809 void GLArea::meshSetVisibility(MeshModel *mp, bool visibility)
1810 {
1811 mp->visible=visibility;
1812 meshVisibilityMap[mp->id()]=visibility;
1813 }
1814
addRasterSetVisibility(int rasterId,bool visibility)1815 void GLArea::addRasterSetVisibility(int rasterId, bool visibility)
1816 {
1817 rasterVisibilityMap.insert(rasterId,visibility);
1818 }
1819
1820 //void GLArea::getPerDocGlobalRenderingData(MLRenderingData& dt) const
1821 //{
1822 // dt = _perdocglobaldt;
1823 //}
1824 //
1825 //void GLArea::setPerDocGlobalRenderingData(const MLRenderingData& dt)
1826 //{
1827 // _perdocglobaldt = dt;
1828 //}
1829
1830 // --------------- Raster view -------------------------------------
setIsRaster(bool viewMode)1831 void GLArea::setIsRaster(bool viewMode){
1832 _isRaster= viewMode;
1833 }
1834
1835 // this slot is called when someone press the showraster button on the toolbar
showRaster(bool resetViewFlag)1836 void GLArea::showRaster(bool resetViewFlag)
1837 {
1838 makeCurrent();
1839 if(!this->isRaster())
1840 {
1841 lastViewBeforeRasterMode = this->viewToText();
1842 setIsRaster(true);
1843 loadRaster(md()->rm()->id() );
1844 } else
1845 {
1846 this->setIsRaster(false);
1847 QDomDocument doc("StringDoc");
1848 doc.setContent(lastViewBeforeRasterMode);
1849 if(resetViewFlag) this->loadViewFromViewStateFile(doc);
1850 else this->update();
1851 }
1852 }
1853
loadRaster(int id)1854 void GLArea::loadRaster(int id)
1855 {
1856 lastloadedraster = id;
1857 foreach(RasterModel *rm, this->md()->rasterList)
1858 if(rm->id()==id)
1859 {
1860 this->md()->setCurrentRaster(id);
1861 if (rm->currentPlane->image.isNull())
1862 {
1863 Logf(0,"Image file %s has not been correctly loaded, a fake image is going to be shown.",rm->currentPlane->fullPathFileName.toUtf8().constData());
1864 rm->currentPlane->image.load(":/images/dummy.png");
1865 }
1866 setTarget(rm->currentPlane->image);
1867 //load his shot or a default shot
1868
1869 if (rm->shot.IsValid())
1870 {
1871 fov = (rm->shot.Intrinsics.cameraType == 0) ? rm->shot.GetFovFromFocal() : 5.0;
1872
1873 // this code seems useless, and if the camera translation is[0 0 0] (or even just with a small z), there is a division by zero
1874 //float cameraDist = getCameraDistance();
1875 //Matrix44f rotFrom;
1876 //rm->shot.Extrinsics.Rot().ToMatrix(rotFrom);
1877 //Point3f p1 = rotFrom*(vcg::Point3f::Construct(rm->shot.Extrinsics.Tra()));
1878 //Point3f p2 = (Point3f(0,0,cameraDist));
1879 //trackball.track.sca =fabs(p2.Z()/p1.Z());
1880
1881 trackball.track.sca = 3.0f / this->md()->bbox().Diag(); // hack, we reset the trackball scale factor to the size of the mesh object
1882
1883 /*
1884 Box3m bb;
1885 float sceneCamSize = this->md()->bbox().Diag();
1886 bb.Add(this->md()->bbox());
1887 bb.Add(rm->shot.Extrinsics.Tra());
1888 sceneCamSize = bb.Diag();
1889 trackball.track.sca = 1.0f / sceneCamSize; // hack, we reset the trackball scale factor to the size of the mesh object + viewpoint DOES NOT WORK !
1890 */
1891
1892 loadShot(QPair<Shotm, float> (rm->shot,trackball.track.sca));
1893 }
1894 else
1895 createOrthoView("Front");
1896 }
1897 }
1898
drawTarget()1899 void GLArea::drawTarget()
1900 {
1901 makeCurrent();
1902 if(!targetTex) return;
1903
1904 if(this->md()->rm()==0) return;
1905 QImage &curImg = this->md()->rm()->currentPlane->image;
1906 float imageRatio = float(curImg.width())/float(curImg.height());
1907 float screenRatio = float(this->width())/float(this->height());
1908 //set orthogonal view
1909 glPushMatrix();
1910 glLoadIdentity();
1911 glMatrixMode(GL_PROJECTION);
1912 glPushMatrix();
1913 glLoadIdentity();
1914 gluOrtho2D(-1.0f*screenRatio, 1.0f*screenRatio, -1, 1);
1915
1916 glColor4f(1, 1, 1, opacity);
1917 glDisable(GL_LIGHTING);
1918 glDisable(GL_DEPTH_TEST);
1919 glEnable(GL_BLEND);
1920 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1921 glEnable(GL_TEXTURE_2D);
1922 glBindTexture(GL_TEXTURE_2D, targetTex);
1923 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1924
1925 glBegin(GL_QUADS);
1926 glTexCoord2f(0.0f, 0.0f); //first point
1927 glVertex3f(-1.0f*imageRatio, -1.0f, 0.0f);
1928 glTexCoord2f(1.0f, 0.0f); //second point
1929 glVertex3f(1.0f*imageRatio, -1.0f, 0.0f);
1930 glTexCoord2f(1.0f, 1.0f); //third point
1931 glVertex3f(1.0f*imageRatio, 1.0f, 0.0f);
1932 glTexCoord2f(0.0f, 1.0f); //fourth point
1933 glVertex3f(-1.0f*imageRatio, 1.0f, 0.0f);
1934 glEnd();
1935
1936 glEnable(GL_DEPTH_TEST);
1937 glEnable(GL_LIGHTING);
1938
1939 glBindTexture(GL_TEXTURE_2D, 0);
1940 glDisable(GL_TEXTURE_2D);
1941
1942 //restore view
1943 glPopMatrix();
1944 glMatrixMode(GL_MODELVIEW);
1945 glPopMatrix();
1946 }
1947
1948
setTarget(QImage & image)1949 void GLArea::setTarget(QImage &image) {
1950 makeCurrent();
1951 if (image.isNull())
1952 return;
1953 if (targetTex) {
1954 glDeleteTextures(1, &targetTex);
1955 targetTex = 0;
1956 }
1957 // create texture
1958 glGenTextures(1, &targetTex);
1959 QImage tximg = QGLWidget::convertToGLFormat(image);
1960 glBindTexture(GL_TEXTURE_2D, targetTex);
1961 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1962 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1963 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
1964 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1965 glTexImage2D(GL_TEXTURE_2D, 0, 3, tximg.width(), tximg.height(),
1966 0, GL_RGBA, GL_UNSIGNED_BYTE, tximg.bits());
1967
1968 glBindTexture(GL_TEXTURE_2D, 0);
1969 }
1970
1971 // --------------- Methods involving shots -------------------------------------
1972
getCameraDistance()1973 float GLArea::getCameraDistance()
1974 {
1975 float cameraDist = viewRatio() / tanf(vcg::math::ToRad(fov*.5f));
1976 return cameraDist;
1977 }
1978
initializeShot(Shotm & shot)1979 void GLArea::initializeShot(Shotm &shot)
1980 {
1981 shot.Intrinsics.PixelSizeMm[0]=0.036916077f;
1982 shot.Intrinsics.PixelSizeMm[1]=0.036916077f;
1983
1984 shot.Intrinsics.DistorCenterPx[0]=width()/2;
1985 shot.Intrinsics.DistorCenterPx[1]=height()/2;
1986 shot.Intrinsics.CenterPx[0]=width()/2;
1987 shot.Intrinsics.CenterPx[1]=height()/2;
1988 shot.Intrinsics.ViewportPx[0]=width();
1989 shot.Intrinsics.ViewportPx[1]=height();
1990
1991 double viewportYMm = shot.Intrinsics.PixelSizeMm[1]*shot.Intrinsics.ViewportPx[1];
1992 shot.Intrinsics.FocalMm = viewportYMm/(2*tanf(vcg::math::ToRad(this->fovDefault()/2.0f))); //27.846098mm
1993
1994 shot.Extrinsics.SetIdentity();
1995 }
1996
readViewFromFile()1997 bool GLArea::readViewFromFile()
1998 {
1999 QString filename = QFileDialog::getOpenFileName(this, tr("Load Project"), "./", tr("Xml Files (*.xml)"));
2000 return GLArea::readViewFromFile(filename);
2001 }
2002
readViewFromFile(QString const & filename)2003 bool GLArea::readViewFromFile(QString const& filename)
2004 {
2005 QFile qf(filename);
2006 QFileInfo qfInfo(filename);
2007
2008 if( !qf.open(QIODevice::ReadOnly ) )
2009 return false;
2010
2011 QString project_path = qfInfo.absoluteFilePath();
2012
2013 QDomDocument doc("XmlDocument"); //It represents the XML document
2014 if(!doc.setContent( &qf ))
2015 return false;
2016
2017 QString type = doc.doctype().name();
2018
2019 //TextAlign file project
2020 if(type == "RegProjectML") loadShotFromTextAlignFile(doc);
2021 //View State file
2022 else if(type == "ViewState") loadViewFromViewStateFile(doc);
2023
2024 // qDebug("End file reading");
2025 qf.close();
2026
2027 return true;
2028 }
2029
saveViewToFile()2030 bool GLArea::saveViewToFile()
2031 {
2032 QFileDialog saveDiag(this, tr("Save View To File"), "./", tr("View file (*.xml)"));
2033
2034 #if defined(Q_OS_WIN)
2035 saveDiag.setOption(QFileDialog::DontUseNativeDialog);
2036 #endif
2037 saveDiag.setAcceptMode(QFileDialog::AcceptSave);
2038 saveDiag.exec();
2039 QStringList files = saveDiag.selectedFiles();
2040 if (files.size() != 1)
2041 return false;
2042 QString fileName = files[0];
2043 QFileInfo fi(fileName);
2044 if (fi.isDir())
2045 return false;
2046 if (fi.suffix().isEmpty())
2047 {
2048 QRegExp reg("\\.\\w+");
2049 saveDiag.selectedNameFilter().indexOf(reg);
2050 QString ext = reg.cap();
2051 fileName.append(ext);
2052 fi.setFile(fileName);
2053 }
2054 QDir::setCurrent(fi.absoluteDir().absolutePath());
2055
2056 bool ret = false;
2057 qDebug("Saving a file %s\n", qUtf8Printable(fileName));
2058 if (fileName.isEmpty()) return false;
2059 else
2060 {
2061 QFile qFile(fileName);
2062 if (qFile.open(QIODevice::WriteOnly)) {
2063 QTextStream out(&qFile); out << this->viewToText();
2064 qFile.close();
2065 ret = true;
2066 }
2067 }
2068
2069 if (!ret)
2070 QMessageBox::critical(this, tr("Meshlab Saving Error"), QString("Unable to save view file %1\n").arg(fileName));
2071
2072 return true;
2073 }
2074
loadShotFromTextAlignFile(const QDomDocument & doc)2075 void GLArea::loadShotFromTextAlignFile(const QDomDocument &doc)
2076 {
2077 QDomElement root = doc.documentElement();
2078 QDomNode node;
2079 Shotm shot;
2080
2081 node = root.firstChild();
2082
2083 //Devices
2084 while(!node.isNull()){
2085 if(QString::compare(node.nodeName(),"Device")==0)
2086 {
2087 QString type = node.attributes().namedItem("type").nodeValue();
2088 if (type== "GlImageWidget")
2089 {
2090 //Aligned Image
2091 if(QString::compare(node.attributes().namedItem("aligned").nodeValue(),"1")==0){
2092 QDomNode nodeb = node.firstChild();
2093 ReadShotFromOLDXML(shot,nodeb);
2094 }
2095 }
2096 }
2097 node = node.nextSibling();
2098 }
2099
2100 //Adjust params for Meshlab settings
2101
2102 //resize viewport
2103 int w = shot.Intrinsics.ViewportPx[0];
2104 int h = shot.Intrinsics.ViewportPx[1];
2105
2106 shot.Intrinsics.DistorCenterPx[0]=w/2;
2107 shot.Intrinsics.DistorCenterPx[1]=h/2;
2108 shot.Intrinsics.CenterPx[0]=w/2;
2109 shot.Intrinsics.CenterPx[1]=h/2;
2110 shot.Intrinsics.ViewportPx[0]=w;
2111 shot.Intrinsics.ViewportPx[1]=h;
2112
2113 // The shot loaded from TextAlign doesn't have a scale. Trackball needs it.
2114 // The scale factor is computed as the ratio between cameraDistance and the z coordinate of the translation
2115 // introduced by the shot.
2116 fov = (shot.Intrinsics.cameraType == 0) ? shot.GetFovFromFocal() : 5.0;
2117
2118 // float cameraDist = getCameraDistance();
2119
2120 Matrix44f rotFrom;
2121 shot.Extrinsics.Rot().ToMatrix(rotFrom);
2122
2123 // this code seems useless, and if the camera translation is[0 0 0] (or even just with a small z), there is a division by zero
2124 //Point3f p1 = rotFrom*(vcg::Point3f::Construct(rm->shot.Extrinsics.Tra()));
2125 //Point3f p2 = (Point3f(0,0,cameraDist));
2126 //trackball.track.sca =fabs(p2.Z()/p1.Z());
2127
2128 loadShot(QPair<Shotm, float> (shot,trackball.track.sca));
2129
2130 }
2131
2132 /*
2133 ViewState file is an xml file format created by Meshlab with the action "copyToClipboard"
2134 */
loadViewFromViewStateFile(const QDomDocument & doc)2135 void GLArea::loadViewFromViewStateFile(const QDomDocument &doc)
2136 {
2137 Shotm shot;
2138 QDomElement root = doc.documentElement();
2139 QDomNode node = root.firstChild();
2140
2141 while(!node.isNull())
2142 {
2143 if (QString::compare(node.nodeName(),"VCGCamera")==0)
2144 ReadShotFromQDomNode(shot,node);
2145 else if (QString::compare(node.nodeName(),"CamParam")==0)
2146 ReadShotFromOLDXML(shot,node);
2147
2148 else if (QString::compare(node.nodeName(),"ViewSettings")==0)
2149 {
2150 QDomNamedNodeMap attr = node.attributes();
2151 trackball.track.sca = attr.namedItem("TrackScale").nodeValue().section(' ',0,0).toFloat();
2152 nearPlane = attr.namedItem("NearPlane").nodeValue().section(' ',0,0).toFloat();
2153 farPlane = attr.namedItem("FarPlane").nodeValue().section(' ',0,0).toFloat();
2154 fov = (shot.Intrinsics.cameraType == 0) ? shot.GetFovFromFocal() : 5.0;
2155 clipRatioNear = nearPlane/getCameraDistance();
2156 clipRatioFar = farPlane/getCameraDistance();
2157 }
2158 /*else if (QString::compare(node.nodeName(),"Render")==0)
2159 {
2160 QDomNamedNodeMap attr = node.attributes();
2161 rm.drawMode = (vcg::GLW::DrawMode) (attr.namedItem("DrawMode").nodeValue().section(' ',0,0).toInt());
2162 rm.colorMode = (vcg::GLW::ColorMode) (attr.namedItem("ColorMode").nodeValue().section(' ',0,0).toInt());
2163 rm.textureMode = (vcg::GLW::TextureMode) (attr.namedItem("TextureMode").nodeValue().section(' ',0,0).toInt());
2164 rm.lighting = (attr.namedItem("Lighting").nodeValue().section(' ',0,0).toInt() != 0);
2165 rm.backFaceCull = (attr.namedItem("BackFaceCull").nodeValue().section(' ',0,0).toInt() != 0);
2166 rm.doubleSideLighting = (attr.namedItem("DoubleSideLighting").nodeValue().section(' ',0,0).toInt() != 0);
2167 rm.fancyLighting = (attr.namedItem("FancyLighting").nodeValue().section(' ',0,0).toInt() != 0);
2168 }*/
2169 node = node.nextSibling();
2170 }
2171
2172 loadShot(QPair<Shotm, float> (shot,trackball.track.sca));
2173 }
viewToText()2174 QString GLArea::viewToText()
2175 {
2176 QString docString;
2177
2178 Shotm shot = shotFromTrackball().first;
2179
2180 QDomDocument doc("ViewState");
2181 QDomElement root = doc.createElement("project");
2182 doc.appendChild( root );
2183
2184 QDomElement shotElem = WriteShotToQDomNode(shot,doc);
2185 root.appendChild(shotElem);
2186
2187 QDomElement settingsElem = doc.createElement( "ViewSettings" );
2188 settingsElem.setAttribute( "TrackScale", trackball.track.sca);
2189 settingsElem.setAttribute( "NearPlane", nearPlane);
2190 settingsElem.setAttribute( "FarPlane", farPlane);
2191 root.appendChild(settingsElem);
2192
2193 /*QDomElement renderElem = doc.createElement( "Render");
2194 renderElem.setAttribute("DrawMode",rm.drawMode);
2195 renderElem.setAttribute("ColorMode",rm.colorMode);
2196 renderElem.setAttribute("TextureMode",rm.textureMode);
2197 renderElem.setAttribute("Lighting",rm.lighting);
2198 renderElem.setAttribute("BackFaceCull",rm.backFaceCull);
2199 renderElem.setAttribute("DoubleSideLighting",rm.doubleSideLighting);
2200 renderElem.setAttribute("FancyLighting",rm.fancyLighting);
2201 root.appendChild(renderElem);*/
2202
2203 return doc.toString();
2204 }
2205
viewToClipboard()2206 void GLArea::viewToClipboard()
2207 {
2208 QApplication::clipboard()->setText(this->viewToText());
2209 }
2210
viewFromClipboard()2211 void GLArea::viewFromClipboard()
2212 {
2213 QClipboard *clipboard = QApplication::clipboard();
2214 QString shotString = clipboard->text();
2215 QDomDocument doc("StringDoc");
2216 doc.setContent(shotString);
2217 loadViewFromViewStateFile(doc);
2218 }
2219
shotFromTrackball()2220 QPair<Shotm,float> GLArea::shotFromTrackball()
2221 {
2222 Shotm shot;
2223 initializeShot(shot);
2224
2225 double viewportYMm=shot.Intrinsics.PixelSizeMm[1]*shot.Intrinsics.ViewportPx[1];
2226 shot.Intrinsics.FocalMm = viewportYMm/(2*tanf(vcg::math::ToRad(fov/2)));
2227
2228 // in MeshLab, fov < 5.0 means orthographic camera
2229 if (fov > 5.0)
2230 shot.Intrinsics.cameraType = 0; //perspective
2231 else
2232 shot.Intrinsics.cameraType = 1; //orthographic
2233
2234 float cameraDist = getCameraDistance();
2235
2236 //add the translation introduced by gluLookAt() (0,0,cameraDist), in order to have te same view---------------
2237 //T(gl)*S*R*T(t) => SR(gl+t) => S R (S^(-1)R^(-1)gl + t)
2238 //Add translation S^(-1) R^(-1)(gl)
2239 //Shotd doesn't introduce scaling
2240 //---------------------------------------------------------------------
2241 shot.Extrinsics.SetTra( shot.Extrinsics.Tra() + (Inverse(shot.Extrinsics.Rot())*Point3m(0, 0, cameraDist)));
2242
2243 Shotm newShot = track2ShotCPU<Shotm::ScalarType>(shot, &trackball);
2244
2245 return QPair<Shotm, float> (newShot,trackball.track.sca);
2246 }
2247
viewFromCurrentShot(QString kind)2248 void GLArea::viewFromCurrentShot(QString kind)
2249 {
2250 Shotm localShot;
2251 if(kind=="Mesh" && this->md()->mm()) localShot = this->md()->mm()->cm.shot;
2252 if(kind=="Raster" && this->md()->rm()) localShot = this->md()->rm()->shot;
2253 if(!localShot.IsValid())
2254 {
2255 this->Logf(GLLogStream::SYSTEM, "Unable to set Shot from current %s", qUtf8Printable(kind));
2256 return;
2257 }
2258
2259 loadShot(QPair<Shotm, float>(localShot,trackball.track.sca));
2260 }
2261
2262
loadShot(const QPair<Shotm,float> & shotAndScale)2263 void GLArea::loadShot(const QPair<Shotm,float> &shotAndScale){
2264
2265 Shotm shot = shotAndScale.first;
2266
2267 fov = (shot.Intrinsics.cameraType == 0) ? shot.GetFovFromFocal() : 5.0;
2268
2269 float cameraDist = getCameraDistance();
2270
2271 //reset trackball. The point of view must be set only by the shot
2272 trackball.Reset();
2273 trackball.track.sca = shotAndScale.second;
2274
2275 shot2Track(shot, cameraDist, trackball);
2276
2277 /*Point3f point = this->md()->bbox().Center();
2278 Point3f p1 = ((trackball.track.Matrix()*(point-trackball.center))- Point3f(0,0,cameraDist));*/
2279 //Expressing the translation along Z with a scale factor k
2280 //Point3f p2 = ((trackball.track.Matrix()*(point-trackball.center))- Point3f(0,0,cameraDist));
2281
2282 ////k is the ratio between the distances along z of two correspondent points (before and after the traslation)
2283 ////from the point of view
2284 //float k= abs(p2.Z()/p1.Z());
2285
2286 //float sca= trackball.track.sca/k;
2287 //Point3f tra = trackball.track.tra;
2288 //
2289 //// Apply this formula:
2290 //// SR(t+p) -v = k[S'R'(t'+p) -v] forall p, R=R', k is a constant
2291 //// SR(t) -v = k[S'R(t') -v]
2292 //// t' = 1/k* S'^-1St + (k-1)/k S'^-1*R^-1v
2293 //Matrix44f s0 = Matrix44f().SetScale(trackball.track.sca,trackball.track.sca, trackball.track.sca);
2294 //Matrix44f s1 = Matrix44f().SetScale(sca, sca, sca);
2295 //Matrix44f r;
2296 //trackball.track.rot.ToMatrix(r);
2297 //Matrix44f rapM = Matrix44f().SetScale(1/k, 1/k, 1/k);
2298 //Matrix44f rapM2 = Matrix44f().SetScale(1-1/k, 1-1/k, 1-1/k);
2299 //Point3f t1 = rapM*Inverse(s1)*s0*tra + rapM2*Inverse(s1)*Inverse(r)*Point3f(0,0,cameraDist);
2300
2301 //trackball.track.sca =sca;
2302 //trackball.track.tra =t1 /*+ tb.track.rot.Inverse().Rotate(glLookAt)*/ ;
2303
2304 update();
2305 }
2306
createOrthoView(QString dir)2307 void GLArea::createOrthoView(QString dir)
2308 {
2309 Shotm view;
2310 initializeShot(view);
2311
2312 fov =5;
2313 double viewportYMm = view.Intrinsics.PixelSizeMm[1]*view.Intrinsics.ViewportPx[1];
2314 view.Intrinsics.FocalMm = viewportYMm/(2*tanf(vcg::math::ToRad(fov/2))); //27.846098 equivalente a circa 60 gradi
2315
2316 trackball.Reset();
2317 float newScale= 3.0f/this->md()->bbox().Diag();
2318 trackball.track.sca = newScale;
2319 trackball.track.tra.Import(-this->md()->bbox().Center());
2320
2321 Matrix44m rot;
2322
2323 if(dir == tr("Top"))
2324 rot.SetRotateDeg(90,Point3m(1,0,0));
2325 else if(dir == tr("Bottom"))
2326 rot.SetRotateDeg(90,Point3m(-1,0,0));
2327 else if(dir == tr("Left"))
2328 rot.SetRotateDeg(90,Point3m(0,1,0));
2329 else if(dir == tr("Right"))
2330 rot.SetRotateDeg(90,Point3m(0,-1,0));
2331 else if(dir == tr("Front"))
2332 rot.SetRotateDeg(0,Point3m(0,1,0));
2333 else if(dir == tr("Back"))
2334 rot.SetRotateDeg(180,Point3m(0,1,0));
2335 // scene uses "engineering" reference system, with Z as vertical axis
2336 else if (dir == tr("Top (Z is up)"))
2337 rot.SetRotateDeg(0, Point3m(1, 0, 0));
2338 else if (dir == tr("Bottom (Z is up)"))
2339 rot.SetRotateDeg(180, Point3m(1, 0, 0));
2340 else if (dir == tr("Left (Z is up)"))
2341 rot = Matrix44m().SetRotateDeg(90, Point3m(0, 1, 0)) * Matrix44m().SetRotateDeg(90, Point3m(-1, 0, 0));
2342 else if (dir == tr("Right (Z is up)"))
2343 rot = Matrix44m().SetRotateDeg(90, Point3m(0, -1, 0)) * Matrix44m().SetRotateDeg(90, Point3m(-1, 0, 0));
2344 else if (dir == tr("Front (Z is up)"))
2345 rot.SetRotateDeg(90, Point3m(-1, 0, 0));
2346 else if (dir == tr("Back (Z is up)"))
2347 rot = Matrix44m().SetRotateDeg(90, Point3m(1, 0, 0)) * Matrix44m().SetRotateDeg(180, Point3m(0, 1, 0));
2348
2349 view.Extrinsics.SetRot(rot);
2350
2351 float cameraDist = getCameraDistance();
2352
2353 //add the translation introduced by gluLookAt() (0,0,cameraDist), in order to have te same view---------------
2354 //T(gl)*S*R*T(t) => SR(gl+t) => S R (S^(-1)R^(-1)gl + t)
2355 //Add translation S^(-1) R^(-1)(gl)
2356 //Shotd doesn't introduce scaling
2357 //---------------------------------------------------------------------
2358 view.Extrinsics.SetTra( view.Extrinsics.Tra() + (Inverse(view.Extrinsics.Rot())*Point3m(0, 0, cameraDist)));
2359
2360 Shotm shot = track2ShotCPU(view, &trackball);
2361
2362 QPair<Shotm,float> shotAndScale = QPair<Shotm,float> (shot, trackball.track.sca);
2363 loadShot(shotAndScale);
2364
2365 this->Logf(GLLogStream::SYSTEM, "View scene from %s", qUtf8Printable(dir));
2366 }
2367
toggleOrtho()2368 void GLArea::toggleOrtho()
2369 {
2370 if (fov == 5.0)
2371 fov = 35.0;
2372 else
2373 fov = 5.0;
2374
2375 update();
2376 }
2377
trackballStep(QString dir)2378 void GLArea::trackballStep(QString dir)
2379 {
2380 float stepAngle = float(M_PI / 12.0);
2381
2382 if (dir == tr("Horizontal +"))
2383 trackball.track.rot = Quaternionf(-stepAngle, Point3f(0.0, 1.0, 0.0)) * trackball.track.rot;
2384 else if (dir == tr("Horizontal -"))
2385 trackball.track.rot = Quaternionf( stepAngle, Point3f(0.0, 1.0, 0.0)) * trackball.track.rot;
2386 else if (dir == tr("Vertical +"))
2387 trackball.track.rot = Quaternionf(-stepAngle, Point3f(1.0, 0.0, 0.0)) * trackball.track.rot;
2388 else if (dir == tr("Vertical -"))
2389 trackball.track.rot = Quaternionf( stepAngle, Point3f(1.0, 0.0, 0.0)) * trackball.track.rot;
2390 else if (dir == tr("Axial +"))
2391 trackball.track.rot = Quaternionf(-stepAngle, Point3f(0.0, 0.0, 1.0)) * trackball.track.rot;
2392 else if (dir == tr("Axial -"))
2393 trackball.track.rot = Quaternionf( stepAngle, Point3f(0.0, 0.0, 1.0)) * trackball.track.rot;
2394
2395 update();
2396 }
2397
2398
2399 //MultiViewer_Container * GLArea::mvc()
2400 //{
2401 // QObject * curParent = this->parent();
2402 // while(qobject_cast<MultiViewer_Container *>(curParent) == 0)
2403 // {
2404 // if (curParent != NULL)
2405 // curParent = curParent->parent();
2406 // else
2407 // return NULL;
2408 // }
2409 // return qobject_cast<MultiViewer_Container *>(curParent);
2410 //}
2411
2412
showInterruptButton() const2413 bool GLArea::showInterruptButton() const
2414 {
2415 return interrbutshow;
2416 }
2417
showInterruptButton(const bool & show)2418 void GLArea::showInterruptButton( const bool& show )
2419 {
2420 interrbutshow = show;
2421 }
2422
completeUpdateRequested()2423 void GLArea::completeUpdateRequested()
2424 {
2425 makeCurrent();
2426 if ((this->md() != NULL) && (this->md()->rm() != NULL))
2427 loadRaster(this->md()->rm()->id());
2428 //if (md()->mm() != NULL)
2429 // trackball.center = md()->mm()->cm.bbox.Center();
2430 update();
2431 //doneCurrent();
2432 }
2433
2434 //RenderMode* GLArea::getCurrentRenderMode()
2435 //{
2436 // if ((md() != NULL) && (md()->mm() != NULL))
2437 // {
2438 // QMap<int,RenderMode>::iterator it = rendermodemap.find(md()->mm()->id());
2439 // if (it != rendermodemap.end())
2440 // return &it.value();
2441 // }
2442 // return NULL;
2443 //}
2444
meshAdded(int)2445 void GLArea::meshAdded( int /*index*/)
2446 {
2447 emit updateLayerTable();
2448 }
2449
meshRemoved(int)2450 void GLArea::meshRemoved( int /*index*/ )
2451 {
2452 emit updateLayerTable();
2453 }
2454
setupTextureEnv(GLuint textid)2455 void GLArea::setupTextureEnv( GLuint textid )
2456 {
2457 makeCurrent();
2458 glPushAttrib(GL_ENABLE_BIT);
2459 glEnable(GL_TEXTURE_2D);
2460 glBindTexture(GL_TEXTURE_2D,textid);
2461 if(glas.textureMagFilter == 0 )
2462 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
2463 else
2464 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
2465 if(glas.textureMinFilter == 0 )
2466 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
2467 else
2468 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
2469
2470 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2471 glBindTexture(GL_TEXTURE_2D,0);
2472 glPopAttrib();
2473 }
2474
mw()2475 MainWindow * GLArea::mw()
2476 {
2477 QObject * curParent = parent();
2478 while(qobject_cast<MainWindow *>(curParent) == 0)
2479 {
2480 curParent = curParent->parent();
2481 }
2482 return qobject_cast<MainWindow *>(curParent);
2483 }
2484
2485