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 #ifndef openfx_supportext_ofxsImageBlenderMasked_h
21 #define openfx_supportext_ofxsImageBlenderMasked_h
22 
23 #include "ofxsProcessing.H"
24 #include "ofxsMaskMix.h"
25 #include "ofxsImageBlender.H"
26 
27 namespace OFX {
28 /** @brief  Base class used to blend two images together */
29 class ImageBlenderMaskedBase
30     : public ImageBlenderBase
31 {
32 protected:
33     bool _doMasking;
34     const OFX::Image *_maskImg;
35     bool _maskInvert;
36 
37 public:
38     /** @brief no arg ctor */
ImageBlenderMaskedBase(OFX::ImageEffect & instance)39     ImageBlenderMaskedBase(OFX::ImageEffect &instance)
40         : ImageBlenderBase(instance)
41         , _doMasking(false)
42         , _maskImg(NULL)
43         , _maskInvert(false)
44     {
45     }
46 
setMaskImg(const OFX::Image * v,bool maskInvert)47     void setMaskImg(const OFX::Image *v,
48                     bool maskInvert)
49     {
50         _maskImg = v; _maskInvert = maskInvert;
51     }
52 
doMasking(bool v)53     void doMasking(bool v)
54     {
55         _doMasking = v;
56     }
57 };
58 
59 /** @brief templated class to blend between two images */
60 template <class PIX, int nComponents, int maxValue, bool masked>
61 class ImageBlenderMasked
62     : public ImageBlenderMaskedBase
63 {
64 public:
65     // ctor
ImageBlenderMasked(OFX::ImageEffect & instance)66     ImageBlenderMasked(OFX::ImageEffect &instance)
67         : ImageBlenderMaskedBase(instance)
68     {
69     }
70 
Lerp(const PIX & v1,const PIX & v2,float blend)71     static PIX Lerp(const PIX &v1,
72                     const PIX &v2,
73                     float blend)
74     {
75         return PIX( (v2 - v1) * blend + v1 );
76     }
77 
78     // and do some processing
multiThreadProcessImages(OfxRectI procWindow)79     void multiThreadProcessImages(OfxRectI procWindow)
80     {
81         float tmpPix[nComponents];
82         float blend = _blend;
83         float blendComp = 1.0f - blend;
84 
85         for (int y = procWindow.y1; y < procWindow.y2; y++) {
86             if ( _effect.abort() ) {
87                 break;
88             }
89 
90             PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y);
91 
92             for (int x = procWindow.x1; x < procWindow.x2; x++) {
93                 PIX *fromPix = (PIX *)  (_fromImg ? _fromImg->getPixelAddress(x, y) : 0);
94                 PIX *toPix   = (PIX *)  (_toImg   ? _toImg->getPixelAddress(x, y)   : 0);
95 
96                 if ( masked && (fromPix || toPix) ) {
97                     for (int c = 0; c < nComponents; ++c) {
98                         // all images are supposed to be black and transparent outside o
99                         tmpPix[c] = toPix ? (float)toPix[c] : 0.f;
100                     }
101                     ofxsMaskMixPix<PIX, nComponents, maxValue, masked>(tmpPix, x, y, fromPix, _doMasking, _maskImg, blend, _maskInvert, dstPix);
102                 } else if (fromPix && toPix) {
103                     assert(!masked);
104                     for (int c = 0; c < nComponents; ++c) {
105                         dstPix[c] = Lerp(fromPix[c], toPix[c], blend);
106                     }
107                 } else if (fromPix) {
108                     assert(!masked);
109                     for (int c = 0; c < nComponents; ++c) {
110                         dstPix[c] = PIX(fromPix[c] * blendComp);
111                     }
112                 } else if (toPix) {
113                     assert(!masked);
114                     for (int c = 0; c < nComponents; ++c) {
115                         dstPix[c] = PIX(toPix[c] * blend);
116                     }
117                 } else {
118                     // everything is black and transparent
119                     for (int c = 0; c < nComponents; ++c) {
120                         dstPix[c] = PIX(0);
121                     }
122                 }
123 
124                 dstPix += nComponents;
125             }
126         }
127     }
128 };
129 };
130 
131 #endif // ifndef openfx_supportext_ofxsImageBlenderMasked_h
132 
133 
134