1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * This file is part of openfx-supportext <https://github.com/devernay/openfx-supportext>,
4  * Copyright (C) 2013-2018 INRIA
5  *
6  * openfx-supportext is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * openfx-supportext is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with openfx-supportext.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>
18  * ***** END LICENSE BLOCK ***** */
19 
20 //
21 //  ofxsCopier.h
22 //
23 
24 #ifndef IO_ofxsCopier_h
25 #define IO_ofxsCopier_h
26 
27 #include <cstring>
28 #include <algorithm>
29 
30 #include "ofxsPixelProcessor.h"
31 #include "ofxsMaskMix.h"
32 
33 namespace OFX {
34 // Base class for the RGBA and the Alpha processor
35 
36 template <class PIX, int nComponents>
37 class PixelCopier
38     : public OFX::PixelProcessorFilterBase
39 {
40 public:
41     // ctor
PixelCopier(OFX::ImageEffect & instance)42     PixelCopier(OFX::ImageEffect &instance)
43         : OFX::PixelProcessorFilterBase(instance)
44     {
45     }
46 
47     // and do some processing
multiThreadProcessImages(OfxRectI procWindow)48     void multiThreadProcessImages(OfxRectI procWindow)
49     {
50         assert(_dstBounds.x1 <= procWindow.x1 && procWindow.x2 <= _dstBounds.x2 && _dstBounds.y1 <= procWindow.y1 && procWindow.y2 <= _dstBounds.y2);
51         // for more safety, make sure procWindow is within dstBounds (as covered by the above assert)
52         if (_dstBounds.x1 > procWindow.x1) {
53             procWindow.x1 = _dstBounds.x1;
54         }
55         if (_dstBounds.x2 < procWindow.x2) {
56             procWindow.x2 = _dstBounds.x2;
57         }
58         if (_dstBounds.y1 > procWindow.y1) {
59             procWindow.y1 = _dstBounds.y1;
60         }
61         if (_dstBounds.y2 < procWindow.y2) {
62             procWindow.y2 = _dstBounds.y2;
63         }
64 
65         int rowBytes = sizeof(PIX) * nComponents * (procWindow.x2 - procWindow.x1);
66 
67         for (int dsty = procWindow.y1; dsty < procWindow.y2; ++dsty) {
68             if ( _effect.abort() ) {
69                 break;
70             }
71 
72             PIX *dstPix = (PIX *) getDstPixelAddress(procWindow.x1, dsty);
73             assert(dstPix);
74             if (!dstPix) {
75                 // coverity[dead_error_line]
76                 continue;
77             }
78 
79             int srcy = dsty;
80 
81             if (_srcBoundary == 1) {
82                 if (_srcBounds.y2 <= srcy) {
83                     srcy = _srcBounds.y2 - 1;
84                 }
85                 if (srcy < _srcBounds.y1) {
86                     srcy = _srcBounds.y1;
87                 }
88             } else if (_srcBoundary == 2) {
89                 if ( (srcy < _srcBounds.y1) || (_srcBounds.y2 <= srcy) ) {
90                     srcy = _srcBounds.y1 + positive_modulo(srcy - _srcBounds.y1, _srcBounds.y2 - _srcBounds.y1);
91                 }
92             }
93 
94             if ( (srcy < _srcBounds.y1) || (_srcBounds.y2 <= srcy) || (_srcBounds.y2 <= _srcBounds.y1) ) {
95                 assert(_srcBoundary == 0);
96                 std::memset(dstPix, 0, rowBytes);
97             } else {
98                 int x1 = (std::max)(_srcBounds.x1, procWindow.x1);
99                 int x2 = (std::min)(_srcBounds.x2, procWindow.x2);
100                 // start of line may be black
101                 if (procWindow.x1 < x1) {
102                     if ( (_srcBoundary != 1) && (_srcBoundary != 2) ) {
103                         std::memset( dstPix, 0, sizeof(PIX) * nComponents * (x1 - procWindow.x1) );
104                         dstPix += nComponents * (x1 - procWindow.x1);
105                     } else if (_srcBoundary == 1) {
106                         const PIX *srcPix = (const PIX *) getSrcPixelAddress(x1, srcy);
107                         assert(srcPix);
108                         if (!srcPix) {
109                             std::memset( dstPix, 0, sizeof(PIX) * nComponents * (x1 - procWindow.x1) );
110                             dstPix += nComponents * (x1 - procWindow.x1);
111                         } else {
112 #                        ifdef DEBUG
113                             for (int c = 0; c < nComponents; ++c) {
114                                 assert( !OFX::IsNaN(srcPix[c]) ); // check for NaN
115                             }
116 #                        endif
117                             for (int x = procWindow.x1; x < x1; ++x) {
118                                 std::copy(srcPix, srcPix + nComponents, dstPix);
119                                 dstPix += nComponents;
120                             }
121                         }
122                     } else if (_srcBoundary == 2) {
123                         int srcx = procWindow.x1;
124                         if ( (srcx < _srcBounds.x1) || (_srcBounds.x2 <= srcx) ) {
125                             srcx = _srcBounds.x1 + positive_modulo(srcx - _srcBounds.x1, _srcBounds.x2 - _srcBounds.x1);
126                         }
127 
128                         const PIX *srcPix = (const PIX *) getSrcPixelAddress(srcx, srcy);
129                         assert(srcPix);
130                         if (!srcPix) {
131                             std::memset( dstPix, 0, sizeof(PIX) * nComponents * (x1 - procWindow.x1) );
132                             dstPix += nComponents * (x1 - procWindow.x1);
133                         } else {
134                             for (int x = procWindow.x1; x < x1; ++x) {
135 #                             ifdef DEBUG
136                                 for (int c = 0; c < nComponents; ++c) {
137                                     assert( !OFX::IsNaN(srcPix[c]) ); // check for NaN
138                                 }
139 #                             endif
140                                 std::copy(srcPix, srcPix + nComponents, dstPix);
141                                 dstPix += nComponents;
142                                 ++srcx;
143                                 if (_srcBounds.x2 <= srcx) {
144                                     srcx -= (_srcBounds.x2 - _srcBounds.x1);
145                                     srcPix -= (_srcBounds.x2 - _srcBounds.x1) * nComponents;
146                                 }
147                             }
148                         }
149                     }
150                 }
151                 // then, copy the relevant fraction of src
152                 if ( (x1 < x2) && (procWindow.x1 <= x1) && (x2 <= procWindow.x2) ) {
153                     const PIX *srcPix = (const PIX *) getSrcPixelAddress(x1, srcy);
154                     assert(srcPix);
155                     if (!srcPix) {
156                         std::memset( dstPix, 0, sizeof(PIX) * nComponents * (x2 - x1) );
157                     } else {
158 #                     ifdef DEBUG
159                         for (int c = 0; c < nComponents * (x2 - x1); ++c) {
160                             assert( !OFX::IsNaN(srcPix[c]) ); // check for NaN
161                         }
162 #                     endif
163                         std::memcpy( dstPix, srcPix, sizeof(PIX) * nComponents * (x2 - x1) );
164                     }
165                     dstPix += nComponents * (x2 - x1);
166                 }
167                 // end of line may be black
168                 if (x2 < procWindow.x2) {
169                     if ( (_srcBoundary != 1) && (_srcBoundary != 2) ) {
170                         std::memset( dstPix, 0, sizeof(PIX) * nComponents * (procWindow.x2 - x2) );
171                         dstPix += nComponents * (procWindow.x2 - x2);
172                     } else if (_srcBoundary == 1) {
173                         const PIX *srcPix = (const PIX *) getSrcPixelAddress(x2 - 1, srcy);
174                         assert(srcPix);
175                         if (!srcPix) {
176                             std::memset( dstPix, 0, sizeof(PIX) * nComponents * (procWindow.x2 - x2) );
177                         } else {
178                             for (int x = x2; x < procWindow.x2; ++x) {
179                                 std::memcpy( dstPix, srcPix, sizeof(PIX) * nComponents );
180                                 dstPix += nComponents;
181                             }
182                         }
183                     } else if (_srcBoundary == 2) {
184                         int srcx = x2;
185                         while (_srcBounds.x2 <= srcx) {
186                             srcx -= (_srcBounds.x2 - _srcBounds.x1);
187                         }
188 
189                         const PIX *srcPix = (const PIX *) getSrcPixelAddress(srcx, srcy);
190                         assert(srcPix);
191                         if (!srcPix) {
192                             std::memset( dstPix, 0, sizeof(PIX) * nComponents * (procWindow.x2 - x2) );
193                             dstPix += nComponents * (procWindow.x2 - x2);
194                         } else {
195                             for (int x = x2; x < procWindow.x2; ++x) {
196 #                             ifdef DEBUG
197                                 for (int c = 0; c < nComponents; ++c) {
198                                     assert( !OFX::IsNaN(srcPix[c]) ); // check for NaN
199                                 }
200 #                             endif
201                                 std::copy(srcPix, srcPix + nComponents, dstPix);
202                                 dstPix += nComponents;
203                                 ++srcx;
204                                 if (_srcBounds.x2 <= srcx) {
205                                     srcx -= (_srcBounds.x2 - _srcBounds.x1);
206                                     srcPix -= (_srcBounds.x2 - _srcBounds.x1) * nComponents;
207                                 }
208                             }
209                         }
210                     }
211                 }
212             }
213         }
214     } // multiThreadProcessImages
215 };
216 
217 /*
218  * @brief Same as PixelCopier except that the alpha channel is set to maxValue instead of being copied
219  */
220 template <class PIX, int nComponents, int maxValue>
221 class PixelCopierOpaque
222     : public OFX::PixelProcessorFilterBase
223 {
224 public:
225     // ctor
PixelCopierOpaque(OFX::ImageEffect & instance)226     PixelCopierOpaque(OFX::ImageEffect &instance)
227         : OFX::PixelProcessorFilterBase(instance)
228     {
229     }
230 
231     // and do some processing
multiThreadProcessImages(OfxRectI procWindow)232     void multiThreadProcessImages(OfxRectI procWindow)
233     {
234         assert(_dstBounds.x1 <= procWindow.x1 && procWindow.x2 <= _dstBounds.x2 && _dstBounds.y1 <= procWindow.y1 && procWindow.y2 <= _dstBounds.y2);
235         // for more safety, make sure procWindow is within dstBounds (as covered by the above assert)
236         if (_dstBounds.x1 > procWindow.x1) {
237             procWindow.x1 = _dstBounds.x1;
238         }
239         if (_dstBounds.x2 < procWindow.x2) {
240             procWindow.x2 = _dstBounds.x2;
241         }
242         if (_dstBounds.y1 > procWindow.y1) {
243             procWindow.y1 = _dstBounds.y1;
244         }
245         if (_dstBounds.y2 < procWindow.y2) {
246             procWindow.y2 = _dstBounds.y2;
247         }
248         assert(nComponents == 4 || nComponents == 1);
249         for (int dsty = procWindow.y1; dsty < procWindow.y2; ++dsty) {
250             if ( _effect.abort() ) {
251                 break;
252             }
253 
254             int srcy = dsty;
255 
256             if (_srcBoundary == 1) {
257                 if (_srcBounds.y2 <= srcy) {
258                     srcy = _srcBounds.y2 - 1;
259                 }
260                 if (srcy < _srcBounds.y1) {
261                     srcy = _srcBounds.y1;
262                 }
263             } else if (_srcBoundary == 2) {
264                 if ( (srcy < _srcBounds.y1) || (_srcBounds.y2 <= srcy) ) {
265                     srcy = _srcBounds.y1 + positive_modulo(srcy - _srcBounds.y1, _srcBounds.y2 - _srcBounds.y1);
266                 }
267             }
268 
269             PIX *dstPix = (PIX *) getDstPixelAddress(procWindow.x1, dsty);
270             assert(dstPix);
271             if (!dstPix) {
272                 // coverity[dead_error_line]
273                 continue;
274             }
275 
276             for (int dstx = procWindow.x1; dstx < procWindow.x2; ++dstx) {
277                 int srcx = dstx;
278 
279                 if (_srcBoundary == 1) {
280                     if (_srcBounds.x2 <= srcx) {
281                         srcx = _srcBounds.x2 - 1;
282                     }
283                     if (srcx < _srcBounds.x1) {
284                         srcx = _srcBounds.x1;
285                     }
286                 } else if (_srcBoundary == 2) {
287                     if ( (srcx < _srcBounds.x1) || (_srcBounds.x2 <= srcx) ) {
288                         srcx = _srcBounds.x1 + positive_modulo(srcx - _srcBounds.x1, _srcBounds.x2 - _srcBounds.x1);
289                     }
290                 }
291 
292                 // origPix is at dstx,dsty
293                 const PIX *srcPix = (const PIX *) getSrcPixelAddress(srcx, srcy);
294                 if (srcPix) {
295                     std::copy(srcPix, srcPix + nComponents - 1, dstPix);
296                     dstPix[nComponents - 1] = maxValue;
297                 } else {
298                   std::fill( dstPix, dstPix + nComponents, PIX() ); // no src pixel here, be black and transparent
299                 }
300                 // increment the dst pixel
301                 dstPix += nComponents;
302             }
303         }
304     } // multiThreadProcessImages
305 };
306 
307 
308 template <class PIX, int nComponents, int maxValue, bool masked>
309 class PixelCopierMaskMix
310     : public OFX::PixelProcessorFilterBase
311 {
312 public:
313     // ctor
PixelCopierMaskMix(OFX::ImageEffect & instance)314     PixelCopierMaskMix(OFX::ImageEffect &instance)
315         : OFX::PixelProcessorFilterBase(instance)
316     {
317     }
318 
319     // and do some processing
multiThreadProcessImages(OfxRectI procWindow)320     void multiThreadProcessImages(OfxRectI procWindow)
321     {
322         assert(_dstBounds.x1 <= procWindow.x1 && procWindow.x2 <= _dstBounds.x2 && _dstBounds.y1 <= procWindow.y1 && procWindow.y2 <= _dstBounds.y2);
323         // for more safety, make sure procWindow is within dstBounds (as covered by the above assert)
324         if (_dstBounds.x1 > procWindow.x1) {
325             procWindow.x1 = _dstBounds.x1;
326         }
327         if (_dstBounds.x2 < procWindow.x2) {
328             procWindow.x2 = _dstBounds.x2;
329         }
330         if (_dstBounds.y1 > procWindow.y1) {
331             procWindow.y1 = _dstBounds.y1;
332         }
333         if (_dstBounds.y2 < procWindow.y2) {
334             procWindow.y2 = _dstBounds.y2;
335         }
336         float tmpPix[nComponents];
337 
338         for (int dsty = procWindow.y1; dsty < procWindow.y2; ++dsty) {
339             if ( _effect.abort() ) {
340                 break;
341             }
342 
343             int srcy = dsty;
344 
345             if (_srcBoundary == 1) {
346                 if (_srcBounds.y2 <= srcy) {
347                     srcy = _srcBounds.y2 - 1;
348                 }
349                 if (srcy < _srcBounds.y1) {
350                     srcy = _srcBounds.y1;
351                 }
352             } else if (_srcBoundary == 2) {
353                 if ( (srcy < _srcBounds.y1) || (_srcBounds.y2 <= srcy) ) {
354                     srcy = _srcBounds.y1 + positive_modulo(srcy - _srcBounds.y1, _srcBounds.y2 - _srcBounds.y1);
355                 }
356             }
357 
358             PIX *dstPix = (PIX *) getDstPixelAddress(procWindow.x1, dsty);
359             assert(dstPix);
360             if (!dstPix) {
361                 // coverity[dead_error_line]
362                 continue;
363             }
364 
365             for (int dstx = procWindow.x1; dstx < procWindow.x2; ++dstx) {
366                 int srcx = dstx;
367 
368                 if (_srcBoundary == 1) {
369                     if (_srcBounds.x2 <= srcx) {
370                         srcx = _srcBounds.x2 - 1;
371                     }
372                     if (srcx < _srcBounds.x1) {
373                         srcx = _srcBounds.x1;
374                     }
375                 } else if (_srcBoundary == 2) {
376                     if ( (srcx < _srcBounds.x1) || (_srcBounds.x2 <= srcx) ) {
377                         srcx = _srcBounds.x1 + positive_modulo(srcx - _srcBounds.x1, _srcBounds.x2 - _srcBounds.x1);
378                     }
379                 }
380 
381                 // origPix is at dstx,dsty
382                 const PIX *origPix = (const PIX *)  (_origImg ? _origImg->getPixelAddress(dstx, dsty) : 0);
383                 const PIX *srcPix = (const PIX *) getSrcPixelAddress(srcx, srcy);
384                 if (srcPix) {
385                     std::copy(srcPix, srcPix + nComponents, tmpPix);
386                 } else {
387                     std::fill(tmpPix, tmpPix + nComponents, 0.f); // no src pixel here, be black and transparent
388                 }
389                 // dstx,dsty are the mask image coordinates (no boundary conditions)
390                 ofxsMaskMixPix<PIX, nComponents, maxValue, masked>(tmpPix, dstx, dsty, origPix, _doMasking, _maskImg, (float)_mix, _maskInvert, dstPix);
391                 // increment the dst pixel
392                 dstPix += nComponents;
393             }
394         }
395     } // multiThreadProcessImages
396 };
397 
398 template <class SRCPIX, int srcNComponents, int srcMaxValue, class DSTPIX, int dstNComponents, int dstMaxValue>
399 class PixelCopierUnPremult
400     : public OFX::PixelProcessorFilterBase
401 {
402 public:
403     // ctor
PixelCopierUnPremult(OFX::ImageEffect & instance)404     PixelCopierUnPremult(OFX::ImageEffect &instance)
405         : OFX::PixelProcessorFilterBase(instance)
406     {
407         assert( (srcNComponents == 3 || srcNComponents == 4) && (dstNComponents == 3 || dstNComponents == 4) );
408     }
409 
410     // and do some processing
multiThreadProcessImages(OfxRectI procWindow)411     void multiThreadProcessImages(OfxRectI procWindow)
412     {
413         assert(_dstBounds.x1 <= procWindow.x1 && procWindow.x2 <= _dstBounds.x2 && _dstBounds.y1 <= procWindow.y1 && procWindow.y2 <= _dstBounds.y2);
414         // for more safety, make sure procWindow is within dstBounds (as covered by the above assert)
415         if (_dstBounds.x1 > procWindow.x1) {
416             procWindow.x1 = _dstBounds.x1;
417         }
418         if (_dstBounds.x2 < procWindow.x2) {
419             procWindow.x2 = _dstBounds.x2;
420         }
421         if (_dstBounds.y1 > procWindow.y1) {
422             procWindow.y1 = _dstBounds.y1;
423         }
424         if (_dstBounds.y2 < procWindow.y2) {
425             procWindow.y2 = _dstBounds.y2;
426         }
427         float unpPix[4];
428 
429         for (int dsty = procWindow.y1; dsty < procWindow.y2; ++dsty) {
430             if ( _effect.abort() ) {
431                 break;
432             }
433 
434             int srcy = dsty;
435 
436             if (_srcBoundary == 1) {
437                 if (_srcBounds.y2 <= srcy) {
438                     srcy = _srcBounds.y2 - 1;
439                 }
440                 if (srcy < _srcBounds.y1) {
441                     srcy = _srcBounds.y1;
442                 }
443             } else if (_srcBoundary == 2) {
444                 if ( (srcy < _srcBounds.y1) || (_srcBounds.y2 <= srcy) ) {
445                     srcy = _srcBounds.y1 + positive_modulo(srcy - _srcBounds.y1, _srcBounds.y2 - _srcBounds.y1);
446                 }
447             }
448 
449             DSTPIX *dstPix = (DSTPIX *) getDstPixelAddress(procWindow.x1, dsty);
450             assert(dstPix);
451             if (!dstPix) {
452                 // coverity[dead_error_line]
453                 continue;
454             }
455 
456             for (int dstx = procWindow.x1; dstx < procWindow.x2; ++dstx) {
457                 int srcx = dstx;
458 
459                 if (_srcBoundary == 1) {
460                     if (_srcBounds.x2 <= srcx) {
461                         srcx = _srcBounds.x2 - 1;
462                     }
463                     if (srcx < _srcBounds.x1) {
464                         srcx = _srcBounds.x1;
465                     }
466                 } else if (_srcBoundary == 2) {
467                     if ( (srcx < _srcBounds.x1) || (_srcBounds.x2 <= srcx) ) {
468                         srcx = _srcBounds.x1 + positive_modulo(srcx - _srcBounds.x1, _srcBounds.x2 - _srcBounds.x1);
469                     }
470                 }
471 
472                 const SRCPIX *srcPix = (const SRCPIX *) getSrcPixelAddress(srcx, srcy);
473                 ofxsUnPremult<SRCPIX, srcNComponents, srcMaxValue>(srcPix, unpPix, _premult, _premultChannel);
474                 for (int c = 0; c < dstNComponents; ++c) {
475                     float v = unpPix[c] * dstMaxValue;
476                     dstPix[c] = ofxsClampIfInt<DSTPIX, dstMaxValue>(v, 0, dstMaxValue);
477                 }
478                 // increment the dst pixel
479                 dstPix += dstNComponents;
480             }
481         }
482     } // multiThreadProcessImages
483 };
484 
485 template <class SRCPIX, int srcNComponents, int srcMaxValue, class DSTPIX, int dstNComponents, int dstMaxValue>
486 class PixelCopierPremult
487     : public OFX::PixelProcessorFilterBase
488 {
489 public:
490     // ctor
PixelCopierPremult(OFX::ImageEffect & instance)491     PixelCopierPremult(OFX::ImageEffect &instance)
492         : OFX::PixelProcessorFilterBase(instance)
493     {
494         assert(srcMaxValue);
495         assert( (srcNComponents == 3 || srcNComponents == 4) && (dstNComponents == 3 || dstNComponents == 4) );
496     }
497 
498     // and do some processing
multiThreadProcessImages(OfxRectI procWindow)499     void multiThreadProcessImages(OfxRectI procWindow)
500     {
501         assert(_dstBounds.x1 <= procWindow.x1 && procWindow.x2 <= _dstBounds.x2 && _dstBounds.y1 <= procWindow.y1 && procWindow.y2 <= _dstBounds.y2);
502         // for more safety, make sure procWindow is within dstBounds (as covered by the above assert)
503         if (_dstBounds.x1 > procWindow.x1) {
504             procWindow.x1 = _dstBounds.x1;
505         }
506         if (_dstBounds.x2 < procWindow.x2) {
507             procWindow.x2 = _dstBounds.x2;
508         }
509         if (_dstBounds.y1 > procWindow.y1) {
510             procWindow.y1 = _dstBounds.y1;
511         }
512         if (_dstBounds.y2 < procWindow.y2) {
513             procWindow.y2 = _dstBounds.y2;
514         }
515         for (int dsty = procWindow.y1; dsty < procWindow.y2; ++dsty) {
516             if ( _effect.abort() ) {
517                 break;
518             }
519 
520             int srcy = dsty;
521 
522             if (_srcBoundary == 1) {
523                 if (_srcBounds.y2 <= srcy) {
524                     srcy = _srcBounds.y2 - 1;
525                 }
526                 if (srcy < _srcBounds.y1) {
527                     srcy = _srcBounds.y1;
528                 }
529             } else if (_srcBoundary == 2) {
530                 if ( (srcy < _srcBounds.y1) || (_srcBounds.y2 <= srcy) ) {
531                     srcy = _srcBounds.y1 + positive_modulo(srcy - _srcBounds.y1, _srcBounds.y2 - _srcBounds.y1);
532                 }
533             }
534 
535             DSTPIX *dstPix = (DSTPIX *) getDstPixelAddress(procWindow.x1, dsty);
536             assert(dstPix);
537             if (!dstPix) {
538                 // coverity[dead_error_line]
539                 continue;
540             }
541 
542             for (int dstx = procWindow.x1; dstx < procWindow.x2; ++dstx) {
543                 int srcx = dstx;
544 
545                 if (_srcBoundary == 1) {
546                     if (_srcBounds.x2 <= srcx) {
547                         srcx = _srcBounds.x2 - 1;
548                     }
549                     if (srcx < _srcBounds.x1) {
550                         srcx = _srcBounds.x1;
551                     }
552                 } else if (_srcBoundary == 2) {
553                     if ( (srcx < _srcBounds.x1) || (_srcBounds.x2 <= srcx) ) {
554                         srcx = _srcBounds.x1 + positive_modulo(srcx - _srcBounds.x1, _srcBounds.x2 - _srcBounds.x1);
555                     }
556                 }
557 
558                 const SRCPIX *srcPix = (const SRCPIX *) getSrcPixelAddress(srcx, srcy);
559                 if (!srcPix) {
560                     // no source, be black and transparent
561                     for (int c = 0; c < dstNComponents; ++c) {
562                         dstPix[c] = DSTPIX();
563                     }
564                 } else {
565                     float unpPix[4];
566                     if (srcNComponents == 1) {
567                         unpPix[0] = 0.f;
568                         unpPix[1] = 0.f;
569                         unpPix[2] = 0.f;
570                         unpPix[3] = srcPix[0] * (1.f / srcMaxValue);
571                     } else {
572                         unpPix[0] = srcPix[0] * (1.f / srcMaxValue);
573                         unpPix[1] = srcPix[1] * (1.f / srcMaxValue);
574                         unpPix[2] = srcPix[2] * (1.f / srcMaxValue);
575                         unpPix[3] = (srcNComponents == 4) ? (srcPix[3] * (1.f / srcMaxValue)) : 1.0f;
576                     }
577                     float pPix[dstNComponents];
578                     // unpPix is in [0, 1]
579                     // premultiply and denormalize in [0, maxValue]
580                     // if premult is false, just denormalize
581                     ofxsPremult<DSTPIX, dstNComponents, dstMaxValue>(unpPix, pPix, _premult, _premultChannel);
582                     for (int c = 0; c < dstNComponents; ++c) {
583                         dstPix[c] = ofxsClampIfInt<DSTPIX, dstMaxValue>(pPix[c], 0, dstMaxValue);
584                     }
585                 }
586                 // increment the dst pixel
587                 dstPix += dstNComponents;
588             }
589         }
590     } // multiThreadProcessImages
591 };
592 
593 // _srcBoundarys The border condition type { 0=zero |  1=dirichlet | 2=periodic }.
594 // template to do the RGBA processing
595 template <class SRCPIX, int srcNComponents, int srcMaxValue, class DSTPIX, int dstNComponents, int dstMaxValue>
596 class PixelCopierPremultMaskMix
597     : public OFX::PixelProcessorFilterBase
598 {
599 public:
600     // ctor
PixelCopierPremultMaskMix(OFX::ImageEffect & instance)601     PixelCopierPremultMaskMix(OFX::ImageEffect &instance)
602         : OFX::PixelProcessorFilterBase(instance)
603     {
604         assert( (srcNComponents == 3 || srcNComponents == 4) && (dstNComponents == 3 || dstNComponents == 4) );
605     }
606 
607     // and do some processing
multiThreadProcessImages(OfxRectI procWindow)608     void multiThreadProcessImages(OfxRectI procWindow)
609     {
610         assert(_dstBounds.x1 <= procWindow.x1 && procWindow.x2 <= _dstBounds.x2 && _dstBounds.y1 <= procWindow.y1 && procWindow.y2 <= _dstBounds.y2);
611         // for more safety, make sure procWindow is within dstBounds (as covered by the above assert)
612         if (_dstBounds.x1 > procWindow.x1) {
613             procWindow.x1 = _dstBounds.x1;
614         }
615         if (_dstBounds.x2 < procWindow.x2) {
616             procWindow.x2 = _dstBounds.x2;
617         }
618         if (_dstBounds.y1 > procWindow.y1) {
619             procWindow.y1 = _dstBounds.y1;
620         }
621         if (_dstBounds.y2 < procWindow.y2) {
622             procWindow.y2 = _dstBounds.y2;
623         }
624         float unpPix[4];
625 
626         if (srcNComponents == 3) {
627             unpPix[3] = 1.f;
628         }
629         for (int dsty = procWindow.y1; dsty < procWindow.y2; ++dsty) {
630             if ( _effect.abort() ) {
631                 break;
632             }
633 
634             int srcy = dsty;
635 
636             if (_srcBoundary == 1) {
637                 if (_srcBounds.y2 <= srcy) {
638                     srcy = _srcBounds.y2 - 1;
639                 }
640                 if (srcy < _srcBounds.y1) {
641                     srcy = _srcBounds.y1;
642                 }
643             } else if (_srcBoundary == 2) {
644                 if ( (srcy < _srcBounds.y1) || (_srcBounds.y2 <= srcy) ) {
645                     srcy = _srcBounds.y1 + positive_modulo(srcy - _srcBounds.y1, _srcBounds.y2 - _srcBounds.y1);
646                 }
647             }
648 
649             DSTPIX *dstPix = (DSTPIX *) getDstPixelAddress(procWindow.x1, dsty);
650             assert(dstPix);
651             if (!dstPix) {
652                 // coverity[dead_error_line]
653                 continue;
654             }
655 
656             for (int dstx = procWindow.x1; dstx < procWindow.x2; ++dstx) {
657                 int srcx = dstx;
658 
659                 if (_srcBoundary == 1) {
660                     if (_srcBounds.x2 <= srcx) {
661                         srcx = _srcBounds.x2 - 1;
662                     }
663                     if (srcx < _srcBounds.x1) {
664                         srcx = _srcBounds.x1;
665                     }
666                 } else if (_srcBoundary == 2) {
667                     if ( (srcx < _srcBounds.x1) || (_srcBounds.x2 <= srcx) ) {
668                         srcx = _srcBounds.x1 + positive_modulo(srcx - _srcBounds.x1, _srcBounds.x2 - _srcBounds.x1);
669                     }
670                 }
671                 // origPix is at dstx,dsty
672                 const DSTPIX *origPix = (const DSTPIX *)  (_origImg ? _origImg->getPixelAddress(dstx, dsty) : 0);
673                 const SRCPIX *srcPix = (const SRCPIX *) getSrcPixelAddress(srcx, srcy);
674                 for (int c = 0; c < srcNComponents; ++c) {
675                     unpPix[c] = (srcPix ? (srcPix[c] * (1.f / srcMaxValue)) : 0.f);
676                 }
677                 // dstx,dsty are the mask image coordinates (no boundary conditions)
678                 ofxsPremultMaskMixPix<DSTPIX, dstNComponents, dstMaxValue, true>(unpPix, _premult, _premultChannel, dstx, dsty, origPix, _doMasking, _maskImg, (float)_mix, _maskInvert, dstPix);
679                 // increment the dst pixel
680                 dstPix += dstNComponents;
681             }
682         }
683     } // multiThreadProcessImages
684 };
685 
686 template <class PIX>
687 class BlackFiller
688     : public OFX::PixelProcessorFilterBase
689 {
690 public:
691     // ctor
BlackFiller(OFX::ImageEffect & instance,int comps)692     BlackFiller(OFX::ImageEffect &instance,
693                 int comps)
694         : OFX::PixelProcessorFilterBase(instance)
695         , _nComponents(comps)
696     {
697     }
698 
699     // and do some processing
multiThreadProcessImages(OfxRectI procWindow)700     void multiThreadProcessImages(OfxRectI procWindow)
701     {
702         assert(_dstBounds.x1 <= procWindow.x1 && procWindow.x2 <= _dstBounds.x2 && _dstBounds.y1 <= procWindow.y1 && procWindow.y2 <= _dstBounds.y2);
703         // for more safety, make sure procWindow is within dstBounds (as covered by the above assert)
704         if (_dstBounds.x1 > procWindow.x1) {
705             procWindow.x1 = _dstBounds.x1;
706         }
707         if (_dstBounds.x2 < procWindow.x2) {
708             procWindow.x2 = _dstBounds.x2;
709         }
710         if (_dstBounds.y1 > procWindow.y1) {
711             procWindow.y1 = _dstBounds.y1;
712         }
713         if (_dstBounds.y2 < procWindow.y2) {
714             procWindow.y2 = _dstBounds.y2;
715         }
716         int rowSize =  _nComponents * (procWindow.x2 - procWindow.x1);
717 
718         for (int y = procWindow.y1; y < procWindow.y2; ++y) {
719             if ( _effect.abort() ) {
720                 break;
721             }
722 
723             PIX *dstPix = (PIX *) getDstPixelAddress(procWindow.x1, y);
724             assert(dstPix);
725             if (!dstPix) {
726                 // coverity[dead_error_line]
727                 continue;
728             }
729             std::fill( dstPix, dstPix + rowSize, PIX() );
730         }
731     }
732 
733 private:
734     int _nComponents;
735 };
736 
737 // black fillers, non-threaded versions
738 template<class PIX>
739 void
fillBlackNTForDepth(const OfxRectI & renderWindow,void * dstPixelData,const OfxRectI & dstBounds,int dstPixelComponentCount,int dstRowBytes)740 fillBlackNTForDepth(const OfxRectI & renderWindow,
741                     void *dstPixelData,
742                     const OfxRectI & dstBounds,
743                     int dstPixelComponentCount,
744                     int dstRowBytes)
745 {
746     assert(dstPixelData);
747     // do the rendering
748     int dstRowElements = dstRowBytes / sizeof(PIX);
749     int x1 = (std::max)(renderWindow.x1, dstBounds.x1);
750     int x2 = (std::min)(renderWindow.x2, dstBounds.x2);
751     int y1 = (std::max)(renderWindow.y1, dstBounds.y1);
752     int y2 = (std::min)(renderWindow.y2, dstBounds.y2);
753     PIX* dstPixels = (PIX*)dstPixelData + (size_t)(y1 - dstBounds.y1) * dstRowElements + (x1 - dstBounds.x1) * dstPixelComponentCount;
754     int rowElements = dstPixelComponentCount * (x2 - renderWindow.x1);
755 
756     for (int y = y1; y < y2; ++y, dstPixels += dstRowElements) {
757         std::fill( dstPixels, dstPixels + rowElements, PIX() ); // no src pixel here, be black and transparent
758     }
759 }
760 
761 inline void
fillBlackNT(const OfxRectI & renderWindow,void * dstPixelData,const OfxRectI & dstBounds,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)762 fillBlackNT(const OfxRectI & renderWindow,
763             void *dstPixelData,
764             const OfxRectI & dstBounds,
765             int dstPixelComponentCount,
766             OFX::BitDepthEnum dstBitDepth,
767             int dstRowBytes)
768 {
769     assert(dstPixelData);
770     if (!dstPixelData) {
771         // coverity[dead_error_line]
772         return;
773     }
774     // do the rendering
775     if ( (dstBitDepth != OFX::eBitDepthUByte) && (dstBitDepth != OFX::eBitDepthUShort) && (dstBitDepth != OFX::eBitDepthHalf) && (dstBitDepth != OFX::eBitDepthFloat) ) {
776         OFX::throwSuiteStatusException(kOfxStatErrFormat);
777 
778         return;
779     }
780     if (dstBitDepth == OFX::eBitDepthUByte) {
781         fillBlackNTForDepth<unsigned char>(renderWindow,
782                                            dstPixelData, dstBounds, dstPixelComponentCount, dstRowBytes);
783     } else if ( (dstBitDepth == OFX::eBitDepthUShort) || (dstBitDepth == OFX::eBitDepthHalf) ) {
784         fillBlackNTForDepth<unsigned short>(renderWindow,
785                                             dstPixelData, dstBounds, dstPixelComponentCount, dstRowBytes);
786     } else if (dstBitDepth == OFX::eBitDepthFloat) {
787         fillBlackNTForDepth<float>(renderWindow,
788                                    dstPixelData, dstBounds, dstPixelComponentCount, dstRowBytes);
789     } // switch
790 }
791 
792 inline void
fillBlackNT(const OfxRectI & renderWindow,OFX::Image * dstImg)793 fillBlackNT(const OfxRectI & renderWindow,
794             OFX::Image* dstImg)
795 {
796     void* dstPixelData;
797     OfxRectI dstBounds;
798     OFX::PixelComponentEnum dstPixelComponents;
799     OFX::BitDepthEnum dstBitDepth;
800     int dstRowBytes;
801 
802     assert(dstImg);
803     if (!dstImg) {
804         // coverity[dead_error_line]
805         return;
806     }
807     getImageData(dstImg, &dstPixelData, &dstBounds, &dstPixelComponents, &dstBitDepth, &dstRowBytes);
808     int dstPixelComponentCount = dstImg->getPixelComponentCount();
809 
810     return fillBlackNT(renderWindow, dstPixelData, dstBounds, dstPixelComponentCount, dstBitDepth, dstRowBytes);
811 }
812 
813 #if 0 // Don't use threaded version: very probably less efficient
814 
815 // black fillers, threaded versions
816 template<class PIX, int nComponents>
817 void
818 fillBlackForDepthAndComponents(OFX::ImageEffect &instance,
819                                const OfxRectI & renderWindow,
820                                PIX *dstPixelData,
821                                const OfxRectI & dstBounds,
822                                OFX::PixelComponentEnum dstPixelComponents,
823                                int dstPixelComponentCount,
824                                OFX::BitDepthEnum dstBitDepth,
825                                int dstRowBytes)
826 {
827     (void)dstPixelComponents;
828     (void)dstBitDepth;
829 
830     OFX::BlackFiller<PIX> processor(instance, nComponents);
831     // set the images
832     processor.setDstImg(dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
833 
834     // set the render window
835     processor.setRenderWindow(renderWindow);
836 
837     // Call the base class process member, this will call the derived templated process code
838     processor.process();
839 }
840 
841 template<class PIX>
842 void
843 fillBlackForDepth(OFX::ImageEffect &instance,
844                   const OfxRectI & renderWindow,
845                   void *dstPixelData,
846                   const OfxRectI & dstBounds,
847                   OFX::PixelComponentEnum dstPixelComponents,
848                   int dstPixelComponentCount,
849                   OFX::BitDepthEnum dstBitDepth,
850                   int dstRowBytes)
851 {
852     assert(dstPixelData);
853     if (!dstPixelData) {
854         // coverity[dead_error_line]
855         return;
856     }
857     // do the rendering
858     if ( (dstPixelComponentCount < 0) || (4 < dstPixelComponentCount) ) {
859         OFX::throwSuiteStatusException(kOfxStatErrFormat);
860 
861         return;
862     }
863     if (dstPixelComponentCount == 4) {
864         fillBlackForDepthAndComponents<PIX, 4>(instance, renderWindow,
865                                                (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
866     } else if (dstPixelComponentCount == 3) {
867         fillBlackForDepthAndComponents<PIX, 3>(instance, renderWindow,
868                                                (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
869     } else if (dstPixelComponentCount == 2) {
870         fillBlackForDepthAndComponents<PIX, 2>(instance, renderWindow,
871                                                (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
872     }  else if (dstPixelComponentCount == 1) {
873         fillBlackForDepthAndComponents<PIX, 1>(instance, renderWindow,
874                                                (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
875     } // switch
876 }
877 
878 inline void
879 fillBlack(OFX::ImageEffect &instance,
880           const OfxRectI & renderWindow,
881           void *dstPixelData,
882           const OfxRectI & dstBounds,
883           OFX::PixelComponentEnum dstPixelComponents,
884           int dstPixelComponentCount,
885           OFX::BitDepthEnum dstBitDepth,
886           int dstRowBytes)
887 {
888     assert(dstPixelData);
889     if (!dstPixelData) {
890         // coverity[dead_error_line]
891         return;
892     }
893     // do the rendering
894     if ( (dstBitDepth != OFX::eBitDepthUByte) && (dstBitDepth != OFX::eBitDepthUShort) && (dstBitDepth != OFX::eBitDepthHalf) && (dstBitDepth != OFX::eBitDepthFloat) ) {
895         OFX::throwSuiteStatusException(kOfxStatErrFormat);
896 
897         return;
898     }
899     if (dstBitDepth == OFX::eBitDepthUByte) {
900         fillBlackForDepth<unsigned char>(instance, renderWindow,
901                                          dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
902     } else if ( (dstBitDepth == OFX::eBitDepthUShort) || (dstBitDepth == OFX::eBitDepthHalf) ) {
903         fillBlackForDepth<unsigned short>(instance, renderWindow,
904                                           dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
905     } else if (dstBitDepth == OFX::eBitDepthFloat) {
906         fillBlackForDepth<float>(instance, renderWindow,
907                                  dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
908     } // switch
909 }
910 
911 inline void
912 fillBlack(OFX::ImageEffect &instance,
913           const OfxRectI & renderWindow,
914           OFX::Image* dstImg)
915 {
916     void* dstPixelData;
917     OfxRectI dstBounds;
918     OFX::PixelComponentEnum dstPixelComponents;
919     OFX::BitDepthEnum dstBitDepth;
920     int dstRowBytes;
921 
922     assert(dstImg);
923     if (!dstImg) {
924         // coverity[dead_error_line]
925         return;
926     }
927     getImageData(dstImg, &dstPixelData, &dstBounds, &dstPixelComponents, &dstBitDepth, &dstRowBytes);
928     int dstPixelComponentCount = dstImg->getPixelComponentCount();
929 
930     return fillBlack(instance, renderWindow, dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
931 }
932 
933 #else // if 0
934 
935 // Use non-threaded version: probably more efficient
936 
937 inline void
fillBlack(OFX::ImageEffect & instance,const OfxRectI & renderWindow,void * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)938 fillBlack(OFX::ImageEffect &instance,
939           const OfxRectI & renderWindow,
940           void *dstPixelData,
941           const OfxRectI & dstBounds,
942           OFX::PixelComponentEnum dstPixelComponents,
943           int dstPixelComponentCount,
944           OFX::BitDepthEnum dstBitDepth,
945           int dstRowBytes)
946 {
947     (void)instance;
948     (void)dstPixelComponents;
949 
950     return fillBlackNT(renderWindow, dstPixelData, dstBounds, dstPixelComponentCount, dstBitDepth, dstRowBytes);
951 }
952 
953 inline void
fillBlack(OFX::ImageEffect & instance,const OfxRectI & renderWindow,OFX::Image * dstImg)954 fillBlack(OFX::ImageEffect &instance,
955           const OfxRectI & renderWindow,
956           OFX::Image* dstImg)
957 {
958     (void)instance;
959 
960     return fillBlackNT(renderWindow, dstImg);
961 }
962 
963 #endif // if 0
964 
965 // pixel copiers, non-threaded versions
966 template<class PIX, int nComponents>
967 void
copyPixelsNTForDepthAndComponents(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const PIX * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,PIX * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)968 copyPixelsNTForDepthAndComponents(OFX::ImageEffect &instance,
969                                   const OfxRectI & renderWindow,
970                                   const PIX *srcPixelData,
971                                   const OfxRectI & srcBounds,
972                                   OFX::PixelComponentEnum srcPixelComponents,
973                                   int srcPixelComponentCount,
974                                   OFX::BitDepthEnum srcBitDepth,
975                                   int srcRowBytes,
976                                   PIX *dstPixelData,
977                                   const OfxRectI & dstBounds,
978                                   OFX::PixelComponentEnum dstPixelComponents,
979                                   int dstPixelComponentCount,
980                                   OFX::BitDepthEnum dstBitDepth,
981                                   int dstRowBytes)
982 {
983     assert(srcBitDepth == dstBitDepth);
984     assert(srcPixelComponentCount == dstPixelComponentCount);
985     assert(srcPixelComponentCount == nComponents);
986     (void)srcPixelComponents;
987     (void)srcPixelComponentCount;
988     (void)srcBitDepth;
989     (void)dstPixelComponents;
990     (void)dstPixelComponentCount;
991     (void)dstBitDepth;
992     (void)instance;
993 
994     unsigned int srcRowElements = srcRowBytes / sizeof(PIX);
995     assert(srcBounds.y1 <= renderWindow.y1 && renderWindow.y1 <= renderWindow.y2 && renderWindow.y2 <= srcBounds.y2);
996     assert(srcBounds.x1 <= renderWindow.x1 && renderWindow.x1 <= renderWindow.x2 && renderWindow.x2 <= srcBounds.x2);
997     int x1 = (std::max)( renderWindow.x1, (std::max)(dstBounds.x1, srcBounds.x1) );
998     int x2 = (std::min)( renderWindow.x2, (std::min)(dstBounds.x2, srcBounds.x2) );
999     int y1 = (std::max)( renderWindow.y1, (std::max)(dstBounds.y1, srcBounds.y1) );
1000     int y2 = (std::min)( renderWindow.y2, (std::min)(dstBounds.y2, srcBounds.y2) );
1001     const PIX* srcPixels = srcPixelData + (size_t)(y1 - srcBounds.y1) * srcRowElements + (x1 - srcBounds.x1) * nComponents;
1002     unsigned int dstRowElements = dstRowBytes / sizeof(PIX);
1003     PIX* dstPixels = dstPixelData + (size_t)(y1 - dstBounds.y1) * dstRowElements + (x1 - dstBounds.x1) * nComponents;
1004     unsigned int rowBytes = sizeof(PIX) * nComponents * (x2 - x1);
1005 
1006     for (int y = y1; y < y2; ++y, srcPixels += srcRowElements, dstPixels += dstRowElements) {
1007         std::memcpy(dstPixels, srcPixels, rowBytes);
1008     }
1009 }
1010 
1011 template<class PIX>
1012 void
copyPixelsNTForDepth(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const void * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,void * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)1013 copyPixelsNTForDepth(OFX::ImageEffect &instance,
1014                      const OfxRectI & renderWindow,
1015                      const void *srcPixelData,
1016                      const OfxRectI & srcBounds,
1017                      OFX::PixelComponentEnum srcPixelComponents,
1018                      int srcPixelComponentCount,
1019                      OFX::BitDepthEnum srcBitDepth,
1020                      int srcRowBytes,
1021                      void *dstPixelData,
1022                      const OfxRectI & dstBounds,
1023                      OFX::PixelComponentEnum dstPixelComponents,
1024                      int dstPixelComponentCount,
1025                      OFX::BitDepthEnum dstBitDepth,
1026                      int dstRowBytes)
1027 {
1028     assert(srcPixelData && dstPixelData);
1029     assert(srcBitDepth == dstBitDepth);
1030     assert(srcPixelComponentCount == dstPixelComponentCount);
1031     // do the rendering
1032     if ( (dstPixelComponents != OFX::ePixelComponentRGBA) && (dstPixelComponents != OFX::ePixelComponentRGB) && (dstPixelComponents != OFX::ePixelComponentAlpha) ) {
1033         OFX::throwSuiteStatusException(kOfxStatErrFormat);
1034 
1035         return;
1036     }
1037     if (dstPixelComponents == OFX::ePixelComponentRGBA) {
1038         copyPixelsNTForDepthAndComponents<PIX, 4>(instance, renderWindow,
1039                                                   (const PIX*)srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1040                                                   (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1041     } else if (dstPixelComponents == OFX::ePixelComponentRGB) {
1042         copyPixelsNTForDepthAndComponents<PIX, 3>(instance, renderWindow,
1043                                                   (const PIX*)srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1044                                                   (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1045     }  else if (dstPixelComponents == OFX::ePixelComponentAlpha) {
1046         copyPixelsNTForDepthAndComponents<PIX, 1>(instance, renderWindow,
1047                                                   (const PIX*)srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1048                                                   (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1049     } // switch
1050 }
1051 
1052 inline void
copyPixelsNT(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const void * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,void * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)1053 copyPixelsNT(OFX::ImageEffect &instance,
1054              const OfxRectI & renderWindow,
1055              const void *srcPixelData,
1056              const OfxRectI & srcBounds,
1057              OFX::PixelComponentEnum srcPixelComponents,
1058              int srcPixelComponentCount,
1059              OFX::BitDepthEnum srcBitDepth,
1060              int srcRowBytes,
1061              void *dstPixelData,
1062              const OfxRectI & dstBounds,
1063              OFX::PixelComponentEnum dstPixelComponents,
1064              int dstPixelComponentCount,
1065              OFX::BitDepthEnum dstBitDepth,
1066              int dstRowBytes)
1067 {
1068     assert(srcPixelData && dstPixelData);
1069     assert(srcBitDepth == dstBitDepth);
1070     assert(srcPixelComponentCount == dstPixelComponentCount);
1071 
1072     // do the rendering
1073     if ( (dstBitDepth != OFX::eBitDepthUByte) && (dstBitDepth != OFX::eBitDepthUShort) && (dstBitDepth != OFX::eBitDepthHalf) && (dstBitDepth != OFX::eBitDepthFloat) ) {
1074         OFX::throwSuiteStatusException(kOfxStatErrFormat);
1075 
1076         return;
1077     }
1078     if (dstBitDepth == OFX::eBitDepthUByte) {
1079         copyPixelsNTForDepth<unsigned char>(instance, renderWindow,
1080                                             srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1081                                             dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1082     } else if ( (dstBitDepth == OFX::eBitDepthUShort) || (dstBitDepth == OFX::eBitDepthHalf) ) {
1083         copyPixelsNTForDepth<unsigned short>(instance, renderWindow,
1084                                              srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1085                                              dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1086     } else if (dstBitDepth == OFX::eBitDepthFloat) {
1087         copyPixelsNTForDepth<float>(instance, renderWindow,
1088                                     srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1089                                     dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1090     } // switch
1091 }
1092 
1093 // pixel copiers, threaded versions
1094 template<class PIX, int nComponents>
1095 void
copyPixelsForDepthAndComponents(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const PIX * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,PIX * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)1096 copyPixelsForDepthAndComponents(OFX::ImageEffect &instance,
1097                                 const OfxRectI & renderWindow,
1098                                 const PIX *srcPixelData,
1099                                 const OfxRectI & srcBounds,
1100                                 OFX::PixelComponentEnum srcPixelComponents,
1101                                 int srcPixelComponentCount,
1102                                 OFX::BitDepthEnum srcBitDepth,
1103                                 int srcRowBytes,
1104                                 PIX *dstPixelData,
1105                                 const OfxRectI & dstBounds,
1106                                 OFX::PixelComponentEnum dstPixelComponents,
1107                                 int dstPixelComponentCount,
1108                                 OFX::BitDepthEnum dstBitDepth,
1109                                 int dstRowBytes)
1110 {
1111     assert(srcPixelData && dstPixelData);
1112     //assert(srcBounds.y1 <= renderWindow.y1 && renderWindow.y1 <= renderWindow.y2 && renderWindow.y2 <= srcBounds.y2); // not necessary, PixelCopier should handle this
1113     //assert(srcBounds.x1 <= renderWindow.x1 && renderWindow.x1 <= renderWindow.x2 && renderWindow.x2 <= srcBounds.x2); // not necessary, PixelCopier should handle this
1114     assert(srcBitDepth == dstBitDepth);
1115     assert(srcPixelComponentCount == dstPixelComponentCount);
1116     (void)srcPixelComponents;
1117     (void)srcBitDepth;
1118     (void)dstPixelComponents;
1119     (void)dstBitDepth;
1120 
1121     OFX::PixelCopier<PIX, nComponents> processor(instance);
1122     // set the images
1123     processor.setDstImg(dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1124     processor.setSrcImg(srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes, 0);
1125 
1126     // set the render window
1127     processor.setRenderWindow(renderWindow);
1128 
1129     // Call the base class process member, this will call the derived templated process code
1130     processor.process();
1131 }
1132 
1133 template<class PIX>
1134 void
copyPixelsForDepth(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const void * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,void * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)1135 copyPixelsForDepth(OFX::ImageEffect &instance,
1136                    const OfxRectI & renderWindow,
1137                    const void *srcPixelData,
1138                    const OfxRectI & srcBounds,
1139                    OFX::PixelComponentEnum srcPixelComponents,
1140                    int srcPixelComponentCount,
1141                    OFX::BitDepthEnum srcBitDepth,
1142                    int srcRowBytes,
1143                    void *dstPixelData,
1144                    const OfxRectI & dstBounds,
1145                    OFX::PixelComponentEnum dstPixelComponents,
1146                    int dstPixelComponentCount,
1147                    OFX::BitDepthEnum dstBitDepth,
1148                    int dstRowBytes)
1149 {
1150     assert(srcPixelData && dstPixelData);
1151     assert(srcBitDepth == dstBitDepth);
1152     assert(srcPixelComponentCount == dstPixelComponentCount);
1153     // do the rendering
1154     if ( (dstPixelComponentCount < 0) || (4 < dstPixelComponentCount) ) {
1155         OFX::throwSuiteStatusException(kOfxStatErrFormat);
1156 
1157         return;
1158     }
1159     if (dstPixelComponentCount == 4) {
1160         copyPixelsForDepthAndComponents<PIX, 4>(instance, renderWindow,
1161                                                 (const PIX*)srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1162                                                 (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1163     } else if (dstPixelComponentCount == 3) {
1164         copyPixelsForDepthAndComponents<PIX, 3>(instance, renderWindow,
1165                                                 (const PIX*)srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1166                                                 (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1167     } else if (dstPixelComponentCount == 2) {
1168         copyPixelsForDepthAndComponents<PIX, 2>(instance, renderWindow,
1169                                                 (const PIX*)srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1170                                                 (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1171     }  else if (dstPixelComponentCount == 1) {
1172         copyPixelsForDepthAndComponents<PIX, 1>(instance, renderWindow,
1173                                                 (const PIX*)srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1174                                                 (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1175     } // switch
1176 }
1177 
1178 inline void
copyPixels(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const void * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,void * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)1179 copyPixels(OFX::ImageEffect &instance,
1180            const OfxRectI & renderWindow,
1181            const void *srcPixelData,
1182            const OfxRectI & srcBounds,
1183            OFX::PixelComponentEnum srcPixelComponents,
1184            int srcPixelComponentCount,
1185            OFX::BitDepthEnum srcBitDepth,
1186            int srcRowBytes,
1187            void *dstPixelData,
1188            const OfxRectI & dstBounds,
1189            OFX::PixelComponentEnum dstPixelComponents,
1190            int dstPixelComponentCount,
1191            OFX::BitDepthEnum dstBitDepth,
1192            int dstRowBytes)
1193 {
1194     assert(dstPixelData);
1195     if (!srcPixelData) {
1196         // no input, be black and transparent
1197         return fillBlack(instance, renderWindow,
1198                          dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1199     }
1200     assert(srcPixelComponentCount == dstPixelComponentCount && srcBitDepth == dstBitDepth);
1201     // do the rendering
1202     if ( (dstBitDepth != OFX::eBitDepthUByte) && (dstBitDepth != OFX::eBitDepthUShort) && (dstBitDepth != OFX::eBitDepthHalf) && (dstBitDepth != OFX::eBitDepthFloat) ) {
1203         OFX::throwSuiteStatusException(kOfxStatErrFormat);
1204 
1205         return;
1206     }
1207     if (dstBitDepth == OFX::eBitDepthUByte) {
1208         copyPixelsForDepth<unsigned char>(instance, renderWindow,
1209                                           srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1210                                           dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1211     } else if ( (dstBitDepth == OFX::eBitDepthUShort) || (dstBitDepth == OFX::eBitDepthHalf) ) {
1212         copyPixelsForDepth<unsigned short>(instance, renderWindow,
1213                                            srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1214                                            dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1215     } else if (dstBitDepth == OFX::eBitDepthFloat) {
1216         copyPixelsForDepth<float>(instance, renderWindow,
1217                                   srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1218                                   dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1219     } // switch
1220 }
1221 
1222 inline void
copyPixels(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const OFX::Image * srcImg,void * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)1223 copyPixels(OFX::ImageEffect &instance,
1224            const OfxRectI & renderWindow,
1225            const OFX::Image* srcImg,
1226            void *dstPixelData,
1227            const OfxRectI & dstBounds,
1228            OFX::PixelComponentEnum dstPixelComponents,
1229            int dstPixelComponentCount,
1230            OFX::BitDepthEnum dstBitDepth,
1231            int dstRowBytes)
1232 {
1233     const void* srcPixelData;
1234     OfxRectI srcBounds;
1235     OFX::PixelComponentEnum srcPixelComponents;
1236     OFX::BitDepthEnum srcBitDepth;
1237     int srcRowBytes;
1238 
1239     getImageData(srcImg, &srcPixelData, &srcBounds, &srcPixelComponents, &srcBitDepth, &srcRowBytes);
1240     int srcPixelComponentCount = srcImg->getPixelComponentCount();
1241 
1242     return copyPixels(instance, renderWindow, srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes, dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1243 }
1244 
1245 inline void
copyPixels(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const OFX::Image * srcImg,OFX::Image * dstImg)1246 copyPixels(OFX::ImageEffect &instance,
1247            const OfxRectI & renderWindow,
1248            const OFX::Image* srcImg,
1249            OFX::Image* dstImg)
1250 {
1251     void* dstPixelData;
1252     OfxRectI dstBounds;
1253     OFX::PixelComponentEnum dstPixelComponents;
1254     OFX::BitDepthEnum dstBitDepth;
1255     int dstRowBytes;
1256 
1257     getImageData(dstImg, &dstPixelData, &dstBounds, &dstPixelComponents, &dstBitDepth, &dstRowBytes);
1258     int dstPixelComponentCount = dstImg->getPixelComponentCount();
1259 
1260     return copyPixels(instance, renderWindow, srcImg, dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1261 }
1262 
1263 inline void
copyPixels(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const void * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,OFX::Image * dstImg)1264 copyPixels(OFX::ImageEffect &instance,
1265            const OfxRectI & renderWindow,
1266            const void *srcPixelData,
1267            const OfxRectI & srcBounds,
1268            OFX::PixelComponentEnum srcPixelComponents,
1269            int srcPixelComponentCount,
1270            OFX::BitDepthEnum srcBitDepth,
1271            int srcRowBytes,
1272            OFX::Image* dstImg)
1273 {
1274     void* dstPixelData;
1275     OfxRectI dstBounds;
1276     OFX::PixelComponentEnum dstPixelComponents;
1277     OFX::BitDepthEnum dstBitDepth;
1278     int dstRowBytes;
1279 
1280     getImageData(dstImg, &dstPixelData, &dstBounds, &dstPixelComponents, &dstBitDepth, &dstRowBytes);
1281     int dstPixelComponentCount = dstImg->getPixelComponentCount();
1282 
1283     return copyPixels(instance, renderWindow, srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes, dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1284 }
1285 
1286 // pixel copiers, threaded versions
1287 template<class PIX, int nComponents, int maxValue>
1288 void
copyPixelsOpaqueForDepthAndComponents(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const PIX * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,PIX * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)1289 copyPixelsOpaqueForDepthAndComponents(OFX::ImageEffect &instance,
1290                                       const OfxRectI & renderWindow,
1291                                       const PIX *srcPixelData,
1292                                       const OfxRectI & srcBounds,
1293                                       OFX::PixelComponentEnum srcPixelComponents,
1294                                       int srcPixelComponentCount,
1295                                       OFX::BitDepthEnum srcBitDepth,
1296                                       int srcRowBytes,
1297                                       PIX *dstPixelData,
1298                                       const OfxRectI & dstBounds,
1299                                       OFX::PixelComponentEnum dstPixelComponents,
1300                                       int dstPixelComponentCount,
1301                                       OFX::BitDepthEnum dstBitDepth,
1302                                       int dstRowBytes)
1303 {
1304     assert(srcPixelData && dstPixelData);
1305     //assert(srcBounds.y1 <= renderWindow.y1 && renderWindow.y1 <= renderWindow.y2 && renderWindow.y2 <= srcBounds.y2); // not necessary, PixelCopier should handle this
1306     //assert(srcBounds.x1 <= renderWindow.x1 && renderWindow.x1 <= renderWindow.x2 && renderWindow.x2 <= srcBounds.x2); // not necessary, PixelCopier should handle this
1307     assert(srcPixelComponents == dstPixelComponents && srcBitDepth == dstBitDepth);
1308     assert(srcPixelComponentCount == dstPixelComponentCount);
1309     (void)srcPixelComponents;
1310     (void)srcBitDepth;
1311     (void)dstPixelComponents;
1312     (void)dstBitDepth;
1313 
1314     OFX::PixelCopierOpaque<PIX, nComponents, maxValue> processor(instance);
1315     // set the images
1316     processor.setDstImg(dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1317     processor.setSrcImg(srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes, 0);
1318 
1319     // set the render window
1320     processor.setRenderWindow(renderWindow);
1321 
1322     // Call the base class process member, this will call the derived templated process code
1323     processor.process();
1324 }
1325 
1326 template<class PIX, int maxValue>
1327 void
copyPixelsOpaqueForDepth(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const void * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,void * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)1328 copyPixelsOpaqueForDepth(OFX::ImageEffect &instance,
1329                          const OfxRectI & renderWindow,
1330                          const void *srcPixelData,
1331                          const OfxRectI & srcBounds,
1332                          OFX::PixelComponentEnum srcPixelComponents,
1333                          int srcPixelComponentCount,
1334                          OFX::BitDepthEnum srcBitDepth,
1335                          int srcRowBytes,
1336                          void *dstPixelData,
1337                          const OfxRectI & dstBounds,
1338                          OFX::PixelComponentEnum dstPixelComponents,
1339                          int dstPixelComponentCount,
1340                          OFX::BitDepthEnum dstBitDepth,
1341                          int dstRowBytes)
1342 {
1343     if ( (dstPixelComponentCount < 0) || (4 < dstPixelComponentCount) ) {
1344         OFX::throwSuiteStatusException(kOfxStatErrFormat);
1345 
1346         return;
1347     }
1348     assert(srcPixelData && dstPixelData);
1349     assert(srcPixelComponents == dstPixelComponents && srcBitDepth == dstBitDepth);
1350     assert(srcPixelComponentCount == dstPixelComponentCount);
1351     // do the rendering
1352     if ( (dstPixelComponentCount == 4) || (dstPixelComponentCount == 1) ) {
1353         if (dstPixelComponentCount == 4) {
1354             copyPixelsOpaqueForDepthAndComponents<PIX, 4, maxValue>(instance, renderWindow,
1355                                                                     (const PIX*)srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1356                                                                     (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1357         } else {
1358             copyPixelsOpaqueForDepthAndComponents<PIX, 1, maxValue>(instance, renderWindow,
1359                                                                     (const PIX*)srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1360                                                                     (PIX *)dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1361         }
1362     } else {
1363         copyPixelsForDepth<PIX>(instance, renderWindow,
1364                                 srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1365                                 dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1366     }
1367 }
1368 
1369 inline void
copyPixelsOpaque(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const void * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,void * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)1370 copyPixelsOpaque(OFX::ImageEffect &instance,
1371                  const OfxRectI & renderWindow,
1372                  const void *srcPixelData,
1373                  const OfxRectI & srcBounds,
1374                  OFX::PixelComponentEnum srcPixelComponents,
1375                  int srcPixelComponentCount,
1376                  OFX::BitDepthEnum srcBitDepth,
1377                  int srcRowBytes,
1378                  void *dstPixelData,
1379                  const OfxRectI & dstBounds,
1380                  OFX::PixelComponentEnum dstPixelComponents,
1381                  int dstPixelComponentCount,
1382                  OFX::BitDepthEnum dstBitDepth,
1383                  int dstRowBytes)
1384 {
1385     if ( ( (dstPixelComponents != ePixelComponentRGBA) && (dstPixelComponents != ePixelComponentAlpha) ) ||
1386          !srcPixelData ) {
1387         assert(dstPixelComponentCount != 4 || !srcPixelData);
1388 
1389         return copyPixels(instance,
1390                           renderWindow,
1391                           srcPixelData,
1392                           srcBounds,
1393                           srcPixelComponents,
1394                           srcPixelComponentCount,
1395                           srcBitDepth,
1396                           srcRowBytes,
1397                           dstPixelData,
1398                           dstBounds,
1399                           dstPixelComponents,
1400                           dstPixelComponentCount,
1401                           dstBitDepth,
1402                           dstRowBytes);
1403     }
1404     assert(dstPixelData && srcPixelData);
1405     assert(srcPixelComponents == dstPixelComponents && srcBitDepth == dstBitDepth);
1406     // do the rendering
1407     switch (dstBitDepth) {
1408     case OFX::eBitDepthUByte: {
1409         copyPixelsOpaqueForDepth<unsigned char, 255>(instance, renderWindow,
1410                                                      srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1411                                                      dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1412         break;
1413     }
1414     case OFX::eBitDepthUShort: {
1415         copyPixelsOpaqueForDepth<unsigned short, 65535>(instance, renderWindow,
1416                                                         srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1417                                                         dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1418         break;
1419     }
1420     case OFX::eBitDepthHalf: {
1421         // the unsigned short representation of 1.h is 15360
1422         // #include <OpenEXR/half.h>
1423         // half one(1.);
1424         // cout << "the unsigned short representation of 1.h is " << one.bits() << endl;
1425         copyPixelsOpaqueForDepth<unsigned short, 15360>(instance, renderWindow,
1426                                                         srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1427                                                         dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1428         break;
1429     }
1430     case OFX::eBitDepthFloat: {
1431         copyPixelsOpaqueForDepth<float, 1>(instance, renderWindow,
1432                                            srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes,
1433                                            dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1434         break;
1435     }
1436     default:
1437         OFX::throwSuiteStatusException(kOfxStatErrFormat);
1438 
1439         return;
1440     } // switch
1441 } // copyPixelsOpaque
1442 
1443 inline void
copyPixelsOpaque(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const OFX::Image * srcImg,void * dstPixelData,const OfxRectI & dstBounds,OFX::PixelComponentEnum dstPixelComponents,int dstPixelComponentCount,OFX::BitDepthEnum dstBitDepth,int dstRowBytes)1444 copyPixelsOpaque(OFX::ImageEffect &instance,
1445                  const OfxRectI & renderWindow,
1446                  const OFX::Image* srcImg,
1447                  void *dstPixelData,
1448                  const OfxRectI & dstBounds,
1449                  OFX::PixelComponentEnum dstPixelComponents,
1450                  int dstPixelComponentCount,
1451                  OFX::BitDepthEnum dstBitDepth,
1452                  int dstRowBytes)
1453 {
1454     const void* srcPixelData;
1455     OfxRectI srcBounds;
1456     OFX::PixelComponentEnum srcPixelComponents;
1457     OFX::BitDepthEnum srcBitDepth;
1458     int srcRowBytes;
1459 
1460     getImageData(srcImg, &srcPixelData, &srcBounds, &srcPixelComponents, &srcBitDepth, &srcRowBytes);
1461     int srcPixelComponentCount = srcImg->getPixelComponentCount();
1462 
1463     return copyPixelsOpaque(instance, renderWindow, srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes, dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1464 }
1465 
1466 inline void
copyPixelsOpaque(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const OFX::Image * srcImg,OFX::Image * dstImg)1467 copyPixelsOpaque(OFX::ImageEffect &instance,
1468                  const OfxRectI & renderWindow,
1469                  const OFX::Image* srcImg,
1470                  OFX::Image* dstImg)
1471 {
1472     void* dstPixelData;
1473     OfxRectI dstBounds;
1474     OFX::PixelComponentEnum dstPixelComponents;
1475     OFX::BitDepthEnum dstBitDepth;
1476     int dstRowBytes;
1477 
1478     getImageData(dstImg, &dstPixelData, &dstBounds, &dstPixelComponents, &dstBitDepth, &dstRowBytes);
1479     int dstPixelComponentCount = dstImg->getPixelComponentCount();
1480 
1481     return copyPixelsOpaque(instance, renderWindow, srcImg, dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1482 }
1483 
1484 inline void
copyPixelsOpaque(OFX::ImageEffect & instance,const OfxRectI & renderWindow,const void * srcPixelData,const OfxRectI & srcBounds,OFX::PixelComponentEnum srcPixelComponents,int srcPixelComponentCount,OFX::BitDepthEnum srcBitDepth,int srcRowBytes,OFX::Image * dstImg)1485 copyPixelsOpaque(OFX::ImageEffect &instance,
1486                  const OfxRectI & renderWindow,
1487                  const void *srcPixelData,
1488                  const OfxRectI & srcBounds,
1489                  OFX::PixelComponentEnum srcPixelComponents,
1490                  int srcPixelComponentCount,
1491                  OFX::BitDepthEnum srcBitDepth,
1492                  int srcRowBytes,
1493                  OFX::Image* dstImg)
1494 {
1495     void* dstPixelData;
1496     OfxRectI dstBounds;
1497     OFX::PixelComponentEnum dstPixelComponents;
1498     OFX::BitDepthEnum dstBitDepth;
1499     int dstRowBytes;
1500 
1501     getImageData(dstImg, &dstPixelData, &dstBounds, &dstPixelComponents, &dstBitDepth, &dstRowBytes);
1502     int dstPixelComponentCount = dstImg->getPixelComponentCount();
1503 
1504     return copyPixelsOpaque(instance, renderWindow, srcPixelData, srcBounds, srcPixelComponents, srcPixelComponentCount, srcBitDepth, srcRowBytes, dstPixelData, dstBounds, dstPixelComponents, dstPixelComponentCount, dstBitDepth, dstRowBytes);
1505 }
1506 } // OFX
1507 
1508 #endif // ifndef IO_ofxsCopier_h
1509