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