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