1 
2 
3 #include "toonzqt/planeviewer.h"
4 
5 // TnzQt includes
6 #include "toonzqt/imageutils.h"
7 #include "toonzqt/menubarcommand.h"
8 #include "toonzqt/viewcommandids.h"
9 
10 #include "../toonz/menubarcommandids.h"
11 
12 // TnzLib includes
13 #include "toonz/stage.h"
14 
15 // TnzCore includes
16 #include "trasterimage.h"
17 #include "ttoonzimage.h"
18 #include "tvectorimage.h"
19 #include "trop.h"
20 #include "tvectorrenderdata.h"
21 #include "tgl.h"
22 #include "tvectorgl.h"
23 #include "tpalette.h"
24 
25 // Qt includes
26 #include <QMouseEvent>
27 #include <QWheelEvent>
28 #include <QResizeEvent>
29 #include <QHideEvent>
30 #include <QGestureEvent>
31 
32 //#define PRINT_AFF
33 
34 //**********************************************************************************
35 //    Local namespace  stuff
36 //**********************************************************************************
37 
38 namespace {
39 
40 struct PlaneViewerZoomer final : public ImageUtils::ShortcutZoomer {
PlaneViewerZoomer__anon75537ef60111::PlaneViewerZoomer41   PlaneViewerZoomer(PlaneViewer *planeViewer) : ShortcutZoomer(planeViewer) {}
42 
43 private:
44   bool zoom(bool zoomin, bool resetZoom) override;
45   bool fit() override;
46 };
47 
48 //========================================================================
49 
zoom(bool zoomin,bool resetZoom)50 bool PlaneViewerZoomer::zoom(bool zoomin, bool resetZoom) {
51   PlaneViewer &planeViewer = static_cast<PlaneViewer &>(*getWidget());
52 
53   resetZoom ? planeViewer.resetView() : zoomin ? planeViewer.zoomIn()
54                                                : planeViewer.zoomOut();
55 
56   return true;
57 }
58 
fit()59 bool PlaneViewerZoomer::fit() {
60   PlaneViewer &planeViewer = static_cast<PlaneViewer &>(*getWidget());
61 
62   planeViewer.fitView();
63 
64   return true;
65 }
66 }  // namespace
67 
68 //=========================================================================================
69 
PlaneViewer(QWidget * parent)70 PlaneViewer::PlaneViewer(QWidget *parent)
71     : GLWidgetForHighDpi(parent)
72     , m_firstResize(true)
73     , m_xpos(0)
74     , m_ypos(0)
75     , m_aff()  // initialized at the first resize
76     , m_chessSize(40.0)
77     , m_firstDraw(true)
78     , m_dpiX(0.0)
79     , m_dpiY(0.0) {
80   m_zoomRange[0] = 1e-3, m_zoomRange[1] = 1024.0;
81   setBgColor(TPixel32(235, 235, 235), TPixel32(235, 235, 235));
82 
83   setAttribute(Qt::WA_AcceptTouchEvents);
84   grabGesture(Qt::SwipeGesture);
85   grabGesture(Qt::PanGesture);
86   grabGesture(Qt::PinchGesture);
87 }
88 
89 //=========================================================================================
90 
setZoomRange(double zoomMin,double zoomMax)91 void PlaneViewer::setZoomRange(double zoomMin, double zoomMax) {
92   m_zoomRange[0] = zoomMin, m_zoomRange[1] = zoomMax;
93 }
94 
95 //------------------------------------------------------------------------
96 
setBgColor(const TPixel32 & color1,const TPixel32 & color2)97 void PlaneViewer::setBgColor(const TPixel32 &color1, const TPixel32 &color2) {
98   m_bgColorF[0] = color1.r / 255.0, m_bgColorF[1] = color1.g / 255.0,
99   m_bgColorF[2] = color1.b / 255.0;
100   m_bgColorF[3] = color2.r / 255.0, m_bgColorF[4] = color2.g / 255.0,
101   m_bgColorF[5] = color2.b / 255.0;
102 }
103 
104 //------------------------------------------------------------------------
105 
getBgColor(TPixel32 & color1,TPixel32 & color2) const106 void PlaneViewer::getBgColor(TPixel32 &color1, TPixel32 &color2) const {
107   color1.r = m_bgColorF[0] * 255.0, color1.g = m_bgColorF[1] * 255.0,
108   color1.b = m_bgColorF[2] * 255.0;
109   color2.r = m_bgColorF[3] * 255.0, color2.g = m_bgColorF[4] * 255.0,
110   color2.b = m_bgColorF[5] * 255.0;
111 }
112 
113 //------------------------------------------------------------------------
114 
drawBackground()115 void PlaneViewer::drawBackground() {
116   glClearColor(m_bgColorF[0], m_bgColorF[1], m_bgColorF[2], 1.0);
117   glClear(GL_COLOR_BUFFER_BIT);
118 
119   if (m_bgColorF[0] != m_bgColorF[3] || m_bgColorF[1] != m_bgColorF[4] ||
120       m_bgColorF[2] != m_bgColorF[5]) {
121     // Cast the widget rect to world rect
122     TRectD rect(winToWorld(0, 0), winToWorld(width(), height()));
123 
124     // Deduce chess geometry
125     TRect chessRect(tfloor(rect.x0 / m_chessSize),
126                     tfloor(rect.y0 / m_chessSize), tceil(rect.x1 / m_chessSize),
127                     tceil(rect.y1 / m_chessSize));
128 
129     // Draw chess squares
130     glColor3f(m_bgColorF[3], m_bgColorF[4], m_bgColorF[5]);
131     glBegin(GL_QUADS);
132 
133     int x, y;
134     TPointD pos;
135     double chessSize2 = 2.0 * m_chessSize;
136 
137     for (y = chessRect.y0; y < chessRect.y1; ++y) {
138       pos.y = y * m_chessSize;
139       for (x = chessRect.x0 + ((chessRect.x0 + y) % 2), pos.x = x * m_chessSize;
140            x < chessRect.x1; x += 2, pos.x += chessSize2) {
141         glVertex2d(pos.x, pos.y);
142         glVertex2d(pos.x + m_chessSize, pos.y);
143         glVertex2d(pos.x + m_chessSize, pos.y + m_chessSize);
144         glVertex2d(pos.x, pos.y + m_chessSize);
145       }
146     }
147 
148     glEnd();
149   }
150 }
151 
152 //=========================================================================================
153 
initializeGL()154 void PlaneViewer::initializeGL() { initializeOpenGLFunctions(); }
155 
resizeGL(int width,int height)156 void PlaneViewer::resizeGL(int width, int height) {
157   width *= getDevPixRatio();
158   height *= getDevPixRatio();
159   glViewport(0, 0, width, height);
160 
161   glMatrixMode(GL_PROJECTION);
162   glLoadIdentity();
163   gluOrtho2D(0, width, 0, height);
164 
165   glMatrixMode(GL_MODELVIEW);
166   glLoadIdentity();
167 
168   if (m_firstResize) {
169     m_firstResize = false;
170     m_aff         = TTranslation(0.5 * width, 0.5 * height);
171     m_width       = width;
172     m_height      = height;
173   } else {
174     TPointD oldCenter(m_width * 0.5, m_height * 0.5);
175     TPointD newCenter(width * 0.5, height * 0.5);
176 
177     m_aff    = m_aff.place(m_aff.inv() * oldCenter, newCenter);
178     m_width  = width;
179     m_height = height;
180   }
181 }
182 
183 //=========================================================================================
184 
mouseMoveEvent(QMouseEvent * event)185 void PlaneViewer::mouseMoveEvent(QMouseEvent *event) {
186   if (m_gestureActive && m_touchDevice == QTouchDevice::TouchScreen &&
187       !m_stylusUsed) {
188     return;
189   }
190 
191   QPoint curPos = event->pos() * getDevPixRatio();
192   if (event->buttons() & Qt::MidButton)
193     moveView(curPos.x() - m_xpos, height() - curPos.y() - m_ypos);
194 
195   m_xpos = curPos.x(), m_ypos = height() - curPos.y();
196 }
197 
198 //------------------------------------------------------
199 
mousePressEvent(QMouseEvent * event)200 void PlaneViewer::mousePressEvent(QMouseEvent *event) {
201   // qDebug() << "[mousePressEvent]";
202   if (m_gestureActive && m_touchDevice == QTouchDevice::TouchScreen &&
203       !m_stylusUsed) {
204     return;
205   }
206 
207   m_xpos = event->x() * getDevPixRatio();
208   m_ypos = height() - event->y() * getDevPixRatio();
209 }
210 
211 //------------------------------------------------------
212 
mouseDoubleClickEvent(QMouseEvent * event)213 void PlaneViewer::mouseDoubleClickEvent(QMouseEvent *event) {
214   // qDebug() << "[mouseDoubleClickEvent]";
215   if (m_gestureActive && !m_stylusUsed) {
216     m_gestureActive = false;
217     fitView();
218     return;
219   }
220 }
221 
222 //------------------------------------------------------
223 
mouseReleaseEvent(QMouseEvent * event)224 void PlaneViewer::mouseReleaseEvent(QMouseEvent *event) {
225   m_gestureActive = false;
226   m_zooming       = false;
227   m_panning       = false;
228   m_stylusUsed    = false;
229 }
230 
231 //------------------------------------------------------
232 
wheelEvent(QWheelEvent * event)233 void PlaneViewer::wheelEvent(QWheelEvent *event) {
234   int delta = 0;
235   switch (event->source()) {
236   case Qt::MouseEventNotSynthesized: {
237     if (event->modifiers() & Qt::AltModifier)
238       delta = event->angleDelta().x();
239     else
240       delta = event->angleDelta().y();
241     break;
242   }
243 
244   case Qt::MouseEventSynthesizedBySystem: {
245     QPoint numPixels  = event->pixelDelta();
246     QPoint numDegrees = event->angleDelta() / 8;
247     if (!numPixels.isNull()) {
248       delta = event->pixelDelta().y();
249     } else if (!numDegrees.isNull()) {
250       QPoint numSteps = numDegrees / 15;
251       delta           = numSteps.y();
252     }
253     break;
254   }
255 
256   default:  // Qt::MouseEventSynthesizedByQt,
257             // Qt::MouseEventSynthesizedByApplication
258     {
259       std::cout << "not supported event: Qt::MouseEventSynthesizedByQt, "
260                    "Qt::MouseEventSynthesizedByApplication"
261                 << std::endl;
262       break;
263     }
264 
265   }  // end switch
266 
267   if (abs(delta) > 0) {
268     if ((m_gestureActive == true &&
269          m_touchDevice == QTouchDevice::TouchScreen) ||
270         m_gestureActive == false) {
271       TPointD pos(event->x() * getDevPixRatio(),
272                   height() - event->y() * getDevPixRatio());
273       double zoom_par = 1 + event->delta() * 0.001;
274 
275       zoomView(pos.x, pos.y, zoom_par);
276     }
277   }
278   event->accept();
279 }
280 
281 //------------------------------------------------------
282 
keyPressEvent(QKeyEvent * event)283 void PlaneViewer::keyPressEvent(QKeyEvent *event) {
284   if (PlaneViewerZoomer(this).exec(event)) return;
285 
286   QOpenGLWidget::keyPressEvent(event);
287 }
288 
289 //------------------------------------------------------
290 
291 //! Disposes of the auxiliary internal rasterBuffer().
hideEvent(QHideEvent * event)292 void PlaneViewer::hideEvent(QHideEvent *event) {
293   m_rasterBuffer = TRaster32P();
294   m_dpiX         = 0.0;  // reset dpi
295   m_dpiY         = 0.0;
296 }
297 
298 //------------------------------------------------------------------
299 
contextMenuEvent(QContextMenuEvent * event)300 void PlaneViewer::contextMenuEvent(QContextMenuEvent *event) {
301   QMenu *menu = new QMenu(this);
302 
303   QAction *reset = menu->addAction(tr("Reset View"));
304   reset->setShortcut(
305       QKeySequence(CommandManager::instance()->getKeyFromId(V_ZoomReset)));
306   connect(reset, SIGNAL(triggered()), SLOT(resetView()));
307 
308   QAction *fit = menu->addAction(tr("Fit To Window"));
309   fit->setShortcut(
310       QKeySequence(CommandManager::instance()->getKeyFromId(V_ZoomFit)));
311   connect(fit, SIGNAL(triggered()), SLOT(fitView()));
312 
313   menu->exec(event->globalPos());
314 
315   delete menu;
316   update();
317 }
318 
319 //------------------------------------------------------------------
320 
tabletEvent(QTabletEvent * e)321 void PlaneViewer::tabletEvent(QTabletEvent *e) {
322   // qDebug() << "[tabletEvent]";
323   if (e->type() == QTabletEvent::TabletPress) {
324     m_stylusUsed = e->pointerType() ? true : false;
325   } else if (e->type() == QTabletEvent::TabletRelease) {
326     m_stylusUsed = false;
327   }
328 
329   e->accept();
330 }
331 
332 //------------------------------------------------------------------
333 
gestureEvent(QGestureEvent * e)334 void PlaneViewer::gestureEvent(QGestureEvent *e) {
335   // qDebug() << "[gestureEvent]";
336   m_gestureActive = false;
337   if (QGesture *swipe = e->gesture(Qt::SwipeGesture)) {
338     m_gestureActive = true;
339   } else if (QGesture *pan = e->gesture(Qt::PanGesture)) {
340     m_gestureActive = true;
341   }
342   if (QGesture *pinch = e->gesture(Qt::PinchGesture)) {
343     QPinchGesture *gesture = static_cast<QPinchGesture *>(pinch);
344     QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
345     QPoint firstCenter                     = gesture->centerPoint().toPoint();
346     if (m_touchDevice == QTouchDevice::TouchScreen)
347       firstCenter = mapFromGlobal(firstCenter);
348 
349     if (gesture->state() == Qt::GestureStarted) {
350       m_gestureActive = true;
351     } else if (gesture->state() == Qt::GestureFinished) {
352       m_gestureActive = false;
353       m_zooming       = false;
354       m_scaleFactor   = 0.0;
355     } else {
356       if (changeFlags & QPinchGesture::ScaleFactorChanged) {
357         double scaleFactor = gesture->scaleFactor();
358         // the scale factor makes for too sensitive scaling
359         // divide the change in half
360         if (scaleFactor > 1) {
361           double decimalValue = scaleFactor - 1;
362           decimalValue /= 1.5;
363           scaleFactor = 1 + decimalValue;
364         } else if (scaleFactor < 1) {
365           double decimalValue = 1 - scaleFactor;
366           decimalValue /= 1.5;
367           scaleFactor = 1 - decimalValue;
368         }
369         if (!m_zooming) {
370           double delta = scaleFactor - 1;
371           m_scaleFactor += delta;
372           if (m_scaleFactor > .2 || m_scaleFactor < -.2) {
373             m_zooming = true;
374           }
375         }
376         if (m_zooming) {
377           zoomView(firstCenter.x() * getDevPixRatio(),
378                    firstCenter.y() * getDevPixRatio(), scaleFactor);
379           m_panning = false;
380         }
381         m_gestureActive = true;
382       }
383 
384       if (changeFlags & QPinchGesture::CenterPointChanged) {
385         QPointF centerDelta = (gesture->centerPoint() * getDevPixRatio()) -
386                               (gesture->lastCenterPoint() * getDevPixRatio());
387         if (centerDelta.manhattanLength() > 1) {
388           // panQt(centerDelta.toPoint());
389         }
390         m_gestureActive = true;
391       }
392     }
393   }
394   e->accept();
395 }
396 
touchEvent(QTouchEvent * e,int type)397 void PlaneViewer::touchEvent(QTouchEvent *e, int type) {
398   // qDebug() << "[touchEvent]";
399   if (type == QEvent::TouchBegin) {
400     m_touchActive   = true;
401     m_firstPanPoint = e->touchPoints().at(0).pos();
402     // obtain device type
403     m_touchDevice = e->device()->type();
404   } else if (m_touchActive) {
405     // touchpads must have 2 finger panning for tools and navigation to be
406     // functional on other devices, 1 finger panning is preferred
407     if ((e->touchPoints().count() == 2 &&
408          m_touchDevice == QTouchDevice::TouchPad) ||
409         (e->touchPoints().count() == 1 &&
410          m_touchDevice == QTouchDevice::TouchScreen)) {
411       QTouchEvent::TouchPoint panPoint = e->touchPoints().at(0);
412       if (!m_panning) {
413         QPointF deltaPoint = panPoint.pos() - m_firstPanPoint;
414         // minimize accidental and jerky zooming/rotating during 2 finger
415         // panning
416         if ((deltaPoint.manhattanLength() > 100) && !m_zooming) {
417           m_panning = true;
418         }
419       }
420       if (m_panning) {
421         QPoint curPos      = panPoint.pos().toPoint() * getDevPixRatio();
422         QPoint lastPos     = panPoint.lastPos().toPoint() * getDevPixRatio();
423         QPoint centerDelta = curPos - lastPos;
424         moveView(centerDelta.x(), -centerDelta.y());
425       }
426     }
427   }
428   if (type == QEvent::TouchEnd || type == QEvent::TouchCancel) {
429     m_touchActive = false;
430     m_panning     = false;
431   }
432   e->accept();
433 }
434 
event(QEvent * e)435 bool PlaneViewer::event(QEvent *e) {
436   /*
437   switch (e->type()) {
438   case QEvent::TabletPress: {
439   QTabletEvent *te = static_cast<QTabletEvent *>(e);
440   qDebug() << "[event] TabletPress: pointerType(" << te->pointerType()
441   << ") device(" << te->device() << ")";
442   } break;
443   case QEvent::TabletRelease:
444   qDebug() << "[event] TabletRelease";
445   break;
446   case QEvent::TouchBegin:
447   qDebug() << "[event] TouchBegin";
448   break;
449   case QEvent::TouchEnd:
450   qDebug() << "[event] TouchEnd";
451   break;
452   case QEvent::TouchCancel:
453   qDebug() << "[event] TouchCancel";
454   break;
455   case QEvent::MouseButtonPress:
456   qDebug() << "[event] MouseButtonPress";
457   break;
458   case QEvent::MouseButtonDblClick:
459   qDebug() << "[event] MouseButtonDblClick";
460   break;
461   case QEvent::MouseButtonRelease:
462   qDebug() << "[event] MouseButtonRelease";
463   break;
464   case QEvent::Gesture:
465   qDebug() << "[event] Gesture";
466   break;
467   default:
468   break;
469   }
470   */
471 
472   if (e->type() == QEvent::Gesture &&
473       CommandManager::instance()
474           ->getAction(MI_TouchGestureControl)
475           ->isChecked()) {
476     gestureEvent(static_cast<QGestureEvent *>(e));
477     return true;
478   }
479   if ((e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchEnd ||
480        e->type() == QEvent::TouchCancel || e->type() == QEvent::TouchUpdate) &&
481       CommandManager::instance()
482           ->getAction(MI_TouchGestureControl)
483           ->isChecked()) {
484     touchEvent(static_cast<QTouchEvent *>(e), e->type());
485     m_gestureActive = true;
486     return true;
487   }
488   return GLWidgetForHighDpi::event(e);
489 }
490 
491 //=========================================================================================
492 
resetView()493 void PlaneViewer::resetView() {
494   m_aff = TTranslation(0.5 * width(), 0.5 * height());
495   update();
496 }
497 
fitView()498 void PlaneViewer::fitView() {
499   if (m_imageBounds.isEmpty()) return;
500   m_aff = TTranslation(0.5 * width(), 0.5 * height());
501 
502   double imageScale = std::min(width() / (double)m_imageBounds.getLx(),
503                                height() / (double)m_imageBounds.getLy());
504 
505   m_aff = TScale(imageScale, imageScale);
506   if (m_dpiX != 0.0 && m_dpiY != 0.0)
507     m_aff *= TScale(m_dpiX / Stage::inch, m_dpiY / Stage::inch);
508   m_aff.a13 = 0.5 * width();
509   m_aff.a23 = 0.5 * height();
510 
511   update();
512 }
513 
514 //------------------------------------------------------
515 
setViewPos(double x,double y)516 void PlaneViewer::setViewPos(double x, double y) {
517   m_aff.a13 = x, m_aff.a23 = y;
518   update();
519 
520 #ifdef PRINT_AFF
521   qDebug("zoom = %.4f;  pos = %.4f, %.4f", m_aff.a11, m_aff.a13, m_aff.a23);
522 #endif
523 }
524 
525 //------------------------------------------------------
526 
setViewZoom(double x,double y,double zoom)527 void PlaneViewer::setViewZoom(double x, double y, double zoom) {
528   zoom         = tcrop(zoom, m_zoomRange[0], m_zoomRange[1]);
529   double delta = zoom / m_aff.a11;
530 
531   m_aff.a13 = x + delta * (m_aff.a13 - x);
532   m_aff.a23 = y + delta * (m_aff.a23 - y);
533   m_aff.a11 = m_aff.a22 = zoom;
534 
535   update();
536 
537 #ifdef PRINT_AFF
538   qDebug("zoom = %.4f;  pos = %.4f, %.4f", m_aff.a11, m_aff.a13, m_aff.a23);
539 #endif
540 }
541 
542 //------------------------------------------------------
543 
zoomIn()544 void PlaneViewer::zoomIn() {
545   setViewZoom(ImageUtils::getQuantizedZoomFactor(m_aff.a11, true));
546 }
547 
548 //------------------------------------------------------
549 
zoomOut()550 void PlaneViewer::zoomOut() {
551   setViewZoom(ImageUtils::getQuantizedZoomFactor(m_aff.a11, false));
552 }
553 
554 //=========================================================================================
555 
pushGLWorldCoordinates()556 void PlaneViewer::pushGLWorldCoordinates() {
557   m_matrix[0]  = m_aff.a11;
558   m_matrix[4]  = m_aff.a12;
559   m_matrix[12] = m_aff.a13;
560   m_matrix[1]  = m_aff.a21;
561   m_matrix[5]  = m_aff.a22;
562   m_matrix[13] = m_aff.a23;
563 
564   m_matrix[2] = m_matrix[3] = m_matrix[6] = m_matrix[7] = m_matrix[8] =
565       m_matrix[9] = m_matrix[10] = m_matrix[11] = m_matrix[14] = 0;
566 
567   m_matrix[15] = 1.0;
568 
569   glPushMatrix();
570   glLoadMatrixd(m_matrix);  //(GLdouble*) &m_matrix
571 }
572 
573 //------------------------------------------------------
574 
pushGLWinCoordinates()575 void PlaneViewer::pushGLWinCoordinates() {
576   glPushMatrix();
577   glLoadIdentity();
578 }
579 
580 //------------------------------------------------------
581 
popGLCoordinates()582 void PlaneViewer::popGLCoordinates() { glPopMatrix(); }
583 
584 //=========================================================================================
585 
rasterBuffer()586 TRaster32P PlaneViewer::rasterBuffer() {
587   if (!m_rasterBuffer || m_rasterBuffer->getLx() != width() ||
588       m_rasterBuffer->getLy() != height())
589     m_rasterBuffer = TRaster32P(width(), height());
590 
591   return m_rasterBuffer;
592 }
593 
594 //------------------------------------------------------
595 
flushRasterBuffer()596 void PlaneViewer::flushRasterBuffer() {
597   assert(m_rasterBuffer);
598 
599   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
600   glRasterPos2d(0, 0);
601   glDrawPixels(width(), height(), TGL_FMT, TGL_TYPE,
602                m_rasterBuffer->getRawData());
603 }
604 
605 //=========================================================================================
606 
draw(TRasterP ras,double dpiX,double dpiY,TPalette * pal)607 void PlaneViewer::draw(TRasterP ras, double dpiX, double dpiY, TPalette *pal) {
608   TPointD rasCenter(ras->getCenterD());
609 
610   TRaster32P aux(rasterBuffer());
611 
612   m_imageBounds = ras->getBounds();
613   if (m_dpiX == 0.0 || m_dpiY == 0.0) {
614     m_dpiX = dpiX;
615     m_dpiY = dpiY;
616   }
617   if (m_firstDraw && !m_imageBounds.isEmpty()) {
618     m_firstDraw = false;
619     fitView();
620   }
621 
622   aux->lock();
623   ras->lock();
624 
625   glGetDoublev(GL_MODELVIEW_MATRIX, m_matrix);
626   TAffine viewAff(m_matrix[0], m_matrix[4], m_matrix[12], m_matrix[1],
627                   m_matrix[5], m_matrix[13]);
628   viewAff = viewAff * TScale(Stage::inch / dpiX, Stage::inch / dpiY) *
629             TTranslation(-rasCenter);
630 
631   pushGLWinCoordinates();
632 
633   aux->clear();
634   if (pal)
635     TRop::quickPut(aux, (TRasterCM32P)ras, pal, viewAff);
636   else
637     TRop::quickPut(aux, ras, viewAff);
638 
639   flushRasterBuffer();
640   popGLCoordinates();
641 }
642 
643 /*NOTE:
644 glRasterPos2d could be used, along glBitmap and glPixelZoom...
645 however, i've never been able to use them effectively...
646 */
647 
648 //------------------------------------------------------
649 
draw(TRasterImageP ri)650 void PlaneViewer::draw(TRasterImageP ri) {
651   double dpiX, dpiY;
652   ri->getDpi(dpiX, dpiY);
653 
654   if (dpiX == 0.0 || dpiY == 0.0) dpiX = dpiY = Stage::inch;
655 
656   draw(ri->getRaster(), dpiX, dpiY);
657 }
658 
659 //------------------------------------------------------
660 
draw(TToonzImageP ti)661 void PlaneViewer::draw(TToonzImageP ti) {
662   double dpiX, dpiY;
663   ti->getDpi(dpiX, dpiY);
664 
665   if (dpiX == 0.0 || dpiY == 0.0) dpiX = dpiY = Stage::inch;
666 
667   draw(ti->getRaster(), dpiX, dpiY, ti->getPalette());
668 }
669 
670 //------------------------------------------------------
671 
draw(TVectorImageP vi)672 void PlaneViewer::draw(TVectorImageP vi) {
673   TRectD bbox(vi->getBBox());
674   TRect bboxI(tfloor(bbox.x0), tfloor(bbox.y0), tceil(bbox.x1) - 1,
675               tceil(bbox.y1) - 1);
676   m_imageBounds = bboxI;
677   if (m_dpiX == 0.0 || m_dpiY == 0.0) {
678     m_dpiX = Stage::inch;
679     m_dpiY = Stage::inch;
680   }
681   if (m_firstDraw) {
682     m_firstDraw = false;
683     fitView();
684   }
685   TVectorRenderData rd(TAffine(), bboxI, vi->getPalette(), 0, true, true);
686   tglDraw(rd, vi.getPointer());
687 }
688 
689 //------------------------------------------------------
690 
draw(TImageP img)691 void PlaneViewer::draw(TImageP img) {
692   {
693     TRasterImageP ri(img);
694     if (ri) {
695       draw(ri);
696       return;
697     }
698   }
699   {
700     TToonzImageP ti(img);
701     if (ti) {
702       draw(ti);
703       return;
704     }
705   }
706   {
707     TVectorImageP vi(img);
708     if (vi) {
709       draw(vi);
710       return;
711     }
712   }
713 }
714