1
2
3 // TnzCore includes
4 #include "tfilepath.h"
5 #include "tfiletype.h"
6 #include "tstream.h"
7 #include "tsystem.h"
8 #include "timagecache.h"
9 #include "tpixelutils.h"
10 #include "tropcm.h"
11 #include "timageinfo.h"
12 #include "timage_io.h"
13 #include "tlevel_io.h"
14 #include "tofflinegl.h"
15 #include "tgl.h"
16 #include "tvectorrenderdata.h"
17 #include "tstroke.h"
18 #include "tthreadmessage.h"
19 #include "tpalette.h"
20 #include "trasterimage.h"
21 #include "tvectorimage.h"
22 #include "ttoonzimage.h"
23 #include "tmeshimage.h"
24
25 // TnzExt includes
26 #include "ext/meshutils.h"
27
28 // TnzLib includes
29 #include "toonz/toonzscene.h"
30 #include "toonz/sceneproperties.h"
31 #include "toonz/txsheet.h"
32 #include "toonz/tscenehandle.h"
33 #include "toonz/txshlevel.h"
34 #include "toonz/txshleveltypes.h"
35 #include "toonz/txshsimplelevel.h"
36 #include "toonz/txshchildlevel.h"
37 #include "toonz/tstageobjectspline.h"
38 #include "toonz/preferences.h"
39 #include "toonz/sceneresources.h"
40 #include "toonz/stage2.h"
41
42 // TnzQt includes
43 #include "toonzqt/gutil.h"
44
45 #include "toonzqt/icongenerator.h"
46
47 //=============================================================================
48
49 //===================================
50 //
51 // Local namespace
52 //
53 //-----------------------------------
54
55 namespace {
56 const TDimension IconSize(80, 60);
57 TDimension FilmstripIconSize(0, 0);
58
59 // Access name-based storage
60 std::set<std::string> iconsMap;
61 typedef std::set<std::string>::iterator IconIterator;
62
63 //-----------------------------------------------------------------------------
64
65 // Returns true if the image request was already submitted.
getIcon(const std::string & iconName,QPixmap & pix,TXshSimpleLevel * simpleLevel=0,TDimension standardSize=TDimension (0,0))66 bool getIcon(const std::string &iconName, QPixmap &pix,
67 TXshSimpleLevel *simpleLevel = 0,
68 TDimension standardSize = TDimension(0, 0)) {
69 IconIterator it;
70 it = iconsMap.find(iconName);
71
72 if (it != iconsMap.end()) {
73 TImageP im = TImageCache::instance()->get(iconName, false);
74 TToonzImage *timgp = dynamic_cast<TToonzImage *>(im.getPointer());
75
76 if (simpleLevel && timgp) {
77 IconGenerator::Settings settings =
78 IconGenerator::instance()->getSettings();
79
80 TRaster32P icon(timgp->getSize());
81 icon->clear();
82 icon->fill((settings.m_blackBgCheck) ? TPixel::Black : TPixel::White);
83 if (settings.m_transparencyCheck || settings.m_inkIndex != -1 ||
84 settings.m_paintIndex != -1) {
85 TRop::CmappedQuickputSettings s;
86 s.m_globalColorScale = TPixel32::Black;
87 s.m_inksOnly = false;
88 s.m_transparencyCheck = settings.m_transparencyCheck;
89 s.m_blackBgCheck = settings.m_blackBgCheck;
90 s.m_inkIndex = settings.m_inkIndex;
91 s.m_paintIndex = settings.m_paintIndex;
92 Preferences::instance()->getTranspCheckData(
93 s.m_transpCheckBg, s.m_transpCheckInk, s.m_transpCheckPaint);
94
95 TRop::quickPut(icon, timgp->getRaster(), simpleLevel->getPalette(),
96 TAffine(), s);
97 } else
98 TRop::quickPut(icon, timgp->getRaster(), simpleLevel->getPalette(),
99 TAffine());
100 pix = rasterToQPixmap(icon, false);
101 return true;
102 }
103 TRasterImageP img = static_cast<TRasterImageP>(im);
104
105 if (!img) {
106 pix = QPixmap();
107 return true;
108 }
109 assert(!(TRasterGR8P)img->getRaster());
110 const TRaster32P &ras = img->getRaster();
111 bool isHighDpi = false;
112 // If the icon raster obtained in higher resolution than the standard
113 // icon size, it may be icon displayed in high dpi monitors.
114 // In such case set the device pixel ratio to the pixmap.
115 // Note that the humbnails of regular levels are standardsize even if
116 // they are displayed in high dpi monitors for now.
117 if (standardSize != TDimension(0, 0) &&
118 ras->getSize().lx > standardSize.lx &&
119 ras->getSize().ly > standardSize.ly)
120 isHighDpi = true;
121 pix = rasterToQPixmap(ras, false, isHighDpi);
122 return true;
123 }
124
125 return false;
126 }
127
128 //-----------------------------------------------------------------------------
129
setIcon(const std::string & iconName,const TRaster32P & icon)130 void setIcon(const std::string &iconName, const TRaster32P &icon) {
131 if (iconsMap.find(iconName) != iconsMap.end())
132 TImageCache::instance()->add(iconName, TRasterImageP(icon), true);
133 }
134
135 //-----------------------------------------------------------------------------
136 /*! Cache icon data in TToonzImage format if ToonzImageIconRenderer generates
137 * them
138 */
setIcon_TnzImg(const std::string & iconName,const TRasterCM32P & icon)139 void setIcon_TnzImg(const std::string &iconName, const TRasterCM32P &icon) {
140 if (iconsMap.find(iconName) != iconsMap.end())
141 TImageCache::instance()->add(
142 iconName, TToonzImageP(icon, TRect(icon->getSize())), true);
143 }
144
145 //-----------------------------------------------------------------------------
146
removeIcon(const std::string & iconName)147 void removeIcon(const std::string &iconName) {
148 IconIterator it;
149 it = iconsMap.find(iconName);
150 if (it != iconsMap.end()) {
151 TImageCache::instance()->remove(iconName);
152 }
153 iconsMap.erase(iconName);
154 }
155
156 //-----------------------------------------------------------------------------
157
isUnpremultiplied(const TRaster32P & r)158 bool isUnpremultiplied(const TRaster32P &r) {
159 int lx = r->getLx();
160 int y = r->getLy();
161 r->lock();
162 while (--y >= 0) {
163 TPixel32 *pix = r->pixels(y);
164 TPixel32 *endPix = pix + lx;
165 while (pix < endPix) {
166 if (pix->r > pix->m || pix->g > pix->m || pix->b > pix->m) {
167 r->unlock();
168 return true;
169 }
170 ++pix;
171 }
172 }
173 r->unlock();
174 return false;
175 }
176
177 //-----------------------------------------------------------------------------
178
makeChessBackground(const TRaster32P & ras)179 void makeChessBackground(const TRaster32P &ras) {
180 ras->lock();
181
182 const TPixel32 gray1(230, 230, 230, 255), gray2(180, 180, 180, 255);
183
184 int lx = ras->getLx(), ly = ras->getLy();
185 for (int y = 0; y != ly; ++y) {
186 TPixel32 *pix = ras->pixels(y), *lineEnd = pix + lx;
187
188 int yCol = (y & 4);
189
190 for (int x = 0; pix != lineEnd; ++x, ++pix)
191 if (pix->m != 255) *pix = overPix((x & 4) == yCol ? gray1 : gray2, *pix);
192 }
193
194 ras->unlock();
195 }
196
197 } // namespace
198
199 //=============================================================================
200
201 //==========================================
202 //
203 // Image-to-Icon convertion methods
204 //
205 //------------------------------------------
206
207 namespace {
convertToIcon(TVectorImageP vimage,int frame,const TDimension & iconSize,const IconGenerator::Settings & settings)208 TRaster32P convertToIcon(TVectorImageP vimage, int frame,
209 const TDimension &iconSize,
210 const IconGenerator::Settings &settings) {
211 if (!vimage) return TRaster32P();
212
213 TPalette *plt = vimage->getPalette()->clone();
214 if (!plt) return TRaster32P();
215 plt->setFrame(frame);
216
217 TOfflineGL *glContext = IconGenerator::instance()->getOfflineGLContext();
218
219 // The image and contained within Imagebox
220 // (add a small margin also to prevent problems with empty images)
221 TRectD imageBox;
222 {
223 QMutexLocker sl(vimage->getMutex());
224 imageBox = vimage->getBBox().enlarge(.1);
225 }
226 TPointD imageCenter = (imageBox.getP00() + imageBox.getP11()) * 0.5;
227
228 // Calculate a transformation matrix that moves the image inside the icon.
229 // The scale factor is chosen so that the image is entirely
230 // contained in the icon (with a margin of 'margin' pixels)
231 const int margin = 10;
232 double scx = (iconSize.lx - margin) / imageBox.getLx();
233 double scy = (iconSize.ly - margin) / imageBox.getLy();
234 double sc = std::min(scx, scy);
235 // Add the translation: the center point of the image is at the point
236 // middle of the pixmap.
237 TPointD iconCenter(iconSize.lx * 0.5, iconSize.ly * 0.5);
238 TAffine aff = TScale(sc).place(imageCenter, iconCenter);
239
240 // RenderData
241 TVectorRenderData rd(aff, TRect(iconSize), plt, 0, true);
242
243 rd.m_tcheckEnabled = settings.m_transparencyCheck;
244 rd.m_blackBgEnabled = settings.m_blackBgCheck;
245 rd.m_drawRegions = !settings.m_inksOnly;
246 rd.m_inkCheckEnabled = settings.m_inkIndex != -1;
247 rd.m_paintCheckEnabled = settings.m_paintIndex != -1;
248 rd.m_colorCheckIndex =
249 rd.m_inkCheckEnabled ? settings.m_inkIndex : settings.m_paintIndex;
250 rd.m_isIcon = true;
251
252 // Draw the image.
253 glContext->makeCurrent();
254 glContext->clear(rd.m_blackBgEnabled ? TPixel::Black : TPixel32::White);
255 glContext->draw(vimage, rd);
256
257 TRaster32P ras(iconSize);
258 glContext->getRaster(ras);
259
260 glContext->doneCurrent();
261
262 delete plt;
263
264 return ras;
265 }
266
267 //-------------------------------------------------------------------------
268
convertToIcon(TToonzImageP timage,int frame,const TDimension & iconSize,const IconGenerator::Settings & settings)269 TRaster32P convertToIcon(TToonzImageP timage, int frame,
270 const TDimension &iconSize,
271 const IconGenerator::Settings &settings) {
272 if (!timage) return TRaster32P();
273
274 TPalette *plt = timage->getPalette();
275 if (!plt) return TRaster32P();
276
277 plt->setFrame(frame);
278
279 TRasterCM32P rasCM32 = timage->getRaster();
280 if (!rasCM32.getPointer()) return TRaster32P();
281
282 int lx = rasCM32->getSize().lx;
283 int ly = rasCM32->getSize().ly;
284 int iconLx = iconSize.lx, iconLy = iconSize.ly;
285 if (std::max(double(lx) / iconSize.lx, double(ly) / iconSize.ly) ==
286 double(ly) / iconSize.ly)
287 iconLx = tround((double(lx) * iconSize.ly) / ly);
288 else
289 iconLy = tround((double(ly) * iconSize.lx) / lx);
290
291 // icon size with correct aspect ratio
292 TDimension iconSize2 = TDimension(iconLx, iconLy);
293
294 TRaster32P icon(iconSize2);
295 icon->clear();
296 icon->fill(settings.m_blackBgCheck ? TPixel::Black : TPixel::White);
297
298 TDimension dim = rasCM32->getSize();
299 if (dim != iconSize2) {
300 TRasterCM32P auxCM32(icon->getSize());
301 auxCM32->clear();
302 TRop::makeIcon(auxCM32, rasCM32);
303 rasCM32 = auxCM32;
304 }
305
306 if (settings.m_transparencyCheck || settings.m_inksOnly ||
307 settings.m_inkIndex != -1 || settings.m_paintIndex != -1) {
308 TRop::CmappedQuickputSettings s;
309 s.m_globalColorScale = TPixel32::Black;
310 s.m_inksOnly = settings.m_inksOnly;
311 s.m_transparencyCheck = settings.m_transparencyCheck;
312 s.m_blackBgCheck = settings.m_blackBgCheck;
313 s.m_inkIndex = settings.m_inkIndex;
314 s.m_paintIndex = settings.m_paintIndex;
315 Preferences::instance()->getTranspCheckData(
316 s.m_transpCheckBg, s.m_transpCheckInk, s.m_transpCheckPaint);
317
318 TRop::quickPut(icon, rasCM32, timage->getPalette(), TAffine(), s);
319 } else
320 TRop::quickPut(icon, rasCM32, timage->getPalette(), TAffine());
321
322 assert(iconSize2.lx <= iconSize.lx && iconSize2.ly <= iconSize.ly);
323 TRaster32P outIcon(iconSize);
324 outIcon->clear();
325 int dx = (outIcon->getLx() - icon->getLx()) / 2;
326 int dy = (outIcon->getLy() - icon->getLy()) / 2;
327 assert(dx >= 0 && dy >= 0);
328 TRect box = outIcon->getBounds().enlarge(-dx, -dy);
329 TRop::copy(outIcon->extract(box), icon);
330
331 return outIcon;
332 }
333
334 //-------------------------------------------------------------------------
335
convertToIcon(TRasterImageP rimage,const TDimension & iconSize)336 TRaster32P convertToIcon(TRasterImageP rimage, const TDimension &iconSize) {
337 if (!rimage) return TRaster32P();
338
339 TRasterP ras = rimage->getRaster();
340
341 if (!(TRaster32P)ras && !(TRasterGR8P)ras) return TRaster32P();
342
343 if (ras->getSize() == iconSize) return ras;
344
345 TRaster32P icon(iconSize);
346 icon->fill(TPixel32(235, 235, 235));
347
348 double sx = (double)icon->getLx() / ras->getLx();
349 double sy = (double)icon->getLy() / ras->getLy();
350 double sc = sx < sy ? sx : sy;
351
352 TAffine aff = TScale(sc).place(ras->getCenterD(), icon->getCenterD());
353 TRop::resample(icon, ras, aff, TRop::Bilinear);
354 TRop::addBackground(icon, TPixel32::White);
355
356 return icon;
357 }
358
359 //-------------------------------------------------------------------------
360
convertToIcon(TMeshImageP mi,int frame,const TDimension & iconSize,const IconGenerator::Settings & settings)361 TRaster32P convertToIcon(TMeshImageP mi, int frame, const TDimension &iconSize,
362 const IconGenerator::Settings &settings) {
363 if (!mi) return TRaster32P();
364
365 TOfflineGL *glContext = IconGenerator::instance()->getOfflineGLContext();
366
367 // The image and contained within Imagebox
368 // (add a small margin also to prevent problems with empty images)
369 TRectD imageBox;
370 imageBox = mi->getBBox().enlarge(.1);
371
372 TPointD imageCenter(0.5 * (imageBox.getP00() + imageBox.getP11()));
373
374 // Calculate a transformation matrix that moves the image inside the icon.
375 // The scale factor is chosen so that the image is entirely
376 // contained in the icon (with a margin of 'margin' pixels)
377 const int margin = 10;
378 double scx = (iconSize.lx - margin) / imageBox.getLx();
379 double scy = (iconSize.ly - margin) / imageBox.getLy();
380 double sc = std::min(scx, scy);
381
382 // Add the translation: the center point of the image is at the point
383 // middle of the pixmap.
384 TPointD iconCenter(iconSize.lx * 0.5, iconSize.ly * 0.5);
385 TAffine aff = TScale(sc).place(imageCenter, iconCenter);
386
387 // Draw the image.
388 glContext->makeCurrent();
389 glContext->clear(settings.m_blackBgCheck ? TPixel::Black : TPixel32::White);
390
391 glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT);
392 glEnable(GL_BLEND);
393 glEnable(GL_LINE_SMOOTH);
394
395 glPushMatrix();
396 tglMultMatrix(aff);
397
398 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
399
400 glColor4f(0.0f, 1.0f, 0.0f, 0.7f);
401 tglDrawEdges(*mi);
402
403 glPopMatrix();
404
405 glPopAttrib();
406
407 TRaster32P ras(iconSize);
408 glContext->getRaster(ras);
409
410 glContext->doneCurrent();
411
412 return ras;
413 }
414
415 //-------------------------------------------------------------------------
416
convertToIcon(TImageP image,int frame,const TDimension & iconSize,const IconGenerator::Settings & settings)417 TRaster32P convertToIcon(TImageP image, int frame, const TDimension &iconSize,
418 const IconGenerator::Settings &settings) {
419 TRasterImageP ri(image);
420 if (ri) return convertToIcon(ri, iconSize);
421
422 TToonzImageP ti(image);
423 if (ti) return convertToIcon(ti, frame, iconSize, settings);
424
425 TVectorImageP vi(image);
426 if (vi) return convertToIcon(vi, frame, iconSize, settings);
427
428 TMeshImageP mi(image);
429 if (mi) return convertToIcon(mi, frame, iconSize, settings);
430
431 return TRaster32P();
432 }
433
434 } // namespace
435
436 //=============================================================================
437
438 //============================
439 //
440 // IconRenderer class
441 //
442 //----------------------------
443
444 class IconRenderer : public TThread::Runnable {
445 TRaster32P m_icon;
446 TDimension m_iconSize;
447 std::string m_id;
448
449 bool m_started;
450 bool m_terminated;
451
452 public:
453 IconRenderer(const std::string &id, const TDimension &iconSize);
454 virtual ~IconRenderer();
455
456 void run() override = 0;
457
setIcon(const TRaster32P & icon)458 void setIcon(const TRaster32P &icon) { m_icon = icon; }
getIcon() const459 TRaster32P getIcon() const { return m_icon; }
460
getIconSize()461 TDimension getIconSize() { return m_iconSize; }
getId() const462 const std::string &getId() const { return m_id; }
463
hasStarted()464 bool &hasStarted() { return m_started; }
wasTerminated()465 bool &wasTerminated() { return m_terminated; }
466 };
467
468 //-----------------------------------------------------------------------------
469
IconRenderer(const std::string & id,const TDimension & iconSize)470 IconRenderer::IconRenderer(const std::string &id, const TDimension &iconSize)
471 : m_icon()
472 , m_iconSize(iconSize)
473 , m_id(id)
474 , m_started(false)
475 , m_terminated(false) {
476 connect(this, SIGNAL(started(TThread::RunnableP)), IconGenerator::instance(),
477 SLOT(onStarted(TThread::RunnableP)));
478 connect(this, SIGNAL(finished(TThread::RunnableP)), IconGenerator::instance(),
479 SLOT(onFinished(TThread::RunnableP)));
480 connect(this, SIGNAL(canceled(TThread::RunnableP)), IconGenerator::instance(),
481 SLOT(onCanceled(TThread::RunnableP)), Qt::QueuedConnection);
482 connect(this, SIGNAL(terminated(TThread::RunnableP)),
483 IconGenerator::instance(), SLOT(onTerminated(TThread::RunnableP)),
484 Qt::QueuedConnection);
485 }
486
487 //-----------------------------------------------------------------------------
488
~IconRenderer()489 IconRenderer::~IconRenderer() {}
490
491 //=============================================================================
492
493 //===================================
494 //
495 // Specific icon renderers
496 //
497 //-----------------------------------
498
499 //=============================================================================
500
501 //======================================
502 // VectorImageIconRenderer class
503 //--------------------------------------
504
505 class VectorImageIconRenderer final : public IconRenderer {
506 TVectorImageP m_vimage;
507 TXshSimpleLevelP m_sl;
508 TFrameId m_fid;
509 IconGenerator::Settings m_settings;
510
511 public:
VectorImageIconRenderer(const std::string & id,const TDimension & iconSize,TXshSimpleLevelP sl,const TFrameId & fid,const IconGenerator::Settings & settings)512 VectorImageIconRenderer(const std::string &id, const TDimension &iconSize,
513 TXshSimpleLevelP sl, const TFrameId &fid,
514 const IconGenerator::Settings &settings)
515 : IconRenderer(id, iconSize)
516 , m_vimage()
517 , m_sl(sl)
518 , m_fid(fid)
519 , m_settings(settings) {}
520
VectorImageIconRenderer(const std::string & id,const TDimension & iconSize,TVectorImageP vimage,const IconGenerator::Settings & settings)521 VectorImageIconRenderer(const std::string &id, const TDimension &iconSize,
522 TVectorImageP vimage,
523 const IconGenerator::Settings &settings)
524 : IconRenderer(id, iconSize)
525 , m_vimage(vimage)
526 , m_sl(0)
527 , m_fid(-1)
528 , m_settings(settings) {}
529
530 TRaster32P generateRaster(const TDimension &iconSize) const;
531 void run() override;
532 };
533
534 //-----------------------------------------------------------------------------
535
generateRaster(const TDimension & iconSize) const536 TRaster32P VectorImageIconRenderer::generateRaster(
537 const TDimension &iconSize) const {
538 TVectorImageP vimage;
539
540 int frame = 0;
541 if (!m_vimage) {
542 assert(m_sl);
543 if (!m_sl->isFid(m_fid)) return TRaster32P();
544 TImageP image = m_sl->getFrameIcon(m_fid);
545 if (!image) return TRaster32P();
546 vimage = (TVectorImageP)image;
547 if (!vimage) return TRaster32P();
548 frame = m_sl->guessIndex(m_fid);
549 } else
550 vimage = m_vimage;
551 assert(vimage);
552
553 TRaster32P ras(convertToIcon(vimage, frame, iconSize, m_settings));
554
555 return ras;
556 }
557
558 //-----------------------------------------------------------------------------
559
run()560 void VectorImageIconRenderer::run() {
561 try {
562 TRaster32P ras(generateRaster(getIconSize()));
563
564 if (ras) setIcon(ras);
565 } catch (...) {
566 }
567 }
568
569 //=============================================================================
570
571 //======================================
572 // SplineImageIconRenderer class
573 //--------------------------------------
574
575 class SplineIconRenderer final : public IconRenderer {
576 TStageObjectSpline *m_spline;
577
578 public:
SplineIconRenderer(const std::string & id,const TDimension & iconSize,TStageObjectSpline * spline)579 SplineIconRenderer(const std::string &id, const TDimension &iconSize,
580 TStageObjectSpline *spline)
581 : IconRenderer(id, iconSize), m_spline(spline) {}
582
583 TRaster32P generateRaster(const TDimension &iconSize) const;
584 void run() override;
585 };
586
587 //-----------------------------------------------------------------------------
588
generateRaster(const TDimension & iconSize) const589 TRaster32P SplineIconRenderer::generateRaster(
590 const TDimension &iconSize) const {
591 // get the glContext
592 TOfflineGL *glContext = IconGenerator::instance()->getOfflineGLContext();
593 glContext->makeCurrent();
594 glContext->clear(TPixel32::White);
595
596 const TStroke *stroke = m_spline->getStroke();
597 assert(stroke);
598 if (!stroke) {
599 glContext->doneCurrent();
600 return TRaster32P();
601 }
602 TRectD sbbox = stroke->getBBox();
603
604 glColor3d(0, 0, 0);
605 double scaleX = 1, scaleY = 1;
606 if (sbbox.getLx() > 0.0) scaleX = (double)iconSize.lx / sbbox.getLx();
607 if (sbbox.getLy() > 0.0) scaleY = (double)iconSize.ly / sbbox.getLy();
608 double scale = 0.8 * std::min(scaleX, scaleY);
609 TPointD centerStroke = 0.5 * (sbbox.getP00() + sbbox.getP11());
610 TPointD centerPixmap(iconSize.lx * 0.5, iconSize.ly * 0.5);
611 glPushMatrix();
612 tglMultMatrix(TScale(scale).place(centerStroke, centerPixmap));
613 int n = 50;
614 glBegin(GL_LINE_STRIP);
615 for (int i = 0; i < n; i++)
616 tglVertex(stroke->getPoint((double)i / (double)(n - 1)));
617 glEnd();
618 glPopMatrix();
619
620 TRaster32P ras(iconSize);
621 glContext->getRaster(ras);
622 glContext->doneCurrent();
623 return ras;
624 }
625
626 //-----------------------------------------------------------------------------
627
run()628 void SplineIconRenderer::run() {
629 TRaster32P raster = generateRaster(getIconSize());
630 if (raster) setIcon(raster);
631 }
632
633 //=============================================================================
634
635 //======================================
636 // RasterImageIconRenderer class
637 //--------------------------------------
638
639 class RasterImageIconRenderer final : public IconRenderer {
640 TXshSimpleLevelP m_sl;
641 TFrameId m_fid;
642
643 public:
RasterImageIconRenderer(const std::string & id,const TDimension & iconSize,TXshSimpleLevelP sl,const TFrameId & fid)644 RasterImageIconRenderer(const std::string &id, const TDimension &iconSize,
645 TXshSimpleLevelP sl, const TFrameId &fid)
646 : IconRenderer(id, iconSize), m_sl(sl), m_fid(fid) {}
647
648 void run() override;
649 };
650
651 //-----------------------------------------------------------------------------
652
run()653 void RasterImageIconRenderer::run() {
654 if (!m_sl->isFid(m_fid)) return;
655
656 TImageP image = m_sl->getFrameIcon(m_fid);
657 if (!image) return;
658
659 TRasterImageP rimage = (TRasterImageP)image;
660 assert(rimage);
661
662 TRaster32P icon(convertToIcon(rimage, getIconSize()));
663
664 if (icon) setIcon(icon);
665 }
666
667 //=============================================================================
668
669 //======================================
670 // ToonzImageIconRenderer class
671 //--------------------------------------
672
673 class ToonzImageIconRenderer final : public IconRenderer {
674 TXshSimpleLevelP m_sl;
675 TFrameId m_fid;
676 IconGenerator::Settings m_settings;
677
678 TRasterCM32P m_tnzImgIcon;
679
680 public:
ToonzImageIconRenderer(const std::string & id,const TDimension & iconSize,TXshSimpleLevelP sl,const TFrameId & fid,const IconGenerator::Settings & settings)681 ToonzImageIconRenderer(const std::string &id, const TDimension &iconSize,
682 TXshSimpleLevelP sl, const TFrameId &fid,
683 const IconGenerator::Settings &settings)
684 : IconRenderer(id, iconSize)
685 , m_sl(sl)
686 , m_fid(fid)
687 , m_settings(settings)
688 , m_tnzImgIcon(0) {}
689
690 void run() override;
691
setIcon_TnzImg(const TRasterCM32P & timgp)692 void setIcon_TnzImg(const TRasterCM32P &timgp) { m_tnzImgIcon = timgp; }
getIcon_TnzImg() const693 TRasterCM32P getIcon_TnzImg() const { return m_tnzImgIcon; }
694 };
695
696 //-----------------------------------------------------------------------------
697
run()698 void ToonzImageIconRenderer::run() {
699 if (!m_sl->isFid(m_fid)) return;
700
701 TImageP image = m_sl->getFrameIcon(m_fid);
702 if (!image) return;
703
704 TRasterImageP rimage(image);
705 if (rimage) {
706 TRaster32P icon(convertToIcon(rimage, getIconSize()));
707 if (icon) setIcon(icon);
708
709 return;
710 }
711
712 TToonzImageP timage = (TToonzImageP)image;
713
714 TDimension iconSize(getIconSize());
715 if (!timage) {
716 TRaster32P p(iconSize.lx, iconSize.ly);
717 p->fill(TPixelRGBM32::Yellow);
718 setIcon(p);
719
720 return;
721 }
722
723 TRasterCM32P rasCM32 = timage->getRaster();
724 if (!rasCM32.getPointer()) return;
725
726 int lx = rasCM32->getSize().lx;
727 int ly = rasCM32->getSize().ly;
728 int iconLx = iconSize.lx, iconLy = iconSize.ly;
729
730 TRaster32P icon(iconSize);
731
732 icon->fill(m_settings.m_blackBgCheck ? TPixel::Black : TPixel::White);
733
734 if (lx != iconLx && ly != iconLy) {
735 // The icons stored in the tlv file don't have the required size.
736 // Fetch the original and iconize it.
737
738 image = m_sl->getFrame(m_fid, ImageManager::dontPutInCache,
739 0); // 0 uses the level properties' subsampling
740 if (!image) return;
741
742 timage = (TToonzImageP)image;
743 if (!timage) {
744 TRaster32P p(iconSize.lx, iconSize.ly);
745 p->fill(TPixelRGBM32::Yellow);
746 setIcon(p);
747
748 return;
749 }
750
751 rasCM32 = timage->getRaster();
752 if (!rasCM32.getPointer()) return;
753
754 TRasterCM32P auxCM32(icon->getSize());
755 auxCM32->clear();
756
757 TRop::makeIcon(auxCM32, rasCM32);
758 rasCM32 = auxCM32;
759 }
760
761 if (!m_sl->getPalette()) return;
762
763 TPaletteP plt = m_sl->getPalette()->clone();
764 if (!plt) return;
765
766 int frame = m_sl->guessIndex(m_fid);
767 plt->setFrame(frame);
768
769 setIcon_TnzImg(rasCM32);
770 }
771
772 //=============================================================================
773
774 //======================================
775 // MeshImageIconRenderer class
776 //--------------------------------------
777
778 class MeshImageIconRenderer final : public IconRenderer {
779 TMeshImageP m_image;
780 TXshSimpleLevelP m_sl;
781 TFrameId m_fid;
782 IconGenerator::Settings m_settings;
783
784 public:
MeshImageIconRenderer(const std::string & id,const TDimension & iconSize,TXshSimpleLevelP sl,const TFrameId & fid,const IconGenerator::Settings & settings)785 MeshImageIconRenderer(const std::string &id, const TDimension &iconSize,
786 TXshSimpleLevelP sl, const TFrameId &fid,
787 const IconGenerator::Settings &settings)
788 : IconRenderer(id, iconSize)
789 , m_image()
790 , m_sl(sl)
791 , m_fid(fid)
792 , m_settings(settings) {}
793
MeshImageIconRenderer(const std::string & id,const TDimension & iconSize,TMeshImageP image,const IconGenerator::Settings & settings)794 MeshImageIconRenderer(const std::string &id, const TDimension &iconSize,
795 TMeshImageP image,
796 const IconGenerator::Settings &settings)
797 : IconRenderer(id, iconSize)
798 , m_image(image)
799 , m_sl(0)
800 , m_fid(-1)
801 , m_settings(settings) {}
802
803 TRaster32P generateRaster(const TDimension &iconSize) const;
804 void run() override;
805 };
806
807 //-----------------------------------------------------------------------------
808
generateRaster(const TDimension & iconSize) const809 TRaster32P MeshImageIconRenderer::generateRaster(
810 const TDimension &iconSize) const {
811 TMeshImageP mi;
812
813 int frame = 0;
814 if (!m_image) {
815 assert(m_sl);
816 if (!m_sl->isFid(m_fid)) return TRaster32P();
817
818 TImageP image = m_sl->getFrameIcon(m_fid);
819 if (!image) return TRaster32P();
820
821 mi = (TMeshImageP)image;
822 if (!mi) return TRaster32P();
823
824 frame = m_sl->guessIndex(m_fid);
825 } else
826 mi = m_image;
827
828 assert(mi);
829
830 return convertToIcon(mi, frame, iconSize, m_settings);
831 }
832
833 //-----------------------------------------------------------------------------
834
run()835 void MeshImageIconRenderer::run() {
836 try {
837 TRaster32P ras(generateRaster(getIconSize()));
838
839 if (ras) setIcon(ras);
840 } catch (...) {
841 }
842 }
843
844 //=============================================================================
845
846 //==================================
847 // XsheetIconRenderer class
848 //----------------------------------
849
850 class XsheetIconRenderer final : public IconRenderer {
851 TXsheet *m_xsheet;
852 int m_row;
853
854 public:
XsheetIconRenderer(const std::string & id,const TDimension & iconSize,TXsheet * xsheet,int row=0)855 XsheetIconRenderer(const std::string &id, const TDimension &iconSize,
856 TXsheet *xsheet, int row = 0)
857 : IconRenderer(id, iconSize), m_xsheet(xsheet), m_row(row) {
858 if (m_xsheet) {
859 assert(m_xsheet->getRefCount() > 0);
860 m_xsheet->addRef();
861 }
862 }
863
~XsheetIconRenderer()864 ~XsheetIconRenderer() {
865 if (m_xsheet) m_xsheet->release();
866 }
867
getId(TXshChildLevel * level,int row)868 static std::string getId(TXshChildLevel *level, int row) {
869 return "sub:" + ::to_string(level->getName()) + std::to_string(row);
870 }
871
872 TRaster32P generateRaster(const TDimension &iconSize) const;
873 void run() override;
874 };
875
876 //-----------------------------------------------------------------------------
877
generateRaster(const TDimension & iconSize) const878 TRaster32P XsheetIconRenderer::generateRaster(
879 const TDimension &iconSize) const {
880 ToonzScene *scene = m_xsheet->getScene();
881
882 TRaster32P ras(iconSize);
883
884 TPixel32 bgColor = scene->getProperties()->getBgColor();
885 bgColor.m = 255;
886 ras->fill(bgColor);
887
888 TImageCache::instance()->setEnabled(false);
889 // temporarily disable "Visualize Vector As Raster" option to prevent crash.
890 // (see the issue #2862)
891 bool rasterizePli = TXshSimpleLevel::m_rasterizePli;
892 TXshSimpleLevel::m_rasterizePli = false;
893
894 // All checks are disabled
895 scene->renderFrame(ras, m_row, m_xsheet, false);
896
897 TXshSimpleLevel::m_rasterizePli = rasterizePli;
898 TImageCache::instance()->setEnabled(true);
899
900 return ras;
901 }
902
903 //-----------------------------------------------------------------------------
904
run()905 void XsheetIconRenderer::run() {
906 TRaster32P ras = generateRaster(getIconSize());
907 if (ras) setIcon(ras);
908 }
909
910 //=============================================================================
911
912 //================================
913 // FileIconRenderer class
914 //--------------------------------
915
916 class FileIconRenderer final : public IconRenderer {
917 TFilePath m_path;
918 TFrameId m_fid;
919
920 public:
FileIconRenderer(const TDimension & iconSize,const TFilePath & path,const TFrameId & fid)921 FileIconRenderer(const TDimension &iconSize, const TFilePath &path,
922 const TFrameId &fid)
923 : IconRenderer(getId(path, fid), iconSize), m_path(path), m_fid(fid) {}
924
925 static std::string getId(const TFilePath &path, const TFrameId &fid);
926
927 void run() override;
928 };
929
930 //-----------------------------------------------------------------------------
931
getId(const TFilePath & path,const TFrameId & fid)932 std::string FileIconRenderer::getId(const TFilePath &path,
933 const TFrameId &fid) {
934 std::string type(path.getType());
935
936 if (type == "tab" || type == "tnz" ||
937 type == "mesh" || // meshes are not currently viewable
938 TFileType::isViewable(TFileType::getInfo(path))) {
939 std::string fidNumber;
940 if (fid != TFrameId::NO_FRAME)
941 fidNumber = "frame:" + fid.expand(TFrameId::NO_PAD);
942 return "$:" + ::to_string(path) + fidNumber;
943 }
944
945 // All the other types whose icon is the same for file type, get the same id
946 // per type.
947 else if (type == "tpl")
948 return "$:tpl";
949 else if (type == "tzp")
950 return "$:tzp";
951 else if (type == "svg")
952 return "$:svg";
953 else if (type == "tzu")
954 return "$:tzu";
955 else if (TFileType::getInfo(path) == TFileType::AUDIO_LEVEL)
956 return "$:audio";
957 else if (type == "scr")
958 return "$:scr";
959 else if (type == "mpath")
960 return "$:mpath";
961 else if (type == "curve")
962 return "$:curve";
963 else if (type == "cln")
964 return "$:cln";
965 else if (type == "tnzbat")
966 return "$:tnzbat";
967 else
968 return "$:unknown";
969 }
970
971 //-----------------------------------------------------------------------------
972
generateVectorFileIcon(const TFilePath & path,const TDimension & iconSize,const TFrameId & fid)973 TRaster32P IconGenerator::generateVectorFileIcon(const TFilePath &path,
974 const TDimension &iconSize,
975 const TFrameId &fid) {
976 TLevelReaderP lr(path);
977 TLevelP level = lr->loadInfo();
978 if (level->begin() == level->end()) return TRaster32P();
979 TFrameId frameId = fid;
980 if (fid == TFrameId::NO_FRAME) frameId = level->begin()->first;
981 TImageP img = lr->getFrameReader(frameId)->load();
982 TVectorImageP vi = img;
983 if (!vi) return TRaster32P();
984 vi->setPalette(level->getPalette());
985 VectorImageIconRenderer vir("", iconSize, vi.getPointer(),
986 IconGenerator::Settings());
987 return vir.generateRaster(iconSize);
988 }
989
990 //-----------------------------------------------------------------------------
991
generateRasterFileIcon(const TFilePath & path,const TDimension & iconSize,const TFrameId & fid)992 TRaster32P IconGenerator::generateRasterFileIcon(const TFilePath &path,
993 const TDimension &iconSize,
994 const TFrameId &fid) {
995 TImageP img;
996
997 try {
998 // Attempt image reading
999 TLevelReaderP lr(path);
1000 TLevelP level = lr->loadInfo();
1001
1002 if (level->begin() == level->end()) return TRaster32P();
1003
1004 TFrameId frameId = fid;
1005 if (fid == TFrameId::NO_FRAME) // In case no frame was specified, pick the
1006 frameId = level->begin()->first; // first level frame
1007
1008 TImageReaderP ir = lr->getFrameReader(frameId);
1009
1010 if (const TImageInfo *ii = ir->getImageInfo()) {
1011 int shrinkX = ii->m_lx / iconSize.lx;
1012 int shrinkY = ii->m_ly / iconSize.ly;
1013 int shrink = shrinkX < shrinkY ? shrinkX : shrinkY;
1014
1015 if (shrink > 1) ir->setShrink(shrink);
1016 }
1017
1018 img = (toUpper(path.getType()) == "TLV") ? ir->loadIcon() : ir->load();
1019 } catch (...) {
1020 }
1021
1022 // Extract a 32-bit fullcolor raster from img
1023 TRaster32P ras32;
1024
1025 if (TRasterImageP ri = img) {
1026 ras32 = ri->getRaster();
1027
1028 if (!ras32) {
1029 if (TRasterGR8P rasGR8 = ri->getRaster()) {
1030 TRaster32P raux(rasGR8->getSize());
1031 TRop::convert(raux, rasGR8);
1032 ras32 = raux;
1033 }
1034 }
1035 } else if (TToonzImageP ti = img) {
1036 TRasterCM32P auxRaster = ti->getRaster();
1037 TRaster32P dstRaster(auxRaster->getSize());
1038
1039 if (TPaletteP plt = ti->getPalette())
1040 TRop::convert(dstRaster, auxRaster, plt, false);
1041 else
1042 dstRaster->fill(TPixel32::Magenta);
1043
1044 ras32 = dstRaster;
1045 }
1046
1047 if (!ras32) return TRaster32P();
1048
1049 /*
1050 // NOTE: The following was possible with the old Qt version 4.3.3 - but in the
1051 new 4.5.0
1052 // it's not: 'It is not safe to use QPixmaps outside the GUI thread'...
1053 TRaster32P icon;
1054 {
1055 QPixmap p(rasterToQPixmap(ras32));
1056 icon = rasterFromQPixmap(
1057 scalePixmapKeepingAspectRatio(p, QSize(iconSize.lx, iconSize.ly),
1058 Qt::transparent)
1059 , false);
1060 }
1061 */
1062
1063 TRaster32P icon(iconSize);
1064
1065 double sx = double(iconSize.lx) / ras32->getLx();
1066 double sy = double(iconSize.ly) / ras32->getLy();
1067 double sc = std::min(sx, sy); // show all the image, possibly adding bands
1068
1069 TAffine aff = TScale(sc).place(ras32->getCenterD(), icon->getCenterD());
1070
1071 icon->fill(TPixel32(255, 0, 0)); // "bands" color
1072 TRop::resample(icon, ras32, aff, TRop::Triangle);
1073
1074 if (icon) {
1075 if (::isUnpremultiplied(icon)) // APPALLING. I'm not touching this, but
1076 TRop::premultiply(
1077 icon); // YOU JUST CAN'T TELL IF AN IMAGE IS PREMULTIPLIED
1078 // OR NOT BY SCANNING ITS PIXELS.
1079 // You either know it FOR A GIVEN, or you don't... >_<
1080 TRectI srcBBoxI = ras32->getBounds();
1081 TRectD srcBBoxD = aff * TRectD(srcBBoxI.x0, srcBBoxI.y0, srcBBoxI.x1 + 1,
1082 srcBBoxI.y1 + 1);
1083
1084 TRect bbox = TRect(tfloor(srcBBoxD.x0), tceil(srcBBoxD.y0) - 1,
1085 tfloor(srcBBoxD.x1), tceil(srcBBoxD.y1) - 1);
1086
1087 bbox = (bbox * icon->getBounds())
1088 .enlarge(-1); // Add a 1 pixel transparent margin - this
1089 if (bbox.getLx() > 0 &&
1090 bbox.getLy() > 0) // way the actual content doesn't look trimmed.
1091 ::makeChessBackground(icon->extract(bbox));
1092 } else
1093 icon->fill(TPixel32(255, 0, 0));
1094
1095 return icon;
1096 }
1097
1098 //-----------------------------------------------------------------------------
1099
generateSplineFileIcon(const TFilePath & path,const TDimension & iconSize)1100 TRaster32P IconGenerator::generateSplineFileIcon(const TFilePath &path,
1101 const TDimension &iconSize) {
1102 TStageObjectSpline *spline = new TStageObjectSpline();
1103 TIStream is(path);
1104 spline->loadData(is);
1105 SplineIconRenderer sr("", iconSize, spline);
1106 TRaster32P icon = sr.generateRaster(iconSize);
1107 delete spline;
1108 return icon;
1109 }
1110
1111 //-----------------------------------------------------------------------------
1112
generateMeshFileIcon(const TFilePath & path,const TDimension & iconSize,const TFrameId & fid)1113 TRaster32P IconGenerator::generateMeshFileIcon(const TFilePath &path,
1114 const TDimension &iconSize,
1115 const TFrameId &fid) {
1116 TLevelReaderP lr(path);
1117 TLevelP level = lr->loadInfo();
1118 if (level->begin() == level->end()) return TRaster32P();
1119
1120 TFrameId frameId = fid;
1121 if (fid == TFrameId::NO_FRAME) frameId = level->begin()->first;
1122
1123 TMeshImageP mi = lr->getFrameReader(frameId)->load();
1124 if (!mi) return TRaster32P();
1125
1126 MeshImageIconRenderer mir("", iconSize, mi.getPointer(),
1127 IconGenerator::Settings());
1128 return mir.generateRaster(iconSize);
1129 }
1130
1131 //-----------------------------------------------------------------------------
1132
generateSceneFileIcon(const TFilePath & path,const TDimension & iconSize,int row)1133 TRaster32P IconGenerator::generateSceneFileIcon(const TFilePath &path,
1134 const TDimension &iconSize,
1135 int row) {
1136 if (row == 0 || row == TFrameId::NO_FRAME - 1) {
1137 TFilePath iconPath =
1138 path.getParentDir() + "sceneIcons" + (path.getWideName() + L" .png");
1139 return generateRasterFileIcon(iconPath, iconSize, TFrameId::NO_FRAME);
1140 } else {
1141 // obsolete
1142 ToonzScene scene;
1143 scene.load(path);
1144 XsheetIconRenderer ir("", iconSize, scene.getXsheet(), row);
1145 return ir.generateRaster(iconSize);
1146 }
1147 }
1148
1149 //-----------------------------------------------------------------------------
1150
run()1151 void FileIconRenderer::run() {
1152 TDimension iconSize(getIconSize());
1153 try {
1154 TRaster32P iconRaster;
1155 std::string type(m_path.getType());
1156
1157 if (type == "tnz" || type == "tab")
1158 iconRaster = IconGenerator::generateSceneFileIcon(m_path, iconSize,
1159 m_fid.getNumber() - 1);
1160 else if (type == "pli")
1161 iconRaster =
1162 IconGenerator::generateVectorFileIcon(m_path, iconSize, m_fid);
1163 else if (type == "tpl") {
1164 QImage palette(":Resources/paletteicon.svg");
1165 setIcon(rasterFromQImage(palette));
1166 return;
1167 } else if (type == "tzp") {
1168 QImage palette(":Resources/tzpicon.png");
1169 setIcon(rasterFromQImage(palette));
1170 return;
1171 } else if (type == "svg") {
1172 QPixmap svg(svgToPixmap(getIconThemePath("mimetypes/60/svg_icon.svg"),
1173 QSize(iconSize.lx, iconSize.ly),
1174 Qt::KeepAspectRatio));
1175 setIcon(rasterFromQPixmap(svg));
1176 return;
1177 } else if (type == "tzu") {
1178 QImage palette(":Resources/tzuicon.png");
1179 setIcon(rasterFromQImage(palette));
1180 return;
1181 } else if (TFileType::getInfo(m_path) == TFileType::AUDIO_LEVEL) {
1182 QPixmap loudspeaker(
1183 svgToPixmap(getIconThemePath("mimetypes/60/audio_icon.svg"),
1184 QSize(iconSize.lx, iconSize.ly), Qt::KeepAspectRatio));
1185 setIcon(rasterFromQPixmap(loudspeaker));
1186 return;
1187 } else if (type == "scr") {
1188 QImage screensaver(":Resources/savescreen.png");
1189 setIcon(rasterFromQImage(screensaver));
1190 return;
1191 } else if (type == "psd") {
1192 QPixmap psdPath(svgToPixmap(getIconThemePath("mimetypes/60/psd_icon.svg"),
1193 QSize(iconSize.lx, iconSize.ly),
1194 Qt::KeepAspectRatio));
1195 setIcon(rasterFromQPixmap(psdPath));
1196 return;
1197 } else if (type == "mesh")
1198 iconRaster = IconGenerator::generateMeshFileIcon(m_path, iconSize, m_fid);
1199 else if (TFileType::isViewable(TFileType::getInfo(m_path)) || type == "tlv")
1200 iconRaster =
1201 IconGenerator::generateRasterFileIcon(m_path, iconSize, m_fid);
1202 else if (type == "mpath") {
1203 QPixmap motionPath(
1204 svgToPixmap(getIconThemePath("mimetypes/60/motionpath_icon.svg"),
1205 QSize(iconSize.lx, iconSize.ly), Qt::KeepAspectRatio));
1206 setIcon(rasterFromQPixmap(motionPath));
1207 return;
1208 } else if (type == "curve") {
1209 QPixmap curve(svgToPixmap(getIconThemePath("mimetypes/60/curve_icon.svg"),
1210 QSize(iconSize.lx, iconSize.ly),
1211 Qt::KeepAspectRatio));
1212 setIcon(rasterFromQPixmap(curve));
1213 return;
1214 } else if (type == "cln") {
1215 QPixmap cln(svgToPixmap(getIconThemePath("mimetypes/60/cleanup_icon.svg"),
1216 QSize(iconSize.lx, iconSize.ly),
1217 Qt::KeepAspectRatio));
1218 setIcon(rasterFromQPixmap(cln));
1219 return;
1220 } else if (type == "tnzbat") {
1221 QPixmap tnzBat(
1222 svgToPixmap(getIconThemePath("mimetypes/60/tasklist_icon.svg"),
1223 QSize(iconSize.lx, iconSize.ly), Qt::KeepAspectRatio));
1224 setIcon(rasterFromQPixmap(tnzBat));
1225 return;
1226 } else if (type == "tls") {
1227 QPixmap tls(svgToPixmap(":Resources/magpie.svg",
1228 QSize(iconSize.lx, iconSize.ly),
1229 Qt::KeepAspectRatio));
1230 setIcon(rasterFromQPixmap(tls));
1231 return;
1232 } else if (type == "xdts") {
1233 QPixmap xdts(svgToPixmap(getIconThemePath("mimetypes/60/xdts_icon.svg"),
1234 QSize(iconSize.lx, iconSize.ly),
1235 Qt::KeepAspectRatio));
1236 setIcon(rasterFromQPixmap(xdts));
1237 return;
1238 } else if (type == "js") {
1239 QPixmap script(
1240 svgToPixmap(getIconThemePath("mimetypes/60/script_icon.svg"),
1241 QSize(iconSize.lx, iconSize.ly), Qt::KeepAspectRatio));
1242 setIcon(rasterFromQPixmap(script));
1243 return;
1244 }
1245
1246 else {
1247 QPixmap unknown(
1248 svgToPixmap(getIconThemePath("mimetypes/60/unknown_icon.svg"),
1249 QSize(iconSize.lx, iconSize.ly), Qt::KeepAspectRatio));
1250 setIcon(rasterFromQPixmap(unknown));
1251 return;
1252 }
1253 if (!iconRaster) {
1254 QPixmap broken(
1255 svgToPixmap(getIconThemePath("mimetypes/60/broken_icon.svg"),
1256 QSize(iconSize.lx, iconSize.ly), Qt::KeepAspectRatio));
1257 setIcon(rasterFromQPixmap(broken));
1258 return;
1259 }
1260 setIcon(iconRaster);
1261 } catch (const TImageVersionException &) {
1262 QPixmap unknown(
1263 svgToPixmap(getIconThemePath("mimetypes/60/unknown_icon.svg"),
1264 QSize(iconSize.lx, iconSize.ly), Qt::KeepAspectRatio));
1265 setIcon(rasterFromQPixmap(unknown));
1266 } catch (...) {
1267 QPixmap broken(svgToPixmap(getIconThemePath("mimetypes/60/broken_icon.svg"),
1268 QSize(iconSize.lx, iconSize.ly),
1269 Qt::KeepAspectRatio));
1270 setIcon(rasterFromQPixmap(broken));
1271 }
1272 }
1273
1274 //=============================================================================
1275
1276 //================================
1277 // SceneIconRenderer class
1278 //--------------------------------
1279
1280 class SceneIconRenderer final : public IconRenderer {
1281 ToonzScene *m_toonzScene;
1282
1283 public:
SceneIconRenderer(const TDimension & iconSize,ToonzScene * scene)1284 SceneIconRenderer(const TDimension &iconSize, ToonzScene *scene)
1285 : IconRenderer(getId(), iconSize), m_toonzScene(scene) {}
1286
getId()1287 static std::string getId() { return "currentScene"; }
1288
1289 void run() override;
1290 TRaster32P generateIcon(const TDimension &iconSize) const;
1291 };
1292
1293 //-----------------------------------------------------------------------------
1294
generateIcon(const TDimension & iconSize) const1295 TRaster32P SceneIconRenderer::generateIcon(const TDimension &iconSize) const {
1296 TRaster32P ras(iconSize);
1297
1298 TPixel32 bgColor = m_toonzScene->getProperties()->getBgColor();
1299 bgColor.m = 255;
1300 ras->fill(bgColor);
1301
1302 m_toonzScene->renderFrame(ras, 0, 0, false);
1303
1304 return ras;
1305 }
1306
1307 //-----------------------------------------------------------------------------
1308
run()1309 void SceneIconRenderer::run() { setIcon(generateIcon(getIconSize())); }
1310
1311 //=============================================================================
1312
1313 //===================================
1314 //
1315 // IconGenerator class
1316 //
1317 //-----------------------------------
1318
IconGenerator()1319 IconGenerator::IconGenerator() : m_iconSize(FilmstripIconSize) {
1320 m_executor.setMaxActiveTasks(1); // Only one thread to render icons...
1321 m_executor.setDedicatedThreads(true);
1322 }
1323
1324 //-----------------------------------------------------------------------------
1325
~IconGenerator()1326 IconGenerator::~IconGenerator() {}
1327
1328 //-----------------------------------------------------------------------------
1329
instance()1330 IconGenerator *IconGenerator::instance() {
1331 static IconGenerator _instance;
1332 return &_instance;
1333 }
1334
1335 //-----------------------------------------------------------------------------
1336
setFilmstripIconSize(const TDimension & dim)1337 void IconGenerator::setFilmstripIconSize(const TDimension &dim) {
1338 FilmstripIconSize = dim;
1339 }
1340
1341 //-----------------------------------------------------------------------------
1342
getIconSize() const1343 TDimension IconGenerator::getIconSize() const { return FilmstripIconSize; }
1344
1345 //-----------------------------------------------------------------------------
1346
getOfflineGLContext()1347 TOfflineGL *IconGenerator::getOfflineGLContext() {
1348 // One context per rendering thread
1349 if (!m_contexts.hasLocalData()) {
1350 TDimension contextSize(std::max(FilmstripIconSize.lx, IconSize.lx),
1351 std::max(FilmstripIconSize.ly, IconSize.ly));
1352 m_contexts.setLocalData(new TOfflineGL(contextSize));
1353 }
1354 return m_contexts.localData();
1355 }
1356
1357 //-----------------------------------------------------------------------------
1358
addTask(const std::string & id,TThread::RunnableP iconRenderer)1359 void IconGenerator::addTask(const std::string &id,
1360 TThread::RunnableP iconRenderer) {
1361 iconsMap.insert(id);
1362 m_executor.addTask(iconRenderer);
1363 }
1364
1365 //-----------------------------------------------------------------------------
1366
getIcon(TXshLevel * xl,const TFrameId & fid,bool filmStrip,bool onDemand)1367 QPixmap IconGenerator::getIcon(TXshLevel *xl, const TFrameId &fid,
1368 bool filmStrip, bool onDemand) {
1369 if (!xl) return QPixmap();
1370
1371 if (TXshChildLevel *cl = xl->getChildLevel()) {
1372 if (filmStrip) return QPixmap();
1373
1374 std::string id = XsheetIconRenderer::getId(cl, fid.getNumber() - 1);
1375 QPixmap pix;
1376 if (::getIcon(id, pix)) return pix;
1377
1378 if (onDemand) return pix;
1379
1380 TDimension iconSize = TDimension(80, 60);
1381
1382 // The icon must be calculated - add an IconRenderer task.
1383 // storeIcon(id, QPixmap()); //It was automatically added by the former
1384 // access
1385 addTask(id, new XsheetIconRenderer(id, iconSize, cl->getXsheet()));
1386 }
1387
1388 if (TXshSimpleLevel *sl = xl->getSimpleLevel()) {
1389 // make thumbnails for cleanup preview and cameratest to be the same as
1390 // normal TLV
1391 std::string id;
1392 int status = sl->getFrameStatus(fid);
1393 if (sl->getType() == TZP_XSHLEVEL &&
1394 status & TXshSimpleLevel::CleanupPreview) {
1395 sl->setFrameStatus(fid, status & ~TXshSimpleLevel::CleanupPreview);
1396 id = sl->getIconId(fid);
1397 sl->setFrameStatus(fid, status);
1398 } else
1399 id = sl->getIconId(fid);
1400
1401 if (!filmStrip) id += "_small";
1402
1403 QPixmap pix;
1404 if (::getIcon(id, pix, xl->getSimpleLevel())) return pix;
1405
1406 if (onDemand) return pix;
1407
1408 IconGenerator::Settings oldSettings = m_settings;
1409
1410 // Disable transparency check for cast and xsheet icons
1411 if (!filmStrip) m_settings = IconGenerator::Settings();
1412
1413 TDimension iconSize = filmStrip ? m_iconSize : TDimension(80, 60);
1414
1415 // storeIcon(id, QPixmap());
1416
1417 int type = sl->getType();
1418 switch (type) {
1419 case OVL_XSHLEVEL:
1420 case TZI_XSHLEVEL:
1421 addTask(id, new RasterImageIconRenderer(id, iconSize, sl, fid));
1422 break;
1423 case PLI_XSHLEVEL:
1424 addTask(id,
1425 new VectorImageIconRenderer(id, iconSize, sl, fid, m_settings));
1426 break;
1427 case TZP_XSHLEVEL:
1428 // Yep, we could have rasters, due to a cleanupping process
1429 if (status == TXshSimpleLevel::Scanned)
1430 addTask(id, new RasterImageIconRenderer(id, iconSize, sl, fid));
1431 else
1432 addTask(id,
1433 new ToonzImageIconRenderer(id, iconSize, sl, fid, m_settings));
1434 break;
1435 case MESH_XSHLEVEL:
1436 addTask(id, new MeshImageIconRenderer(id, iconSize, sl, fid, m_settings));
1437 break;
1438 default:
1439 assert(false);
1440 break;
1441 }
1442
1443 m_settings = oldSettings;
1444 }
1445
1446 return QPixmap();
1447 }
1448
1449 //-----------------------------------------------------------------------------
1450
getSizedIcon(TXshLevel * xl,const TFrameId & fid,std::string newId,TDimension dim)1451 QPixmap IconGenerator::getSizedIcon(TXshLevel *xl, const TFrameId &fid,
1452 std::string newId, TDimension dim) {
1453 if (!xl) return QPixmap();
1454
1455 if (TXshChildLevel *cl = xl->getChildLevel()) {
1456 std::string id = XsheetIconRenderer::getId(cl, fid.getNumber() - 1);
1457 QPixmap pix;
1458 if (::getIcon(id, pix)) return pix;
1459
1460 // if (onDemand) return pix;
1461
1462 TDimension iconSize = TDimension(80, 60);
1463 if (dim != TDimension(0, 0)) {
1464 iconSize = dim;
1465 }
1466
1467 // The icon must be calculated - add an IconRenderer task.
1468 // storeIcon(id, QPixmap()); //It was automatically added by the former
1469 // access
1470 addTask(id, new XsheetIconRenderer(id, iconSize, cl->getXsheet()));
1471 }
1472
1473 if (TXshSimpleLevel *sl = xl->getSimpleLevel()) {
1474 // make thumbnails for cleanup preview and cameratest to be the same as
1475 // normal TLV
1476 std::string id;
1477 int status = sl->getFrameStatus(fid);
1478 if (sl->getType() == TZP_XSHLEVEL &&
1479 status & TXshSimpleLevel::CleanupPreview) {
1480 sl->setFrameStatus(fid, status & ~TXshSimpleLevel::CleanupPreview);
1481 id = sl->getIconId(fid);
1482 sl->setFrameStatus(fid, status);
1483 } else
1484 id = sl->getIconId(fid);
1485
1486 id += newId;
1487
1488 QPixmap pix;
1489 if (::getIcon(id, pix, xl->getSimpleLevel())) return pix;
1490
1491 // if (onDemand) return pix;
1492
1493 IconGenerator::Settings oldSettings = m_settings;
1494
1495 // Disable transparency check for cast and xsheet icons
1496 // if (!filmStrip) m_settings = IconGenerator::Settings();
1497
1498 TDimension iconSize = TDimension(80, 60);
1499 if (dim != TDimension(0, 0)) {
1500 iconSize = dim;
1501 }
1502
1503 // storeIcon(id, QPixmap());
1504
1505 int type = sl->getType();
1506 switch (type) {
1507 case OVL_XSHLEVEL:
1508 case TZI_XSHLEVEL:
1509 addTask(id, new RasterImageIconRenderer(id, iconSize, sl, fid));
1510 break;
1511 case PLI_XSHLEVEL:
1512 addTask(id,
1513 new VectorImageIconRenderer(id, iconSize, sl, fid, m_settings));
1514 break;
1515 case TZP_XSHLEVEL:
1516 // Yep, we could have rasters, due to a cleanupping process
1517 if (status == TXshSimpleLevel::Scanned)
1518 addTask(id, new RasterImageIconRenderer(id, iconSize, sl, fid));
1519 else
1520 addTask(id,
1521 new ToonzImageIconRenderer(id, iconSize, sl, fid, m_settings));
1522 break;
1523 case MESH_XSHLEVEL:
1524 addTask(id, new MeshImageIconRenderer(id, iconSize, sl, fid, m_settings));
1525 break;
1526 default:
1527 assert(false);
1528 break;
1529 }
1530
1531 m_settings = oldSettings;
1532 }
1533
1534 return QPixmap();
1535 }
1536
1537 //-----------------------------------------------------------------------------
1538
invalidate(TXshLevel * xl,const TFrameId & fid,bool onlyFilmStrip)1539 void IconGenerator::invalidate(TXshLevel *xl, const TFrameId &fid,
1540 bool onlyFilmStrip) {
1541 if (!xl) return;
1542
1543 if (TXshSimpleLevel *sl = xl->getSimpleLevel()) {
1544 std::string id = sl->getIconId(fid);
1545
1546 int type = sl->getType();
1547
1548 switch (type) {
1549 case OVL_XSHLEVEL:
1550 case TZI_XSHLEVEL:
1551 addTask(id, new RasterImageIconRenderer(id, getIconSize(), sl, fid));
1552 break;
1553 case PLI_XSHLEVEL:
1554 removeIcon(id);
1555 addTask(id, new VectorImageIconRenderer(id, getIconSize(), sl, fid,
1556 m_settings));
1557 break;
1558 case TZP_XSHLEVEL:
1559 if (sl->getFrameStatus(fid) == TXshSimpleLevel::Scanned)
1560 addTask(id, new RasterImageIconRenderer(id, getIconSize(), sl, fid));
1561 else
1562 addTask(id, new ToonzImageIconRenderer(id, getIconSize(), sl, fid,
1563 m_settings));
1564 break;
1565 case MESH_XSHLEVEL:
1566 addTask(id, new MeshImageIconRenderer(id, getIconSize(), sl, fid,
1567 m_settings));
1568 break;
1569 default:
1570 assert(false);
1571 break;
1572 }
1573
1574 if (onlyFilmStrip) return;
1575
1576 id += "_small";
1577 if (iconsMap.find(id) == iconsMap.end()) return;
1578
1579 // Not-filmstrip icons diable all checks
1580 IconGenerator::Settings oldSettings = m_settings;
1581 m_settings.m_transparencyCheck = false;
1582 m_settings.m_inkIndex = -1;
1583 m_settings.m_paintIndex = -1;
1584 m_settings.m_blackBgCheck = false;
1585
1586 switch (type) {
1587 case OVL_XSHLEVEL:
1588 case TZI_XSHLEVEL:
1589 addTask(id, new RasterImageIconRenderer(id, TDimension(80, 60), sl, fid));
1590 break;
1591 case PLI_XSHLEVEL:
1592 addTask(id, new VectorImageIconRenderer(id, TDimension(80, 60), sl, fid,
1593 m_settings));
1594 break;
1595 case TZP_XSHLEVEL:
1596 if (sl->getFrameStatus(fid) == TXshSimpleLevel::Scanned)
1597 addTask(id,
1598 new RasterImageIconRenderer(id, TDimension(80, 60), sl, fid));
1599 else
1600 addTask(id, new ToonzImageIconRenderer(id, TDimension(80, 60), sl, fid,
1601 m_settings));
1602 break;
1603 case MESH_XSHLEVEL:
1604 addTask(id, new MeshImageIconRenderer(id, TDimension(80, 60), sl, fid,
1605 m_settings));
1606 break;
1607 default:
1608 assert(false);
1609 break;
1610 }
1611
1612 m_settings = oldSettings;
1613 } else if (TXshChildLevel *cl = xl->getChildLevel()) {
1614 if (onlyFilmStrip) return;
1615
1616 std::string id = XsheetIconRenderer::getId(cl, fid.getNumber() - 1);
1617 removeIcon(id);
1618
1619 getIcon(xl, fid);
1620 }
1621 }
1622
1623 //-----------------------------------------------------------------------------
1624
remove(TXshLevel * xl,const TFrameId & fid,bool onlyFilmStrip)1625 void IconGenerator::remove(TXshLevel *xl, const TFrameId &fid,
1626 bool onlyFilmStrip) {
1627 if (!xl) return;
1628 if (TXshSimpleLevel *sl = xl->getSimpleLevel()) {
1629 std::string id(sl->getIconId(fid));
1630
1631 removeIcon(id);
1632 if (!onlyFilmStrip) removeIcon(id + "_small");
1633 } else {
1634 TXshChildLevel *cl = xl->getChildLevel();
1635 if (cl && !onlyFilmStrip)
1636 removeIcon(XsheetIconRenderer::getId(cl, fid.getNumber() - 1));
1637 }
1638 }
1639
1640 //-----------------------------------------------------------------------------
1641
getIcon(TStageObjectSpline * spline)1642 QPixmap IconGenerator::getIcon(TStageObjectSpline *spline) {
1643 if (!spline) return QPixmap();
1644 std::string iconName = spline->getIconId();
1645
1646 QPixmap pix;
1647 if (::getIcon(iconName, pix)) return pix;
1648
1649 // storeIcon(id, QPixmap());
1650 addTask(iconName, new SplineIconRenderer(iconName, getIconSize(), spline));
1651
1652 return QPixmap();
1653 }
1654
1655 //-----------------------------------------------------------------------------
1656
invalidate(TStageObjectSpline * spline)1657 void IconGenerator::invalidate(TStageObjectSpline *spline) {
1658 if (!spline) return;
1659 std::string iconName = spline->getIconId();
1660 removeIcon(iconName);
1661
1662 addTask(iconName, new SplineIconRenderer(iconName, getIconSize(), spline));
1663 }
1664
1665 //-----------------------------------------------------------------------------
1666
remove(TStageObjectSpline * spline)1667 void IconGenerator::remove(TStageObjectSpline *spline) {
1668 if (!spline) return;
1669 std::string iconName = spline->getIconId();
1670 removeIcon(iconName);
1671 }
1672
1673 //-----------------------------------------------------------------------------
1674
getIcon(const TFilePath & path,const TFrameId & fid)1675 QPixmap IconGenerator::getIcon(const TFilePath &path, const TFrameId &fid) {
1676 std::string id = FileIconRenderer::getId(path, fid);
1677
1678 QPixmap pix;
1679 TDimension fileIconSize(80, 60);
1680 // Here the fileIconSize is input in order to check if the icon is obtained
1681 // with high-dpi (i.e. devPixRatio > 1.0).
1682 if (::getIcon(id, pix, 0, fileIconSize)) return pix;
1683
1684 addTask(id, new FileIconRenderer(fileIconSize, path, fid));
1685
1686 return QPixmap();
1687 }
1688
1689 //-----------------------------------------------------------------------------
1690
invalidate(const TFilePath & path,const TFrameId & fid)1691 void IconGenerator::invalidate(const TFilePath &path, const TFrameId &fid) {
1692 std::string id = FileIconRenderer::getId(path, fid);
1693 removeIcon(id);
1694 addTask(id, new FileIconRenderer(TDimension(80, 60), path, fid));
1695 }
1696
1697 //-----------------------------------------------------------------------------
1698
remove(const TFilePath & path,const TFrameId & fid)1699 void IconGenerator::remove(const TFilePath &path, const TFrameId &fid) {
1700 removeIcon(FileIconRenderer::getId(path, fid));
1701 }
1702
1703 //-----------------------------------------------------------------------------
1704
getSceneIcon(ToonzScene * scene)1705 QPixmap IconGenerator::getSceneIcon(ToonzScene *scene) {
1706 std::string id(SceneIconRenderer::getId());
1707
1708 QPixmap pix;
1709 if (::getIcon(id, pix)) return pix;
1710
1711 // storeIcon(id, QPixmap());
1712 addTask(id, new SceneIconRenderer(getIconSize(), scene));
1713
1714 return QPixmap();
1715 }
1716
1717 //-----------------------------------------------------------------------------
1718
invalidateSceneIcon()1719 void IconGenerator::invalidateSceneIcon() {
1720 removeIcon(SceneIconRenderer::getId());
1721 }
1722
1723 //-----------------------------------------------------------------------------
1724
remap(const std::string & newIconId,const std::string & oldIconId)1725 void IconGenerator::remap(const std::string &newIconId,
1726 const std::string &oldIconId) {
1727 IconIterator it = iconsMap.find(oldIconId);
1728 if (it == iconsMap.end()) return;
1729
1730 iconsMap.erase(it);
1731 iconsMap.insert(newIconId);
1732
1733 TImageCache::instance()->remap(newIconId, oldIconId);
1734 }
1735
1736 //-----------------------------------------------------------------------------
1737
clearRequests()1738 void IconGenerator::clearRequests() { m_executor.cancelAll(); }
1739
1740 //-----------------------------------------------------------------------------
1741
clearSceneIcons()1742 void IconGenerator::clearSceneIcons() {
1743 // Eliminate all icons whose prefix is not "$:" (that is, scene-independent
1744 // images).
1745 // The abovementioned prefix is internally recognized by the image cache when
1746 // the scene
1747 // changes to avoid clearing file browser's icons.
1748
1749 // Observe that image cache's clear function invoked during scene changes is
1750 // called through
1751 // the ImageManager::clear() method, including FilmStrip icons.
1752
1753 // note the ';' - which follows ':' in the ascii table
1754 iconsMap.erase(iconsMap.begin(), iconsMap.lower_bound("$:"));
1755 iconsMap.erase(iconsMap.lower_bound("$;"), iconsMap.end());
1756 }
1757
1758 //-----------------------------------------------------------------------------
1759
onStarted(TThread::RunnableP iconRenderer)1760 void IconGenerator::onStarted(TThread::RunnableP iconRenderer) {
1761 IconRenderer *ir = static_cast<IconRenderer *>(iconRenderer.getPointer());
1762
1763 ir->hasStarted() = true;
1764 }
1765
1766 //-----------------------------------------------------------------------------
1767
onCanceled(TThread::RunnableP iconRenderer)1768 void IconGenerator::onCanceled(TThread::RunnableP iconRenderer) {
1769 IconRenderer *ir = static_cast<IconRenderer *>(iconRenderer.getPointer());
1770
1771 if (!ir->hasStarted()) {
1772 removeIcon(ir->getId());
1773 }
1774 }
1775
1776 //-----------------------------------------------------------------------------
1777
onFinished(TThread::RunnableP iconRenderer)1778 void IconGenerator::onFinished(TThread::RunnableP iconRenderer) {
1779 IconRenderer *ir = static_cast<IconRenderer *>(iconRenderer.getPointer());
1780
1781 // if the icon was generated in TToonzImage format, cache it instead
1782 ToonzImageIconRenderer *tir = dynamic_cast<ToonzImageIconRenderer *>(ir);
1783 if (tir) {
1784 TRasterCM32P timgp = tir->getIcon_TnzImg();
1785 if (timgp) {
1786 ::setIcon_TnzImg(ir->getId(), timgp);
1787 emit iconGenerated();
1788 if (ir->wasTerminated()) m_iconsTerminationLoop.quit();
1789 return;
1790 }
1791 }
1792
1793 // Update the icons map
1794 if (ir->getIcon()) {
1795 ::setIcon(ir->getId(), ir->getIcon());
1796 emit iconGenerated();
1797 }
1798
1799 if (ir->wasTerminated()) m_iconsTerminationLoop.quit();
1800 }
1801
1802 //-----------------------------------------------------------------------------
1803
onException(TThread::RunnableP iconRenderer)1804 void IconGenerator::onException(TThread::RunnableP iconRenderer) {
1805 IconRenderer *ir = static_cast<IconRenderer *>(iconRenderer.getPointer());
1806
1807 if (ir->wasTerminated()) m_iconsTerminationLoop.quit();
1808 }
1809
1810 //-----------------------------------------------------------------------------
1811
onTerminated(TThread::RunnableP iconRenderer)1812 void IconGenerator::onTerminated(TThread::RunnableP iconRenderer) {
1813 IconRenderer *ir = static_cast<IconRenderer *>(iconRenderer.getPointer());
1814
1815 ir->wasTerminated() = true;
1816 m_iconsTerminationLoop.exec();
1817 }
1818