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  * OFX generic rectangle interact with 4 corner points + center point and 4 mid-points.
22  * You can use it to define any rectangle in an image resizable by the user.
23  */
24 
25 #ifndef openfx_supportext_ofxsRamp_h
26 #define openfx_supportext_ofxsRamp_h
27 
28 #include <cmath>
29 
30 #include <ofxsInteract.h>
31 #include <ofxsImageEffect.h>
32 #include "ofxsMacros.h"
33 #include "ofxsOGLTextRenderer.h"
34 
35 #define kParamRampPoint0 "rampPoint0"
36 #define kParamRampPoint0Label "Point 0"
37 
38 #define kParamRampColor0 "rampColor0"
39 #define kParamRampColor0Label "Color 0"
40 
41 #define kParamRampPoint1 "rampPoint1"
42 #define kParamRampPoint1Label "Point 1"
43 
44 #define kParamRampColor1 "rampColor1"
45 #define kParamRampColor1Label "Color 1"
46 
47 #define kParamRampType "rampType"
48 #define kParamRampTypeLabel "Ramp Type", "The type of interpolation used to generate the ramp"
49 #define kParamRampTypeOptionLinear "Linear", "Linear ramp.", "linear"
50 #define kParamRampTypeOptionPLinear "PLinear", "Perceptually linear ramp in Rec.709.", "plinear"
51 #define kParamRampTypeOptionEaseIn "Ease-in", "Catmull-Rom spline, smooth start, linear end (a.k.a. smooth0).", "easein"
52 #define kParamRampTypeOptionEaseOut "Ease-out", "Catmull-Rom spline, linear start, smooth end (a.k.a. smooth1).", "easeout"
53 #define kParamRampTypeOptionSmooth "Smooth", "Traditional smoothstep ramp.", "smooth"
54 #define kParamRampTypeOptionNone "None", "No color gradient.", "none"
55 
56 #define kParamRampInteractOpen "rampInteractOpen"
57 #define kParamRampInteractOpenLabel "Show Interact", "If checked, the ramp interact is displayed over the image."
58 
59 #define kParamRampInteractive "rampInteractive"
60 #define kParamRampInteractiveLabel "Interactive Update", "If checked, update the parameter values during interaction with the image viewer, else update the values when pen is released."
61 
62 // old names, for the Ramp plugin only
63 #define kParamRampPoint0Old "point0"
64 #define kParamRampColor0Old "color0"
65 #define kParamRampPoint1Old "point1"
66 #define kParamRampColor1Old "color1"
67 #define kParamRampTypeOld "type"
68 #define kParamRampInteractiveOld "interactive"
69 
70 namespace OFX {
71 enum RampTypeEnum
72 {
73     eRampTypeLinear = 0,
74     eRampTypePLinear,
75     eRampTypeEaseIn,
76     eRampTypeEaseOut,
77     eRampTypeSmooth,
78     eRampTypeNone
79 };
80 
81 class RampInteractHelper
82     : private OFX::InteractAbstract
83 {
84     enum InteractState
85     {
86         eInteractStateIdle = 0,
87         eInteractStateDraggingPoint0,
88         eInteractStateDraggingPoint1
89     };
90 
91     Double2DParam* _point0;
92     Double2DParam* _point1;
93     ChoiceParam* _type;
94     BooleanParam* _interactOpen;
95     BooleanParam* _interactive;
96     OfxPointD _point0DragPos, _point1DragPos;
97     bool _interactiveDrag;
98     OfxPointD _lastMousePos;
99     InteractState _state;
100     OFX::ImageEffect* _effect;
101     OFX::Interact* _interact;
102     Clip *_dstClip;
103 
104 public:
105     RampInteractHelper(OFX::ImageEffect* effect,
106                        OFX::Interact* interact,
107                        bool oldParams = false)
_point0(NULL)108         : _point0(NULL)
109         , _point1(NULL)
110         , _type(NULL)
111         , _interactOpen(NULL)
112         , _interactive(NULL)
113         , _point0DragPos()
114         , _point1DragPos()
115         , _interactiveDrag(false)
116         , _lastMousePos()
117         , _state(eInteractStateIdle)
118         , _effect(effect)
119         , _interact(interact)
120         , _dstClip(NULL)
121     {
122         if (oldParams) {
123             _point0 = effect->fetchDouble2DParam(kParamRampPoint0Old);
124             _point1 = effect->fetchDouble2DParam(kParamRampPoint1Old);
125             _type = effect->fetchChoiceParam(kParamRampTypeOld);
126             _interactive = effect->fetchBooleanParam(kParamRampInteractiveOld);
127         } else {
128             _point0 = effect->fetchDouble2DParam(kParamRampPoint0);
129             _point1 = effect->fetchDouble2DParam(kParamRampPoint1);
130             _type = effect->fetchChoiceParam(kParamRampType);
131             _interactive = effect->fetchBooleanParam(kParamRampInteractive);
132         }
133         _interactOpen = _effect->fetchBooleanParam(kParamRampInteractOpen);
134         assert(_point0 && _point1 && _type && _interactOpen && _interactive);
135         assert(_effect && _interact);
136         _dstClip = _effect->fetchClip(kOfxImageEffectOutputClipName);
137         assert(_dstClip);
138     }
139 
140     /** @brief virtual destructor */
~RampInteractHelper()141     virtual ~RampInteractHelper()
142     {
143         // fetched clips and params are owned and deleted by the ImageEffect and its ParamSet
144     }
145 
146     /** @brief the function called to draw in the interact */
147     virtual bool draw(const DrawArgs &args) OVERRIDE;
148 
149     /** @brief the function called to handle pen motion in the interact
150 
151        returns true if the interact trapped the action in some sense. This will block the action being passed to
152        any other interact that may share the viewer.
153      */
154     virtual bool penMotion(const PenArgs &args) OVERRIDE;
155 
156     /** @brief the function called to handle pen down events in the interact
157 
158        returns true if the interact trapped the action in some sense. This will block the action being passed to
159        any other interact that may share the viewer.
160      */
161     virtual bool penDown(const PenArgs &args) OVERRIDE;
162 
163     /** @brief the function called to handle pen up events in the interact
164 
165        returns true if the interact trapped the action in some sense. This will block the action being passed to
166        any other interact that may share the viewer.
167      */
168     virtual bool penUp(const PenArgs &args) OVERRIDE;
169 
170     /** @brief the function called to handle key down events in the interact
171 
172        returns true if the interact trapped the action in some sense. This will block the action being passed to
173        any other interact that may share the viewer.
174      */
keyDown(const KeyArgs &)175     virtual bool keyDown(const KeyArgs & /*args*/) OVERRIDE { return false; };
176 
177     /** @brief the function called to handle key up events in the interact
178 
179        returns true if the interact trapped the action in some sense. This will block the action being passed to
180        any other interact that may share the viewer.
181      */
keyUp(const KeyArgs &)182     virtual bool keyUp(const KeyArgs & /*args*/) OVERRIDE { return false; };
183 
184     /** @brief the function called to handle key down repeat events in the interact
185 
186        returns true if the interact trapped the action in some sense. This will block the action being passed to
187        any other interact that may share the viewer.
188      */
keyRepeat(const KeyArgs &)189     virtual bool keyRepeat(const KeyArgs & /*args*/) OVERRIDE { return false; };
190 
191     /** @brief Called when the interact is given input focus */
gainFocus(const FocusArgs &)192     virtual void gainFocus(const FocusArgs & /*args*/) OVERRIDE {};
193 
194     /** @brief Called when the interact is loses input focus */
195     virtual void loseFocus(const FocusArgs &args) OVERRIDE;
196 };
197 
198 typedef OverlayInteractFromHelper<RampInteractHelper> RampInteract;
199 
200 class RampOverlayDescriptor
201     : public DefaultEffectOverlayDescriptor<RampOverlayDescriptor, RampInteract>
202 {
203 };
204 
205 class RampInteractHelperOldParams
206     : public RampInteractHelper
207 {
208 public:
RampInteractHelperOldParams(OFX::ImageEffect * effect,OFX::Interact * interact)209     RampInteractHelperOldParams(OFX::ImageEffect* effect,
210                                 OFX::Interact* interact)
211         : RampInteractHelper(effect, interact, true) {}
212 };
213 
214 typedef OverlayInteractFromHelper<RampInteractHelperOldParams> RampInteractOldParams;
215 
216 class RampOverlayDescriptorOldParams
217     : public DefaultEffectOverlayDescriptor<RampOverlayDescriptorOldParams, RampInteractOldParams>
218 {
219 };
220 
221 
222 template<RampTypeEnum type>
223 double
ofxsRampFunc(double t)224 ofxsRampFunc(double t)
225 {
226     if ( (t >= 1.) || (type == eRampTypeNone) ) {
227         t = 1.;
228     } else if (t <= 0) {
229         t = 0.;
230     } else {
231         // from http://www.comp-fu.com/2012/01/nukes-smooth-ramp-functions/
232         // linear
233         //y = x
234         // plinear: perceptually linear in rec709
235         //y = pow(x, 3)
236         // smooth: traditional smoothstep
237         //y = x*x*(3 - 2*x)
238         // smooth0: Catmull-Rom spline, smooth start, linear end
239         //y = x*x*(2 - x)
240         // smooth1: Catmull-Rom spline, linear start, smooth end
241         //y = x*(1 + x*(1 - x))
242         switch (type) {
243         case eRampTypeLinear:
244             break;
245         case eRampTypePLinear:
246             // plinear: perceptually linear in rec709
247             t = t * t * t;
248             break;
249         case eRampTypeEaseIn:
250             //t *= t; // old version, end of curve is too sharp
251             // smooth0: Catmull-Rom spline, smooth start, linear end
252             t = t * t * (2 - t);
253             break;
254         case eRampTypeEaseOut:
255             //t = - t * (t - 2); // old version, start of curve is too sharp
256             // smooth1: Catmull-Rom spline, linear start, smooth end
257             t = t * ( 1 + t * (1 - t) );
258             break;
259         case eRampTypeSmooth:
260             /*
261                t *= 2.;
262                if (t < 1) {
263                t = t * t / (2.);
264                } else {
265                --t;
266                t =  -0.5 * (t * (t - 2) - 1);
267                }
268              */
269             // smooth: traditional smoothstep
270             t = t * t * (3 - 2 * t);
271             break;
272         case eRampTypeNone:
273             t = 1.;
274             break;
275         default:
276             break;
277         }
278     }
279 
280     return t;
281 } // ofxsRampFunc
282 
283 template<RampTypeEnum type>
284 double
ofxsRampFunc(const OfxPointD & p0,double nx,double ny,const OfxPointD & p)285 ofxsRampFunc(const OfxPointD& p0,
286              double nx,
287              double ny,
288              const OfxPointD& p)
289 {
290     double t = (p.x - p0.x) * nx + (p.y - p0.y) * ny;
291 
292     return ofxsRampFunc<type>(t);
293 }
294 
295 inline double
ofxsRampFunc(const OfxPointD & p0,double nx,double ny,RampTypeEnum type,const OfxPointD & p)296 ofxsRampFunc(const OfxPointD& p0,
297              double nx,
298              double ny,
299              RampTypeEnum type,
300              const OfxPointD& p)
301 {
302     double t = (p.x - p0.x) * nx + (p.y - p0.y) * ny;
303 
304     switch (type) {
305     case eRampTypeLinear:
306 
307         return ofxsRampFunc<eRampTypeLinear>(t);
308         break;
309     case eRampTypePLinear:
310 
311         return ofxsRampFunc<eRampTypePLinear>(t);
312         break;
313     case eRampTypeEaseIn:
314 
315         return ofxsRampFunc<eRampTypeEaseIn>(t);
316         break;
317     case eRampTypeEaseOut:
318 
319         return ofxsRampFunc<eRampTypeEaseOut>(t);
320         break;
321     case eRampTypeSmooth:
322 
323         return ofxsRampFunc<eRampTypeSmooth>(t);
324         break;
325     case eRampTypeNone:
326         t = 1.;
327         break;
328     default:
329         break;
330     }
331 
332     return t;
333 }
334 
335 void ofxsRampDescribeParams(OFX::ImageEffectDescriptor &desc,
336                             OFX::PageParamDescriptor *page,
337                             OFX::GroupParamDescriptor *group,
338                             RampTypeEnum defaultType,
339                             bool isOpen,
340                             bool oldParams);
341 } // namespace OFX
342 
343 #endif /* defined(openfx_supportext_ofxsRamp_h) */
344