1 
2 
3 #include "tsystem.h"
4 
5 #include <set>
6 
7 #include "tropcm.h"
8 
9 #include "tcolorstyles.h"
10 #include "tpixelutils.h"
11 #include "ttile.h"
12 #include "tpalette.h"
13 #include "timage_io.h"
14 #include "trasterimage.h"
15 #include "tsimplecolorstyles.h"
16 
17 //#include "tlevel.h"
18 //#include "ttoonzimage.h"
19 //#include "tgeometry.h"
20 //#include "timage_io.h"
21 
22 extern "C" {
23 #include "toonz4.6/raster.h"
24 }
25 
26 #if defined(_WIN32) && defined(x64)
27 #define USE_SSE2
28 #endif
29 
30 #ifdef USE_SSE2
31 #include <emmintrin.h>
32 
33 //---------------------------------------------------------
34 
35 namespace {
36 
37 DV_ALIGNED(16) class TPixelFloat {
38 public:
TPixelFloat()39   TPixelFloat() : b(0), g(0), r(0), m(0) {}
40 
TPixelFloat(float rr,float gg,float bb,float mm)41   TPixelFloat(float rr, float gg, float bb, float mm)
42       : b(bb), g(gg), r(rr), m(mm) {}
43 
TPixelFloat(const TPixel32 & pix)44   TPixelFloat(const TPixel32 &pix) : b(pix.b), g(pix.g), r(pix.r), m(pix.m) {}
45 
46   float b, g, r, m;
47 };
48 
49 }  // anonymous namespace
50 
51 #endif
52 
53 //-----------------------------------------------------------------------------
54 
55 bool renderRas32(const TTile &tileOut, const TTile &tileIn,
56                  const TPaletteP palette);
57 
58 //-----------------------------------------------------------------------------
59 
60 const TPixel32 c_transparencyCheckPaint = TPixel32(80, 80, 80, 255);
61 const TPixel32 c_transparencyCheckInk   = TPixel32::Black;
62 
convert(const TRaster32P & rasOut,const TRasterCM32P & rasIn,const TPaletteP palette,bool transparencyCheck)63 void TRop::convert(const TRaster32P &rasOut, const TRasterCM32P &rasIn,
64                    const TPaletteP palette, bool transparencyCheck) {
65   int count = palette->getStyleCount();
66   int count2 =
67       std::max({count, TPixelCM32::getMaxInk(), TPixelCM32::getMaxPaint()});
68 
69   // per poter utilizzare lo switch (piu' efficiente) si utilizza 255
70   // anziche' TPixelCM32::getMaxTone()
71   assert(TPixelCM32::getMaxTone() == 255);
72 
73   int rasLx = rasOut->getLx();
74   int rasLy = rasOut->getLy();
75 
76   rasOut->lock();
77   rasIn->lock();
78 #ifdef USE_SSE2
79   if (TSystem::getCPUExtensions() & TSystem::CpuSupportsSse2) {
80     __m128i zeros = _mm_setzero_si128();
81     TPixelFloat *paints =
82         (TPixelFloat *)_aligned_malloc(count2 * sizeof(TPixelFloat), 16);
83     TPixelFloat *inks =
84         (TPixelFloat *)_aligned_malloc(count2 * sizeof(TPixelFloat), 16);
85 
86     std::vector<TPixel32> paints2(count2);
87     std::vector<TPixel32> inks2(count2);
88     if (transparencyCheck) {
89       for (int i = 0; i < palette->getStyleCount(); i++) {
90         paints2[i] = c_transparencyCheckPaint;
91         inks2[i]   = c_transparencyCheckInk;
92         paints[i]  = TPixelFloat(paints2[i]);
93         inks[i]    = TPixelFloat(inks2[i]);
94       }
95       paints2[0] = TPixel32::Transparent;
96       paints[0]  = TPixelFloat(TPixel32::Transparent);
97     }
98     /*
99 else if (true)
100 {
101             for(int i=0;i<palette->getStyleCount();i++)
102 {
103 paints2[i] = c_transparencyCheckPaint;
104                     inks2[i]   = c_transparencyCheckInk;
105 paints[i]  = TPixelFloat(paints2[i]);
106                     inks[i]    = TPixelFloat(inks2[i]);
107             paints2[i] = TPixel32::Transparent;
108             paints[i] = TPixelFloat(TPixel32::Transparent);
109 }
110             paints2[0] = TPixel32::Transparent;
111             paints[0] = TPixelFloat(TPixel32::Transparent);
112 }
113 */
114     else
115       for (int i = 0; i < palette->getStyleCount(); i++) {
116         TPixel32 color = ::premultiply(palette->getStyle(i)->getAverageColor());
117         paints[i] = inks[i] = TPixelFloat(color);
118         paints2[i] = inks2[i] = color;
119       }
120 
121     float maxTone     = (float)TPixelCM32::getMaxTone();
122     __m128 den_packed = _mm_load1_ps(&maxTone);
123 
124     for (int y = 0; y < rasLy; ++y) {
125       TPixel32 *pix32   = rasOut->pixels(y);
126       TPixelCM32 *pixIn = rasIn->pixels(y);
127 
128       TPixelCM32 *endPixIn = pixIn + rasLx;
129 
130       while (pixIn < endPixIn) {
131         int tt = pixIn->getTone();
132         int p  = pixIn->getPaint();
133         int i  = pixIn->getInk();
134         switch (tt) {
135         case 255:
136           *pix32++ = paints2[p];
137           break;
138         case 0:
139           *pix32++ = inks2[i];
140           break;
141         default: {
142           float t         = (float)tt;
143           __m128 a_packed = _mm_load_ps((float *)&(inks[i]));
144           __m128 b_packed = _mm_load_ps((float *)&(paints[p]));
145 
146           __m128 num_packed  = _mm_load1_ps(&t);
147           __m128 diff_packed = _mm_sub_ps(den_packed, num_packed);
148 
149           // calcola in modo vettoriale out = ((den-num)*a + num*b)/den
150           __m128 outPix_packed = _mm_mul_ps(diff_packed, a_packed);
151           __m128 tmpPix_packed = _mm_mul_ps(num_packed, b_packed);
152 
153           outPix_packed = _mm_add_ps(outPix_packed, tmpPix_packed);
154           outPix_packed = _mm_div_ps(outPix_packed, den_packed);
155 
156           // converte i canali da float a char
157           __m128i outPix_packed_i = _mm_cvtps_epi32(outPix_packed);
158           outPix_packed_i         = _mm_packs_epi32(outPix_packed_i, zeros);
159           outPix_packed_i         = _mm_packus_epi16(outPix_packed_i, zeros);
160 
161           *(DWORD *)(pix32) = _mm_cvtsi128_si32(outPix_packed_i);
162           ++pix32;
163         }
164         }
165         ++pixIn;
166       }
167     }
168 
169     _aligned_free(paints);
170     _aligned_free(inks);
171 
172   } else  // SSE2 not supported
173 #endif    // _WIN32
174   {
175 
176     std::vector<TPixel32> paints(count2, TPixel32(255, 0, 0));
177     std::vector<TPixel32> inks(count2, TPixel32(255, 0, 0));
178     if (transparencyCheck) {
179       for (int i = 0; i < palette->getStyleCount(); i++) {
180         paints[i] = c_transparencyCheckPaint;
181         inks[i]   = c_transparencyCheckInk;
182       }
183       paints[0] = TPixel32::Transparent;
184     } else
185       for (int i = 0; i < palette->getStyleCount(); i++)
186         paints[i] = inks[i] =
187             ::premultiply(palette->getStyle(i)->getAverageColor());
188 
189     for (int y = 0; y < rasLy; ++y) {
190       TPixel32 *pix32      = rasOut->pixels(y);
191       TPixelCM32 *pixIn    = rasIn->pixels(y);
192       TPixelCM32 *endPixIn = pixIn + rasLx;
193 
194       while (pixIn < endPixIn) {
195         int t = pixIn->getTone();
196         int p = pixIn->getPaint();
197         int i = pixIn->getInk();
198 
199         if (t == TPixelCM32::getMaxTone())
200           *pix32++ = paints[p];
201         else if (t == 0)
202           *pix32++ = inks[i];
203         else
204           *pix32++ = blend(inks[i], paints[p], t, TPixelCM32::getMaxTone());
205 
206         ++pixIn;
207       }
208     }
209   }
210   rasOut->unlock();
211   rasIn->unlock();
212 }
213 
214 //-----------------------------------------------------------------------------------------------
215 
do_convert(const TTile & dst,const TTile & src,const TPaletteP palette,bool transparencyCheck,bool applyFx)216 static void do_convert(const TTile &dst, const TTile &src,
217                        const TPaletteP palette, bool transparencyCheck,
218                        bool applyFx) {
219   // assert(palette);
220   // assert(_rasOut && _rasIn);
221   // assert(rasOut->getSize() == rasIn->getSize());
222 
223   if (applyFx && renderRas32(dst, src, palette)) return;
224 
225   TRaster32P rasOut;
226   TRasterCM32P rasIn;
227 
228   if (dst.getRaster()->getSize() != src.getRaster()->getSize()) {
229     TRect rect = TRect(convert(dst.m_pos), dst.getRaster()->getSize()) *
230                  TRect(convert(src.m_pos), src.getRaster()->getSize());
231     TRect rectOut = rect - convert(dst.m_pos);
232     rasOut        = dst.getRaster()->extract(rectOut);
233     TRect rectIn  = rect - convert(src.m_pos);
234     rasIn         = src.getRaster()->extract(rectIn);
235   } else {
236     rasOut = dst.getRaster();
237     rasIn  = src.getRaster();
238   }
239   TRop::convert(rasOut, rasIn, palette, transparencyCheck);
240 }
241 
242 //-----------------------------------------------------------------------------------------------
243 
convert(const TRaster32P & rasOut,const TRasterCM32P & rasIn,TPaletteP palette,const TRect & theClipRect,bool transparencyCheck,bool applyFx)244 void TRop::convert(
245     const TRaster32P &rasOut, const TRasterCM32P &rasIn, TPaletteP palette,
246     const TRect &theClipRect,  // il rect su cui e' applicata la conversione
247     bool transparencyCheck, bool applyFx) {
248   assert(palette);
249   assert(rasIn && rasOut);
250 
251   TRect clipRect(theClipRect);
252   if (clipRect.isEmpty())
253     clipRect = rasIn->getBounds();
254   else {
255     if (!clipRect.overlaps(rasIn->getBounds())) return;
256     clipRect = clipRect * rasIn->getBounds();
257   }
258   if (clipRect.isEmpty()) return;
259 
260   TRect clipRectIn, clipRectOut;
261 
262   if (applyFx && palette->getFxRects(clipRect, clipRectIn, clipRectOut)) {
263     TRect rAux = clipRectIn;
264     TRasterP rAuxIn =
265         rasIn->extract(clipRectIn);  // la extract modifica clipRectIn
266     if (rAux != clipRectIn && rAux != rasIn->getBounds()) {
267       TRasterCM32P rNew(rAux.getSize());
268       TRect tmpRect = clipRectIn - rAux.getP00();
269       rNew->extract(tmpRect)->copy(rAuxIn);
270       rAuxIn     = rNew;
271       clipRectIn = rAux;
272     }
273 
274     TTile tileIn(rAuxIn, ::convert(clipRectIn.getP00()));
275 
276     rAux = clipRectOut;
277     TRasterP rAuxOut =
278         rasOut->extract(clipRectOut);  // la extract modifica clipRectOut
279     TTile tileOut(rAuxOut, ::convert(clipRectOut.getP00()));
280     TRop::convert(tileOut, tileIn, palette, transparencyCheck, true);
281   } else {
282     TRect clipRectIn  = clipRect;
283     TRect clipRectOut = clipRect;
284     TRasterP _rasOut  = rasOut->extract(clipRectOut);
285     TRasterP _rasIn   = rasIn->extract(clipRectIn);
286 
287     TTile t1(_rasOut, ::convert(clipRectOut.getP00()));
288     TTile t2(_rasIn, ::convert(clipRectIn.getP00()));
289 
290     TRop::convert(t1, t2, palette, transparencyCheck, false);
291   }
292 }
293 
294 //-----------------------------------------------------------------------------
295 
convert(const TTile & dst,const TTile & src,const TPaletteP plt,bool transparencyCheck,bool applyFxs)296 void TRop::convert(const TTile &dst, const TTile &src, const TPaletteP plt,
297                    bool transparencyCheck, bool applyFxs) {
298   // if (dst->getSize() != src->getSize())
299   //  throw TRopException("convert: size mismatch");
300 
301   // assert(plt);
302   if ((TRaster32P)dst.getRaster())
303     do_convert(dst, src, plt, transparencyCheck, applyFxs);
304   else if ((TRaster64P)dst.getRaster()) {
305     TRaster32P aux(dst.getRaster()->getLx(), dst.getRaster()->getLy());
306     TTile taux(aux, dst.m_pos);
307     do_convert(taux, src, plt, transparencyCheck, applyFxs);
308     TRop::convert(dst.getRaster(), aux);
309   } else
310     throw TRopException("unsupported pixel type");
311 }
312 
313 //-----------------------------------------------------------------------------
314 
315 //-----------------------------------------------------------------------------
316 
317 namespace {
318 
putSinglePaintInRaster(TRasterCM32P & rasIn,int paintId,TPixel32 color)319 TRasterP putSinglePaintInRaster(TRasterCM32P &rasIn, int paintId,
320                                 TPixel32 color) {
321   TRaster32P rasOut;
322 
323   for (int y = 0; y < rasIn->getLy(); y++) {
324     TPixelCM32 *pixIn  = rasIn->pixels(y);
325     TPixelCM32 *endPix = pixIn + rasIn->getLx();
326     TPixel32 *pixOut   = 0;
327 
328     if (rasOut) pixOut = rasOut->pixels(y);
329 
330     while (pixIn < endPix) {
331       if (pixIn->getPaint() == paintId) {
332         if (!rasOut) {
333           rasOut = TRaster32P(rasIn->getLx(), rasIn->getLy());
334           rasOut->fill(TPixel32::Transparent);
335           pixOut = rasOut->pixels(y) + (pixIn - rasIn->pixels(y));
336         }
337 
338         if (!pixIn->isPureInk()) *pixOut = color;
339         /*else if (!pixIn->isPureInk())
340   {
341         assert(TPixelCM32::getMaxTone()==0xff);
342         pixOut->m = pixIn->getTone();
343         pixOut->r = 255*color.r/pixOut->m;
344         pixOut->g = 255*color.g/pixOut->m;
345         pixOut->b = 255*color.b/pixOut->m;
346 }*/
347         pixIn->setPaint(0);
348         // pixIn->setTone(0);
349       }
350       pixIn++;
351       pixOut++;
352     }
353   }
354   return rasOut;
355 }
356 
357 /*------------------------------------------------------------------------*/
358 
putSingleInkInRasterGR8(TRasterCM32P & rasIn,int inkId)359 TRasterP putSingleInkInRasterGR8(TRasterCM32P &rasIn, int inkId) {
360   TRasterGR8P rasOut;
361 
362   for (int y = 0; y < rasIn->getLy(); y++) {
363     TPixelCM32 *pixIn  = rasIn->pixels(y);
364     TPixelCM32 *endPix = pixIn + rasIn->getLx();
365     TPixelGR8 *pixOut;
366 
367     if (rasOut) pixOut = rasOut->pixels(y);
368 
369     while (pixIn < endPix) {
370       if (pixIn->getInk() == inkId) {
371         assert(TPixelCM32::getMaxTone() == 0xff);
372         if (!rasOut) {
373           rasOut = TRasterGR8P(rasIn->getLx(), rasIn->getLy());
374           rasOut->fill(0);
375           pixOut = rasOut->pixels(y) + (pixIn - rasIn->pixels(y));
376         }
377 
378         *pixOut = 255 - pixIn->getTone();
379         // pixIn->setInk(0);
380         pixIn->setTone(TPixelCM32::getMaxTone());
381       }
382 
383       pixIn++;
384       pixOut++;
385     }
386   }
387   return rasOut;
388 }
389 
390 /*------------------------------------------------------------------------*/
putSingleInkInRasterRGBM(TRasterCM32P & rasIn,int inkId)391 TRasterP putSingleInkInRasterRGBM(TRasterCM32P &rasIn, int inkId) {
392   TRaster32P rasOut;
393 
394   for (int y = 0; y < rasIn->getLy(); y++) {
395     TPixelCM32 *pixIn  = rasIn->pixels(y);
396     TPixelCM32 *endPix = pixIn + rasIn->getLx();
397     TPixel *pixOut;
398 
399     if (rasOut) pixOut = rasOut->pixels(y);
400 
401     while (pixIn < endPix) {
402       if (pixIn->getInk() == inkId) {
403         assert(TPixelCM32::getMaxTone() == 0xff);
404         if (!rasOut) {
405           rasOut = TRaster32P(rasIn->getLx(), rasIn->getLy());
406           rasOut->fill(TPixel32::Transparent);
407           pixOut = rasOut->pixels(y) + (pixIn - rasIn->pixels(y));
408         }
409 
410         pixOut->r = pixOut->g = pixOut->b = pixOut->m = 255 - pixIn->getTone();
411         // pixIn->setInk(0);
412         pixIn->setTone(TPixelCM32::getMaxTone());
413       }
414       pixIn++;
415       if (rasOut) pixOut++;
416     }
417   }
418   return rasOut;
419 }
420 
421 /*------------------------------------------------------------------------*/
422 /*------------------------------------------------------------------------*/
423 
424 // filename!!
425 // interactive!!
426 
computePaletteFx(const std::vector<std::pair<TColorStyle *,int>> & fx,const TTile & tileOut,const TTile & tileIn,const TPaletteP plt)427 bool computePaletteFx(const std::vector<std::pair<TColorStyle *, int>> &fx,
428                       const TTile &tileOut, const TTile &tileIn,
429                       const TPaletteP plt) {
430   int i;
431   TRasterCM32P rasIn = tileIn.getRaster();
432   TRaster32P rAux32, rasOut = tileOut.getRaster();
433   TRasterGR8P rAuxGR;
434 
435   int frame = plt->getFrame();
436 
437   std::vector<TRasterP> paintLayers(fx.size());
438   std::vector<TRasterP> inkLayers(fx.size());
439 
440   // tolgo dal raster d'ingresso gli ink e i paint con gli effetti, mettendoli
441   // in dei raster layer
442   for (i = 0; i < (int)fx.size(); i++) {
443     TRasterStyleFx *rfx = fx[i].first->getRasterStyleFx();
444 
445     if (rfx->isPaintStyle())
446       paintLayers[i] = putSinglePaintInRaster(rasIn, fx[i].second,
447                                               fx[i].first->getMainColor());
448     if (rfx->isInkStyle()) {
449       if (rfx->inkFxNeedRGBMRaster())
450         inkLayers[i] = putSingleInkInRasterRGBM(rasIn, fx[i].second);
451       else
452         inkLayers[i] = putSingleInkInRasterGR8(rasIn, fx[i].second);
453     }
454   }
455 
456   // raster d'ingresso senza i colori fx, viene renderizzato nel raster d'uscita
457 
458   do_convert(tileOut, tileIn, plt, false, false);
459 
460   // ogni layer viene "effettato".; se il risultato e' non nullo, viene
461   // sovrapposto sul raster d'uscita
462   // prima vengono messi tutti i layer di paint, poi quelli di ink
463 
464   TRect rectOut =
465       TRect(convert(tileOut.m_pos), tileOut.getRaster()->getSize()) -
466       convert(tileIn.m_pos);
467 
468   for (i = 0; i < (int)fx.size(); i++)
469     if (paintLayers[i]) {
470       TRasterStyleFx::Params params(paintLayers[i], convert(tileIn.m_pos),
471                                     rasIn, fx[i].second, frame);
472       if (fx[i].first->getRasterStyleFx()->compute(params))
473         TRop::over(rasOut, paintLayers[i]->extract(rectOut), rasOut);
474     }
475 
476   for (i = 0; i < (int)fx.size(); i++)
477     if (inkLayers[i]) {
478       TRasterStyleFx *rfx = fx[i].first->getRasterStyleFx();
479 
480       TRasterStyleFx::Params params(inkLayers[i], convert(tileIn.m_pos), rasIn,
481                                     fx[i].second, frame);
482       if (rfx->compute(params)) {
483         if (rfx->inkFxNeedRGBMRaster())
484           TRop::over(rasOut, rasOut, inkLayers[i]->extract(rectOut));
485         else
486           TRop::over(rasOut, inkLayers[i]->extract(rectOut),
487                      fx[i].first->getMainColor());
488       }
489     }
490 
491   return true;
492 }
493 
494 /*------------------------------------------------------------------------*/
495 
496 }  // namespace
497 
498 /*------------------------------------------------------------------------*/
499 
renderRas32(const TTile & tileOut,const TTile & tileIn,const TPaletteP palette)500 bool renderRas32(const TTile &tileOut, const TTile &tileIn,
501                  const TPaletteP palette) {
502   assert(TRect(convert(tileIn.m_pos), tileIn.getRaster()->getSize())
503              .contains(TRect(convert(tileOut.m_pos),
504                              tileOut.getRaster()->getSize())));
505   assert((TRasterCM32P)tileIn.getRaster());
506 
507   // Shrink = shrink;
508   // INIT_TCM(rin)
509 
510   /* mark up are made apart */
511   // computeMarkup(rasIn, palette);
512 
513   std::vector<std::pair<TColorStyle *, int>> fxArray;
514 
515   for (int i = 0; i < palette->getStyleCount(); i++)
516     if (palette->getStyle(i)->isRasterStyle())
517       fxArray.push_back(std::pair<TColorStyle *, int>(palette->getStyle(i), i));
518 
519   if (fxArray.empty()) return false;
520 
521   TTile _tileIn(tileIn.getRaster()->clone(), tileIn.m_pos);
522 
523   tileIn.getRaster()->lock();
524   tileOut.getRaster()->lock();
525   computePaletteFx(fxArray, tileOut, _tileIn, palette);
526   tileIn.getRaster()->unlock();
527   tileOut.getRaster()->unlock();
528 
529   return true;
530 }
531 
532 /*------------------------------------------------------------------------*/
533 
534 //--------------------------------------------------------------------------------------------
535 
536 namespace {
537 
addColor(TPaletteP plt,int index,const TPaletteP & upPlt,std::map<int,int> & usedInks)538 void addColor(TPaletteP plt, int index, const TPaletteP &upPlt,
539               std::map<int, int> &usedInks) {
540   TColorStyle *cs = upPlt->getStyle(index);
541   if (cs && cs->getMainColor() == plt->getStyle(index)->getMainColor()) {
542     usedInks[index] = index;
543     return;
544   }
545   int firstStyleId = plt->getFirstUnpagedStyle();
546   if (firstStyleId == -1) firstStyleId = plt->getStyleCount();
547   usedInks[index] = firstStyleId;
548   plt->getPage(0)->addStyle(TPixel32::Red);
549 }
550 
addColor(TPaletteP plt,int index,std::map<int,int> & usedInks)551 void addColor(TPaletteP plt, int index, std::map<int, int> &usedInks) {
552   int firstStyleId = plt->getFirstUnpagedStyle();
553   if (firstStyleId == -1) firstStyleId = plt->getStyleCount();
554   usedInks[index] = firstStyleId;
555   plt->getPage(0)->addStyle(TPixel32::Red);
556 }
557 
558 // Check if the downPlt has the same style (same color, same index) and use it.
559 // If the same style is not found, then add it as a new style.
tryMergeInkOrAddColor(TPaletteP downPlt,const TPaletteP matchPlt,int index,std::map<int,int> & usedInks)560 void tryMergeInkOrAddColor(TPaletteP downPlt, const TPaletteP matchPlt,
561                            int index, std::map<int, int> &usedInks) {
562   if (0 <= index && index < downPlt->getStyleCount() &&
563       index < matchPlt->getStyleCount()) {
564     TSolidColorStyle *solidDownStyle =
565         dynamic_cast<TSolidColorStyle *>(downPlt->getStyle(index));
566     TSolidColorStyle *solidMatchStyle =
567         dynamic_cast<TSolidColorStyle *>(matchPlt->getStyle(index));
568     if (solidDownStyle && solidMatchStyle &&
569         solidDownStyle->getMainColor() == solidMatchStyle->getMainColor()) {
570       usedInks[index] = index;
571       return;
572     }
573   }
574   addColor(downPlt, index, usedInks);
575 }
576 
577 //------------------------------------------------------------
578 // std::map<int,int>& usedInk  upInkId -> downInkId
doMergeCmapped(TRasterCM32P rasOut,const TRasterCM32P & rasUp,const TPaletteP & pltOut,const TPaletteP & matchPlt,bool onlyInks,int matchlinePrevalence,std::map<int,int> & usedInks,bool mergePalette)579 void doMergeCmapped(TRasterCM32P rasOut, const TRasterCM32P &rasUp,
580                     const TPaletteP &pltOut, const TPaletteP &matchPlt,
581                     bool onlyInks, int matchlinePrevalence,
582                     std::map<int, int> &usedInks, bool mergePalette) {
583   double val = matchlinePrevalence / 100.0;  // matchlinePrevalence ==0 always
584                                              // ink down; matchlinePrevalence ==
585                                              // 100 always ink up;
586   assert(rasOut && rasUp);
587   assert(rasOut->getSize() == rasUp->getSize());
588 
589   TPaletteP downPlt = pltOut->clone();
590   std::map<int, int>::iterator it;
591   for (it = usedInks.begin(); it != usedInks.end(); it++)
592     downPlt->getPage(0)->addStyle(TPixel32::Red);
593   for (int y = 0; y < rasOut->getLy(); y++) {
594     TPixelCM32 *pixDown = rasOut->pixels(y),
595                *endPix  = pixDown + rasOut->getLx();
596     TPixelCM32 *pixUp   = rasUp->pixels(y);
597 
598     while (pixDown < endPix) {
599       // there is lines in matchline
600       if (!pixUp->isPurePaint()) {
601         int toneDown = pixDown->getTone();
602         int toneUp   = pixUp->getTone();
603         if (usedInks.find(pixUp->getInk()) == usedInks.end()) {
604           if (mergePalette)
605             tryMergeInkOrAddColor(downPlt, matchPlt, pixUp->getInk(), usedInks);
606           else
607             addColor(downPlt, pixUp->getInk(), usedInks);
608         }
609 
610         if (val == 1) {  // Matchline is on top, with gap
611           pixDown->setTone(toneUp);
612           pixDown->setInk(usedInks[pixUp->getInk()]);
613         } else if (val == 0) {  // Matchline is on bottom, with gap
614           if (pixDown->isPurePaint()) {
615             pixDown->setTone(toneUp);
616             pixDown->setInk(usedInks[pixUp->getInk()]);
617           } else {
618             //*pixOut = *pixDown;
619           }
620         } else {
621           if ((val > 0 && toneUp < toneDown) ||
622               (val == 0 && toneDown == 255))  //(toneUp<toneDown)
623             pixDown->setTone(toneUp);
624 
625           if ((255 - toneDown) * (1 - val) <=
626               val * (255 - toneUp - 1))  // val==0 -> if (toneDown== 255)....
627             // val==0.5 -> if (toneup<toneDown)...
628             // val==1 -> if (toneup<255)...
629             pixDown->setInk(usedInks[pixUp->getInk()]);
630         }
631       }
632       int paintIndex;
633       if (!onlyInks && (paintIndex = pixUp->getPaint()) > 0) {
634         if (usedInks.find(paintIndex) == usedInks.end())
635           addColor(downPlt, paintIndex, usedInks);
636         pixDown->setPaint(usedInks[paintIndex]);
637       }
638       pixUp++;
639       pixDown++;
640       // pixOut++;
641     }
642   }
643 }
644 /*------------------------------------------------------------------------*/
645 
addColors(const TPixelCM32 & color,TPaletteP plt,const TPaletteP & upPlt,std::map<int,int> & usedColors)646 void addColors(const TPixelCM32 &color, TPaletteP plt, const TPaletteP &upPlt,
647                std::map<int, int> &usedColors) {
648   if (usedColors.find(color.getInk()) == usedColors.end())
649     addColor(plt, color.getInk(), upPlt, usedColors);
650   if (usedColors.find(color.getPaint()) == usedColors.end())
651     addColor(plt, color.getPaint(), upPlt, usedColors);
652 }
653 
654 //---------------------------------------------------------------------------
addColors(const TPixelCM32 & color,TPaletteP plt,std::map<int,int> & usedColors)655 void addColors(const TPixelCM32 &color, TPaletteP plt,
656                std::map<int, int> &usedColors) {
657   if (usedColors.find(color.getInk()) == usedColors.end())
658     addColor(plt, color.getInk(), usedColors);
659   if (usedColors.find(color.getPaint()) == usedColors.end())
660     addColor(plt, color.getPaint(), usedColors);
661 }
662 
663 /*------------------------------------------------------------------------*/
664 
doApplyMatchLines(TRasterCM32P rasOut,const TRasterCM32P & rasUp,int inkIndex,int matchlinePrevalence)665 void doApplyMatchLines(TRasterCM32P rasOut, const TRasterCM32P &rasUp,
666                        int inkIndex, int matchlinePrevalence) {
667   double val = matchlinePrevalence / 100.0;  // matchlinePrevalence ==0->always
668                                              // ink down; matchlinePrevalence ==
669                                              // 100 always ink up;
670 
671   assert(rasOut && rasUp);
672   assert(rasOut->getSize() == rasUp->getSize());
673 
674   for (int y = 0; y < rasOut->getLy(); y++) {
675     TPixelCM32 *pixDown = rasOut->pixels(y),
676                *endPix  = pixDown + rasOut->getLx();
677     TPixelCM32 *pixUp   = rasUp->pixels(y);
678 
679     while (pixDown < endPix) {
680       if (!pixUp->isPurePaint()) {
681         int toneDown = pixDown->getTone();
682         int toneUp   = pixUp->getTone();
683         if (val == 1) {  // Matchline is on top, with gap
684           pixDown->setTone(toneUp);
685           pixDown->setInk(inkIndex);
686         } else if (val == 0) {  // Matchline is on bottom, with gap
687           if (pixDown->isPurePaint()) {
688             pixDown->setTone(toneUp);
689             pixDown->setInk(inkIndex);
690           } else {
691           }
692           //*pixOut = *pixDown;
693         }
694         if ((val > 0 && toneUp < toneDown) || (val == 0 && toneDown == 255))
695           pixDown->setTone(toneUp);
696 
697         if ((255 - toneDown) * (1 - val) <=
698             val * (255 - toneUp - 1))  // val==0 -> if (toneDown == 255)....
699           // val==0.5 -> if (toneup<toneDown)...
700           // val==1 -> if (toneup<255)...
701           pixDown->setInk(inkIndex);
702       }
703 
704       pixUp++;
705       pixDown++;
706     }
707   }
708 }
709 /*------------------------------------------------------------------------*/
710 
711 }  // namespace
712 
713 #ifdef LEVO
714 
eraseColors(TRasterCM32P ras,vector<int> & colorIds,bool eraseInks,bool keepColor)715 void TRop::eraseColors(TRasterCM32P ras, vector<int> &colorIds, bool eraseInks,
716                        bool keepColor) {
717   assert(ras);
718 
719   vector<int> curColorIds;
720   std::sort(colorIds.begin(), colorIds.end());
721 
722   if (!keepColor)
723     curColorIds = colorIds;
724   else {
725     // prendo tutti i colori ECCETTO quelli nel vettore colorIds
726     unsigned int count1 = 0, count2 = 0;
727     int size = eraseInks ? TPixelCM32::getMaxInk() : TPixelCM32::getMaxPaint();
728 
729     curColorIds.resize(size + 1 - colorIds.size());
730     for (int i = 0; i < size; i++)
731       if (count1 < colorIds.size() && colorIds[count1] == i)
732         count1++;
733       else
734         curColorIds[count2++] = i;
735   }
736 
737   for (int y = 0; y < ras->getLy(); y++) {
738     TPixelCM32 *pix = ras->pixels(y), *endPix = pix + ras->getLx();
739 
740     while (pix < endPix) {
741       unsigned int i;
742       int color = eraseInks ? pix->getInk() : pix->getPaint();
743 
744       if (color != 0)
745         for (i = 0; i < curColorIds.size() && curColorIds[i] <= color; i++)
746           if (color == curColorIds[i]) {
747             *pix = eraseInks ? TPixelCM32(0, pix->getPaint(),
748                                           TPixelCM32::getMaxTone())
749                              : TPixelCM32(pix->getInk(), 0, pix->getTone());
750             break;
751           }
752       pix++;
753     }
754   }
755 }
756 
757 #endif
758 
759 /*------------------------------------------------------------------------*/
760 namespace {
expandAreaAndFillGaps(TRasterCM32P ras)761 void expandAreaAndFillGaps(TRasterCM32P ras) {
762   // expand neighbor pixels and fill the gaps
763   while (1) {
764     bool found = false;
765     for (int y = 0; y < ras->getLy(); y++) {
766       TPixelCM32 *pix   = ras->pixels(y);
767       TPixelCM32 *upPix = (y == 0) ? ras->pixels(y) : ras->pixels(y - 1);
768       TPixelCM32 *dnPix =
769           (y == ras->getLy() - 1) ? ras->pixels(y) : ras->pixels(y + 1);
770       for (int x = 0; x < ras->getLx(); x++, pix++, upPix++, dnPix++) {
771         // pixels which were filled in the previous loop
772         if (pix->getInk() == TPixelCM32::getMaxInk()) {
773           pix->setInk(0);
774           continue;
775         }
776         // pixels which are non-gap or already finished
777         if (pix->getPaint() != TPixelCM32::getMaxPaint()) continue;
778 
779         int paint = TPixelCM32::getMaxPaint();
780         // check the neibor pixes and take the smallest styleId
781         if (upPix != pix && upPix->getInk() != TPixelCM32::getMaxInk())
782           paint = upPix->getPaint();
783         if (dnPix != pix && dnPix->getInk() != TPixelCM32::getMaxInk())
784           paint = std::min(paint, dnPix->getPaint());
785         if (x != 0 && (pix - 1)->getInk() != TPixelCM32::getMaxInk())
786           paint = std::min(paint, (pix - 1)->getPaint());
787         if (x != ras->getLx() - 1 &&
788             (pix + 1)->getInk() != TPixelCM32::getMaxInk())
789           paint = std::min(paint, (pix + 1)->getPaint());
790 
791         if (paint != TPixelCM32::getMaxPaint()) {
792           pix->setPaint(paint);
793           // use inkId = 4095 as mark of newly-filled pixels
794           // This pixel will be finalized in the next loop
795           pix->setInk(TPixelCM32::getMaxInk());
796         }
797         found = true;
798       }
799     }
800     if (!found) break;
801   }
802 }
803 }  // namespace
804 
eraseColors(TRasterCM32P ras,std::vector<int> * colorIds,bool eraseInks,bool noGap)805 void TRop::eraseColors(TRasterCM32P ras, std::vector<int> *colorIds,
806                        bool eraseInks, bool noGap) {
807   // noGap option is available only when erasing Inks
808   assert(eraseInks || !noGap);
809   if (colorIds) std::sort(colorIds->begin(), colorIds->end());
810 
811   bool hasGapPixel = false;
812 
813   for (int y = 0; y < ras->getLy(); y++) {
814     TPixelCM32 *pix = ras->pixels(y), *endPix = pix + ras->getLx();
815 
816     for (; pix < endPix; pix++) {
817       unsigned int i = 0;
818       int color      = eraseInks ? pix->getInk() : pix->getPaint();
819 
820       if (color == 0) continue;
821 
822       if (colorIds &&
823           !std::binary_search(colorIds->begin(), colorIds->end(), color))
824         continue;
825 
826       if (eraseInks) {
827         // no-gap case.
828         // even if some area is filled under the solid line, delete it and
829         // expand-fill again to make sure the colors will be separated at the
830         // center of the lines.
831         if (noGap && pix->getTone() == 0) {
832           pix->setPaint(
833               TPixelCM32::getMaxPaint());  // use paintId = 4095 as mark of
834                                            // pixels to be filled
835           hasGapPixel = true;
836         }
837         pix->setInk(0);
838         pix->setTone(TPixelCM32::getMaxTone());
839       } else
840         pix->setPaint(0);
841     }
842   }
843 
844   if (hasGapPixel) expandAreaAndFillGaps(ras);
845 }
846 
847 //--------------------------------
848 /*
849 void TRop::overaCmapped(TRasterCM32P rasOut, const TRasterCM32P& rasUp, const
850 TPaletteP &pltOut, int matchlinePrevalence, std::map<int,int>& usedColors)
851 {
852 doMergeCmapped(rasOut, rasUp, pltOut, false, matchlinePrevalence, usedColors);
853 }
854 */
855 //-----------------------------------------------------------------
856 
applyMatchLines(TRasterCM32P rasOut,const TRasterCM32P & rasUp,const TPaletteP & pltOut,const TPaletteP & matchPlt,int inkIndex,int matchlinePrevalence,std::map<int,int> & usedInks)857 void TRop::applyMatchLines(TRasterCM32P rasOut, const TRasterCM32P &rasUp,
858                            const TPaletteP &pltOut, const TPaletteP &matchPlt,
859                            int inkIndex, int matchlinePrevalence,
860                            std::map<int, int> &usedInks) {
861   assert(matchlinePrevalence >= 0);
862   if (inkIndex == -1)
863     doMergeCmapped(rasOut, rasUp, pltOut, matchPlt, true, matchlinePrevalence,
864                    usedInks, false);
865   else if (inkIndex == -2)
866     doMergeCmapped(rasOut, rasUp, pltOut, matchPlt, true, matchlinePrevalence,
867                    usedInks, true);
868   else
869     doApplyMatchLines(rasOut, rasUp, inkIndex, matchlinePrevalence);
870 }
871 
872 /*------------------------------------------------------------------------*/
873 
eraseStyleIds(TToonzImage * image,const std::vector<int> styleIds)874 void TRop::eraseStyleIds(TToonzImage *image, const std::vector<int> styleIds) {
875   assert(image);
876   TRasterCM32P ras = image->getRaster();
877 
878   int i;
879   for (i = 0; i < (int)styleIds.size(); i++) {
880     int styleId = styleIds[i];
881     ras->lock();
882     for (int y = 0; y < ras->getLy(); y++) {
883       TPixelCM32 *pix = ras->pixels(y), *endPix = pix + ras->getLx();
884       while (pix < endPix) {
885         bool isPaint = (pix->getPaint() == styleId);
886         bool isInk   = (pix->getInk() == styleId);
887         if (!isPaint && !isInk) {
888           pix++;
889           continue;
890         } else if (isPaint && !isInk)
891           *pix = TPixelCM32(pix->getInk(), 0, pix->getTone());
892         else if (!isPaint && isInk)
893           *pix = TPixelCM32(0, pix->getPaint(), TPixelCM32::getMaxTone());
894         else if (isPaint && isInk)
895           *pix = TPixelCM32(0, 0, pix->getTone());
896         else
897           assert(0);
898         pix++;
899       }
900     }
901     ras->unlock();
902   }
903 }
904 
905 /*------------------------------------------------------------------------*/
906 
isTransparent(TPixelCM32 * pix)907 inline bool isTransparent(TPixelCM32 *pix) {
908   return (((*((ULONG *)pix)) & 0x000fffff) == 0xff);
909 }
910 
overlayCmapped(TRasterCM32P rasOut,const TRasterCM32P & rasUp,const TPaletteP & pltOut,const TPaletteP & upPlt,std::map<int,int> & usedColors)911 void TRop::overlayCmapped(TRasterCM32P rasOut, const TRasterCM32P &rasUp,
912                           const TPaletteP &pltOut, const TPaletteP &upPlt,
913                           std::map<int, int> &usedColors) {
914   assert(rasOut && rasUp);
915   assert(rasOut->getSize() == rasUp->getSize());
916 
917   TPaletteP downPlt = pltOut->clone();
918   std::map<int, int>::iterator it;
919   for (it = usedColors.begin(); it != usedColors.end(); it++)
920     downPlt->getPage(0)->addStyle(TPixel32::Red);
921 
922   for (int y = 0; y < rasOut->getLy(); y++) {
923     TPixelCM32 *pixDown = rasOut->pixels(y);
924     TPixelCM32 *pixUp   = rasUp->pixels(y);
925 
926     for (int x = 0; x < rasOut->getLx(); x++, pixUp++, pixDown++) {
927       if (isTransparent(pixUp))  // WARNING! cannot check transparent pixels
928                                  // with *pixup==TPixelCM32() since also
929                                  // 0x183000ff i.e., is a valid transparent
930                                  // value
931         continue;
932       int tone = pixUp->getTone();
933       if (isTransparent(pixDown) || tone == 255 || tone == 0 ||
934           pixUp->getPaint() !=
935               0)  // up e' punto interno, o esterno non antialiasato
936       {
937         addColors(*pixUp, downPlt, upPlt, usedColors);
938         pixDown->setInk(usedColors[pixUp->getInk()]);
939         pixDown->setPaint(usedColors[pixUp->getPaint()]);
940         pixDown->setTone(tone);
941       } else if (tone <= pixDown->getTone() || tone < 128)  // up e' bordo
942                                                             // esterno
943                                                             // antialiasato piu'
944                                                             // opaco di down
945       {
946         int ink = pixUp->getInk();
947         if (usedColors.find(ink) == usedColors.end())
948           addColor(downPlt, ink, upPlt, usedColors);
949         pixDown->setInk(usedColors[ink]);
950         pixDown->setTone(tone < 128 ? 0 : tone);
951       }
952     }
953   }
954 }
955 
956 //-----------------------------------------------------
957 
958 namespace {
959 
960 #define MAGICFAC (257U * 256U + 1U)
961 /*
962 #define PIX_CM32_PENMAP_IDX(PIX) ((PIX)>>12 & 0xfff00 | (PIX) & 0xff)
963 #define PIX_CM32_COLMAP_IDX(PIX) ((PIX) & 0xfffff)
964 
965 
966 #define PIX_CM32_PENMAP_COLMAP_TO_RGBM(PIX,PENMAP,COLMAP,RES) \
967   { \
968   ULONG _r = (PIX); \
969   ULONG _s = ((ULONG *)(PENMAP))[MY_PIX_CM32_PENMAP_IDX(_r)] + \
970              ((ULONG *)(COLMAP))[MY_PIX_CM32_COLMAP_IDX(_r)]; \
971   (RES) = *(LPIXEL *)(&_s); \
972   }
973   */
974 
975 /*
976 void fillCmapRamp (RAS_CMAP& cmap, const TPixel32& color, int index)
977 {
978 index = index << cmap.info.tone_bits;
979 int xedni = index + cmap.info.n_tones-1;
980 
981 TPixel32 _color=color;
982         UINT fac = MAGICFAC * _color.m;
983         _color.r=(UINT)(_color.r * fac + (1U<<23))>>24;
984         _color.b=(UINT)(_color.b * fac + (1U<<23))>>24;
985         _color.g=(UINT)(_color.g * fac + (1U<<23))>>24;
986 
987 for (int tone = 0; tone < cmap.info.n_tones; tone++)
988   {
989   LPIXEL val;
990   UINT magic_tone = tone * MAGICFAC;
991   val.r = (UCHAR)((_color.r * magic_tone + (1<<23)) >> 24);
992   val.g = (UCHAR)((_color.g * magic_tone + (1<<23)) >> 24);
993   val.b = (UCHAR)((_color.b * magic_tone + (1<<23)) >> 24);
994   val.m = (UCHAR)((_color.m * magic_tone + (1<<23)) >> 24);
995 
996   cmap.colbuffer[index++] = val;
997   cmap.penbuffer[xedni--] = val;
998   }
999 }
1000 */
1001 
1002 /*---------------------------------------------------------------------------*/
1003 
1004 }  // namespace
1005 
1006 /*---------------------------------------------------------------------------*/
1007 
1008 // \b NOTE: Starting from Toonz 6.1, some important improvements are introduced:
1009 // a) The passed raster is now referenced by the returned _RASTER*, just the
1010 // same way
1011 //    smartpointer to rasters do.
1012 // b) The cache is made aware of the passed raster, mainly because these old 4.6
1013 // raster
1014 //    structures are essentially used for memory-consuming operations with tlv
1015 //    fxs and may
1016 //    need to be shipped to hard disk on critical situations (a matter handled
1017 //    by the cache).
1018 // c) The lockRaster and unlockRaster functions are provided. They are meant to
1019 // specify whether
1020 //    the raster is actively referenced by the raster pointer, or is rather in a
1021 //    lazy state -
1022 //    so that the cache may move it to hard disk if necessary.
1023 
1024 /*
1025 static const TCM_INFO Tcm_my_default_info  = {  8,  8, 12,  20, 12,
1026                                                0x0000, 0x00ff,
1027                                                256, 4096, 256
1028                                              };*/
1029 
1030 /*---------------------------------------------------------------------------*/
1031 
premultiplyLPIXEL(const TPixel32 & pix)1032 inline LPIXEL premultiplyLPIXEL(const TPixel32 &pix) {
1033   // int MAGICFAC = (257U * 256U + 1U);
1034   UINT fac = MAGICFAC * pix.m;
1035   LPIXEL out;
1036   out.r = ((UINT)(pix.r * fac + (1U << 23)) >> 24);
1037   out.g = ((UINT)(pix.g * fac + (1U << 23)) >> 24);
1038   out.b = ((UINT)(pix.b * fac + (1U << 23)) >> 24);
1039   out.m = pix.m;
1040   return out;
1041 }
1042 
convertRaster50to46(const TRasterP & inRas,const TPaletteP & inPalette)1043 _RASTER *TRop::convertRaster50to46(const TRasterP &inRas,
1044                                    const TPaletteP &inPalette) {
1045   int lx   = inRas->getLx();
1046   int ly   = inRas->getLy();
1047   int wrap = inRas->getWrap();
1048 
1049   assert(lx > 0 && ly > 0);
1050   assert(inRas->getRawData());
1051   TRasterGR8P rgr8   = (TRasterGR8P)inRas;
1052   TRasterGR16P rgr16 = (TRasterGR16P)inRas;
1053   TRaster32P r32     = (TRaster32P)inRas;
1054   TRaster64P r64     = (TRaster64P)inRas;
1055   TRasterCM32P rcm   = (TRasterCM32P)inRas;
1056 
1057   RASTER *rout = new RASTER;
1058   memset(rout, 0, sizeof(RASTER));
1059 
1060   std::string id(TImageCache::instance()->getUniqueId());
1061   rout->cacheIdLength = id.size();
1062   rout->cacheId       = new char[rout->cacheIdLength];
1063   memcpy(rout->cacheId, id.data(), sizeof(char) * rout->cacheIdLength);
1064   {
1065     TImageP img;
1066     if (rcm)
1067       img = TToonzImageP(rcm, rcm->getBounds());  // saveBox is not considered
1068                                                   // in RASTER struct anyway
1069     else
1070       img = TRasterImageP(inRas);
1071     TImageCache::instance()->add(id, img);
1072   }
1073   inRas->addRef();
1074 
1075   rout->buffer        = inRas->getRawData();
1076   TRasterP parent     = inRas->getParent();
1077   rout->native_buffer = (parent) ? parent->getRawData() : inRas->getRawData();
1078   rout->lx            = lx;
1079   rout->ly            = ly;
1080   rout->wrap          = wrap;
1081 
1082   if (rgr8)
1083     rout->type = RAS_GR8;
1084   else if (rgr16)
1085     rout->type = RAS_GR16;
1086   else if (r32)
1087     rout->type = RAS_RGBM;
1088   else if (r64)
1089     rout->type = RAS_RGBM64;
1090   else if (rcm)
1091     rout->type = RAS_CM32;
1092   else
1093     assert(!"raster type not convertible!");
1094 
1095   if (rout->type != RAS_CM32) return rout;
1096 
1097   if (!inPalette) {
1098     assert(!"missing palette!");
1099     return NULL;
1100   }
1101 
1102   rout->cmap.info   = Tcm_32_default_info;
1103   rout->cmap.buffer = new LPIXEL[TCM_CMAP_PENBUFFER_SIZE(rout->cmap.info)];
1104   // rout->cmap.penbuffer = new LPIXEL[TCM_CMAP_PENBUFFER_SIZE
1105   // (rout->cmap.info)];
1106   // rout->cmap.colbuffer = new LPIXEL[TCM_CMAP_COLBUFFER_SIZE
1107   // (rout->cmap.info)];
1108 
1109   for (int i = 0; i < inPalette->getStyleCount(); i++)
1110     rout->cmap.buffer[i] =
1111         ::premultiplyLPIXEL(inPalette->getStyle(i)->getAverageColor());
1112   // fillCmapRamp (rout->cmap, inPalette->getStyle(i)->getMainColor(), i);
1113 
1114   return rout;
1115 }
1116 
1117 /*------------------------------------------------------------------------*/
1118 
releaseRaster46(_RASTER * & r,bool doReleaseBuffer)1119 void TRop::releaseRaster46(_RASTER *&r, bool doReleaseBuffer) {
1120   // Buffer release no more supported. These are now intended as smart
1121   // pointers to rasters - they release themselves on their own.
1122   assert(!doReleaseBuffer);
1123 
1124   if (r->type == RAS_CM32) {
1125     delete[] r->cmap.buffer;
1126     // delete [] r->cmap.penbuffer;
1127     // delete [] r->cmap.colbuffer;
1128   }
1129 
1130   if (doReleaseBuffer && r->native_buffer == r->buffer)
1131     delete r->buffer;  // Should not happen
1132 
1133   // Unlock if locked, and remove the cache reference
1134   if (r->buffer) unlockRaster(r);
1135   TImageCache::instance()->remove(std::string(r->cacheId, r->cacheIdLength));
1136   delete[] r->cacheId;
1137 
1138   delete r;
1139   r = 0;
1140 }
1141 
1142 /*------------------------------------------------------------------------*/
1143 
lockRaster(RASTER * raster)1144 void TRop::lockRaster(RASTER *raster) {
1145   TImageP img(TImageCache::instance()->get(
1146       std::string(raster->cacheId, raster->cacheIdLength), true));
1147   TRasterP cacheRas;
1148   if (raster->type == RAS_CM32)
1149     cacheRas = TToonzImageP(img)->getRaster();
1150   else
1151     cacheRas = TRasterImageP(img)->getRaster();
1152   cacheRas->addRef();
1153   raster->buffer  = cacheRas->getRawData();
1154   TRasterP parent = cacheRas->getParent();
1155   raster->native_buffer =
1156       (parent) ? parent->getRawData() : cacheRas->getRawData();
1157 }
1158 
1159 /*------------------------------------------------------------------------*/
1160 
unlockRaster(RASTER * raster)1161 void TRop::unlockRaster(RASTER *raster) {
1162   TImageP img(TImageCache::instance()->get(
1163       std::string(raster->cacheId, raster->cacheIdLength), true));
1164   TRasterP cacheRas;
1165   if (raster->type == RAS_CM32)
1166     cacheRas = TToonzImageP(img)->getRaster();
1167   else
1168     cacheRas = TRasterImageP(img)->getRaster();
1169   cacheRas->release();
1170   raster->buffer        = 0;
1171   raster->native_buffer = 0;
1172 }
1173 
1174 /*------------------------------------------------------------------------*/
1175 
readRaster46(const char * filename)1176 _RASTER *TRop::readRaster46(const char *filename) {
1177   // No more called in Toonz...
1178 
1179   TImageP img;
1180 
1181   TImageReader::load(TFilePath(filename), img);
1182 
1183   if ((TToonzImageP)img) return 0;
1184 
1185   TRasterImageP rimg = (TRasterImageP)img;
1186 
1187   if (!rimg) return 0;
1188   TRasterP ras = rimg->getRaster();
1189 
1190   return TRop::convertRaster50to46(ras, 0);
1191 }
1192 
1193 namespace {
1194 
getPix32(const TPixelCM32 & pixcm,const std::vector<TPixel32> & colors)1195 inline TPixel32 getPix32(const TPixelCM32 &pixcm,
1196                          const std::vector<TPixel32> &colors) {
1197   int t = pixcm.getTone();
1198   int p = pixcm.getPaint();
1199   int i = pixcm.getInk();
1200 
1201   if (t == TPixelCM32::getMaxTone())
1202     return colors[p];
1203   else if (t == 0)
1204     return colors[i];
1205   else
1206     return blend(colors[i], colors[p], t, TPixelCM32::getMaxTone());
1207 }
1208 
1209 }  // namespace
1210 
1211 // from 4.6
1212 
1213 #ifdef LEVO
1214 
zoomOutCm32Rgbm(const TRasterCM32P & rin,TRaster32P & rout,const TPalette & plt,int x1,int y1,int x2,int y2,int newx,int newy,int absZoomLevel)1215 void TRop::zoomOutCm32Rgbm(const TRasterCM32P &rin, TRaster32P &rout,
1216                            const TPalette &plt, int x1, int y1, int x2, int y2,
1217                            int newx, int newy, int absZoomLevel) {
1218   TPixelCM32 *rowin, *pixin, *in, win;
1219   TPixel32 *rowout, *pixout, valin, valout;
1220   int tmp_r, tmp_g, tmp_b, tmp_m;
1221   int wrapin, wrapout;
1222   int x, y, lx, ly, xlast, ylast, xrest, yrest, i, j;
1223   int factor, fac_fac_2_bits;
1224   int fac_fac, yrest_fac, fac_xrest, yrest_xrest;
1225   int fac_fac_2, yrest_fac_2, fac_xrest_2, yrest_xrest_2;
1226   int fac_fac_4;
1227 
1228   int count = plt.getStyleCount();
1229   int count2 =
1230       std::max(count, TPixelCM32::getMaxInk(), TPixelCM32::getMaxPaint());
1231   std::vector<TPixel32> colors(count2);
1232   for (i = 0; i < plt.getStyleCount(); i++)
1233     colors[i] = ::premultiply(plt.getStyle(i)->getAverageColor());
1234 
1235   lx             = x2 - x1 + 1;
1236   ly             = y2 - y1 + 1;
1237   factor         = 1 << absZoomLevel;
1238   xrest          = lx & (factor - 1);
1239   yrest          = ly & (factor - 1);
1240   xlast          = x2 - xrest + 1;
1241   ylast          = y2 - yrest + 1;
1242   fac_fac        = factor * factor;
1243   fac_fac_2      = fac_fac >> 1;
1244   fac_fac_4      = fac_fac >> 2;
1245   fac_fac_2_bits = 2 * absZoomLevel - 1;
1246   yrest_fac      = yrest * factor;
1247   yrest_fac_2    = yrest_fac >> 1;
1248   fac_xrest      = factor * xrest;
1249   fac_xrest_2    = fac_xrest >> 1;
1250   yrest_xrest    = yrest * xrest;
1251   yrest_xrest_2  = yrest_xrest >> 1;
1252   wrapin         = rin->getWrap();
1253   wrapout        = rout->getWrap();
1254   valout.m       = 0xff;
1255 
1256   rowin  = (TPixelCM32 *)rin->getRawData() + wrapin * y1 + x1;
1257   rowout = (TPixel32 *)rout->getRawData() + wrapout * newy + newx;
1258   for (y = y1; y < ylast; y += factor) {
1259     pixin  = rowin;
1260     pixout = rowout;
1261     for (x = x1; x < xlast; x += factor) {
1262       tmp_r = tmp_g = tmp_b = tmp_m = 0;
1263       in                            = pixin;
1264       for (j = 0; j < factor; j += 2) {
1265         for (i = 0; i < factor; i += 2) {
1266           win   = *in;
1267           valin = getPix32(win, colors);
1268           tmp_r += valin.r;
1269           tmp_g += valin.g;
1270           tmp_b += valin.b;
1271           tmp_m += valin.m;
1272           in += wrapin;
1273           in++;
1274           win   = *in;
1275           valin = getPix32(win, colors);
1276           tmp_r += valin.r;
1277           tmp_g += valin.g;
1278           tmp_b += valin.b;
1279           tmp_m += valin.m;
1280           in -= wrapin;
1281           in++;
1282         }
1283         in += 2 * wrapin - factor;
1284       }
1285       valout.r  = (tmp_r + fac_fac_4) >> fac_fac_2_bits;
1286       valout.g  = (tmp_g + fac_fac_4) >> fac_fac_2_bits;
1287       valout.b  = (tmp_b + fac_fac_4) >> fac_fac_2_bits;
1288       valout.m  = (tmp_m + fac_fac_4) >> fac_fac_2_bits;
1289       *pixout++ = valout;
1290       pixin += factor;
1291     }
1292     if (xrest) {
1293       tmp_r = tmp_g = tmp_b = tmp_m = 0;
1294       for (j = 0; j < factor; j++)
1295         for (i = 0; i < xrest; i++) {
1296           win   = pixin[i + j * wrapin];
1297           valin = getPix32(win, colors);
1298           tmp_r += valin.r;
1299           tmp_g += valin.g;
1300           tmp_b += valin.b;
1301           tmp_m += valin.m;
1302         }
1303       valout.r = (tmp_r + fac_xrest_2) / fac_xrest;
1304       valout.g = (tmp_g + fac_xrest_2) / fac_xrest;
1305       valout.b = (tmp_b + fac_xrest_2) / fac_xrest;
1306       valout.m = (tmp_m + fac_xrest_2) / fac_xrest;
1307       *pixout  = valout;
1308     }
1309     rowin += wrapin * factor;
1310     rowout += wrapout;
1311   }
1312   if (yrest) {
1313     pixin  = rowin;
1314     pixout = rowout;
1315     for (x = x1; x < xlast; x += factor) {
1316       tmp_r = tmp_g = tmp_b = tmp_m = 0;
1317       for (j = 0; j < yrest; j++)
1318         for (i = 0; i < factor; i++) {
1319           win   = pixin[i + j * wrapin];
1320           valin = getPix32(win, colors);
1321           tmp_r += valin.r;
1322           tmp_g += valin.g;
1323           tmp_b += valin.b;
1324           tmp_m += valin.m;
1325         }
1326       valout.r  = (tmp_r + yrest_fac_2) / yrest_fac;
1327       valout.g  = (tmp_g + yrest_fac_2) / yrest_fac;
1328       valout.b  = (tmp_b + yrest_fac_2) / yrest_fac;
1329       valout.m  = (tmp_m + yrest_fac_2) / yrest_fac;
1330       *pixout++ = valout;
1331       pixin += factor;
1332     }
1333     if (xrest) {
1334       tmp_r = tmp_g = tmp_b = tmp_m = 0;
1335       for (j = 0; j < yrest; j++)
1336         for (i = 0; i < xrest; i++) {
1337           win   = pixin[i + j * wrapin];
1338           valin = getPix32(win, colors);
1339           tmp_r += valin.r;
1340           tmp_g += valin.g;
1341           tmp_b += valin.b;
1342           tmp_m += valin.m;
1343         }
1344       valout.r = (tmp_r + yrest_xrest_2) / yrest_xrest;
1345       valout.g = (tmp_g + yrest_xrest_2) / yrest_xrest;
1346       valout.b = (tmp_b + yrest_xrest_2) / yrest_xrest;
1347       valout.m = (tmp_m + yrest_xrest_2) / yrest_xrest;
1348       *pixout  = valout;
1349     }
1350   }
1351 }
1352 
1353 #endif
1354 
1355 /*-----------------------------------------------------------------------------*/
1356 
1357 #ifdef LEVO
1358 
makeIcon(TRaster32P & _rout,const TRasterCM32P & rin,const TPaletteP & palette,bool onBlackBg)1359 void TRop::makeIcon(TRaster32P &_rout, const TRasterCM32P &rin,
1360                     const TPaletteP &palette, bool onBlackBg) {
1361   int i, j;
1362   int lx = rin->getLx();
1363   int ly = rin->getLy();
1364 
1365   int count = palette->getStyleCount();
1366   int count2 =
1367       std::max(count, TPixelCM32::getMaxInk(), TPixelCM32::getMaxPaint());
1368   std::vector<TPixel32> colors(count2);
1369   for (i = 0; i < palette->getStyleCount(); i++)
1370     colors[i] =
1371         /*::premultiply(*/ palette->getStyle(i)->getAverageColor();  //);
1372 
1373   TDimension dim(_rout->getSize());
1374   TRaster32P rout;
1375 
1376   double arIn  = (double)lx / ly;
1377   double arOut = (double)dim.lx / dim.ly;
1378   if (!areAlmostEqual(arIn, arOut, 1e-2))  // do not want a stretched icon! I
1379                                            // extract a subraster with same
1380                                            // aspect ration of rin
1381   {
1382     int newlx, newly;
1383     if (arOut < arIn) {
1384       newlx = dim.lx;
1385       newly = dim.lx / arIn;
1386     } else {
1387       newly = dim.ly;
1388       newlx = dim.ly * arIn;
1389     }
1390     _rout->clear();
1391     rout = _rout->extract((dim.lx - newlx) / 2, (dim.ly - newly) / 2,
1392                           (dim.lx - newlx) / 2 + newlx - 1,
1393                           (dim.ly - newly) / 2 + newly - 1);
1394     dim  = rout->getSize();
1395   } else
1396     rout = _rout;
1397 
1398   TPixel32 *pixOut0 = (TPixel32 *)rout->getRawData();
1399 
1400   int countY   = 0;
1401   bool newRow  = true;
1402   int currTone = TPixelCM32::getMaxTone();
1403 
1404   for (i = 0; i < ly; i++) {
1405     TPixelCM32 *pixIn = (TPixelCM32 *)rin->pixels(i);
1406     TPixel32 *pixOut  = pixOut0;
1407     int countX        = 0;
1408     for (j = 0; j < lx; j++) {
1409       if (newRow || currTone > pixIn->getTone()) {
1410         currTone = pixIn->getTone();
1411         if (onBlackBg)
1412           *pixOut = overPixOnBlack(getPix32(*pixIn, colors));
1413         else
1414           *pixOut = overPixOnWhite(getPix32(*pixIn, colors));
1415       }
1416       pixIn++;
1417       countX += dim.lx;
1418       if (countX >= lx)
1419         countX -= lx, pixOut++, currTone = TPixelCM32::getMaxTone();
1420     }
1421 
1422     countY += dim.ly;
1423     if (countY >= ly) {
1424       countY -= ly;
1425       pixOut0 += rout->getWrap();
1426       currTone = TPixelCM32::getMaxTone();
1427       newRow   = true;
1428     } else
1429       newRow = false;
1430   }
1431 }
1432 
1433 #endif
1434 
1435 /*-----------------------------------------------------------------------------*/
1436 
makeIcon(TRasterCM32P & _rout,const TRasterCM32P & rin)1437 void TRop::makeIcon(TRasterCM32P &_rout, const TRasterCM32P &rin) {
1438   int i, j;
1439   int lx = rin->getLx();
1440   int ly = rin->getLy();
1441 
1442   TDimension dim(_rout->getSize());
1443   TRasterCM32P rout;
1444 
1445   rout = _rout;
1446 
1447   rout->lock();
1448   rin->lock();
1449   TPixelCM32 *pixOut0 = (TPixelCM32 *)rout->getRawData();
1450 
1451   int countY  = 0;
1452   bool newRow = true;
1453 
1454   for (i = 0; i < ly; i++) {
1455     TPixelCM32 *pixIn  = (TPixelCM32 *)rin->pixels(i);
1456     TPixelCM32 *pixOut = pixOut0;
1457     int countX         = 0;
1458     bool newColumn     = true;
1459     for (j = 0; j < lx; j++) {
1460       if ((newRow && newColumn) || pixOut->getTone() > pixIn->getTone())
1461         *pixOut = *pixIn;
1462 
1463       pixIn++;
1464       countX += dim.lx;
1465       if (countX >= lx) {
1466         countX -= lx, pixOut++;
1467         newColumn = true;
1468       } else
1469         newColumn = false;
1470     }
1471 
1472     countY += dim.ly;
1473     if (countY >= ly) {
1474       countY -= ly;
1475       pixOut0 += rout->getWrap();
1476       newRow = true;
1477     } else
1478       newRow = false;
1479   }
1480   rout->unlock();
1481   rin->unlock();
1482 }
1483 
1484 /*-----------------------------------------------------------------------------*/
1485