1 /* ***** BEGIN LICENSE BLOCK *****
2 * This file is part of openfx-misc <https://github.com/devernay/openfx-misc>,
3 * Copyright (C) 2013-2018 INRIA
4 *
5 * openfx-misc is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * openfx-misc is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with openfx-misc. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>
17 * ***** END LICENSE BLOCK ***** */
18
19 /*
20 * OFX Distortion plugins.
21 */
22
23 /* TODO:
24 - optionally expand/contract RoD in LensDistortion,
25 see PFBarrelCommon::calculateOutputRect (sample 10 points on each side of image rect)
26 */
27 /*
28 Although the indications from nuke/fnOfxExtensions.h were followed, and the
29 kFnOfxImageEffectActionGetTransform action was implemented in the Support
30 library, that action is never called by the Nuke host, so it cannot be tested.
31 The code is left here for reference or for further extension.
32
33 There is also an open question about how the last plugin in a transform chain
34 may get the concatenated transform from upstream, the untransformed source image,
35 concatenate its own transform and apply the resulting transform in its render
36 action. Should the host be doing this instead?
37 */
38 // This node concatenates transforms upstream.
39
40 #include <cmath>
41 #include <cfloat> // DBL_MAX
42 #include <cstdlib> // atoi
43 #include <cstdio> // fopen
44 #include <iostream>
45 #include <sstream>
46 #include <set>
47 #include <map>
48 #include <vector>
49 #include <algorithm>
50 #include <limits>
51
52 #ifdef __APPLE__
53 #include <OpenGL/gl.h>
54 #else
55 #ifdef _WIN32
56 #define WIN32_LEAN_AND_MEAN
57 #ifndef NOMINMAX
58 #define NOMINMAX
59 #endif
60 #include <windows.h>
61 #endif
62
63 #include <GL/gl.h>
64 #endif
65
66 #include "ofxsImageEffect.h"
67 #include "ofxsProcessing.H"
68 #include "ofxsCoords.h"
69 #include "ofxsMaskMix.h"
70 #include "ofxsFilter.h"
71 #include "ofxsMatrix2D.h"
72 #include "ofxsCopier.h"
73 #include "ofxsMacros.h"
74 #include "ofxsMultiPlane.h"
75 #include "ofxsGenerator.h"
76 #include "ofxsFormatResolution.h"
77
78 #include "DistortionModel.h"
79
80 using namespace OFX;
81
82 OFXS_NAMESPACE_ANONYMOUS_ENTER
83
84 #define kPluginIDistortName "IDistortOFX"
85 #define kPluginIDistortGrouping "Transform"
86 #define kPluginIDistortDescription \
87 "Distort an image, based on a displacement map.\n" \
88 "The U and V channels give the offset in pixels in the destination image to the pixel where the color is taken. " \
89 "For example, if at pixel (45,12) the UV value is (-1.5,3.2), then the color at this pixel is taken from (43.5,15.2) in the source image. " \
90 "This plugin concatenates transforms upstream, so that if the nodes upstream output a 3x3 transform " \
91 "(e.g. Transform, CornerPin, Dot, NoOp, Switch), the original image is sampled only once.\n" \
92 "This plugin concatenates transforms upstream." \
93
94 #define kPluginIDistortIdentifier "net.sf.openfx.IDistort"
95
96 #define kPluginSTMapName "STMapOFX"
97 #define kPluginSTMapGrouping "Transform"
98 #define kPluginSTMapDescription \
99 "Move pixels around an image, based on a UVmap.\n" \
100 "The U and V channels give, for each pixel in the destination image, the normalized position of the pixel where the color is taken. " \
101 "(0,0) is the bottom left corner of the input image, while (1,1) is the top right corner. " \
102 "This plugin concatenates transforms upstream, so that if the nodes upstream output a 3x3 transform " \
103 "(e.g. Transform, CornerPin, Dot, NoOp, Switch), the original image is sampled only once.\n" \
104 "This plugin concatenates transforms upstream." \
105
106 #define kPluginSTMapIdentifier "net.sf.openfx.STMap"
107
108 #define kPluginLensDistortionName "LensDistortionOFX"
109 #define kPluginLensDistortionGrouping "Transform"
110 #define kPluginLensDistortionDescription \
111 "Add or remove lens distortion, or produce an STMap that can be used to apply that transform.\n" \
112 "The region of definition of the transformed image is computed from the region of definition of the Source input. If the input is defined outside of the project format, this may result in a very large region. A Crop effect may be inserted before LensDistortion to avoid this. If the input region of definition is inside the format, the Crop To Format parameter may be used to avoid expanding it.\n" \
113 "LensDistortion can directly apply distortion/undistortion, but if the distortion parameters are not animated, the most efficient way to use LensDistortion and avoid repeated distortion function calculations is the following:\n" \
114 "- If the footage size is not the same as the project size, insert a FrameHold plugin between the footage to distort or undistort and the Source input of LensDistortion. This connection is only used to get the size of the input footage.\n" \
115 "- Set Output Mode to \"STMap\" in LensDistortion.\n" \
116 "- feed the LensDistortion output into the UV input of STMap, and feed the footage into the Source input of STMap.\n" \
117 "This plugin concatenates transforms upstream." \
118
119 #define kPluginLensDistortionIdentifier "net.sf.openfx.LensDistortion"
120
121 // Some hosts (e.g. Resolve) may not support normalized defaults (setDefaultCoordinateSystem(eCoordinatesNormalised))
122 #define kParamDefaultsNormalised "defaultsNormalised"
123
124 /* LensDistortion TODO:
125 - cache the STmap for a set of input parameter and input image size
126 - compute the inverse map and undistort
127 - implement other distortion models (PFBarrel, OpenCV)
128 */
129
130 // History:
131 // version 1.0: initial version
132 // version 2.0: use kNatronOfxParamProcess* parameters
133 #define kPluginVersionMajor 2 // Incrementing this number means that you have broken backwards compatibility of the plug-in.
134 #define kPluginVersionMinor 0 // Increment this when you have fixed a bug or made it faster.
135
136 // version 1.0: initial version
137 // version 2.0: use kNatronOfxParamProcess* parameters
138 // version 3.0: use format instead of rod as the default for distortion domain
139 // version 4.0: add the CropToFormat parameter
140 #define kPluginVersionLensDistortionMajor 4 // Incrementing this number means that you have broken backwards compatibility of the plug-in.
141 #define kPluginVersionLensDistortionMinor 0 // Increment this when you have fixed a bug or made it faster.
142
143 #define kSupportsTiles 1
144 #define kSupportsMultiResolution 1
145 #define kSupportsRenderScale 1
146 #define kSupportsMultipleClipPARs false
147 #define kSupportsMultipleClipDepths false
148 #define kRenderThreadSafety eRenderFullySafe
149
150 static bool gHostSupportsDefaultCoordinateSystem = true; // for kParamDefaultsNormalised
151
152 enum DistortionPluginEnum
153 {
154 eDistortionPluginSTMap,
155 eDistortionPluginIDistort,
156 eDistortionPluginLensDistortion,
157 };
158
159 #ifdef OFX_EXTENSIONS_NATRON
160 #define kParamProcessR kNatronOfxParamProcessR
161 #define kParamProcessRLabel kNatronOfxParamProcessRLabel, kNatronOfxParamProcessRHint
162 #define kParamProcessG kNatronOfxParamProcessG
163 #define kParamProcessGLabel kNatronOfxParamProcessGLabel, kNatronOfxParamProcessGHint
164 #define kParamProcessB kNatronOfxParamProcessB
165 #define kParamProcessBLabel kNatronOfxParamProcessBLabel, kNatronOfxParamProcessBHint
166 #define kParamProcessA kNatronOfxParamProcessA
167 #define kParamProcessALabel kNatronOfxParamProcessALabel, kNatronOfxParamProcessAHint
168 #else
169 #define kParamProcessR "processR"
170 #define kParamProcessRLabel "R", "Process red component."
171 #define kParamProcessG "processG"
172 #define kParamProcessGLabel "G", "Process green component."
173 #define kParamProcessB "processB"
174 #define kParamProcessBLabel "B", "Process blue component."
175 #define kParamProcessA "processA"
176 #define kParamProcessALabel "A", "Process alpha component."
177 #endif
178
179 #define kParamChannelU "channelU"
180 #define kParamChannelULabel "U Channel", "Input U channel from UV."
181
182 #define kParamChannelUChoice kParamChannelU "Choice"
183
184 #define kParamChannelV "channelV"
185 #define kParamChannelVLabel "V Channel", "Input V channel from UV."
186
187 #define kParamChannelVChoice kParamChannelV "Choice"
188
189 #define kParamChannelA "channelA"
190 #define kParamChannelALabel "Alpha Channel", "Input Alpha channel from UV. The Output alpha is set to this value. If \"Unpremult UV\" is checked, the UV values are divided by alpha."
191
192 #define kParamChannelAChoice kParamChannelA "Choice"
193
194 #define kParamChannelUnpremultUV "unpremultUV"
195 #define kParamChannelUnpremultUVLabel "Unpremult UV", "Unpremult UV by Alpha from UV. Check if UV values look small for small values of Alpha (3D software sometimes write premultiplied UV values)."
196
197 #define kParamPremultChanged "premultChanged"
198
199 #define kClipUV "UV"
200
201 #ifdef OFX_EXTENSIONS_NATRON
202 #define OFX_COMPONENTS_OK(c) ((c)== ePixelComponentAlpha || (c) == ePixelComponentXY || (c) == ePixelComponentRGB || (c) == ePixelComponentRGBA)
203 #else
204 #define OFX_COMPONENTS_OK(c) ((c)== ePixelComponentAlpha || (c) == ePixelComponentRGB || (c) == ePixelComponentRGBA)
205 #endif
206
207
208 enum InputChannelEnum
209 {
210 eInputChannelR = 0,
211 eInputChannelG,
212 eInputChannelB,
213 eInputChannelA,
214 eInputChannel0,
215 eInputChannel1,
216 };
217
218 #define kParamWrapU "wrapU"
219 #define kParamWrapULabel "U Wrap Mode", "Wrap mode for U coordinate."
220
221 #define kParamWrapV "wrapV"
222 #define kParamWrapVLabel "V Wrap Mode", "Wrap mode for V coordinate."
223
224 #define kParamWrapOptionClamp "Clamp", "Texture edges are black (if blackOutside is checked) or stretched indefinitely.", "clamp"
225 #define kParamWrapOptionRepeat "Repeat", "Texture is repeated.", "repeat"
226 #define kParamWrapOptionMirror "Mirror", "Texture is mirrored alternatively.", "mirror"
227
228 enum WrapEnum
229 {
230 eWrapClamp = 0,
231 eWrapRepeat,
232 eWrapMirror,
233 };
234
235
236 #define kParamUVOffset "uvOffset"
237 #define kParamUVOffsetLabel "UV Offset", "Offset to apply to the U and V channel (useful if these were stored in a file that cannot handle negative numbers)"
238
239 #define kParamUVScale "uvScale"
240 #define kParamUVScaleLabel "UV Scale", "Scale factor to apply to the U and V channel (useful if these were stored in a file that can only store integer values)"
241
242 #define kParamFormat kParamGeneratorExtent
243 #define kParamFormatLabel "Format", "Reference format for lens distortion."
244
245 #define kParamDistortionModel "model"
246 #define kParamDistortionModelLabel "Model", "Choice of the distortion model, i.e. the function that goes from distorted to undistorted image coordinates."
247 #define kParamDistortionModelOptionNuke "Nuke", "The model used in Nuke's LensDistortion plugin.", "nuke"
248 #define kParamDistortionModelOptionPFBarrel "PFBarrel", "The PFBarrel model used in PFTrack by PixelFarm.", "pfbarrel"
249 #define kParamDistortionModelOption3DEClassic "3DE Classic", "Degree-2 anamorphic and degree-4 radial mixed model, used in 3DEqualizer by Science-D-Visions. Works, but it is recommended to use 3DE4 Radial Standard Degree 4 or 3DE4 Anamorphic Standard Degree 4 instead.", "3declassic"
250 #define kParamDistortionModelOption3DEAnamorphic6 "3DE4 Anamorphic Degree 6", "Degree-6 anamorphic model, used in 3DEqualizer by Science-D-Visions.", "3deanamorphic6"
251 #define kParamDistortionModelOption3DEFishEye8 "3DE4 Radial Fisheye Degree 8", "Radial lens distortion model with equisolid-angle fisheye projection, used in 3DEqualizer by Science-D-Visions.", "3defisheye8"
252 #define kParamDistortionModelOption3DEStandard "3DE4 Radial Standard Degree 4", "Radial lens distortion model, a.k.a. radial decentered cylindric degree 4, which compensates for decentered lenses (and beam splitter artefacts in stereo rigs), used in 3DEqualizer by Science-D-Visions.", "3deradial4"
253 #define kParamDistortionModelOption3DEAnamorphic4 "3DE4 Anamorphic Standard Degree 4", "Degree-4 anamorphic model with anamorphic lens rotation, which handles 'human-touched' mounted anamorphic lenses, used in 3DEqualizer by Science-D-Visions.", "3deanamorphic4"
254 #define kParamDistortionModelOptionPanoTools "PanoTools", "The model used in PanoTools, PTGui, PTAssembler, Hugin. See http://wiki.panotools.org/Lens_correction_model", "panotools"
255
256 /*
257 Possible distortion models:
258 (see also <http://michaelkarp.net/distortion.htm>)
259
260 From Oblique <https://github.com/madesjardins/Obq_Shaders/wiki/Obq_LensDistortion>
261 PFBarrel: PFTrack's distortion model.
262 Nuke: Nuke's distortion model.
263 3DE Classic LD Model: Degree-2 anamorphic and degree-4 radial mixed model
264 Science-D-Visions LDPK (3DEqualizer). see <http://www.3dequalizer.com/user_daten/tech_docs/pdf/ldpk.pdf>
265 3DE4 Anamorphic, Degree 6:
266 3DE4 Radial - Fisheye, Degree 8:
267 3DE4 Radial - Standard, Degree 4: A deprecated model.
268 3DE4 Radial - Decentered Cylindric, Degree 4:
269 3DE4 Anamorphic Rotate Squeeze, Degree 4:
270
271 From RV4 <http://www.tweaksoftware.com/static/documentation/rv/rv-4.0.17/html/rv_reference.html#RVLensWarp>
272 “brown”, “opencv”, “pfbarrel”, “adobe”, “3de4_anamorphic_degree_6”
273
274 Panorama Tools/PtGUI/Hugin/Card3D:
275 http://wiki.panotools.org/Lens_correction_model
276 http://www.ptgui.com/ptguihelp/main_lens.htm
277 http://www.nukepedia.com/written-tutorials/the-lens-distortion-model-in-the-card-node-explained/
278 https://web.archive.org/web/20010409044720/http://www.fh-furtwangen.de/~dersch/barrel/barrel.html
279
280 OpenCV / Matlab Camera Calibration Toolbox:
281 - https://docs.opencv.org/trunk/d9/d0c/group__calib3d.html
282 intrinsic parameters are (fx, fy, cx, cy). fx,fy are the focal lengths expressed in pixel units. (cx,cy) is a principal point that is usually at the image center. These depend on the image resolution.
283 distortion coefficients are a vector (k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τx,τy]]]]) of 4, 5, 8, 12 or 14 elements. These are independent of image resolution.
284
285 OpenCV 3 Fisheye / Matlab Camera Calibration Toolbox Fisheye / Kannala-Brandt:
286 - A Generic Camera Model and Calibration Method for Conventional, Wide-Angle, and Fish-Eye Lenses <http://www.ee.oulu.fi/~jkannala/publications/tpami2006.pdf>
287 The "undocumented" fisheye model contained in the calibration toolbox follows the equidistance projection model described by equation (3) in this very nice paper. The distortion model follows equation (6), to the exception that k1=1 (otherwise indistinguishable from f).
288 - https://docs.opencv.org/trunk/db/d58/group__calib3d__fisheye.html
289 intrinsic parameters are (fx, fy, cx, cy). fx,fy are the focal lengths expressed in pixel units. (cx,cy) is a principal point that is usually at the image center. These depend on the image resolution.
290 distortion coefficients are (k1,k2,k3,k4): θd=θ(1+k1θ^2+k2θ^4+k3θ^6+k4θ^8) (θ is the angle of the incoming ray)
291 The distorted point coordinates are [x'; y'] where
292 x′=(θd/r)a, y′=(θd/r)b (r = sqrt((x/z)^2+(y/z)^2)
293 Finally, conversion into pixel coordinates: The final pixel coordinates vector [u; v] where:
294 u=fx(x′+αy′)+cx, v=fyy′+cy
295 - https://stackoverflow.com/questions/31089265/what-are-the-main-references-to-the-fish-eye-camera-model-in-opencv3-0-0dev
296 */
297
298 enum DistortionModelEnum
299 {
300 eDistortionModelNuke,
301 eDistortionModelPFBarrel,
302 eDistortionModel3DEClassic,
303 eDistortionModel3DEAnamorphic6,
304 eDistortionModel3DEFishEye8,
305 eDistortionModel3DEStandard,
306 eDistortionModel3DEAnamorphic4,
307 eDistortionModelPanoTools,
308 };
309
310
311 #define kParamDistortionDirection "direction"
312 #define kParamDistortionDirectionLabel "Direction", "Should the output corrspond to applying or to removing distortion."
313 #define kParamDistortionDirectionOptionDistort "Distort", "The output corresponds to applying distortion."
314 #define kParamDistortionDirectionOptionUndistort "Undistort", "The output corresponds to removing distortion."
315
316 enum DirectionEnum {
317 eDirectionDistort,
318 eDirectionUndistort,
319 };
320
321 #define kParamDistortionOutputMode "outputMode"
322 #define kParamDistortionOutputModeLabel "Output Mode", "Choice of the output, which may be either a distorted/undistorted image, or a distortion/undistortion STMap."
323 #define kParamDistortionOutputModeOptionImage "Image", "The output is the distorted/undistorted Source."
324 #define kParamDistortionOutputModeOptionSTMap "STMap", "The output is a distortion/undistortion STMap. It is recommended to insert a FrameHold node at the Source input so that the STMap is computed only once if the parameters are not animated."
325
326 enum OutputModeEnum {
327 eOutputModeImage,
328 eOutputModeSTMap,
329 };
330
331 #define kParamK1 "k1"
332 #define kParamK1Label "K1", "Nuke: First radial distortion coefficient (coefficient for r^2)."
333
334 #define kParamK2 "k2"
335 #define kParamK2Label "K2", "Nuke: Second radial distortion coefficient (coefficient for r^4)."
336
337 #if 0
338 #define kParamK3 "k3"
339 #define kParamK3Label "K3", "Nuke: Third radial distortion coefficient (coefficient for r^6)."
340
341 #define kParamP1 "p1"
342 #define kParamP1Label "P1", "Nuke: First tangential distortion coefficient."
343
344 #define kParamP2 "p2"
345 #define kParamP2Label "P2", "Nuke: Second tangential distortion coefficient."
346 #endif
347
348 #define kParamCenter "center"
349 #define kParamCenterLabel "Center", "Nuke: Offset of the distortion center from the image center."
350
351 #define kParamSqueeze "anamorphicSqueeze"
352 #define kParamSqueezeLabel "Squeeze", "Nuke: Anamorphic squeeze (only for anamorphic lens)."
353
354 #define kParamAsymmetric "asymmetricDistortion"
355 #define kParamAsymmetricLabel "Asymmetric", "Nuke: Asymmetric distortion (only for anamorphic lens)."
356
357 #define kParamPFFile "pfFile"
358 #define kParamPFFileLabel "File", "The location of the PFBarrel .pfb file to use. Keyframes are set if present in the file."
359
360 #define kParamPFFileReload "pfReload"
361 #define kParamPFFileReloadLabel "Reload", "Click to reload the PFBarrel file"
362
363 #define kParamPFC3 "pfC3"
364 #define kParamPFC3Label "C3", "PFBarrel: Low order radial distortion coefficient."
365
366 #define kParamPFC5 "pfC5"
367 #define kParamPFC5Label "C5", "PFBarrel: Low order radial distortion coefficient."
368
369 #define kParamPFSqueeze "pfSqueeze"
370 #define kParamPFSqueezeLabel "Squeeze", "PFBarrel: Anamorphic squeeze (only for anamorphic lens)."
371
372 #define kParamPFP "pfP"
373 #define kParamPFPLabel "Center", "PFBarrel: The distortion center of the lens (specified as a factor rather than a pixel value)"
374
375 // 3D Equalizer 4
376
377 //Double_knob(callback,&_xa_fov_unit,DD::Image::IRange(0.0,1.0),"field_of_view_xa_unit","fov left [unit coord]");
378 #define kParam3DE4_xa_fov_unit "tde4_field_of_view_xa_unit"
379 #define kParam3DE4_xa_fov_unitLabel "fov left [unit coord]", "3DE4: Field of view."
380
381 //Double_knob(callback,&_ya_fov_unit,DD::Image::IRange(0.0,1.0),"field_of_view_ya_unit","fov bottom [unit coord]");
382 #define kParam3DE4_ya_fov_unit "tde4_field_of_view_ya_unit"
383 #define kParam3DE4_ya_fov_unitLabel "fov bottom [unit coord]", "3DE4: Field of view."
384
385 //Double_knob(callback,&_xb_fov_unit,DD::Image::IRange(0.0,1.0),"field_of_view_xb_unit","fov right [unit coord]");
386 #define kParam3DE4_xb_fov_unit "tde4_field_of_view_xb_unit"
387 #define kParam3DE4_xb_fov_unitLabel "fov right [unit coord]", "3DE4: Field of view."
388
389 //Double_knob(callback,&_yb_fov_unit,DD::Image::IRange(0.0,1.0),"field_of_view_yb_unit","fov top [unit coord]");
390 #define kParam3DE4_yb_fov_unit "tde4_field_of_view_yb_unit"
391 #define kParam3DE4_yb_fov_unitLabel "fov top [unit coord]", "3DE4: Field of view."
392
393 // First the seven built-in parameters, in this order.
394
395 //fl_cm: Double_knob(callback,&_values_double[i_par_double++],DD::Image::IRange(0.5,50.0),"tde4_focal_length_cm","tde4 focal length [cm]");
396 #define kParam3DE4_focal_length_cm "tde4_focal_length_cm"
397 #define kParam3DE4_focal_length_cmLabel "tde4 focal length [cm]", "3DE4: Focal length."
398
399 //fd_cm: Double_knob(callback,&_values_double[i_par_double++],DD::Image::IRange(10.0,1000.0),"tde4_custom_focus_distance_cm","tde4 focus distance [cm]");
400 #define kParam3DE4_custom_focus_distance_cm "tde4_custom_focus_distance_cm"
401 #define kParam3DE4_custom_focus_distance_cmLabel "tde4 focus distance [cm]", "3DE4: Focus distance."
402
403 //w_fb_cm: Double_knob(callback,&_values_double[i_par_double++],DD::Image::IRange(.1,10.0),"tde4_filmback_width_cm","tde4 filmback width [cm]");
404 #define kParam3DE4_filmback_width_cm "tde4_filmback_width_cm"
405 #define kParam3DE4_filmback_width_cmLabel "tde4 filmback width [cm]", "3DE4: Filmback width."
406
407 //h_fb_cm: Double_knob(callback,&_values_double[i_par_double++],DD::Image::IRange(.1,10.0),"tde4_filmback_height_cm","tde4 filmback height [cm]");
408 #define kParam3DE4_filmback_height_cm "tde4_filmback_height_cm"
409 #define kParam3DE4_filmback_height_cmLabel "tde4 filmback height [cm]", "3DE4: Filmback height."
410
411 //x_lco_cm: Double_knob(callback,&_values_double[i_par_double++],DD::Image::IRange(-5.0,5.0),"tde4_lens_center_offset_x_cm","tde4 lens center offset x [cm]");
412 #define kParam3DE4_lens_center_offset_x_cm "tde4_lens_center_offset_x_cm"
413 #define kParam3DE4_lens_center_offset_x_cmLabel "tde4 lens center offset x [cm]", "3DE4: Lens center horizontal offset."
414
415 //y_lco_cm: Double_knob(callback,&_values_double[i_par_double++],DD::Image::IRange(-5.0,5.0),"tde4_lens_center_offset_y_cm","tde4 lens center offset y [cm]");
416 #define kParam3DE4_lens_center_offset_y_cm "tde4_lens_center_offset_y_cm"
417 #define kParam3DE4_lens_center_offset_y_cmLabel "tde4 lens center offset y [cm]", "3DE4: Lens center vertical offset."
418
419 //pa: Double_knob(callback,&_values_double[i_par_double++],DD::Image::IRange(0.25,4.0),"tde4_pixel_aspect","tde4 pixel aspect");
420 #define kParam3DE4_pixel_aspect "tde4_pixel_aspect"
421 #define kParam3DE4_pixel_aspectLabel "tde4 pixel aspect", "3DE4: Pixel aspect ratio."
422
423
424 // 3DE_Classic_LD_Model
425 //"Distortion", -0.5 .. 0.5
426 #define kParam3DEDistortion "tde4_Distortion"
427 #define kParam3DEDistortionLabel "Distortion", "3DE Classic: Distortion."
428 //"Anamorphic Squeeze", 0.25 ... 4.
429 #define kParam3DEAnamorphicSqueeze "tde4_Anamorphic_Squeeze"
430 #define kParam3DEAnamorphicSqueezeLabel "Anamorphic Squeeze", "3DE Classic: Anamorphic Squeeze."
431
432 //"Curvature X", -0.5 .. 0.5
433 #define kParam3DECurvatureX "tde4_Curvature_X"
434 #define kParam3DECurvatureXLabel "Curvature X", "3DE Classic: Curvature X."
435
436 //"Curvature Y", -0.5 .. 0.5
437 #define kParam3DECurvatureY "tde4_Curvature_Y"
438 #define kParam3DECurvatureYLabel "Curvature Y", "3DE Classic: Curvature Y."
439
440 //"Quartic Distortion" -0.5 .. 0.5
441 #define kParam3DEQuarticDistortion "tde4_Quartic_Distortion"
442 #define kParam3DEQuarticDistortionLabel "Quartic Distortion", "3DE Classic: Quartic Distortion."
443
444 // 3DE4_Radial_Standard_Degree_4
445 #define kParam3DEDistortionDegree2 "tde4_Distortion_Degree_2"
446 #define kParam3DEDistortionDegree2Label "Distortion - Degree 2", "3DE Standard and Fisheye: Distortion."
447 #define kParam3DEUDegree2 "tde4_U_Degree_2"
448 #define kParam3DEUDegree2Label "U - Degree 2", "3DE Standard: U - Degree 2."
449 #define kParam3DEVDegree2 "tde4_V_Degree_2"
450 #define kParam3DEVDegree2Label "V - Degree 2", "3DE Standard: V - Degree 2."
451 #define kParam3DEQuarticDistortionDegree4 "tde4_Quartic_Distortion_Degree_4"
452 #define kParam3DEQuarticDistortionDegree4Label "Quartic Distortion - Degree 4", "3DE Standard and Fisheye: Quartic Distortion - Degree 4."
453 #define kParam3DEUDegree4 "tde4_U_Degree_4"
454 #define kParam3DEUDegree4Label "U - Degree 4", "3DE Standard: U - Degree 4."
455 #define kParam3DEVDegree4 "tde4_V_Degree_4"
456 #define kParam3DEVDegree4Label "V - Degree 4", "3DE Standard: V - Degree 4."
457 #define kParam3DEPhiCylindricDirection "tde4_Phi_Cylindric_Direction"
458 #define kParam3DEPhiCylindricDirectionLabel "Phi - Cylindric Direction", "3DE Standard: Phi - Cylindric Direction."
459 #define kParam3DEBCylindricBending "tde4_B_Cylindric_Bending"
460 #define kParam3DEBCylindricBendingLabel "B - Cylindric Bending", "3DE Standard: B - Cylindric Bending."
461
462 // 3DE4_Anamorphic_Standard_Degree_4
463 #define kParam3DECx02Degree2 "tde4_Cx02_Degree_2"
464 #define kParam3DECx02Degree2Label "Cx02 - Degree 2", "3DE Anamorphic 4 and 6: Cx02 - Degree 2."
465 #define kParam3DECy02Degree2 "tde4_Cy02_Degree_2"
466 #define kParam3DECy02Degree2Label "Cy02 - Degree 2", "3DE Anamorphic 4 and 6: Cy02 - Degree 2."
467 #define kParam3DECx22Degree2 "tde4_Cx22_Degree_2"
468 #define kParam3DECx22Degree2Label "Cx22 - Degree 2", "3DE Anamorphic 4 and 6: Cx22 - Degree 2."
469 #define kParam3DECy22Degree2 "tde4_Cy22_Degree_2"
470 #define kParam3DECy22Degree2Label "Cy22 - Degree 2", "3DE Anamorphic 4 and 6: Cy22 - Degree 2."
471 #define kParam3DECx04Degree4 "tde4_Cx04_Degree_4"
472 #define kParam3DECx04Degree4Label "Cx04 - Degree 4", "3DE Anamorphic 4 and 6: Cx04 - Degree 4."
473 #define kParam3DECy04Degree4 "tde4_Cy04_Degree_4"
474 #define kParam3DECy04Degree4Label "Cy04 - Degree 4", "3DE Anamorphic 4 and 6: Cy04 - Degree 4."
475 #define kParam3DECx24Degree4 "tde4_Cx24_Degree_4"
476 #define kParam3DECx24Degree4Label "Cx24 - Degree 4", "3DE Anamorphic 4 and 6: Cx24 - Degree 4."
477 #define kParam3DECy24Degree4 "tde4_Cy24_Degree_4"
478 #define kParam3DECy24Degree4Label "Cy24 - Degree 4", "3DE Anamorphic 4 and 6: Cy24 - Degree 4."
479 #define kParam3DECx44Degree4 "tde4_Cx44_Degree_4"
480 #define kParam3DECx44Degree4Label "Cx44 - Degree 4", "3DE Anamorphic 4 and 6: Cx44 - Degree 4."
481 #define kParam3DECy44Degree4 "tde4_Cy44_Degree_4"
482 #define kParam3DECy44Degree4Label "Cy44 - Degree 4", "3DE Anamorphic 4 and 6: Cy44 - Degree 4."
483 #define kParam3DELensRotation "tde4_Lens_Rotation"
484 #define kParam3DELensRotationLabel "Lens Rotation 4", "3DE Anamorphic 4: Lens Rotation 4."
485 #define kParam3DESqueezeX "tde4_Squeeze_X"
486 #define kParam3DESqueezeXLabel "Squeeze-X", "3DE Anamorphic 4: Squeeze-X."
487 #define kParam3DESqueezeY "tde4_Squeeze_Y"
488 #define kParam3DESqueezeYLabel "Squeeze-Y", "3DE Anamorphic 4: Squeeze-Y."
489
490 // 3DE4_Anamorphic_Degree_6
491 #define kParam3DECx06Degree6 "tde4_Cx06_Degree_6"
492 #define kParam3DECx06Degree6Label "Cx06 - Degree 6", "3DE Anamorphic 6: Cx06 - Degree 6."
493 #define kParam3DECy06Degree6 "tde4_Cy06_Degree_6"
494 #define kParam3DECy06Degree6Label "Cy06 - Degree 6", "3DE Anamorphic 6: Cy06 - Degree 6."
495 #define kParam3DECx26Degree6 "tde4_Cx26_Degree_6"
496 #define kParam3DECx26Degree6Label "Cx26 - Degree 6", "3DE Anamorphic 6: Cx26 - Degree 6."
497 #define kParam3DECy26Degree6 "tde4_Cy26_Degree_6"
498 #define kParam3DECy26Degree6Label "Cy26 - Degree 6", "3DE Anamorphic 6: Cy26 - Degree 6."
499 #define kParam3DECx46Degree6 "tde4_Cx46_Degree_6"
500 #define kParam3DECx46Degree6Label "Cx46 - Degree 6", "3DE Anamorphic 6: Cx46 - Degree 6."
501 #define kParam3DECy46Degree6 "tde4_Cy46_Degree_6"
502 #define kParam3DECy46Degree6Label "Cy46 - Degree 6", "3DE Anamorphic 6: Cy46 - Degree 6."
503 #define kParam3DECx66Degree6 "tde4_Cx66_Degree_6"
504 #define kParam3DECx66Degree6Label "Cx66 - Degree 6", "3DE Anamorphic 6: Cx66 - Degree 6."
505 #define kParam3DECy66Degree6 "tde4_Cy66_Degree_6"
506 #define kParam3DECy66Degree6Label "Cy66 - Degree 6", "3DE Anamorphic 6: Cy66 - Degree 6."
507
508 // 3DE4_Radial_Fisheye_Degree_8
509 #define kParam3DEDegree6 "tde4_Degree_6"
510 #define kParam3DEDegree6Label "Degree 6", "3DE Fisheye: Degree 6."
511 #define kParam3DEDegree8 "tde4_Degree_8"
512 #define kParam3DEDegree8Label "Degree 8", "3DE Fisheye: Degree 8."
513
514 // PanoTools
515 #define kParamPanoToolsA "pt_a"
516 #define kParamPanoToolsALabel "a", "PanoTools: Radial lens distortion 3rd degree coefficient a."
517 #define kParamPanoToolsB "pt_b"
518 #define kParamPanoToolsBLabel "b", "PanoTools: Radial lens distortion 2nd degree coefficient b."
519 #define kParamPanoToolsC "pt_c"
520 #define kParamPanoToolsCLabel "c", "PanoTools: Radial lens distortion 1st degree coefficient c."
521 #define kParamPanoToolsD "pt_d"
522 #define kParamPanoToolsDLabel "d", "PanoTools: Horizontal lens shift (in pixels)."
523 #define kParamPanoToolsE "pt_e"
524 #define kParamPanoToolsELabel "e", "PanoTools: Vertical lens shift (in pixels)."
525 #define kParamPanoToolsG "pt_g"
526 #define kParamPanoToolsGLabel "g", "PanoTools: Vertical lens shear (in pixels). Use to remove slight misalignment of the line scanner relative to the film transport."
527 #define kParamPanoToolsT "pt_t"
528 #define kParamPanoToolsTLabel "t", "PanoTools: Horizontal lens shear (in pixels)."
529
530 #define kParamCropToFormat "cropToFormat"
531 #define kParamCropToFormatLabel "Crop To Format"
532 #define kParamCropToFormatHint "If the source is inside the format and the effect extends it outside of the format, crop it to avoid unnecessary calculations. To avoid unwanted crops, only the borders that were inside of the format in the source clip will be cropped."
533
534
535
536 // PFBarrel file reader
537
538 // Copyright (C) 2011 The Pixel Farm Ltd
539 // The class that implements compositor-neutral functionality
540
541 class PFBarrelCommon
542 {
543
544 public:
545
546 class FileReader
547 {
548
549 public:
550
551 FileReader(const std::string &filename);
552 ~FileReader();
553
554 std::string readRawLine(void);
555 std::string readLine(void);
556 double readDouble(void);
557 int readInt(void);
558
559 void dump(void);
560
561 FILE *f_;
562 std::string error_;
563
564 int version_;
565 int orig_w_, orig_h_;
566 double orig_pa_;
567 int undist_w_, undist_h_;
568 int model_;
569 double squeeze_;
570 int nkeys_;
571 std::vector<int> frame_;
572 std::vector<double> c3_;
573 std::vector<double> c5_;
574 std::vector<double> xp_;
575 std::vector<double> yp_;
576 };
577 };
578
FileReader(const std::string & filename)579 PFBarrelCommon::FileReader::FileReader(const std::string &filename)
580 {
581 std::string ln;
582
583 version_= -1;
584 error_= "";
585 orig_w_= -1;
586 orig_h_= -1;
587 orig_pa_ = 1.;
588 undist_w_= -1;
589 undist_h_= -1;
590 model_= -1;
591 squeeze_= -1;
592 nkeys_= 0;
593
594 f_= std::fopen(filename.c_str(), "r");
595
596 if (!f_) {
597 error_= "Failed to open file";
598 return;
599 }
600
601 ln= readRawLine();
602 if (ln=="#PFBarrel 2011 v1") {
603 version_= 1;
604 } else if (ln=="#PFBarrel 2011 v2") {
605 version_= 2;
606 } else {
607 error_= "Bad header";
608 return;
609 }
610
611 orig_w_= readInt(); if (error_!="") return;
612 orig_h_= readInt(); if (error_!="") return;
613
614 if (version_==2) {
615 orig_pa_= readDouble(); if (error_!="") return;
616 } else {
617 orig_pa_= 1.0;
618 }
619
620 undist_w_= readInt(); if (error_!="") return;
621 undist_h_= readInt(); if (error_!="") return;
622
623 ln= readLine(); if (error_!="") return;
624
625 if (ln=="Low Order") {
626 model_= 0;
627 } else if (ln=="High Order") {
628 model_= 1;
629 } else {
630 error_= "Bad model";
631 return;
632 }
633
634 squeeze_= readDouble(); if (error_!="") return;
635 nkeys_= readInt(); if (error_!="") return;
636
637 for (int i=0; i<nkeys_; i++) {
638 frame_.push_back(readInt()); if (error_!="") return;
639 c3_.push_back(readDouble()); if (error_!="") return;
640
641 double c5= readDouble(); if (error_!="") return;
642 if (model_==0)
643 c5_.push_back(0.0);
644 else
645 c5_.push_back(c5);
646
647 xp_.push_back(readDouble()); if (error_!="") return;
648 yp_.push_back(readDouble()); if (error_!="") return;
649 }
650 }
651
652
653
~FileReader()654 PFBarrelCommon::FileReader::~FileReader()
655 {
656 if (f_) {
657 std::fclose(f_);
658 f_ = NULL;
659 }
660 }
661
662
663
readLine(void)664 std::string PFBarrelCommon::FileReader::readLine(void)
665 {
666 std::string rv;
667 while (error_=="" && (rv=="" || rv[0]=='#')) {
668 rv= readRawLine();
669 }
670
671 return rv;
672 }
673
674
675
readDouble(void)676 double PFBarrelCommon::FileReader::readDouble(void)
677 {
678 return std::atof(readLine().c_str());
679 }
680
681
682
readInt(void)683 int PFBarrelCommon::FileReader::readInt(void)
684 {
685 return std::atoi(readLine().c_str());
686 }
687
688
689
readRawLine(void)690 std::string PFBarrelCommon::FileReader::readRawLine(void)
691 {
692 std::string rv;
693
694 char buf[512];
695
696 char* s = std::fgets(buf, sizeof(buf), f_);
697 if (s != NULL) {
698 rv= s;
699 rv= rv.erase(rv.length()-1);
700 } else {
701 error_= "Parse error";
702 }
703
704 return rv;
705 }
706
707
708 #ifdef DEBUG
dump(void)709 void PFBarrelCommon::FileReader::dump(void)
710 {
711 std::printf("VERSION [%i]\n", version_);
712 std::printf("ERROR [%s]\n", error_.c_str());
713 std::printf("ORIG WH %i %i PA %f\n", orig_w_, orig_h_, orig_pa_);
714 std::printf("UNDIST WH %i %i\n", undist_w_, undist_h_);
715 std::printf("MODEL %i\n", model_);
716 std::printf("SQUEEZE %f\n", squeeze_);
717 std::printf("NKEYS %i\n", nkeys_);
718
719 for (int i = 0; i < nkeys_; i++) {
720 std::printf("KEY %i FRAME %i\n", i, frame_[i]);
721 std::printf("KEY %i C3 %f\n", i, c3_[i]);
722 std::printf("KEY %i C5 %f\n", i, c5_[i]);
723 std::printf("KEY %i XP %f\n", i, xp_[i]);
724 std::printf("KEY %i YP %f\n", i, yp_[i]);
725 }
726 }
727 #endif
728
729
730
731 static bool gIsMultiPlaneV1;
732 static bool gIsMultiPlaneV2;
733
734 struct InputPlaneChannel
735 {
736 Image* img;
737 int channelIndex;
738 bool fillZero;
739
InputPlaneChannelInputPlaneChannel740 InputPlaneChannel() : img(NULL), channelIndex(-1), fillZero(true) {}
741 };
742
743 class DistortionProcessorBase
744 : public ImageProcessor
745 {
746 protected:
747 const Image *_srcImg;
748 const Image *_maskImg;
749 bool _processR;
750 bool _processG;
751 bool _processB;
752 bool _processA;
753 bool _transformIsIdentity;
754 Matrix3x3 _srcTransformInverse;
755 OfxRectD _format;
756 std::vector<InputPlaneChannel> _planeChannels;
757 bool _unpremultUV;
758 double _uOffset;
759 double _vOffset;
760 double _uScale;
761 double _vScale;
762 WrapEnum _uWrap;
763 WrapEnum _vWrap;
764 OfxPointD _renderScale;
765 const DistortionModel* _distortionModel;
766 DirectionEnum _direction;
767 OutputModeEnum _outputMode;
768 bool _blackOutside;
769 bool _doMasking;
770 double _mix;
771 bool _maskInvert;
772
773 public:
774
DistortionProcessorBase(ImageEffect & instance)775 DistortionProcessorBase(ImageEffect &instance)
776 : ImageProcessor(instance)
777 , _srcImg(NULL)
778 , _maskImg(NULL)
779 , _processR(true)
780 , _processG(true)
781 , _processB(true)
782 , _processA(false)
783 , _transformIsIdentity(true)
784 , _srcTransformInverse()
785 , _planeChannels()
786 , _unpremultUV(true)
787 , _uOffset(0.)
788 , _vOffset(0.)
789 , _uScale(1.)
790 , _vScale(1.)
791 , _uWrap(eWrapClamp)
792 , _vWrap(eWrapClamp)
793 , _distortionModel(NULL)
794 , _direction(eDirectionDistort)
795 , _outputMode(eOutputModeImage)
796 , _blackOutside(false)
797 , _doMasking(false)
798 , _mix(1.)
799 , _maskInvert(false)
800 {
801 _renderScale.x = _renderScale.y = 1.;
802 _format.x1 = _format.y1 = 0.;
803 _format.x2 = _format.y2 = 1.;
804 }
805
setSrcImgs(const Image * src)806 void setSrcImgs(const Image *src) {_srcImg = src; }
807
setMaskImg(const Image * v,bool maskInvert)808 void setMaskImg(const Image *v,
809 bool maskInvert) { _maskImg = v; _maskInvert = maskInvert; }
810
doMasking(bool v)811 void doMasking(bool v) {_doMasking = v; }
812
setValues(bool processR,bool processG,bool processB,bool processA,bool transformIsIdentity,const Matrix3x3 & srcTransformInverse,const OfxRectD & format,const std::vector<InputPlaneChannel> & planeChannels,bool unpremultUV,double uOffset,double vOffset,double uScale,double vScale,WrapEnum uWrap,WrapEnum vWrap,const OfxPointD & renderScale,const DistortionModel * distortionModel,DirectionEnum direction,OutputModeEnum outputMode,bool blackOutside,double mix)813 void setValues(bool processR,
814 bool processG,
815 bool processB,
816 bool processA,
817 bool transformIsIdentity,
818 const Matrix3x3 &srcTransformInverse,
819 const OfxRectD& format,
820 const std::vector<InputPlaneChannel>& planeChannels,
821 bool unpremultUV,
822 double uOffset,
823 double vOffset,
824 double uScale,
825 double vScale,
826 WrapEnum uWrap,
827 WrapEnum vWrap,
828 const OfxPointD& renderScale,
829 const DistortionModel* distortionModel,
830 DirectionEnum direction,
831 OutputModeEnum outputMode,
832 bool blackOutside,
833 double mix)
834 {
835 _processR = processR;
836 _processG = processG;
837 _processB = processB;
838 _processA = processA;
839 _transformIsIdentity = transformIsIdentity;
840 _srcTransformInverse = srcTransformInverse;
841 _format = format;
842 _planeChannels = planeChannels;
843 _unpremultUV = unpremultUV;
844 _uOffset = uOffset;
845 _vOffset = vOffset;
846 _uScale = uScale;
847 _vScale = vScale;
848 _uWrap = uWrap;
849 _vWrap = vWrap;
850 _renderScale = renderScale;
851 _distortionModel = distortionModel;
852 _direction = direction;
853 _outputMode = outputMode;
854 _blackOutside = blackOutside;
855 _mix = mix;
856 }
857
858 private:
859 };
860
861
862
863
864 // The "filter" and "clamp" template parameters allow filter-specific optimization
865 // by the compiler, using the same generic code for all filters.
866 template <class PIX, int nComponents, int maxValue, DistortionPluginEnum plugin, FilterEnum filter, bool clamp>
867 class DistortionProcessor
868 : public DistortionProcessorBase
869 {
870 public:
DistortionProcessor(ImageEffect & instance)871 DistortionProcessor(ImageEffect &instance)
872 : DistortionProcessorBase(instance)
873 {
874 }
875
876 private:
877
878
wrap(double x,WrapEnum wrap)879 static inline double wrap(double x,
880 WrapEnum wrap)
881 {
882 switch (wrap) {
883 default:
884 case eWrapClamp:
885
886 return x;
887 case eWrapRepeat:
888
889 return x - std::floor(x);
890 case eWrapMirror: {
891 double x2 = x / 2 - std::floor(x / 2);
892
893 return (x2 <= 0.5) ? (2 * x2) : (2 - 2 * x2);
894 }
895 }
896 }
897
getPix(unsigned channel,int x,int y)898 const PIX * getPix(unsigned channel,
899 int x,
900 int y)
901 {
902 return (const PIX *) (_planeChannels[channel].img ? _planeChannels[channel].img->getPixelAddress(x, y) : 0);
903 }
904
getVal(unsigned channel,const PIX * p,const PIX * pp)905 double getVal(unsigned channel,
906 const PIX* p,
907 const PIX* pp)
908 {
909 if (!_planeChannels[channel].img) {
910 return _planeChannels[channel].fillZero ? 0. : 1.;
911 }
912 if (!p) {
913 return pp ? pp[_planeChannels[channel].channelIndex] : 0.;
914 }
915
916 return p[_planeChannels[channel].channelIndex];
917 }
918
unpremult(double a,double * u,double * v)919 void unpremult(double a,
920 double *u,
921 double *v)
922 {
923 if ( _unpremultUV && (a != 0.) ) {
924 *u /= a;
925 *v /= a;
926 }
927 }
928
929 void multiThreadProcessImages(OfxRectI procWindow);
930 };
931
932 template <class PIX, int nComponents, int maxValue, DistortionPluginEnum plugin, FilterEnum filter, bool clamp>
933 void
multiThreadProcessImages(OfxRectI procWindow)934 DistortionProcessor<PIX, nComponents, maxValue, plugin, filter, clamp>::multiThreadProcessImages(OfxRectI procWindow)
935 {
936 assert(nComponents == 1 || nComponents == 3 || nComponents == 4);
937 assert(_dstImg);
938 assert(!(plugin == eDistortionPluginSTMap || plugin == eDistortionPluginIDistort) || _planeChannels.size() == 3);
939
940 // required for STMap and LensDistortion
941 //if (plugin == eDistortionPluginSTMap || _outputMode == eOutputModeSTMap) {
942 int srcx1 = _format.x1;
943 int srcx2 = _format.x2;
944 int srcy1 = _format.y1;
945 int srcy2 = _format.y2;
946 //}
947 float tmpPix[4];
948 for (int y = procWindow.y1; y < procWindow.y2; y++) {
949 if ( _effect.abort() ) {
950 break;
951 }
952
953 PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y);
954
955 for (int x = procWindow.x1; x < procWindow.x2; x++) {
956 double sx, sy, sxx, sxy, syx, syy; // the source pixel coordinates and their derivatives
957 double a = 1.;
958
959 switch (plugin) {
960 case eDistortionPluginSTMap:
961 case eDistortionPluginIDistort: {
962 const PIX *uPix = getPix(0, x, y );
963 const PIX *uPix_xn = getPix(0, x + 1, y );
964 const PIX *uPix_xp = getPix(0, x - 1, y );
965 const PIX *uPix_yn = getPix(0, x, y + 1);
966 const PIX *uPix_yp = getPix(0, x, y - 1);
967 const PIX *vPix, *vPix_xn, *vPix_xp, *vPix_yn, *vPix_yp;
968 if (_planeChannels[1].img == _planeChannels[0].img) {
969 vPix = uPix;
970 vPix_xn = uPix_xn;
971 vPix_xp = uPix_xp;
972 vPix_yn = uPix_yn;
973 vPix_yp = uPix_yp;
974 } else {
975 vPix = getPix(1, x, y );
976 vPix_xn = getPix(1, x + 1, y );
977 vPix_xp = getPix(1, x - 1, y );
978 vPix_yn = getPix(1, x, y + 1);
979 vPix_yp = getPix(1, x, y - 1);
980 }
981 const PIX *aPix, *aPix_xn, *aPix_xp, *aPix_yn, *aPix_yp;
982 if (_planeChannels[2].img == _planeChannels[0].img) {
983 aPix = uPix;
984 aPix_xn = uPix_xn;
985 aPix_xp = uPix_xp;
986 aPix_yn = uPix_yn;
987 aPix_yp = uPix_yp;
988 } else if (_planeChannels[2].img == _planeChannels[1].img) {
989 aPix = vPix;
990 aPix_xn = vPix_xn;
991 aPix_xp = vPix_xp;
992 aPix_yn = vPix_yn;
993 aPix_yp = vPix_yp;
994 } else {
995 aPix = getPix(2, x, y );
996 aPix_xn = getPix(2, x + 1, y );
997 aPix_xp = getPix(2, x - 1, y );
998 aPix_yn = getPix(2, x, y + 1);
999 aPix_yp = getPix(2, x, y - 1);
1000 }
1001 // compute gradients before wrapping
1002 double u = getVal(0, uPix, NULL);
1003 double v = getVal(1, vPix, NULL);
1004 a = getVal(2, aPix, NULL);
1005 unpremult(a, &u, &v);
1006
1007 double ux, uy, vx, vy;
1008 {
1009 double u_xn = getVal(0, uPix_xn, uPix);
1010 double u_xp = getVal(0, uPix_xp, uPix);
1011 double u_yn = getVal(0, uPix_yn, uPix);
1012 double u_yp = getVal(0, uPix_yp, uPix);
1013 double v_xn = getVal(1, vPix_xn, vPix);
1014 double v_xp = getVal(1, vPix_xp, vPix);
1015 double v_yn = getVal(1, vPix_yn, vPix);
1016 double v_yp = getVal(1, vPix_yp, vPix);
1017 if (_unpremultUV) {
1018 unpremult(getVal(2, aPix_xn, aPix), &u_xn, &v_xn);
1019 unpremult(getVal(2, aPix_xp, aPix), &u_xp, &v_xp);
1020 unpremult(getVal(2, aPix_yn, aPix), &u_yn, &v_yn);
1021 unpremult(getVal(2, aPix_yp, aPix), &u_yp, &v_yp);
1022 }
1023 ux = (u_xn - u_xp) / 2.;
1024 vx = (v_xn - v_xp) / 2.;
1025 uy = (u_yn - u_yp) / 2.;
1026 vy = (v_yn - v_yp) / 2.;
1027 }
1028 u = (u - _uOffset) * _uScale;
1029 ux *= _uScale;
1030 uy *= _uScale;
1031 v = (v - _vOffset) * _vScale;
1032 vx *= _vScale;
1033 vy *= _vScale;
1034 switch (plugin) {
1035 case eDistortionPluginSTMap:
1036 // wrap u and v
1037 u = wrap(u, _uWrap);
1038 v = wrap(v, _vWrap);
1039 sx = srcx1 + u * (srcx2 - srcx1);
1040 sy = srcy1 + v * (srcy2 - srcy1); // 0,0 corresponds to the lower left corner of the first pixel
1041 // scale gradients by (srcx2 - srcx1)
1042 if (filter != eFilterImpulse) {
1043 sxx = ux * (srcx2 - srcx1);
1044 sxy = uy * (srcx2 - srcx1);
1045 syx = vx * (srcy2 - srcy1);
1046 syy = vy * (srcy2 - srcy1);
1047 }
1048 break;
1049 case eDistortionPluginIDistort:
1050 // 0,0 corresponds to the lower left corner of the first pixel, so we have to add 0.5
1051 // (x,y) = (0,0) and (u,v) = (0,0) means to pick color at (0.5,0.5)
1052 sx = x + u + 0.5;
1053 sy = y + v + 0.5;
1054 if (filter != eFilterImpulse) {
1055 sxx = 1 + ux;
1056 sxy = uy;
1057 syx = vx;
1058 syy = 1 + vy;
1059 }
1060 break;
1061 default:
1062 assert(false);
1063 break;
1064 }
1065 break;
1066 }
1067 case eDistortionPluginLensDistortion: {
1068 assert(_distortionModel);
1069 // undistort/distort take pixel coordinates, do not divide by renderScale
1070 if (_direction == eDirectionDistort) {
1071 _distortionModel->undistort( x + 0.5,
1072 y + 0.5,
1073 &sx, &sy);
1074 } else {
1075 _distortionModel->distort( x + 0.5,
1076 y + 0.5,
1077 &sx, &sy);
1078 }
1079 sxx = 1; // TODO: Jacobian
1080 sxy = 0;
1081 syx = 0;
1082 syy = 1;
1083 break;
1084 }
1085 } // switch
1086 double Jxx = 1., Jxy = 0., Jyx = 0., Jyy = 1.;
1087 if (_transformIsIdentity) {
1088 if (filter != eFilterImpulse) {
1089 Jxx = sxx;
1090 Jxy = sxy;
1091 Jyx = syx;
1092 Jyy = syy;
1093 }
1094 } else {
1095 const Matrix3x3 & H = _srcTransformInverse;
1096 double transformedx = H(0,0) * sx + H(0,1) * sy + H(0,2);
1097 double transformedy = H(1,0) * sx + H(1,1) * sy + H(1,2);
1098 double transformedz = H(2,0) * sx + H(2,1) * sy + H(2,2);
1099 if (transformedz == 0) {
1100 sx = sy = std::numeric_limits<double>::infinity();
1101 } else {
1102 sx = transformedx / transformedz;
1103 sy = transformedy / transformedz;
1104 if (filter != eFilterImpulse) {
1105 Jxx = (H(0,0) * transformedz - transformedx * H(2,0)) / (transformedz * transformedz);
1106 Jxy = (H(0,1) * transformedz - transformedx * H(2,1)) / (transformedz * transformedz);
1107 Jyx = (H(1,0) * transformedz - transformedy * H(2,0)) / (transformedz * transformedz);
1108 Jyy = (H(1,1) * transformedz - transformedy * H(2,1)) / (transformedz * transformedz);
1109 }
1110 }
1111 }
1112
1113 if (_outputMode == eOutputModeSTMap) {
1114 // 0,0 corresponds to the lower left corner of the first pixel
1115 tmpPix[0] = (sx - srcx1) / (srcx2 - srcx1); // u
1116 tmpPix[1] = (sy - srcy1) / (srcy2 - srcy1); // v
1117 tmpPix[2] = 1.; // a
1118 tmpPix[3] = 1.; // be opaque
1119 } else {
1120 if (filter == eFilterImpulse) {
1121 ofxsFilterInterpolate2D<PIX, nComponents, filter, clamp>(sx, sy, _srcImg, _blackOutside, tmpPix);
1122 } else {
1123 ofxsFilterInterpolate2DSuper<PIX, nComponents, filter, clamp>(sx, sy, Jxx, Jxy, Jyx, Jyy, _srcImg, _blackOutside, tmpPix);
1124 }
1125 for (unsigned c = 0; c < nComponents; ++c) {
1126 tmpPix[c] *= a;
1127 }
1128 }
1129 ofxsMaskMix<PIX, nComponents, maxValue, true>(tmpPix, x, y, _srcImg, _doMasking, _maskImg, (float)_mix, _maskInvert, dstPix);
1130 // copy back original values from unprocessed channels
1131 if (nComponents == 1) {
1132 if (!_processA) {
1133 const PIX *srcPix = (const PIX *) (_srcImg ? _srcImg->getPixelAddress(x, y) : 0);
1134 dstPix[0] = srcPix ? srcPix[0] : PIX();
1135 }
1136 } else if ( (nComponents == 3) || (nComponents == 4) ) {
1137 const PIX *srcPix = 0;
1138 if ( !_processR || !_processG || !_processB || ( !_processA && (nComponents == 4) ) ) {
1139 srcPix = (const PIX *) (_srcImg ? _srcImg->getPixelAddress(x, y) : 0);
1140 }
1141 if (!_processR) {
1142 dstPix[0] = srcPix ? srcPix[0] : PIX();
1143 }
1144 if (!_processG) {
1145 dstPix[1] = srcPix ? srcPix[1] : PIX();
1146 }
1147 if (!_processB) {
1148 dstPix[2] = srcPix ? srcPix[2] : PIX();
1149 }
1150 if ( !_processA && (nComponents == 4) ) {
1151 dstPix[3] = srcPix ? srcPix[3] : PIX();
1152 }
1153 }
1154 // increment the dst pixel
1155 dstPix += nComponents;
1156 }
1157 }
1158 } // multiThreadProcessImages
1159
1160
1161 ////////////////////////////////////////////////////////////////////////////////
1162 /** @brief The plugin that does our work */
1163 class DistortionPlugin
1164 : public MultiPlane::MultiPlaneEffect
1165 {
1166 public:
1167 /** @brief ctor */
DistortionPlugin(OfxImageEffectHandle handle,int majorVersion,DistortionPluginEnum plugin)1168 DistortionPlugin(OfxImageEffectHandle handle,
1169 int majorVersion,
1170 DistortionPluginEnum plugin)
1171 : MultiPlane::MultiPlaneEffect(handle)
1172 , _majorVersion(majorVersion)
1173 , _dstClip(NULL)
1174 , _srcClip(NULL)
1175 , _uvClip(NULL)
1176 , _maskClip(NULL)
1177 , _processR(NULL)
1178 , _processG(NULL)
1179 , _processB(NULL)
1180 , _processA(NULL)
1181 , _uvChannels()
1182 , _unpremultUV(NULL)
1183 , _uvOffset(NULL)
1184 , _uvScale(NULL)
1185 , _uWrap(NULL)
1186 , _vWrap(NULL)
1187 , _extent(NULL)
1188 , _format(NULL)
1189 , _formatSize(NULL)
1190 , _formatPar(NULL)
1191 , _btmLeft(NULL)
1192 , _size(NULL)
1193 , _recenter(NULL)
1194 , _distortionModel(NULL)
1195 , _direction(NULL)
1196 , _outputMode(NULL)
1197 , _k1(NULL)
1198 , _k2(NULL)
1199 , _center(NULL)
1200 , _squeeze(NULL)
1201 , _asymmetric(NULL)
1202 , _pfFile(NULL)
1203 , _pfReload(NULL)
1204 , _pfC3(NULL)
1205 , _pfC5(NULL)
1206 , _pfSqueeze(NULL)
1207 , _pfP(NULL)
1208 , _xa_fov_unit(NULL)
1209 , _ya_fov_unit(NULL)
1210 , _xb_fov_unit(NULL)
1211 , _yb_fov_unit(NULL)
1212 , _fl_cm(NULL)
1213 , _fd_cm(NULL)
1214 , _w_fb_cm(NULL)
1215 , _h_fb_cm(NULL)
1216 , _x_lco_cm(NULL)
1217 , _y_lco_cm(NULL)
1218 , _pa(NULL)
1219 , _ld(NULL)
1220 , _sq(NULL)
1221 , _cx(NULL)
1222 , _cy(NULL)
1223 , _qu(NULL)
1224 , _c2(NULL)
1225 , _u1(NULL)
1226 , _v1(NULL)
1227 , _c4(NULL)
1228 , _u3(NULL)
1229 , _v3(NULL)
1230 , _phi(NULL)
1231 , _b(NULL)
1232 , _cx02(NULL)
1233 , _cy02(NULL)
1234 , _cx22(NULL)
1235 , _cy22(NULL)
1236 , _cx04(NULL)
1237 , _cy04(NULL)
1238 , _cx24(NULL)
1239 , _cy24(NULL)
1240 , _cx44(NULL)
1241 , _cy44(NULL)
1242 , _a4phi(NULL)
1243 , _a4sqx(NULL)
1244 , _a4sqy(NULL)
1245 , _cx06(NULL)
1246 , _cy06(NULL)
1247 , _cx26(NULL)
1248 , _cy26(NULL)
1249 , _cx46(NULL)
1250 , _cy46(NULL)
1251 , _cx66(NULL)
1252 , _cy66(NULL)
1253 , _c6(NULL)
1254 , _c8(NULL)
1255 , _pta(NULL)
1256 , _ptb(NULL)
1257 , _ptc(NULL)
1258 , _ptd(NULL)
1259 , _pte(NULL)
1260 , _ptg(NULL)
1261 , _ptt(NULL)
1262 , _filter(NULL)
1263 , _clamp(NULL)
1264 , _blackOutside(NULL)
1265 , _cropToFormat(NULL)
1266 , _mix(NULL)
1267 , _maskApply(NULL)
1268 , _maskInvert(NULL)
1269 , _plugin(plugin)
1270 {
1271 _dstClip = fetchClip(kOfxImageEffectOutputClipName);
1272 assert( _dstClip && (!_dstClip->isConnected() || _dstClip->getPixelComponents() == ePixelComponentRGB ||
1273 _dstClip->getPixelComponents() == ePixelComponentRGBA ||
1274 _dstClip->getPixelComponents() == ePixelComponentAlpha) );
1275 _srcClip = getContext() == eContextGenerator ? NULL : fetchClip(kOfxImageEffectSimpleSourceClipName);
1276 assert( (!_srcClip && getContext() == eContextGenerator) ||
1277 ( _srcClip && (!_srcClip->isConnected() || _srcClip->getPixelComponents() == ePixelComponentRGB ||
1278 _srcClip->getPixelComponents() == ePixelComponentRGBA ||
1279 _srcClip->getPixelComponents() == ePixelComponentAlpha) ) );
1280 if ( (_plugin == eDistortionPluginIDistort) || (_plugin == eDistortionPluginSTMap) ) {
1281 _uvClip = fetchClip(kClipUV);
1282 assert( _uvClip && (_uvClip->getPixelComponents() == ePixelComponentRGB || _uvClip->getPixelComponents() == ePixelComponentRGBA || _uvClip->getPixelComponents() == ePixelComponentAlpha) );
1283 }
1284 _maskClip = fetchClip(getContext() == eContextPaint ? "Brush" : "Mask");
1285 assert(!_maskClip || !_maskClip->isConnected() || _maskClip->getPixelComponents() == ePixelComponentAlpha);
1286 _processR = fetchBooleanParam(kParamProcessR);
1287 _processG = fetchBooleanParam(kParamProcessG);
1288 _processB = fetchBooleanParam(kParamProcessB);
1289 _processA = fetchBooleanParam(kParamProcessA);
1290 assert(_processR && _processG && _processB && _processA);
1291 if ( (plugin == eDistortionPluginIDistort) || (plugin == eDistortionPluginSTMap) ) {
1292 _uvChannels[0] = fetchChoiceParam(kParamChannelU);
1293 _uvChannels[1] = fetchChoiceParam(kParamChannelV);
1294 _uvChannels[2] = fetchChoiceParam(kParamChannelA);
1295 if (gIsMultiPlaneV1 || gIsMultiPlaneV2) {
1296
1297 {
1298 FetchChoiceParamOptions args = FetchChoiceParamOptions::createFetchChoiceParamOptionsForInputChannel();
1299 args.dependsClips.push_back(_uvClip);
1300 fetchDynamicMultiplaneChoiceParameter(kParamChannelU, args);
1301 }
1302 {
1303 FetchChoiceParamOptions args = FetchChoiceParamOptions::createFetchChoiceParamOptionsForInputChannel();
1304 args.dependsClips.push_back(_uvClip);
1305 fetchDynamicMultiplaneChoiceParameter(kParamChannelV, args);
1306 }
1307 {
1308 FetchChoiceParamOptions args = FetchChoiceParamOptions::createFetchChoiceParamOptionsForInputChannel();
1309 args.dependsClips.push_back(_uvClip);
1310 fetchDynamicMultiplaneChoiceParameter(kParamChannelA, args);
1311 }
1312
1313 onAllParametersFetched();
1314 }
1315 _unpremultUV = fetchBooleanParam(kParamChannelUnpremultUV);
1316 _uvOffset = fetchDouble2DParam(kParamUVOffset);
1317 _uvScale = fetchDouble2DParam(kParamUVScale);
1318 assert(_uvChannels[0] && _uvChannels[1] && _uvChannels[2] && _uvOffset && _uvScale);
1319 if (plugin == eDistortionPluginSTMap) {
1320 _uWrap = fetchChoiceParam(kParamWrapU);
1321 _vWrap = fetchChoiceParam(kParamWrapV);
1322 assert(_uWrap && _vWrap);
1323 }
1324 } else {
1325 _uvChannels[0] = _uvChannels[1] = _uvChannels[2] = NULL;
1326 }
1327
1328 /* if (gIsMultiPlane) {
1329 _outputLayer = fetchChoiceParam(kParamOutputChannels);
1330 _outputLayerStr = fetchStringParam(kParamOutputChannelsChoice);
1331 assert(_outputLayer && _outputLayerStr);
1332 }*/
1333 if (_plugin == eDistortionPluginLensDistortion) {
1334 _extent = fetchChoiceParam(kParamGeneratorExtent);
1335 _format = fetchChoiceParam(kParamGeneratorFormat);
1336 _formatSize = fetchInt2DParam(kParamGeneratorSize);
1337 _formatPar= fetchDoubleParam(kParamGeneratorPAR);
1338 _btmLeft = fetchDouble2DParam(kParamRectangleInteractBtmLeft);
1339 _size = fetchDouble2DParam(kParamRectangleInteractSize);
1340 _recenter = fetchPushButtonParam(kParamGeneratorCenter);
1341
1342 _distortionModel = fetchChoiceParam(kParamDistortionModel);
1343 _direction = fetchChoiceParam(kParamDistortionDirection);
1344 _outputMode = fetchChoiceParam(kParamDistortionOutputMode);
1345
1346 // Nuke
1347 _k1 = fetchDoubleParam(kParamK1);
1348 _k2 = fetchDoubleParam(kParamK2);
1349 _center = fetchDouble2DParam(kParamCenter);
1350 _squeeze = fetchDoubleParam(kParamSqueeze);
1351 _asymmetric = fetchDouble2DParam(kParamAsymmetric);
1352 assert(_k1 && _k2 && _center && _squeeze && _asymmetric);
1353
1354 // PFBarrel
1355 _pfFile = fetchStringParam(kParamPFFile);
1356 if ( paramExists(kParamPFFileReload) ) {
1357 _pfReload = fetchPushButtonParam(kParamPFFileReload);
1358 }
1359 _pfC3 = fetchDoubleParam(kParamPFC3);
1360 _pfC5 = fetchDoubleParam(kParamPFC5);
1361 _pfSqueeze = fetchDoubleParam(kParamPFSqueeze);
1362 _pfP = fetchDouble2DParam(kParamPFP);
1363
1364 // 3DEqualizer
1365 _xa_fov_unit = fetchDoubleParam(kParam3DE4_xa_fov_unit);
1366 _ya_fov_unit = fetchDoubleParam(kParam3DE4_ya_fov_unit);
1367 _xb_fov_unit = fetchDoubleParam(kParam3DE4_xb_fov_unit);
1368 _yb_fov_unit = fetchDoubleParam(kParam3DE4_yb_fov_unit);
1369 _fl_cm = fetchDoubleParam(kParam3DE4_focal_length_cm);
1370 _fd_cm = fetchDoubleParam(kParam3DE4_custom_focus_distance_cm);
1371 _w_fb_cm = fetchDoubleParam(kParam3DE4_filmback_width_cm);
1372 _h_fb_cm = fetchDoubleParam(kParam3DE4_filmback_height_cm);
1373 _x_lco_cm = fetchDoubleParam(kParam3DE4_lens_center_offset_x_cm);
1374 _y_lco_cm = fetchDoubleParam(kParam3DE4_lens_center_offset_y_cm);
1375 _pa = fetchDoubleParam(kParam3DE4_pixel_aspect);
1376
1377 // 3DEclassic
1378 _ld = fetchDoubleParam(kParam3DEDistortion);
1379 _sq = fetchDoubleParam(kParam3DEAnamorphicSqueeze);
1380 _cx = fetchDoubleParam(kParam3DECurvatureX);
1381 _cy = fetchDoubleParam(kParam3DECurvatureY);
1382 _qu = fetchDoubleParam(kParam3DEQuarticDistortion);
1383
1384 // 3DEStandard
1385 _c2 = fetchDoubleParam(kParam3DEDistortionDegree2);
1386 _u1 = fetchDoubleParam(kParam3DEUDegree2);
1387 _v1 = fetchDoubleParam(kParam3DEVDegree2);
1388 _c4 = fetchDoubleParam(kParam3DEQuarticDistortionDegree4);
1389 _u3 = fetchDoubleParam(kParam3DEUDegree4);
1390 _v3 = fetchDoubleParam(kParam3DEVDegree4);
1391 _phi = fetchDoubleParam(kParam3DEPhiCylindricDirection);
1392 _b = fetchDoubleParam(kParam3DEBCylindricBending);
1393
1394 // 3DEAnamorphic4
1395 _cx02 = fetchDoubleParam(kParam3DECx02Degree2);
1396 _cy02 = fetchDoubleParam(kParam3DECy02Degree2);
1397 _cx22 = fetchDoubleParam(kParam3DECx22Degree2);
1398 _cy22 = fetchDoubleParam(kParam3DECy22Degree2);
1399 _cx04 = fetchDoubleParam(kParam3DECx04Degree4);
1400 _cy04 = fetchDoubleParam(kParam3DECy04Degree4);
1401 _cx24 = fetchDoubleParam(kParam3DECx24Degree4);
1402 _cy24 = fetchDoubleParam(kParam3DECy24Degree4);
1403 _cx44 = fetchDoubleParam(kParam3DECx44Degree4);
1404 _cy44 = fetchDoubleParam(kParam3DECy44Degree4);
1405 _a4phi = fetchDoubleParam(kParam3DELensRotation);
1406 _a4sqx = fetchDoubleParam(kParam3DESqueezeX);
1407 _a4sqy = fetchDoubleParam(kParam3DESqueezeY);
1408
1409 // 3DEAnamorphic6
1410 _cx06 = fetchDoubleParam(kParam3DECx06Degree6);
1411 _cy06 = fetchDoubleParam(kParam3DECy06Degree6);
1412 _cx26 = fetchDoubleParam(kParam3DECx26Degree6);
1413 _cy26 = fetchDoubleParam(kParam3DECy26Degree6);
1414 _cx46 = fetchDoubleParam(kParam3DECx46Degree6);
1415 _cy46 = fetchDoubleParam(kParam3DECy46Degree6);
1416 _cx66 = fetchDoubleParam(kParam3DECx66Degree6);
1417 _cy66 = fetchDoubleParam(kParam3DECy66Degree6);
1418
1419 // 3DEFishEye8
1420 _c6 = fetchDoubleParam(kParam3DEDegree6);
1421 _c8 = fetchDoubleParam(kParam3DEDegree8);
1422
1423 // PanoTools
1424 _pta = fetchDoubleParam(kParamPanoToolsA);
1425 _ptb = fetchDoubleParam(kParamPanoToolsB);
1426 _ptc = fetchDoubleParam(kParamPanoToolsC);
1427 _ptd = fetchDoubleParam(kParamPanoToolsD);
1428 _pte = fetchDoubleParam(kParamPanoToolsE);
1429 _ptg = fetchDoubleParam(kParamPanoToolsG);
1430 _ptt = fetchDoubleParam(kParamPanoToolsT);
1431 assert(_pta && _ptb && _ptc && _ptd && _pte && _ptg && _ptt);
1432 }
1433 _filter = fetchChoiceParam(kParamFilterType);
1434 _clamp = fetchBooleanParam(kParamFilterClamp);
1435 _blackOutside = fetchBooleanParam(kParamFilterBlackOutside);
1436 assert(_filter && _clamp && _blackOutside);
1437 if ( paramExists(kParamCropToFormat) ) {
1438 _cropToFormat = fetchBooleanParam(kParamCropToFormat);
1439 assert(_cropToFormat);
1440 } else {
1441 assert( !paramExists(kParamCropToFormat) );
1442 }
1443 _mix = fetchDoubleParam(kParamMix);
1444 _maskApply = ( ofxsMaskIsAlwaysConnected( OFX::getImageEffectHostDescription() ) && paramExists(kParamMaskApply) ) ? fetchBooleanParam(kParamMaskApply) : 0;
1445 _maskInvert = fetchBooleanParam(kParamMaskInvert);
1446 assert(_mix && _maskInvert);
1447
1448 // honor kParamDefaultsNormalised
1449 if ( _plugin == eDistortionPluginLensDistortion && paramExists(kParamDefaultsNormalised) ) {
1450 // Some hosts (e.g. Resolve) may not support normalized defaults (setDefaultCoordinateSystem(eCoordinatesNormalised))
1451 // handle these ourselves!
1452 BooleanParam* param = fetchBooleanParam(kParamDefaultsNormalised);
1453 assert(param);
1454 bool normalised = param->getValue();
1455 if (normalised) {
1456 OfxPointD size = getProjectExtent();
1457 OfxPointD origin = getProjectOffset();
1458 OfxPointD p;
1459 // we must denormalise all parameters for which setDefaultCoordinateSystem(eCoordinatesNormalised) couldn't be done
1460 beginEditBlock(kParamDefaultsNormalised);
1461 p = _btmLeft->getValue();
1462 _btmLeft->setValue(p.x * size.x + origin.x, p.y * size.y + origin.y);
1463 p = _size->getValue();
1464 _size->setValue(p.x * size.x, p.y * size.y);
1465 param->setValue(false);
1466 endEditBlock();
1467 }
1468 }
1469
1470 // finally
1471 syncPrivateData();
1472 }
1473
1474
1475 private:
1476 // override the roi call
1477 virtual void getRegionsOfInterest(const RegionsOfInterestArguments &args, RegionOfInterestSetter &rois) OVERRIDE FINAL;
1478 virtual bool getRegionOfDefinition(const RegionOfDefinitionArguments &args, OfxRectD &rod) OVERRIDE FINAL;
1479 #ifdef OFX_EXTENSIONS_NUKE
1480 virtual OfxStatus getClipComponents(const ClipComponentsArguments& args, ClipComponentsSetter& clipComponents) OVERRIDE FINAL;
1481 #endif
1482
1483 /* Override the render */
1484 virtual void render(const RenderArguments &args) OVERRIDE FINAL;
1485
1486 /* internal render function */
1487 template <class PIX, int nComponents, int maxValue, DistortionPluginEnum plugin>
1488 void renderInternalForBitDepth(const RenderArguments &args);
1489
1490 template <int nComponents, DistortionPluginEnum plugin>
1491 void renderInternal(const RenderArguments &args, BitDepthEnum dstBitDepth);
1492
1493 /* set up and run a processor */
1494 void setupAndProcess(DistortionProcessorBase &, const RenderArguments &args);
1495
1496 virtual bool isIdentity(const IsIdentityArguments &args, Clip * &identityClip, double &identityTime, int& view, std::string& plane) OVERRIDE FINAL;
1497 virtual void getClipPreferences(ClipPreferencesSetter &clipPreferences) OVERRIDE FINAL;
1498
1499 /** @brief called when a param has just had its value changed */
1500 void changedParam(const InstanceChangedArgs &args, const std::string ¶mName) OVERRIDE FINAL;
1501
1502 /** @brief The sync private data action, called when the effect needs to sync any private data to persistent parameters */
syncPrivateData(void)1503 virtual void syncPrivateData(void) OVERRIDE FINAL
1504 {
1505 updateVisibility();
1506 }
1507
1508 void updateVisibility();
1509
1510 DistortionModel* getDistortionModel(const OfxRectD& format, const OfxPointD& renderScale, double time);
1511
1512 bool getLensDistortionFormat(double time, const OfxPointD& renderScale, OfxRectD *format, double *par);
1513
1514 private:
1515 int _majorVersion;
1516
1517 // do not need to delete these, the ImageEffect is managing them for us
1518 Clip *_dstClip;
1519 Clip *_srcClip;
1520 Clip *_uvClip;
1521 Clip *_maskClip;
1522 BooleanParam* _processR;
1523 BooleanParam* _processG;
1524 BooleanParam* _processB;
1525 BooleanParam* _processA;
1526 ChoiceParam* _uvChannels[3];
1527 BooleanParam* _unpremultUV;
1528 Double2DParam *_uvOffset;
1529 Double2DParam *_uvScale;
1530 ChoiceParam* _uWrap;
1531 ChoiceParam* _vWrap;
1532
1533 ///////////////////
1534 // LensDistortion
1535
1536 // format params
1537 ChoiceParam* _extent;
1538 ChoiceParam* _format;
1539 Int2DParam* _formatSize;
1540 DoubleParam* _formatPar;
1541 Double2DParam* _btmLeft;
1542 Double2DParam* _size;
1543 PushButtonParam *_recenter;
1544
1545 ChoiceParam* _distortionModel;
1546 ChoiceParam* _direction;
1547 ChoiceParam* _outputMode;
1548
1549 // Nuke
1550 DoubleParam* _k1;
1551 DoubleParam* _k2;
1552 Double2DParam* _center;
1553 DoubleParam* _squeeze;
1554 Double2DParam* _asymmetric;
1555
1556 // PFBarrel
1557 StringParam* _pfFile;
1558 PushButtonParam* _pfReload;
1559 DoubleParam* _pfC3;
1560 DoubleParam* _pfC5;
1561 DoubleParam* _pfSqueeze;
1562 Double2DParam* _pfP;
1563
1564 // 3DEqualizer
1565 // fov parameters
1566 DoubleParam* _xa_fov_unit;
1567 DoubleParam* _ya_fov_unit;
1568 DoubleParam* _xb_fov_unit;
1569 DoubleParam* _yb_fov_unit;
1570 // seven builtin parameters
1571 DoubleParam* _fl_cm;
1572 DoubleParam* _fd_cm;
1573 DoubleParam* _w_fb_cm;
1574 DoubleParam* _h_fb_cm;
1575 DoubleParam* _x_lco_cm;
1576 DoubleParam* _y_lco_cm;
1577 DoubleParam* _pa;
1578 // 3DEClassic model
1579 DoubleParam* _ld;
1580 DoubleParam* _sq;
1581 DoubleParam* _cx;
1582 DoubleParam* _cy;
1583 DoubleParam* _qu;
1584 // 3DEStandard model
1585 DoubleParam* _c2;
1586 DoubleParam* _u1;
1587 DoubleParam* _v1;
1588 DoubleParam* _c4;
1589 DoubleParam* _u3;
1590 DoubleParam* _v3;
1591 DoubleParam* _phi;
1592 DoubleParam* _b;
1593 // 3DEAnamorphic4 model
1594 DoubleParam* _cx02;
1595 DoubleParam* _cy02;
1596 DoubleParam* _cx22;
1597 DoubleParam* _cy22;
1598 DoubleParam* _cx04;
1599 DoubleParam* _cy04;
1600 DoubleParam* _cx24;
1601 DoubleParam* _cy24;
1602 DoubleParam* _cx44;
1603 DoubleParam* _cy44;
1604 DoubleParam* _a4phi;
1605 DoubleParam* _a4sqx;
1606 DoubleParam* _a4sqy;
1607
1608 // 3DEAnamorphic6 model
1609 DoubleParam* _cx06;
1610 DoubleParam* _cy06;
1611 DoubleParam* _cx26;
1612 DoubleParam* _cy26;
1613 DoubleParam* _cx46;
1614 DoubleParam* _cy46;
1615 DoubleParam* _cx66;
1616 DoubleParam* _cy66;
1617
1618 // 3DEFishEye8 model
1619 DoubleParam* _c6;
1620 DoubleParam* _c8;
1621
1622 // PanoTools model
1623 DoubleParam* _pta;
1624 DoubleParam* _ptb;
1625 DoubleParam* _ptc;
1626 DoubleParam* _ptd;
1627 DoubleParam* _pte;
1628 DoubleParam* _ptg;
1629 DoubleParam* _ptt;
1630
1631 ChoiceParam* _filter;
1632 BooleanParam* _clamp;
1633 BooleanParam* _blackOutside;
1634 BooleanParam* _cropToFormat;
1635 DoubleParam* _mix;
1636 BooleanParam* _maskApply;
1637 BooleanParam* _maskInvert;
1638 DistortionPluginEnum _plugin;
1639 };
1640
1641
1642 void
getClipPreferences(ClipPreferencesSetter & clipPreferences)1643 DistortionPlugin::getClipPreferences(ClipPreferencesSetter &clipPreferences)
1644 {
1645 //We have to do this because the processing code does not support varying components for uvClip and srcClip
1646 PixelComponentEnum dstPixelComps = getDefaultOutputClipComponents();
1647
1648 if (_srcClip) {
1649 clipPreferences.setClipComponents(*_srcClip, dstPixelComps);
1650 }
1651 if (gIsMultiPlaneV2 && _uvClip) {
1652 MultiPlaneEffect::getClipPreferences(clipPreferences);
1653 }
1654 if (_plugin == eDistortionPluginLensDistortion) {
1655 OfxRectD format;
1656 double par;
1657 OfxPointD rs1 = {1., 1.};
1658
1659 // we pass 0 as time, since anyway the input RoD is never used, thanks to the test on the return value
1660 bool setFormat = getLensDistortionFormat(0, rs1, &format, &par);
1661 if (setFormat) {
1662 OfxRectI formatI;
1663 // round to nearest
1664 formatI.x1 = std::floor(format.x1 + 0.5);
1665 formatI.y1 = std::floor(format.y1 + 0.5);
1666 formatI.x2 = std::floor(format.x2 + 0.5);
1667 formatI.y2 = std::floor(format.y2 + 0.5);
1668 clipPreferences.setOutputFormat(formatI);
1669 clipPreferences.setPixelAspectRatio(*_dstClip, par);
1670 }
1671 } else if ( _plugin == eDistortionPluginSTMap && _uvClip && _uvClip->isConnected() ) {
1672 OfxRectI uvFormat;
1673 _uvClip->getFormat(uvFormat);
1674 double par = _uvClip->getPixelAspectRatio();
1675 if ( OFX::Coords::rectIsEmpty(uvFormat) ) {
1676 // no format is available, use the RoD instead
1677 const OfxRectD& srcRod = _uvClip->getRegionOfDefinition(0.);
1678 const OfxPointD rs1 = {1., 1.};
1679 Coords::toPixelNearest(srcRod, rs1, par, &uvFormat);
1680 }
1681 clipPreferences.setOutputFormat(uvFormat);
1682 clipPreferences.setPixelAspectRatio(*_dstClip, par);
1683 }
1684 }
1685
1686 ////////////////////////////////////////////////////////////////////////////////
1687 /** @brief render for the filter */
1688
1689
1690 class InputImagesHolder_RAII
1691 {
1692 std::vector<Image*> images;
1693
1694 public:
1695
InputImagesHolder_RAII()1696 InputImagesHolder_RAII()
1697 : images()
1698 {
1699 }
1700
appendImage(Image * img)1701 void appendImage(Image* img)
1702 {
1703 images.push_back(img);
1704 }
1705
~InputImagesHolder_RAII()1706 ~InputImagesHolder_RAII()
1707 {
1708 for (std::size_t i = 0; i < images.size(); ++i) {
1709 delete images[i];
1710 }
1711 }
1712 };
1713
1714
1715 ////////////////////////////////////////////////////////////////////////////////
1716 // basic plugin render function, just a skelington to instantiate templates from
1717 static
1718 int
getChannelIndex(InputChannelEnum e,PixelComponentEnum comps)1719 getChannelIndex(InputChannelEnum e,
1720 PixelComponentEnum comps)
1721 {
1722 int retval;
1723
1724 switch (e) {
1725 case eInputChannelR: {
1726 if (
1727 #ifdef OFX_EXTENSIONS_NATRON
1728 comps == ePixelComponentXY ||
1729 #endif
1730 comps == ePixelComponentRGB || comps == ePixelComponentRGBA) {
1731 retval = 0;
1732 } else {
1733 retval = -1;
1734 }
1735 break;
1736 }
1737 case eInputChannelG: {
1738 if (
1739 #ifdef OFX_EXTENSIONS_NATRON
1740 comps == ePixelComponentXY ||
1741 #endif
1742 comps == ePixelComponentRGB || comps == ePixelComponentRGBA) {
1743 retval = 1;
1744 } else {
1745 retval = -1;
1746 }
1747 break;
1748 }
1749 case eInputChannelB: {
1750 if ( ( comps == ePixelComponentRGB) || ( comps == ePixelComponentRGBA) ) {
1751 retval = 2;
1752 } else {
1753 retval = -1;
1754 }
1755 break;
1756 }
1757 case eInputChannelA: {
1758 if (comps == ePixelComponentAlpha) {
1759 return 0;
1760 } else if (comps == ePixelComponentRGBA) {
1761 retval = 3;
1762 } else {
1763 retval = -1;
1764 }
1765 break;
1766 }
1767 case eInputChannel0:
1768 case eInputChannel1:
1769 default: {
1770 retval = -1;
1771 break;
1772 }
1773 } // switch
1774
1775 return retval;
1776 } // getChannelIndex
1777
1778 // renderScale should be:
1779 // 1,1 when calling from getRoD
1780 // rs when calling from getRoI
1781 // rs when calling from render
1782 // format is in pixels (but may be non-integer)
1783 DistortionModel*
getDistortionModel(const OfxRectD & format,const OfxPointD & renderScale,double time)1784 DistortionPlugin::getDistortionModel(const OfxRectD& format, const OfxPointD& renderScale, double time)
1785 {
1786 if (_plugin != eDistortionPluginLensDistortion) {
1787 return NULL;
1788 }
1789 DistortionModelEnum distortionModelE = (DistortionModelEnum)_distortionModel->getValueAtTime(time);
1790 switch (distortionModelE) {
1791 case eDistortionModelNuke: {
1792 double par = 1.;
1793 if (_srcClip) {
1794 par = _srcClip->getPixelAspectRatio();
1795 }
1796 double k1 = _k1->getValueAtTime(time);
1797 double k2 = _k2->getValueAtTime(time);
1798 double cx, cy;
1799 _center->getValueAtTime(time, cx, cy);
1800 double squeeze = std::max(0.001, _squeeze->getValueAtTime(time));
1801 double ax, ay;
1802 _asymmetric->getValueAtTime(time, ax, ay);
1803 return new DistortionModelNuke(format,
1804 par,
1805 k1,
1806 k2,
1807 cx,
1808 cy,
1809 squeeze,
1810 ax,
1811 ay);
1812 break;
1813 }
1814 case eDistortionModelPFBarrel: {
1815 //double par = 1.;
1816 //if (_srcClip) {
1817 // par = _srcClip->getPixelAspectRatio();
1818 //}
1819 double c3 = _pfC3->getValueAtTime(time);
1820 double c5 = _pfC5->getValueAtTime(time);
1821 double xp, yp;
1822 _pfP->getValueAtTime(time, xp, yp);
1823 double squeeze = _pfSqueeze->getValueAtTime(time);
1824 return new DistortionModelPFBarrel(format,
1825 renderScale,
1826 //par,
1827 c3,
1828 c5,
1829 xp,
1830 yp,
1831 squeeze);
1832 break;
1833 }
1834 case eDistortionModel3DEClassic: {
1835 //double pa = 1.;
1836 //if (_srcClip) {
1837 // pa = _srcClip->getPixelAspectRatio();
1838 //}
1839 double xa_fov_unit = _xa_fov_unit->getValueAtTime(time);
1840 double ya_fov_unit = _ya_fov_unit->getValueAtTime(time);
1841 double xb_fov_unit = _xb_fov_unit->getValueAtTime(time);
1842 double yb_fov_unit = _yb_fov_unit->getValueAtTime(time);
1843 double fl_cm = _fl_cm->getValueAtTime(time);
1844 double fd_cm = _fd_cm->getValueAtTime(time);
1845 double w_fb_cm = _w_fb_cm->getValueAtTime(time);
1846 double h_fb_cm = _h_fb_cm->getValueAtTime(time);
1847 double x_lco_cm = _x_lco_cm->getValueAtTime(time);
1848 double y_lco_cm = _y_lco_cm->getValueAtTime(time);
1849 double pa = _pa->getValueAtTime(time);
1850
1851 double ld = _ld->getValueAtTime(time);
1852 double sq = _sq->getValueAtTime(time);
1853 double cx = _cx->getValueAtTime(time);
1854 double cy = _cy->getValueAtTime(time);
1855 double qu = _qu->getValueAtTime(time);
1856 return new DistortionModel3DEClassic(format,
1857 renderScale,
1858 xa_fov_unit,
1859 ya_fov_unit,
1860 xb_fov_unit,
1861 yb_fov_unit,
1862 fl_cm,
1863 fd_cm,
1864 w_fb_cm,
1865 h_fb_cm,
1866 x_lco_cm,
1867 y_lco_cm,
1868 pa,
1869 ld,
1870 sq,
1871 cx,
1872 cy,
1873 qu);
1874 break;
1875 }
1876 case eDistortionModel3DEAnamorphic6: {
1877 //double pa = 1.;
1878 //if (_srcClip) {
1879 // pa = _srcClip->getPixelAspectRatio();
1880 //}
1881 double xa_fov_unit = _xa_fov_unit->getValueAtTime(time);
1882 double ya_fov_unit = _ya_fov_unit->getValueAtTime(time);
1883 double xb_fov_unit = _xb_fov_unit->getValueAtTime(time);
1884 double yb_fov_unit = _yb_fov_unit->getValueAtTime(time);
1885 double fl_cm = _fl_cm->getValueAtTime(time);
1886 double fd_cm = _fd_cm->getValueAtTime(time);
1887 double w_fb_cm = _w_fb_cm->getValueAtTime(time);
1888 double h_fb_cm = _h_fb_cm->getValueAtTime(time);
1889 double x_lco_cm = _x_lco_cm->getValueAtTime(time);
1890 double y_lco_cm = _y_lco_cm->getValueAtTime(time);
1891 double pa = _pa->getValueAtTime(time);
1892
1893 double cx02 = _cx02->getValueAtTime(time);
1894 double cy02 = _cy02->getValueAtTime(time);
1895 double cx22 = _cx22->getValueAtTime(time);
1896 double cy22 = _cy22->getValueAtTime(time);
1897 double cx04 = _cx04->getValueAtTime(time);
1898 double cy04 = _cy04->getValueAtTime(time);
1899 double cx24 = _cx24->getValueAtTime(time);
1900 double cy24 = _cy24->getValueAtTime(time);
1901 double cx44 = _cx44->getValueAtTime(time);
1902 double cy44 = _cy44->getValueAtTime(time);
1903 double cx06 = _cx06->getValueAtTime(time);
1904 double cy06 = _cy06->getValueAtTime(time);
1905 double cx26 = _cx26->getValueAtTime(time);
1906 double cy26 = _cy26->getValueAtTime(time);
1907 double cx46 = _cx46->getValueAtTime(time);
1908 double cy46 = _cy46->getValueAtTime(time);
1909 double cx66 = _cx66->getValueAtTime(time);
1910 double cy66 = _cy66->getValueAtTime(time);
1911 return new DistortionModel3DEAnamorphic6(format,
1912 renderScale,
1913 xa_fov_unit,
1914 ya_fov_unit,
1915 xb_fov_unit,
1916 yb_fov_unit,
1917 fl_cm,
1918 fd_cm,
1919 w_fb_cm,
1920 h_fb_cm,
1921 x_lco_cm,
1922 y_lco_cm,
1923 pa,
1924 cx02,
1925 cy02,
1926 cx22,
1927 cy22,
1928 cx04,
1929 cy04,
1930 cx24,
1931 cy24,
1932 cx44,
1933 cy44,
1934 cx06,
1935 cy06,
1936 cx26,
1937 cy26,
1938 cx46,
1939 cy46,
1940 cx66,
1941 cy66);
1942 break;
1943 }
1944 case eDistortionModel3DEFishEye8: {
1945 //double pa = 1.;
1946 //if (_srcClip) {
1947 // pa = _srcClip->getPixelAspectRatio();
1948 //}
1949 double xa_fov_unit = _xa_fov_unit->getValueAtTime(time);
1950 double ya_fov_unit = _ya_fov_unit->getValueAtTime(time);
1951 double xb_fov_unit = _xb_fov_unit->getValueAtTime(time);
1952 double yb_fov_unit = _yb_fov_unit->getValueAtTime(time);
1953 double fl_cm = _fl_cm->getValueAtTime(time);
1954 double fd_cm = _fd_cm->getValueAtTime(time);
1955 double w_fb_cm = _w_fb_cm->getValueAtTime(time);
1956 double h_fb_cm = _h_fb_cm->getValueAtTime(time);
1957 double x_lco_cm = _x_lco_cm->getValueAtTime(time);
1958 double y_lco_cm = _y_lco_cm->getValueAtTime(time);
1959 double pa = _pa->getValueAtTime(time);
1960
1961 double c2 = _c2->getValueAtTime(time);
1962 double c4 = _c4->getValueAtTime(time);
1963 double c6 = _c6->getValueAtTime(time);
1964 double c8 = _c8->getValueAtTime(time);
1965 return new DistortionModel3DEFishEye8(format,
1966 renderScale,
1967 xa_fov_unit,
1968 ya_fov_unit,
1969 xb_fov_unit,
1970 yb_fov_unit,
1971 fl_cm,
1972 fd_cm,
1973 w_fb_cm,
1974 h_fb_cm,
1975 x_lco_cm,
1976 y_lco_cm,
1977 pa,
1978 c2,
1979 c4,
1980 c6,
1981 c8);
1982 break;
1983 }
1984 case eDistortionModel3DEStandard: {
1985 //double pa = 1.;
1986 //if (_srcClip) {
1987 // pa = _srcClip->getPixelAspectRatio();
1988 //}
1989 double xa_fov_unit = _xa_fov_unit->getValueAtTime(time);
1990 double ya_fov_unit = _ya_fov_unit->getValueAtTime(time);
1991 double xb_fov_unit = _xb_fov_unit->getValueAtTime(time);
1992 double yb_fov_unit = _yb_fov_unit->getValueAtTime(time);
1993 double fl_cm = _fl_cm->getValueAtTime(time);
1994 double fd_cm = _fd_cm->getValueAtTime(time);
1995 double w_fb_cm = _w_fb_cm->getValueAtTime(time);
1996 double h_fb_cm = _h_fb_cm->getValueAtTime(time);
1997 double x_lco_cm = _x_lco_cm->getValueAtTime(time);
1998 double y_lco_cm = _y_lco_cm->getValueAtTime(time);
1999 double pa = _pa->getValueAtTime(time);
2000
2001 double c2 = _c2->getValueAtTime(time);
2002 double u1 = _u1->getValueAtTime(time);
2003 double v1 = _v1->getValueAtTime(time);
2004 double c4 = _c4->getValueAtTime(time);
2005 double u3 = _u3->getValueAtTime(time);
2006 double v3 = _v3->getValueAtTime(time);
2007 double phi = _phi->getValueAtTime(time);
2008 double b = _b->getValueAtTime(time);
2009 return new DistortionModel3DEStandard(format,
2010 renderScale,
2011 xa_fov_unit,
2012 ya_fov_unit,
2013 xb_fov_unit,
2014 yb_fov_unit,
2015 fl_cm,
2016 fd_cm,
2017 w_fb_cm,
2018 h_fb_cm,
2019 x_lco_cm,
2020 y_lco_cm,
2021 pa,
2022 c2,
2023 u1,
2024 v1,
2025 c4,
2026 u3,
2027 v3,
2028 phi,
2029 b);
2030 break;
2031 }
2032 case eDistortionModel3DEAnamorphic4: {
2033 //double pa = 1.;
2034 //if (_srcClip) {
2035 // pa = _srcClip->getPixelAspectRatio();
2036 //}
2037 double xa_fov_unit = _xa_fov_unit->getValueAtTime(time);
2038 double ya_fov_unit = _ya_fov_unit->getValueAtTime(time);
2039 double xb_fov_unit = _xb_fov_unit->getValueAtTime(time);
2040 double yb_fov_unit = _yb_fov_unit->getValueAtTime(time);
2041 double fl_cm = _fl_cm->getValueAtTime(time);
2042 double fd_cm = _fd_cm->getValueAtTime(time);
2043 double w_fb_cm = _w_fb_cm->getValueAtTime(time);
2044 double h_fb_cm = _h_fb_cm->getValueAtTime(time);
2045 double x_lco_cm = _x_lco_cm->getValueAtTime(time);
2046 double y_lco_cm = _y_lco_cm->getValueAtTime(time);
2047 double pa = _pa->getValueAtTime(time);
2048
2049 double cx02 = _cx02->getValueAtTime(time);
2050 double cy02 = _cy02->getValueAtTime(time);
2051 double cx22 = _cx22->getValueAtTime(time);
2052 double cy22 = _cy22->getValueAtTime(time);
2053 double cx04 = _cx04->getValueAtTime(time);
2054 double cy04 = _cy04->getValueAtTime(time);
2055 double cx24 = _cx24->getValueAtTime(time);
2056 double cy24 = _cy24->getValueAtTime(time);
2057 double cx44 = _cx44->getValueAtTime(time);
2058 double cy44 = _cy44->getValueAtTime(time);
2059 double phi = _a4phi->getValueAtTime(time);
2060 double sqx = _a4sqx->getValueAtTime(time);
2061 double sqy = _a4sqy->getValueAtTime(time);
2062 return new DistortionModel3DEAnamorphic4(format,
2063 renderScale,
2064 xa_fov_unit,
2065 ya_fov_unit,
2066 xb_fov_unit,
2067 yb_fov_unit,
2068 fl_cm,
2069 fd_cm,
2070 w_fb_cm,
2071 h_fb_cm,
2072 x_lco_cm,
2073 y_lco_cm,
2074 pa,
2075 cx02,
2076 cy02,
2077 cx22,
2078 cy22,
2079 cx04,
2080 cy04,
2081 cx24,
2082 cy24,
2083 cx44,
2084 cy44,
2085 phi,
2086 sqx,
2087 sqy);
2088 break;
2089 }
2090 case eDistortionModelPanoTools: {
2091 double par = 1.;
2092 if (_srcClip) {
2093 par = _srcClip->getPixelAspectRatio();
2094 }
2095 double a = _pta->getValueAtTime(time);
2096 double b = _ptb->getValueAtTime(time);
2097 double c = _ptc->getValueAtTime(time);
2098 double d = _ptd->getValueAtTime(time);
2099 double e = _pte->getValueAtTime(time);
2100 double g = _ptg->getValueAtTime(time);
2101 double t = _ptt->getValueAtTime(time);
2102 return new DistortionModelPanoTools(format,
2103 renderScale,
2104 par,
2105 a, b, c,
2106 d, e,
2107 g, t);
2108 break;
2109 }
2110
2111 }
2112 assert(false);
2113 }
2114
2115 // returns true if fixed format (i.e. not the input RoD) and setFormat can be called in getClipPrefs
2116 bool
getLensDistortionFormat(double time,const OfxPointD & renderScale,OfxRectD * format,double * par)2117 DistortionPlugin::getLensDistortionFormat(double time,
2118 const OfxPointD& renderScale,
2119 OfxRectD *format,
2120 double *par)
2121 {
2122 assert(_plugin == eDistortionPluginLensDistortion);
2123
2124 GeneratorExtentEnum extent = (GeneratorExtentEnum)_extent->getValue();
2125
2126 switch (extent) {
2127 case eGeneratorExtentFormat: {
2128 int w, h;
2129 _formatSize->getValue(w, h);
2130 *par = _formatPar->getValue();
2131 format->x1 = format->y1 = 0;
2132 format->x2 = w * renderScale.x;
2133 format->y2 = h * renderScale.y;
2134
2135 return true;
2136 break;
2137 }
2138 case eGeneratorExtentSize: {
2139 OfxRectD rod;
2140 _size->getValue(rod.x2, rod.y2);
2141 _btmLeft->getValue(rod.x1, rod.y1);
2142 rod.x2 += rod.x1;
2143 rod.y2 += rod.y1;
2144 *par = _srcClip ? _srcClip->getPixelAspectRatio() : 1.;
2145 // Coords::toPixelNearest(rod, renderScale, *par, format);
2146 format->x1 = rod.x1 * renderScale.x / *par;
2147 format->y1 = rod.y1 * renderScale.y;
2148 format->x2 = rod.x2 * renderScale.x / *par;
2149 format->y2 = rod.y2 * renderScale.y;
2150
2151 return true;
2152 break;
2153 }
2154 case eGeneratorExtentProject: {
2155 OfxRectD rod;
2156 OfxPointD siz = getProjectSize();
2157 OfxPointD off = getProjectOffset();
2158 rod.x1 = off.x;
2159 rod.x2 = off.x + siz.x;
2160 rod.y1 = off.y;
2161 rod.y2 = off.y + siz.y;
2162 *par = getProjectPixelAspectRatio();
2163 // Coords::toPixelNearest(rod, renderScale, *par, format);
2164 format->x1 = rod.x1 * renderScale.x / *par;
2165 format->y1 = rod.y1 * renderScale.y;
2166 format->x2 = rod.x2 * renderScale.x / *par;
2167 format->y2 = rod.y2 * renderScale.y;
2168
2169 return true;
2170 break;
2171 }
2172 case eGeneratorExtentDefault:
2173 if ( _srcClip && _srcClip->isConnected() ) {
2174 OfxRectI formatI;
2175 formatI.x1 = formatI.y1 = formatI.x2 = formatI.y2 = 0; // default value
2176 if (_majorVersion >= 3) {
2177 // before version 3, LensDistortion was only using RoD
2178 _srcClip->getFormat(formatI);
2179 }
2180 *par = _srcClip->getPixelAspectRatio();
2181 if ( OFX::Coords::rectIsEmpty(formatI) ) {
2182 // no format is available, use the RoD instead
2183 const OfxRectD& srcRod = _srcClip->getRegionOfDefinition(time);
2184 // Coords::toPixelNearest(srcRod, renderScale, *par, format);
2185 format->x1 = srcRod.x1 * renderScale.x / *par;
2186 format->y1 = srcRod.y1 * renderScale.y;
2187 format->x2 = srcRod.x2 * renderScale.x / *par;
2188 format->y2 = srcRod.y2 * renderScale.y;
2189 } else {
2190 format->x1 = formatI.x1 * renderScale.x;
2191 format->y1 = formatI.y1 * renderScale.y;
2192 format->x2 = formatI.x2 * renderScale.x;
2193 format->y2 = formatI.y2 * renderScale.y;
2194 }
2195 } else {
2196 // default to Project Size
2197 OfxRectD srcRod;
2198 OfxPointD siz = getProjectSize();
2199 OfxPointD off = getProjectOffset();
2200 srcRod.x1 = off.x;
2201 srcRod.x2 = off.x + siz.x;
2202 srcRod.y1 = off.y;
2203 srcRod.y2 = off.y + siz.y;
2204 *par = getProjectPixelAspectRatio();
2205 // Coords::toPixelNearest(srcRod, renderScale, *par, format);
2206 format->x1 = srcRod.x1 * renderScale.x / *par;
2207 format->y1 = srcRod.y1 * renderScale.y;
2208 format->x2 = srcRod.x2 * renderScale.x / *par;
2209 format->y2 = srcRod.y2 * renderScale.y;
2210 }
2211
2212 return false;
2213 break;
2214 }
2215 return false;
2216 }
2217
2218 /* set up and run a processor */
2219 void
setupAndProcess(DistortionProcessorBase & processor,const RenderArguments & args)2220 DistortionPlugin::setupAndProcess(DistortionProcessorBase &processor,
2221 const RenderArguments &args)
2222 {
2223 const double time = args.time;
2224
2225 auto_ptr<Image> dst( _dstClip->fetchImage(time) );
2226
2227 if ( !dst.get() ) {
2228 throwSuiteStatusException(kOfxStatFailed);
2229 }
2230 BitDepthEnum dstBitDepth = dst->getPixelDepth();
2231 PixelComponentEnum dstComponents = dst->getPixelComponents();
2232 if ( ( dstBitDepth != _dstClip->getPixelDepth() ) ||
2233 ( dstComponents != _dstClip->getPixelComponents() ) ) {
2234 setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong depth or components");
2235 throwSuiteStatusException(kOfxStatFailed);
2236 }
2237 if ( (dst->getRenderScale().x != args.renderScale.x) ||
2238 ( dst->getRenderScale().y != args.renderScale.y) ||
2239 ( ( dst->getField() != eFieldNone) /* for DaVinci Resolve */ && ( dst->getField() != args.fieldToRender) ) ) {
2240 setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
2241 throwSuiteStatusException(kOfxStatFailed);
2242 }
2243
2244 OutputModeEnum outputMode = _outputMode ? (OutputModeEnum)_outputMode->getValue() : eOutputModeImage;
2245
2246 auto_ptr<const Image> src( ( (outputMode == eOutputModeImage) && _srcClip && _srcClip->isConnected() ) ?
2247 _srcClip->fetchImage(time) : 0 );
2248 if ( src.get() ) {
2249 if ( (src->getRenderScale().x != args.renderScale.x) ||
2250 ( src->getRenderScale().y != args.renderScale.y) ||
2251 ( ( src->getField() != eFieldNone) /* for DaVinci Resolve */ && ( src->getField() != args.fieldToRender) ) ) {
2252 setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
2253 throwSuiteStatusException(kOfxStatFailed);
2254 }
2255 BitDepthEnum srcBitDepth = src->getPixelDepth();
2256 PixelComponentEnum srcComponents = src->getPixelComponents();
2257 if ( (srcBitDepth != dstBitDepth) || (srcComponents != dstComponents) ) {
2258 throwSuiteStatusException(kOfxStatErrImageFormat);
2259 }
2260 }
2261
2262 InputImagesHolder_RAII imagesHolder;
2263 std::vector<InputPlaneChannel> planeChannels;
2264
2265 if (_uvClip) {
2266 if (gIsMultiPlaneV1 || gIsMultiPlaneV2) {
2267 BitDepthEnum srcBitDepth = eBitDepthNone;
2268 std::map<Clip*, std::map<std::string, Image*> > fetchedPlanes;
2269 for (int i = 0; i < 3; ++i) {
2270 InputPlaneChannel p;
2271 p.channelIndex = i;
2272 p.fillZero = false;
2273 //if (_uvClip) {
2274 Clip* clip = 0;
2275 MultiPlane::ImagePlaneDesc plane;
2276 MultiPlane::MultiPlaneEffect::GetPlaneNeededRetCodeEnum stat = getPlaneNeeded(_uvChannels[i]->getName(), &clip, &plane, &p.channelIndex);
2277 if (stat == MultiPlane::MultiPlaneEffect::eGetPlaneNeededRetCodeFailed) {
2278 setPersistentMessage(Message::eMessageError, "", "Cannot find requested channels in input");
2279 throwSuiteStatusException(kOfxStatFailed);
2280 }
2281
2282 p.img = 0;
2283 if (stat == MultiPlane::MultiPlaneEffect::eGetPlaneNeededRetCodeReturnedConstant0 ||
2284 (stat == MultiPlane::MultiPlaneEffect::eGetPlaneNeededRetCodeReturnedPlane && plane.getNumComponents() == 0)) {
2285 p.fillZero = true;
2286 } else if (stat == MultiPlane::MultiPlaneEffect::eGetPlaneNeededRetCodeReturnedConstant1) {
2287 p.fillZero = false;
2288 } else {
2289 std::map<std::string, Image*>& clipPlanes = fetchedPlanes[clip];
2290 std::map<std::string, Image*>::iterator foundPlane = clipPlanes.find(plane.getPlaneID());
2291 if ( foundPlane != clipPlanes.end() ) {
2292 p.img = foundPlane->second;
2293 } else {
2294 #ifdef OFX_EXTENSIONS_NUKE
2295 p.img = clip->fetchImagePlane( time, args.renderView, plane.getPlaneID().c_str() );
2296 #else
2297 p.img = ( clip && clip->isConnected() ) ? clip->fetchImage(time) : 0;
2298 #endif
2299 if (p.img) {
2300 clipPlanes.insert( std::make_pair(plane.getPlaneID(), p.img) );
2301 imagesHolder.appendImage(p.img);
2302 }
2303 }
2304 }
2305
2306 if (p.img) {
2307 if ( (p.img->getRenderScale().x != args.renderScale.x) ||
2308 ( p.img->getRenderScale().y != args.renderScale.y) ||
2309 ( ( p.img->getField() != eFieldNone) /* for DaVinci Resolve */ && ( p.img->getField() != args.fieldToRender) ) ) {
2310 setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
2311 throwSuiteStatusException(kOfxStatFailed);
2312 }
2313 if (srcBitDepth == eBitDepthNone) {
2314 srcBitDepth = p.img->getPixelDepth();
2315 } else {
2316 // both input must have the same bit depth and components
2317 if ( (srcBitDepth != eBitDepthNone) && ( srcBitDepth != p.img->getPixelDepth() ) ) {
2318 throwSuiteStatusException(kOfxStatErrImageFormat);
2319 }
2320 }
2321 // If the channel is unavailabe in the image, fill with 0 (1 for Alpha)
2322 // This may happen if the user selected the hard-coded Alpha channel and the input is RGB
2323 if (p.channelIndex >= p.img->getPixelComponentCount()) {
2324 p.img = 0;
2325 p.fillZero = p.channelIndex != 3;
2326 }
2327 }
2328
2329
2330 //}
2331 planeChannels.push_back(p);
2332 }
2333 } else { //!gIsMultiPlane
2334 InputChannelEnum uChannel = eInputChannelR;
2335 InputChannelEnum vChannel = eInputChannelG;
2336 InputChannelEnum aChannel = eInputChannelA;
2337 if (_uvChannels[0]) {
2338 uChannel = (InputChannelEnum)_uvChannels[0]->getValueAtTime(time);
2339 }
2340 if (_uvChannels[1]) {
2341 vChannel = (InputChannelEnum)_uvChannels[1]->getValueAtTime(time);
2342 }
2343 if (_uvChannels[2]) {
2344 aChannel = (InputChannelEnum)_uvChannels[2]->getValueAtTime(time);
2345 }
2346
2347 Image* uv = NULL;
2348 if ( ( ( (uChannel != eInputChannel0) && (uChannel != eInputChannel1) ) ||
2349 ( (vChannel != eInputChannel0) && (vChannel != eInputChannel1) ) ||
2350 ( (aChannel != eInputChannel0) && (aChannel != eInputChannel1) ) ) &&
2351 ( _uvClip && _uvClip->isConnected() ) ) {
2352 uv = _uvClip->fetchImage(time);
2353 }
2354
2355 PixelComponentEnum uvComponents = ePixelComponentNone;
2356 if (uv) {
2357 imagesHolder.appendImage(uv);
2358 if ( (uv->getRenderScale().x != args.renderScale.x) ||
2359 ( uv->getRenderScale().y != args.renderScale.y) ||
2360 ( ( uv->getField() != eFieldNone) /* for DaVinci Resolve */ && ( uv->getField() != args.fieldToRender) ) ) {
2361 setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
2362 throwSuiteStatusException(kOfxStatFailed);
2363 }
2364 BitDepthEnum uvBitDepth = uv->getPixelDepth();
2365 uvComponents = uv->getPixelComponents();
2366 // only eBitDepthFloat is supported for now (other types require special processing for uv values)
2367 if ( (uvBitDepth != eBitDepthFloat) /*|| (uvComponents != dstComponents)*/ ) {
2368 throwSuiteStatusException(kOfxStatErrImageFormat);
2369 }
2370 }
2371
2372 // fillZero is only used when the channelIndex is -1 (i.e. it does not exist), and in this case:
2373 // - it is true if the inputchannel is 0, R, G or B
2374 // - it is false if the inputchannel is 1, A (images without alpha are considered opaque)
2375 {
2376 InputPlaneChannel u;
2377 u.channelIndex = getChannelIndex(uChannel, uvComponents);
2378 u.img = (u.channelIndex >= 0) ? uv : NULL;
2379 u.fillZero = (u.channelIndex >= 0) ? false : !(uChannel == eInputChannel1 || uChannel == eInputChannelA);
2380 planeChannels.push_back(u);
2381 }
2382 {
2383 InputPlaneChannel v;
2384 v.channelIndex = getChannelIndex(vChannel, uvComponents);
2385 v.img = (v.channelIndex >= 0) ? uv : NULL;
2386 v.fillZero = (v.channelIndex >= 0) ? false : !(vChannel == eInputChannel1 || vChannel == eInputChannelA);
2387 planeChannels.push_back(v);
2388 }
2389 {
2390 InputPlaneChannel a;
2391 a.channelIndex = getChannelIndex(aChannel, uvComponents);
2392 a.img = (a.channelIndex >= 0) ? uv : NULL;
2393 a.fillZero = (a.channelIndex >= 0) ? false : !(aChannel == eInputChannel1 || aChannel == eInputChannelA);
2394 planeChannels.push_back(a);
2395 }
2396 }
2397 } // if (_uvClip)"
2398
2399
2400 // auto ptr for the mask.
2401 bool doMasking = ( ( !_maskApply || _maskApply->getValueAtTime(time) ) && _maskClip && _maskClip->isConnected() );
2402 auto_ptr<const Image> mask(doMasking ? _maskClip->fetchImage(time) : 0);
2403 // do we do masking
2404 if (doMasking) {
2405 if ( mask.get() ) {
2406 if ( (mask->getRenderScale().x != args.renderScale.x) ||
2407 ( mask->getRenderScale().y != args.renderScale.y) ||
2408 ( ( mask->getField() != eFieldNone) /* for DaVinci Resolve */ && ( mask->getField() != args.fieldToRender) ) ) {
2409 setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
2410 throwSuiteStatusException(kOfxStatFailed);
2411 }
2412 }
2413 bool maskInvert = _maskInvert->getValueAtTime(time);
2414 processor.doMasking(true);
2415 processor.setMaskImg(mask.get(), maskInvert);
2416 }
2417
2418 // set the images
2419 processor.setDstImg( dst.get() );
2420 processor.setSrcImgs( src.get() );
2421 // set the render window
2422 processor.setRenderWindow(args.renderWindow);
2423
2424 bool processR = _processR->getValueAtTime(time);
2425 bool processG = _processG->getValueAtTime(time);
2426 bool processB = _processB->getValueAtTime(time);
2427 bool processA = _processA->getValueAtTime(time);
2428 bool unpremultUV = false;
2429 double uScale = 1., vScale = 1.;
2430 double uOffset = 0., vOffset = 0.;
2431 WrapEnum uWrap = eWrapClamp;
2432 WrapEnum vWrap = eWrapClamp;
2433 if ( (_plugin == eDistortionPluginIDistort) || (_plugin == eDistortionPluginSTMap) ) {
2434 unpremultUV = _unpremultUV->getValueAtTime(time);
2435 _uvOffset->getValueAtTime(time, uOffset, vOffset);
2436 _uvScale->getValueAtTime(time, uScale, vScale);
2437 if (_plugin == eDistortionPluginSTMap) {
2438 uWrap = (WrapEnum)_uWrap->getValueAtTime(time);
2439 vWrap = (WrapEnum)_vWrap->getValueAtTime(time);
2440 }
2441 }
2442 bool blackOutside = _blackOutside->getValueAtTime(time);
2443 double mix = _mix->getValueAtTime(time);
2444
2445 bool transformIsIdentity = true;
2446 Matrix3x3 srcTransformInverse;
2447 #ifdef OFX_EXTENSIONS_NUKE
2448 if ( src.get() ) {
2449 transformIsIdentity = src->getTransformIsIdentity();
2450 }
2451 if (!transformIsIdentity) {
2452 double srcTransform[9]; // transform to apply to the source image, in pixel coordinates, from source to destination
2453 src->getTransform(srcTransform);
2454 Matrix3x3 srcTransformMat;
2455 srcTransformMat(0,0) = srcTransform[0];
2456 srcTransformMat(0,1) = srcTransform[1];
2457 srcTransformMat(0,2) = srcTransform[2];
2458 srcTransformMat(1,0) = srcTransform[3];
2459 srcTransformMat(1,1) = srcTransform[4];
2460 srcTransformMat(1,2) = srcTransform[5];
2461 srcTransformMat(2,0) = srcTransform[6];
2462 srcTransformMat(2,1) = srcTransform[7];
2463 srcTransformMat(2,2) = srcTransform[8];
2464 // invert it
2465 if ( !srcTransformMat.inverse(&srcTransformInverse) ) {
2466 transformIsIdentity = true; // no transform
2467 }
2468 }
2469 #endif
2470 if (_plugin == eDistortionPluginIDistort) {
2471 // in IDistort, displacement is given in full-scale pixels
2472 uScale *= args.renderScale.x;
2473 vScale *= args.renderScale.y;
2474 }
2475 OfxRectD format = {0, 0, 1, 1};
2476 if (_plugin == eDistortionPluginLensDistortion) {
2477 double par = 1.;
2478 getLensDistortionFormat(time, args.renderScale, &format, &par);
2479 } else if (_srcClip && _srcClip->isConnected()) {
2480 OfxRectI formatI;
2481 formatI.x1 = formatI.y1 = formatI.x2 = formatI.y2 = 0; // default value
2482 _srcClip->getFormat(formatI);
2483 double par = _srcClip->getPixelAspectRatio();
2484 if ( OFX::Coords::rectIsEmpty(formatI) ) {
2485 // no format is available, use the RoD instead
2486 const OfxRectD& srcRod = _srcClip->getRegionOfDefinition(time);
2487 // Coords::toPixelNearest(srcRod, renderScale, *par, format);
2488 format.x1 = srcRod.x1 * args.renderScale.x / par;
2489 format.y1 = srcRod.y1 * args.renderScale.y;
2490 format.x2 = srcRod.x2 * args.renderScale.x / par;
2491 format.y2 = srcRod.y2 * args.renderScale.y;
2492 } else {
2493 format.x1 = formatI.x1 * args.renderScale.x;
2494 format.y1 = formatI.y1 * args.renderScale.y;
2495 format.x2 = formatI.x2 * args.renderScale.x;
2496 format.y2 = formatI.y2 * args.renderScale.y;
2497 }
2498 }
2499
2500 DirectionEnum direction = _direction ? (DirectionEnum)_direction->getValue() : eDirectionDistort;
2501 auto_ptr<DistortionModel> distortionModel( getDistortionModel(format, args.renderScale, time) );
2502 processor.setValues(processR, processG, processB, processA,
2503 transformIsIdentity, srcTransformInverse,
2504 format,
2505 planeChannels,
2506 unpremultUV,
2507 uOffset, vOffset,
2508 uScale, vScale,
2509 uWrap, vWrap,
2510 args.renderScale,
2511 distortionModel.get(),
2512 direction,
2513 outputMode,
2514 blackOutside, mix);
2515
2516 // Call the base class process member, this will call the derived templated process code
2517 processor.process();
2518 } // DistortionPlugin::setupAndProcess
2519
2520 template <class PIX, int nComponents, int maxValue, DistortionPluginEnum plugin>
2521 void
renderInternalForBitDepth(const RenderArguments & args)2522 DistortionPlugin::renderInternalForBitDepth(const RenderArguments &args)
2523 {
2524 const double time = args.time;
2525 FilterEnum filter = args.renderQualityDraft ? eFilterImpulse : eFilterCubic;
2526
2527 if (!args.renderQualityDraft && _filter) {
2528 filter = (FilterEnum)_filter->getValueAtTime(time);
2529 }
2530 bool clamp = false;
2531 if (_clamp) {
2532 clamp = _clamp->getValueAtTime(time);
2533 }
2534
2535 // as you may see below, some filters don't need explicit clamping, since they are
2536 // "clamped" by construction.
2537 switch (filter) {
2538 case eFilterImpulse: {
2539 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterImpulse, false> fred(*this);
2540 setupAndProcess(fred, args);
2541 break;
2542 }
2543 case eFilterBox: {
2544 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterBox, false> fred(*this);
2545 setupAndProcess(fred, args);
2546 break;
2547 }
2548 case eFilterBilinear: {
2549 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterBilinear, false> fred(*this);
2550 setupAndProcess(fred, args);
2551 break;
2552 }
2553 case eFilterCubic: {
2554 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterCubic, false> fred(*this);
2555 setupAndProcess(fred, args);
2556 break;
2557 }
2558 case eFilterKeys:
2559 if (clamp) {
2560 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterKeys, true> fred(*this);
2561 setupAndProcess(fred, args);
2562 } else {
2563 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterKeys, false> fred(*this);
2564 setupAndProcess(fred, args);
2565 }
2566 break;
2567 case eFilterSimon:
2568 if (clamp) {
2569 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterSimon, true> fred(*this);
2570 setupAndProcess(fred, args);
2571 } else {
2572 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterSimon, false> fred(*this);
2573 setupAndProcess(fred, args);
2574 }
2575 break;
2576 case eFilterRifman:
2577 if (clamp) {
2578 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterRifman, true> fred(*this);
2579 setupAndProcess(fred, args);
2580 } else {
2581 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterRifman, false> fred(*this);
2582 setupAndProcess(fred, args);
2583 }
2584 break;
2585 case eFilterMitchell:
2586 if (clamp) {
2587 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterMitchell, true> fred(*this);
2588 setupAndProcess(fred, args);
2589 } else {
2590 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterMitchell, false> fred(*this);
2591 setupAndProcess(fred, args);
2592 }
2593 break;
2594 case eFilterParzen: {
2595 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterParzen, false> fred(*this);
2596 setupAndProcess(fred, args);
2597 break;
2598 }
2599 case eFilterNotch: {
2600 DistortionProcessor<PIX, nComponents, maxValue, plugin, eFilterNotch, false> fred(*this);
2601 setupAndProcess(fred, args);
2602 break;
2603 }
2604 } // switch
2605 } // renderInternalForBitDepth
2606
2607 // the internal render function
2608 template <int nComponents, DistortionPluginEnum plugin>
2609 void
renderInternal(const RenderArguments & args,BitDepthEnum dstBitDepth)2610 DistortionPlugin::renderInternal(const RenderArguments &args,
2611 BitDepthEnum dstBitDepth)
2612 {
2613 switch (dstBitDepth) {
2614 case eBitDepthUByte:
2615 renderInternalForBitDepth<unsigned char, nComponents, 255, plugin>(args);
2616 break;
2617 case eBitDepthUShort:
2618 renderInternalForBitDepth<unsigned short, nComponents, 65535, plugin>(args);
2619 break;
2620 case eBitDepthFloat:
2621 renderInternalForBitDepth<float, nComponents, 1, plugin>(args);
2622 break;
2623 default:
2624 throwSuiteStatusException(kOfxStatErrUnsupported);
2625 }
2626 }
2627
2628 // the overridden render function
2629 void
render(const RenderArguments & args)2630 DistortionPlugin::render(const RenderArguments &args)
2631 {
2632 // instantiate the render code based on the pixel depth of the dst clip
2633 BitDepthEnum dstBitDepth = _dstClip->getPixelDepth();
2634 PixelComponentEnum dstComponents = _dstClip->getPixelComponents();
2635
2636 assert( kSupportsMultipleClipPARs || !_srcClip || _srcClip->getPixelAspectRatio() == _dstClip->getPixelAspectRatio() );
2637 assert( kSupportsMultipleClipDepths || !_srcClip || _srcClip->getPixelDepth() == _dstClip->getPixelDepth() );
2638 assert(OFX_COMPONENTS_OK(dstComponents));
2639 if (dstComponents == ePixelComponentRGBA) {
2640 switch (_plugin) {
2641 case eDistortionPluginSTMap:
2642 renderInternal<4, eDistortionPluginSTMap>(args, dstBitDepth);
2643 break;
2644 case eDistortionPluginIDistort:
2645 renderInternal<4, eDistortionPluginIDistort>(args, dstBitDepth);
2646 break;
2647 case eDistortionPluginLensDistortion:
2648 renderInternal<4, eDistortionPluginLensDistortion>(args, dstBitDepth);
2649 break;
2650 }
2651 } else if (dstComponents == ePixelComponentRGB) {
2652 switch (_plugin) {
2653 case eDistortionPluginSTMap:
2654 renderInternal<3, eDistortionPluginSTMap>(args, dstBitDepth);
2655 break;
2656 case eDistortionPluginIDistort:
2657 renderInternal<3, eDistortionPluginIDistort>(args, dstBitDepth);
2658 break;
2659 case eDistortionPluginLensDistortion:
2660 renderInternal<3, eDistortionPluginLensDistortion>(args, dstBitDepth);
2661 break;
2662 }
2663 #ifdef OFX_EXTENSIONS_NATRON
2664 } else if (dstComponents == ePixelComponentXY) {
2665 switch (_plugin) {
2666 case eDistortionPluginSTMap:
2667 renderInternal<2, eDistortionPluginSTMap>(args, dstBitDepth);
2668 break;
2669 case eDistortionPluginIDistort:
2670 renderInternal<2, eDistortionPluginIDistort>(args, dstBitDepth);
2671 break;
2672 case eDistortionPluginLensDistortion:
2673 renderInternal<2, eDistortionPluginLensDistortion>(args, dstBitDepth);
2674 break;
2675 }
2676 #endif
2677 } else {
2678 assert(dstComponents == ePixelComponentAlpha);
2679 switch (_plugin) {
2680 case eDistortionPluginSTMap:
2681 renderInternal<1, eDistortionPluginSTMap>(args, dstBitDepth);
2682 break;
2683 case eDistortionPluginIDistort:
2684 renderInternal<1, eDistortionPluginIDistort>(args, dstBitDepth);
2685 break;
2686 case eDistortionPluginLensDistortion:
2687 renderInternal<1, eDistortionPluginLensDistortion>(args, dstBitDepth);
2688 break;
2689 }
2690 }
2691 } // DistortionPlugin::render
2692
2693 bool
isIdentity(const IsIdentityArguments & args,Clip * & identityClip,double &,int &,std::string &)2694 DistortionPlugin::isIdentity(const IsIdentityArguments &args,
2695 Clip * &identityClip,
2696 double & /*identityTime*/
2697 , int& /*view*/, std::string& /*plane*/)
2698 {
2699 const double time = args.time;
2700
2701 if ( (_plugin == eDistortionPluginIDistort) || (_plugin == eDistortionPluginSTMap) ) {
2702 if ( !_uvClip || !_uvClip->isConnected() ) {
2703 identityClip = _srcClip;
2704
2705 return true;
2706 }
2707 }
2708 if (_plugin == eDistortionPluginLensDistortion) {
2709 OutputModeEnum outputMode = _outputMode ? (OutputModeEnum)_outputMode->getValue() : eOutputModeImage;
2710 if (outputMode == eOutputModeSTMap) {
2711 return false;
2712 }
2713 bool identity = false;
2714 DistortionModelEnum distortionModel = (DistortionModelEnum)_distortionModel->getValueAtTime(time);
2715 switch (distortionModel) {
2716 case eDistortionModelNuke: {
2717 double k1 = _k1->getValueAtTime(time);
2718 double k2 = _k2->getValueAtTime(time);
2719 double ax, ay;
2720 _asymmetric->getValueAtTime(time, ax, ay);
2721 identity = (k1 == 0.) && (k2 == 0.) && (ax == 0.) && (ay == 0.);
2722 break;
2723 }
2724 case eDistortionModelPFBarrel: {
2725 double pfC3 = _pfC3->getValueAtTime(time);
2726 double pfC5 = _pfC5->getValueAtTime(time);
2727 identity = (pfC3 == 0.) && (pfC5 == 0.);
2728 break;
2729 }
2730 case eDistortionModel3DEClassic: {
2731 double ld = _ld->getValueAtTime(time);
2732 double cx = _cx->getValueAtTime(time);
2733 double cy = _cy->getValueAtTime(time);
2734 double qu = _qu->getValueAtTime(time);
2735 identity = (ld == 0.) && (cx == 0.) && (cy == 0.) && (qu == 0.);
2736 break;
2737 }
2738 case eDistortionModel3DEAnamorphic6: {
2739 double cx02 = _cx02->getValueAtTime(time);
2740 double cy02 = _cy02->getValueAtTime(time);
2741 double cx22 = _cx22->getValueAtTime(time);
2742 double cy22 = _cy22->getValueAtTime(time);
2743 double cx04 = _cx04->getValueAtTime(time);
2744 double cy04 = _cy04->getValueAtTime(time);
2745 double cx24 = _cx24->getValueAtTime(time);
2746 double cy24 = _cy24->getValueAtTime(time);
2747 double cx44 = _cx44->getValueAtTime(time);
2748 double cy44 = _cy44->getValueAtTime(time);
2749 double cx06 = _cx06->getValueAtTime(time);
2750 double cy06 = _cy06->getValueAtTime(time);
2751 double cx26 = _cx26->getValueAtTime(time);
2752 double cy26 = _cy26->getValueAtTime(time);
2753 double cx46 = _cx46->getValueAtTime(time);
2754 double cy46 = _cy46->getValueAtTime(time);
2755 double cx66 = _cx66->getValueAtTime(time);
2756 double cy66 = _cy66->getValueAtTime(time);
2757 identity = ( (cx02 == 0.) && (cy02 == 0.) && (cx22 == 0.) && (cy22 == 0.) &&
2758 (cx04 == 0.) && (cy04 == 0.) && (cx24 == 0.) && (cy24 == 0.) && (cx44 == 0.) && (cy44 == 0.) &&
2759 (cx06 == 0.) && (cy06 == 0.) && (cx26 == 0.) && (cy26 == 0.) && (cx46 == 0.) && (cy46 == 0.) && (cx66 == 0.) && (cy66 == 0.) );
2760 break;
2761 }
2762 case eDistortionModel3DEFishEye8: {
2763 // fisheye is never identity
2764 break;
2765 }
2766 case eDistortionModel3DEStandard: {
2767 double c2 = _c2->getValueAtTime(time);
2768 double u1 = _u1->getValueAtTime(time);
2769 double v1 = _v1->getValueAtTime(time);
2770 double c4 = _c4->getValueAtTime(time);
2771 double u3 = _u3->getValueAtTime(time);
2772 double v3 = _v3->getValueAtTime(time);
2773 double b = _b->getValueAtTime(time);
2774 identity = ( (c2 == 0.) && (u1 == 0.) && (v1 == 0.) && (c4 == 0.) &&
2775 (u3 == 0.) && (v3 == 0.) && (b == 0.) );
2776 break;
2777 }
2778 case eDistortionModel3DEAnamorphic4: {
2779 double cx02 = _cx02->getValueAtTime(time);
2780 double cy02 = _cy02->getValueAtTime(time);
2781 double cx22 = _cx22->getValueAtTime(time);
2782 double cy22 = _cy22->getValueAtTime(time);
2783 double cx04 = _cx04->getValueAtTime(time);
2784 double cy04 = _cy04->getValueAtTime(time);
2785 double cx24 = _cx24->getValueAtTime(time);
2786 double cy24 = _cy24->getValueAtTime(time);
2787 double cx44 = _cx44->getValueAtTime(time);
2788 double cy44 = _cy44->getValueAtTime(time);
2789 double phi = _a4phi->getValueAtTime(time);
2790 double sqx = _a4sqx->getValueAtTime(time);
2791 double sqy = _a4sqy->getValueAtTime(time);
2792 identity = ( (cx02 == 0.) && (cy02 == 0.) && (cx22 == 0.) && (cy22 == 0.) &&
2793 (cx04 == 0.) && (cy04 == 0.) && (cx24 == 0.) && (cy24 == 0.) && (cx44 == 0.) && (cy44 == 0.) &&
2794 (phi == 0.) && (sqx == 0.) && (sqy == 0.) );
2795 break;
2796 }
2797 case eDistortionModelPanoTools: {
2798 double a = _pta->getValueAtTime(time);
2799 double b = _ptb->getValueAtTime(time);
2800 double c = _ptc->getValueAtTime(time);
2801 double d = _ptd->getValueAtTime(time);
2802 double e = _pte->getValueAtTime(time);
2803 double g = _ptg->getValueAtTime(time);
2804 double t = _ptt->getValueAtTime(time);
2805 identity = (a == 0.) && (b == 0.) && (c == 0.) && (d == 0.) && (e == 0.) && (g == 0.) && (t == 0.);
2806 break;
2807 }
2808 } // switch (distortionModel) {
2809
2810 if (identity) {
2811 identityClip = _srcClip;
2812
2813 return true;
2814 }
2815 }
2816 double mix;
2817 _mix->getValueAtTime(time, mix);
2818
2819 if (mix == 0. /*|| (!processR && !processG && !processB && !processA)*/) {
2820 identityClip = _srcClip;
2821
2822 return true;
2823 }
2824
2825 {
2826 bool processR, processG, processB, processA;
2827 _processR->getValueAtTime(time, processR);
2828 _processG->getValueAtTime(time, processG);
2829 _processB->getValueAtTime(time, processB);
2830 _processA->getValueAtTime(time, processA);
2831 if (!processR && !processG && !processB && !processA) {
2832 identityClip = _srcClip;
2833
2834 return true;
2835 }
2836 }
2837
2838 bool doMasking = ( ( !_maskApply || _maskApply->getValueAtTime(time) ) && _maskClip && _maskClip->isConnected() );
2839 if (doMasking) {
2840 bool maskInvert;
2841 _maskInvert->getValueAtTime(time, maskInvert);
2842 if (!maskInvert) {
2843 OfxRectI maskRoD;
2844 if (getImageEffectHostDescription()->supportsMultiResolution) {
2845 // In Sony Catalyst Edit, clipGetRegionOfDefinition returns the RoD in pixels instead of canonical coordinates.
2846 // In hosts that do not support multiResolution (e.g. Sony Catalyst Edit), all inputs have the same RoD anyway.
2847 Coords::toPixelEnclosing(_maskClip->getRegionOfDefinition(time), args.renderScale, _maskClip->getPixelAspectRatio(), &maskRoD);
2848 // effect is identity if the renderWindow doesn't intersect the mask RoD
2849 if ( !Coords::rectIntersection<OfxRectI>(args.renderWindow, maskRoD, 0) ) {
2850 identityClip = _srcClip;
2851
2852 return true;
2853 }
2854 }
2855 }
2856 }
2857
2858 return false;
2859 } // DistortionPlugin::isIdentity
2860
2861 // override the roi call
2862 // Required if the plugin requires a region from the inputs which is different from the rendered region of the output.
2863 // (this is the case here)
2864 void
getRegionsOfInterest(const RegionsOfInterestArguments & args,RegionOfInterestSetter & rois)2865 DistortionPlugin::getRegionsOfInterest(const RegionsOfInterestArguments &args,
2866 RegionOfInterestSetter &rois)
2867 {
2868 const double time = args.time;
2869
2870 if (!_srcClip || !_srcClip->isConnected()) {
2871 return;
2872 }
2873
2874 if (_plugin == eDistortionPluginLensDistortion) {
2875 OfxRectD format = {0, 1, 0, 1};
2876 double par = 1.;
2877 getLensDistortionFormat(time, args.renderScale, &format, &par);
2878
2879 DirectionEnum direction = _direction ? (DirectionEnum)_direction->getValue() : eDirectionDistort;
2880 auto_ptr<DistortionModel> distortionModel( getDistortionModel(format, args.renderScale, time) );
2881
2882 OfxRectD roiPixel = { std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity() };
2883 assert( OFX::Coords::rectIsEmpty(roiPixel) );
2884
2885 OfxRectI renderWinPixel;
2886 OFX::Coords::toPixelEnclosing(args.regionOfInterest, args.renderScale, par, &renderWinPixel);
2887 OfxRectD renderWin;
2888 renderWin.x1 = renderWinPixel.x1;
2889 renderWin.y1 = renderWinPixel.y1;
2890 renderWin.x2 = renderWinPixel.x2;
2891 renderWin.y2 = renderWinPixel.y2;
2892
2893 const int step = 10;
2894 const double w= (renderWin.x2 - renderWin.x1);
2895 const double h= (renderWin.y2 - renderWin.y1);
2896 const double xstep = w / step;
2897 const double ystep= h / step;
2898 for (int i = 0; i <= step; ++i) {
2899 for (int j = 0; j < 2; ++j) {
2900 double x = renderWin.x1 + xstep * i;
2901 double y = renderWin.y1 + h * j;
2902 double xi, yi;
2903 // undistort/distort take pixel coordinates, do not divide by renderScale
2904 if (direction == eDirectionDistort) {
2905 distortionModel->undistort(x, y, &xi, &yi); // inverse of getRoD
2906 } else {
2907 distortionModel->distort(x, y, &xi, &yi); // inverse of getRoD
2908 }
2909 roiPixel.x1 = std::min(roiPixel.x1, xi);
2910 roiPixel.x2 = std::max(roiPixel.x2, xi);
2911 roiPixel.y1 = std::min(roiPixel.y1, yi);
2912 roiPixel.y2 = std::max(roiPixel.y2, yi);
2913 }
2914 }
2915 for (int i = 0; i < 2; ++i) {
2916 for (int j = 1; j < step; ++j) {
2917 double x = renderWin.x1 + w * i;
2918 double y = renderWin.y1 + ystep * j;
2919 double xi, yi;
2920 // undistort/distort take pixel coordinates, do not divide by renderScale
2921 if (direction == eDirectionDistort) {
2922 distortionModel->undistort(x, y, &xi, &yi); // inverse of getRoD
2923 } else {
2924 distortionModel->distort(x, y, &xi, &yi); // inverse of getRoD
2925 }
2926 roiPixel.x1 = std::min(roiPixel.x1, xi);
2927 roiPixel.x2 = std::max(roiPixel.x2, xi);
2928 roiPixel.y1 = std::min(roiPixel.y1, yi);
2929 roiPixel.y2 = std::max(roiPixel.y2, yi);
2930 }
2931 }
2932 assert( !OFX::Coords::rectIsEmpty(roiPixel) );
2933 // Slight extra margin, just in case.
2934 roiPixel.x1 -= 2;
2935 roiPixel.x2 += 2;
2936 roiPixel.y1 -= 2;
2937 roiPixel.y2 += 2;
2938
2939 OfxRectD roi;
2940 OFX::Coords::toCanonical(roiPixel, args.renderScale, par, &roi);
2941 assert( !OFX::Coords::rectIsEmpty(roi) );
2942 rois.setRegionOfInterest(*_srcClip, roi);
2943 /*
2944 printf("getRegionsOfInterest: rs=(%g,%g) rw=(%g,%g,%g,%g) rwp=(%d,%d,%d,%d) -> roiPixel(%g,%g,%g,%g) roiCanonical=(%g,%g,%g,%g)\n",
2945 args.renderScale.x, args.renderScale.y,
2946 renderWin.x1, renderWin.y1, renderWin.x2, renderWin.y2,
2947 renderWinPixel.x1, renderWinPixel.y1, renderWinPixel.x2, renderWinPixel.y2,
2948 roiPixel.x1, roiPixel.y1, roiPixel.x2, roiPixel.y2,
2949 roi.x1, roi.y1, roi.x2, roi.y2);
2950 */
2951
2952 return;
2953 }
2954
2955 // ask for full RoD of srcClip
2956 const OfxRectD& srcRod = _srcClip->getRegionOfDefinition(time);
2957 rois.setRegionOfInterest(*_srcClip, srcRod);
2958 // only ask for the renderWindow (intersected with the RoD) from uvClip
2959 if (_uvClip) {
2960 OfxRectD uvRoI = _uvClip->getRegionOfDefinition(time);
2961 Coords::rectIntersection(uvRoI, args.regionOfInterest, &uvRoI);
2962 rois.setRegionOfInterest(*_uvClip, uvRoI);
2963 }
2964 }
2965
2966 bool
getRegionOfDefinition(const RegionOfDefinitionArguments & args,OfxRectD & rod)2967 DistortionPlugin::getRegionOfDefinition(const RegionOfDefinitionArguments &args,
2968 OfxRectD &rod)
2969 {
2970 const double time = args.time;
2971
2972 switch (_plugin) {
2973 case eDistortionPluginSTMap: {
2974 if (_uvClip) {
2975 // IDistort: RoD is the same as uv map
2976 rod = _uvClip->getRegionOfDefinition(time);
2977
2978 return true;
2979 }
2980 break;
2981 }
2982 case eDistortionPluginIDistort: {
2983 if (_srcClip) {
2984 // IDistort: RoD is the same as srcClip
2985 rod = _srcClip->getRegionOfDefinition(time);
2986
2987 return true;
2988 }
2989 break;
2990 }
2991 case eDistortionPluginLensDistortion: {
2992 if (_majorVersion < 3) {
2993 return false; // use source RoD
2994 }
2995 OfxRectD format = {0, 1, 0, 1};
2996 double par = 1.;
2997 getLensDistortionFormat(time, args.renderScale, &format, &par);
2998
2999 DirectionEnum direction = _direction ? (DirectionEnum)_direction->getValue() : eDirectionDistort;
3000 auto_ptr<DistortionModel> distortionModel( getDistortionModel(format, args.renderScale, time) );
3001
3002 OfxRectD rodPixel = { std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity() };
3003 assert( OFX::Coords::rectIsEmpty(rodPixel) );
3004
3005 OfxRectD srcRodPixel;
3006 if (_srcClip && _srcClip->isConnected()) {
3007 OfxRectD srcRod = _srcClip->getRegionOfDefinition(time);
3008 double srcPar = _srcClip->getPixelAspectRatio();
3009 srcRodPixel.x1 = srcRod.x1 * args.renderScale.x / srcPar;
3010 srcRodPixel.y1 = srcRod.y1 * args.renderScale.y;
3011 srcRodPixel.x2 = srcRod.x2 * args.renderScale.x / srcPar;
3012 srcRodPixel.y2 = srcRod.y2 * args.renderScale.y;
3013 } else {
3014 srcRodPixel.x1 = format.x1;
3015 srcRodPixel.y1 = format.y1;
3016 srcRodPixel.x2 = format.x2;
3017 srcRodPixel.y2 = format.y2;
3018 }
3019 if (OFX::Coords::rectIsEmpty(srcRodPixel)) {
3020 return false;
3021 }
3022 const int step = 10;
3023 const double w= (srcRodPixel.x2 - srcRodPixel.x1);
3024 const double h= (srcRodPixel.y2 - srcRodPixel.y1);
3025 const double xstep = w / step;
3026 const double ystep= h / step;
3027 for (int i = 0; i <= step; ++i) {
3028 for (int j = 0; j < 2; ++j) {
3029 double x = srcRodPixel.x1 + xstep * i;
3030 double y = srcRodPixel.y1 + h * j;
3031 double xo, yo;
3032 if (direction == eDirectionDistort) {
3033 distortionModel->distort(x, y, &xo, &yo);
3034 } else {
3035 distortionModel->undistort(x, y, &xo, &yo);
3036 }
3037 rodPixel.x1 = std::min(rodPixel.x1, xo);
3038 rodPixel.x2 = std::max(rodPixel.x2, xo);
3039 rodPixel.y1 = std::min(rodPixel.y1, yo);
3040 rodPixel.y2 = std::max(rodPixel.y2, yo);
3041 }
3042 }
3043 for (int i = 0; i < 2; ++i) {
3044 for (int j = 1; j < step; ++j) {
3045 double x = srcRodPixel.x1 + w * i;
3046 double y = srcRodPixel.y1 + ystep * j;
3047 double xo, yo;
3048 if (direction == eDirectionDistort) {
3049 distortionModel->distort(x, y, &xo, &yo);
3050 } else {
3051 distortionModel->undistort(x, y, &xo, &yo);
3052 }
3053 rodPixel.x1 = std::min(rodPixel.x1, xo);
3054 rodPixel.x2 = std::max(rodPixel.x2, xo);
3055 rodPixel.y1 = std::min(rodPixel.y1, yo);
3056 rodPixel.y2 = std::max(rodPixel.y2, yo);
3057 }
3058 }
3059 assert( !OFX::Coords::rectIsEmpty(rodPixel) );
3060 // extra margin for blackOutside
3061 if ( _blackOutside->getValueAtTime(time) ) {
3062 rodPixel.x1 -= 1;
3063 rodPixel.x2 += 1;
3064 rodPixel.y1 -= 1;
3065 rodPixel.y2 += 1;
3066 }
3067 // Slight extra margin, just in case.
3068 rodPixel.x1 -= 2;
3069 rodPixel.x2 += 2;
3070 rodPixel.y1 -= 2;
3071 rodPixel.y2 += 2;
3072
3073 OFX::Coords::toCanonical(rodPixel, args.renderScale, par, &rod);
3074 assert( !OFX::Coords::rectIsEmpty(rod) );
3075 /*
3076 printf("getRegionOfDefinition: rs=(%g,%g) srcrodp=(%g,%g,%g,%g) -> rodPixel(%g,%g,%g,%g) rodCanonical=(%g,%g,%g,%g)\n",
3077 args.renderScale.x, args.renderScale.y,
3078 srcRod.x1, srcRod.y1, srcRod.x2, srcRod.y2,
3079 rodPixel.x1, rodPixel.y1, rodPixel.x2, rodPixel.y2,
3080 rod.x1, rod.y1, rod.x2, rod.y2);
3081 */
3082
3083 if ( _cropToFormat && _cropToFormat->getValueAtTime(time) ) {
3084 // crop to format works by clamping the output rod to the format wherever the input rod was inside the format
3085 // this avoids unwanted crops (cropToFormat is checked by default)
3086 OfxRectI srcFormat;
3087 _srcClip->getFormat(srcFormat);
3088 OfxRectI srcFormatEnclosing;
3089 srcFormatEnclosing.x1 = std::floor(srcFormat.x1 * args.renderScale.x);
3090 srcFormatEnclosing.x2 = std::ceil(srcFormat.x2 * args.renderScale.x);
3091 srcFormatEnclosing.y1 = std::floor(srcFormat.y1 * args.renderScale.y);
3092 srcFormatEnclosing.y2 = std::ceil(srcFormat.y2 * args.renderScale.y);
3093 srcFormat.x1 = std::ceil(srcFormat.x1 * args.renderScale.x);
3094 srcFormat.x2 = std::floor(srcFormat.x2 * args.renderScale.x);
3095 srcFormat.y1 = std::ceil(srcFormat.y1 * args.renderScale.y);
3096 srcFormat.y2 = std::floor(srcFormat.y2 * args.renderScale.y);
3097 if (! Coords::rectIsEmpty(srcFormat) ) {
3098 if (rodPixel.x1 < srcFormat.x1 && srcRodPixel.x1 >= srcFormatEnclosing.x1) {
3099 rod.x1 = srcFormat.x1 / args.renderScale.x * par;
3100 }
3101 if (rodPixel.x2 > srcFormat.x2 && srcRodPixel.x2 <= srcFormatEnclosing.x2) {
3102 rod.x2 = srcFormat.x2 / args.renderScale.x * par;
3103 }
3104 if (rodPixel.y1 < srcFormat.y1 && srcRodPixel.y1 >= srcFormatEnclosing.y1) {
3105 rod.y1 = srcFormat.y1 / args.renderScale.y;
3106 }
3107 if (rodPixel.y2 > srcFormat.y2 && srcRodPixel.y2 <= srcFormatEnclosing.y2) {
3108 rod.y2 = srcFormat.y2 / args.renderScale.y;
3109 }
3110 }
3111 }
3112 return true;
3113 //return false; // use source RoD
3114 break;
3115 }
3116 } // switch (_plugin)
3117
3118 return false;
3119 }
3120
3121 #ifdef OFX_EXTENSIONS_NUKE
3122 OfxStatus
getClipComponents(const ClipComponentsArguments & args,ClipComponentsSetter & clipComponents)3123 DistortionPlugin::getClipComponents(const ClipComponentsArguments& args,
3124 ClipComponentsSetter& clipComponents)
3125 {
3126 assert(gIsMultiPlaneV2);
3127
3128 OfxStatus stat = kOfxStatReplyDefault;
3129 if (_uvClip) {
3130 stat = MultiPlaneEffect::getClipComponents(args, clipComponents);
3131 clipComponents.setPassThroughClip(_srcClip, args.time, args.view);
3132 }
3133 return stat;
3134 } // getClipComponents
3135
3136 #endif
3137
3138 void
updateVisibility()3139 DistortionPlugin::updateVisibility()
3140 {
3141 if (_plugin == eDistortionPluginLensDistortion) {
3142 {
3143 GeneratorExtentEnum extent = (GeneratorExtentEnum)_extent->getValue();
3144 bool hasFormat = (extent == eGeneratorExtentFormat);
3145 bool hasSize = (extent == eGeneratorExtentSize);
3146
3147 _format->setIsSecretAndDisabled(!hasFormat);
3148 _size->setIsSecretAndDisabled(!hasSize);
3149 _recenter->setIsSecretAndDisabled(!hasSize);
3150 _btmLeft->setIsSecretAndDisabled(!hasSize);
3151 }
3152
3153 DistortionModelEnum distortionModel = (DistortionModelEnum)_distortionModel->getValue();
3154
3155 _k1->setIsSecretAndDisabled(distortionModel != eDistortionModelNuke);
3156 _k2->setIsSecretAndDisabled(distortionModel != eDistortionModelNuke);
3157 _center->setIsSecretAndDisabled(distortionModel != eDistortionModelNuke);
3158 _squeeze->setIsSecretAndDisabled(distortionModel != eDistortionModelNuke);
3159 _asymmetric->setIsSecretAndDisabled(distortionModel != eDistortionModelNuke);
3160
3161 _pfFile->setIsSecretAndDisabled(distortionModel != eDistortionModelPFBarrel);
3162 if (_pfReload) {
3163 _pfReload->setIsSecretAndDisabled(distortionModel != eDistortionModelPFBarrel);
3164 }
3165 _pfC3->setIsSecretAndDisabled(distortionModel != eDistortionModelPFBarrel);
3166 _pfC5->setIsSecretAndDisabled(distortionModel != eDistortionModelPFBarrel);
3167 _pfSqueeze->setIsSecretAndDisabled(distortionModel != eDistortionModelPFBarrel);
3168 _pfP->setIsSecretAndDisabled(distortionModel != eDistortionModelPFBarrel);
3169
3170 bool distortionModel3DE = (distortionModel == eDistortionModel3DEClassic ||
3171 distortionModel == eDistortionModel3DEAnamorphic6 ||
3172 distortionModel == eDistortionModel3DEFishEye8 ||
3173 distortionModel == eDistortionModel3DEStandard ||
3174 distortionModel == eDistortionModel3DEAnamorphic4);
3175 _xa_fov_unit->setIsSecretAndDisabled(!distortionModel3DE);
3176 _ya_fov_unit->setIsSecretAndDisabled(!distortionModel3DE);
3177 _xb_fov_unit->setIsSecretAndDisabled(!distortionModel3DE);
3178 _yb_fov_unit->setIsSecretAndDisabled(!distortionModel3DE);
3179 _fl_cm->setIsSecretAndDisabled(!distortionModel3DE);
3180 _fd_cm->setIsSecretAndDisabled(!distortionModel3DE);
3181 _w_fb_cm->setIsSecretAndDisabled(!distortionModel3DE);
3182 _h_fb_cm->setIsSecretAndDisabled(!distortionModel3DE);
3183 _x_lco_cm->setIsSecretAndDisabled(!distortionModel3DE);
3184 _y_lco_cm->setIsSecretAndDisabled(!distortionModel3DE);
3185 _pa->setIsSecretAndDisabled(!distortionModel3DE);
3186
3187 _ld->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEClassic);
3188 _sq->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEClassic);
3189 _cx->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEClassic);
3190 _cy->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEClassic);
3191 _qu->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEClassic);
3192
3193 _c2->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEStandard &&
3194 distortionModel != eDistortionModel3DEFishEye8);
3195 _u1->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEStandard);
3196 _v1->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEStandard);
3197 _c4->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEStandard &&
3198 distortionModel != eDistortionModel3DEFishEye8);
3199 _u3->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEStandard);
3200 _v3->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEStandard);
3201 _phi->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEStandard);
3202 _b->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEStandard);
3203
3204 _cx02->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4 &&
3205 distortionModel != eDistortionModel3DEAnamorphic6);
3206 _cy02->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4 &&
3207 distortionModel != eDistortionModel3DEAnamorphic6);
3208 _cx22->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4 &&
3209 distortionModel != eDistortionModel3DEAnamorphic6);
3210 _cy22->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4 &&
3211 distortionModel != eDistortionModel3DEAnamorphic6);
3212 _cx04->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4 &&
3213 distortionModel != eDistortionModel3DEAnamorphic6);
3214 _cy04->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4 &&
3215 distortionModel != eDistortionModel3DEAnamorphic6);
3216 _cx24->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4 &&
3217 distortionModel != eDistortionModel3DEAnamorphic6);
3218 _cy24->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4 &&
3219 distortionModel != eDistortionModel3DEAnamorphic6);
3220 _cx44->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4 &&
3221 distortionModel != eDistortionModel3DEAnamorphic6);
3222 _cy44->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4 &&
3223 distortionModel != eDistortionModel3DEAnamorphic6);
3224 _cx06->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic6);
3225 _cy06->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic6);
3226 _cx26->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic6);
3227 _cy26->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic6);
3228 _cx46->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic6);
3229 _cy46->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic6);
3230 _cx66->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic6);
3231 _cy66->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic6);
3232 _a4phi->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4);
3233 _a4sqx->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4);
3234 _a4sqy->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEAnamorphic4);
3235
3236 _c6->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEFishEye8);
3237 _c8->setIsSecretAndDisabled(distortionModel != eDistortionModel3DEFishEye8);
3238
3239 _pta->setIsSecretAndDisabled(distortionModel != eDistortionModelPanoTools);
3240 _ptb->setIsSecretAndDisabled(distortionModel != eDistortionModelPanoTools);
3241 _ptc->setIsSecretAndDisabled(distortionModel != eDistortionModelPanoTools);
3242 _ptd->setIsSecretAndDisabled(distortionModel != eDistortionModelPanoTools);
3243 _pte->setIsSecretAndDisabled(distortionModel != eDistortionModelPanoTools);
3244 _ptg->setIsSecretAndDisabled(distortionModel != eDistortionModelPanoTools);
3245 _ptt->setIsSecretAndDisabled(distortionModel != eDistortionModelPanoTools);
3246 }
3247 }
3248
3249 void
changedParam(const InstanceChangedArgs & args,const std::string & paramName)3250 DistortionPlugin::changedParam(const InstanceChangedArgs &args,
3251 const std::string ¶mName)
3252 {
3253 if (_plugin == eDistortionPluginLensDistortion) {
3254 if ( (paramName == kParamDistortionModel) && (args.reason == eChangeUserEdit) ) {
3255 updateVisibility();
3256 } else if ( (paramName == kParamPFFileReload) ||
3257 ( (paramName == kParamPFFile) && (args.reason == eChangeUserEdit) ) ) {
3258 std::string filename;
3259 PFBarrelCommon::FileReader f(filename);
3260
3261 beginEditBlock(kParamPFFile);
3262 _pfC3->deleteAllKeys();
3263 _pfC5->deleteAllKeys();
3264 _pfP->deleteAllKeys();
3265 if (f.model_ == 0) {
3266 _pfC5->setValue(0.);
3267 }
3268 if (f.nkeys_ == 1) {
3269 _pfC3->setValue(f.c3_[0]);
3270 _pfC5->setValue(f.c5_[0]);
3271 _pfP->setValue(f.xp_[0], f.yp_[0]);
3272 } else {
3273 for (int i = 0; i < f.nkeys_; ++i) {
3274 _pfC3->setValueAtTime(f.frame_[i], f.c3_[0]);
3275 if (f.model_ == 1) {
3276 _pfC5->setValueAtTime(f.frame_[i], f.c5_[0]);
3277 }
3278 _pfP->setValueAtTime(f.frame_[i], f.xp_[0], f.yp_[0]);
3279 }
3280 }
3281 endEditBlock();
3282 } else if (paramName == kParamGeneratorExtent) {
3283 updateVisibility();
3284 } else if (paramName == kParamGeneratorFormat) {
3285 //the host does not handle the format itself, do it ourselves
3286 EParamFormat format = (EParamFormat)_format->getValue();
3287 int w = 0, h = 0;
3288 double par = -1;
3289 getFormatResolution(format, &w, &h, &par);
3290 assert(par != -1);
3291 _formatPar->setValue(par);
3292 _formatSize->setValue(w, h);
3293 } else if (paramName == kParamGeneratorCenter) {
3294 Clip* srcClip = _srcClip;
3295 OfxRectD srcRoD;
3296 if ( srcClip && srcClip->isConnected() ) {
3297 srcRoD = srcClip->getRegionOfDefinition(args.time);
3298 } else {
3299 OfxPointD siz = getProjectSize();
3300 OfxPointD off = getProjectOffset();
3301 srcRoD.x1 = off.x;
3302 srcRoD.x2 = off.x + siz.x;
3303 srcRoD.y1 = off.y;
3304 srcRoD.y2 = off.y + siz.y;
3305 }
3306 OfxPointD center;
3307 center.x = (srcRoD.x2 + srcRoD.x1) / 2.;
3308 center.y = (srcRoD.y2 + srcRoD.y1) / 2.;
3309
3310 OfxRectD rectangle;
3311 _size->getValue(rectangle.x2, rectangle.y2);
3312 _btmLeft->getValue(rectangle.x1, rectangle.y1);
3313 rectangle.x2 += rectangle.x1;
3314 rectangle.y2 += rectangle.y1;
3315
3316 OfxRectD newRectangle;
3317 newRectangle.x1 = center.x - (rectangle.x2 - rectangle.x1) / 2.;
3318 newRectangle.y1 = center.y - (rectangle.y2 - rectangle.y1) / 2.;
3319 newRectangle.x2 = newRectangle.x1 + (rectangle.x2 - rectangle.x1);
3320 newRectangle.y2 = newRectangle.y1 + (rectangle.y2 - rectangle.y1);
3321
3322 _size->setValue(newRectangle.x2 - newRectangle.x1, newRectangle.y2 - newRectangle.y1);
3323 _btmLeft->setValue(newRectangle.x1, newRectangle.y1);
3324 }
3325 return;
3326 }
3327 if (_plugin == eDistortionPluginIDistort ||
3328 _plugin == eDistortionPluginSTMap) {
3329 if (gIsMultiPlaneV2) {
3330 MultiPlaneEffect::changedParam(args, paramName);
3331 }
3332 }
3333 }
3334
3335 //mDeclarePluginFactory(DistortionPluginFactory, {ofxsThreadSuiteCheck();}, {});
3336 template<DistortionPluginEnum plugin, int majorVersion>
3337 class DistortionPluginFactory
3338 : public PluginFactoryHelper<DistortionPluginFactory<plugin, majorVersion> >
3339 {
3340 public:
3341 DistortionPluginFactory<plugin, majorVersion>(const std::string & id, unsigned int verMaj, unsigned int verMin)
3342 : PluginFactoryHelper<DistortionPluginFactory>(id, verMaj, verMin)
3343 {
3344 }
load()3345 virtual void load() OVERRIDE FINAL {ofxsThreadSuiteCheck();}
3346 virtual void describe(ImageEffectDescriptor &desc) OVERRIDE FINAL;
3347 virtual void describeInContext(ImageEffectDescriptor &desc, ContextEnum context) OVERRIDE FINAL;
3348 virtual ImageEffect* createInstance(OfxImageEffectHandle handle, ContextEnum context) OVERRIDE FINAL;
3349 };
3350
3351 template<DistortionPluginEnum plugin, int majorVersion>
3352 void
describe(ImageEffectDescriptor & desc)3353 DistortionPluginFactory<plugin, majorVersion>::describe(ImageEffectDescriptor &desc)
3354 {
3355 // basic labels
3356 switch (plugin) {
3357 case eDistortionPluginSTMap:
3358 desc.setLabel(kPluginSTMapName);
3359 desc.setPluginGrouping(kPluginSTMapGrouping);
3360 desc.setPluginDescription(kPluginSTMapDescription);
3361 break;
3362 case eDistortionPluginIDistort:
3363 desc.setLabel(kPluginIDistortName);
3364 desc.setPluginGrouping(kPluginIDistortGrouping);
3365 desc.setPluginDescription(kPluginIDistortDescription);
3366 break;
3367 case eDistortionPluginLensDistortion:
3368 desc.setLabel(kPluginLensDistortionName);
3369 desc.setPluginGrouping(kPluginLensDistortionGrouping);
3370 desc.setPluginDescription(kPluginLensDistortionDescription);
3371 break;
3372 }
3373
3374 //desc.addSupportedContext(eContextFilter);
3375 desc.addSupportedContext(eContextGeneral);
3376 //desc.addSupportedContext(eContextPaint);
3377 switch (plugin) {
3378 case eDistortionPluginSTMap:
3379 //desc.addSupportedBitDepth(eBitDepthUByte); // not yet supported (requires special processing for uv clip values)
3380 //desc.addSupportedBitDepth(eBitDepthUShort);
3381 desc.addSupportedBitDepth(eBitDepthFloat);
3382 break;
3383 case eDistortionPluginIDistort:
3384 //desc.addSupportedBitDepth(eBitDepthUByte); // not yet supported (requires special processing for uv clip values)
3385 //desc.addSupportedBitDepth(eBitDepthUShort);
3386 desc.addSupportedBitDepth(eBitDepthFloat);
3387 break;
3388 case eDistortionPluginLensDistortion:
3389 desc.addSupportedBitDepth(eBitDepthUByte);
3390 desc.addSupportedBitDepth(eBitDepthUShort);
3391 desc.addSupportedBitDepth(eBitDepthFloat);
3392 break;
3393 }
3394
3395
3396 // set a few flags
3397 desc.setSingleInstance(false);
3398 desc.setHostFrameThreading(false);
3399 desc.setSupportsMultiResolution(kSupportsMultiResolution);
3400 desc.setSupportsTiles(kSupportsTiles);
3401 desc.setTemporalClipAccess(false);
3402 desc.setRenderTwiceAlways(false);
3403 desc.setSupportsMultipleClipPARs(kSupportsMultipleClipPARs);
3404 desc.setSupportsMultipleClipDepths(kSupportsMultipleClipDepths);
3405 desc.setRenderThreadSafety(kRenderThreadSafety);
3406 desc.setSupportsRenderQuality(true);
3407 #ifdef OFX_EXTENSIONS_NUKE
3408 // ask the host to render all planes
3409 desc.setPassThroughForNotProcessedPlanes(ePassThroughLevelRenderAllRequestedPlanes);
3410 #endif
3411
3412 #ifdef OFX_EXTENSIONS_NATRON
3413 desc.setChannelSelector(ePixelComponentNone); // we have our own channel selector
3414 #endif
3415
3416
3417 gIsMultiPlaneV1 = false;
3418 gIsMultiPlaneV2 = false;
3419 #if defined(OFX_EXTENSIONS_NUKE)
3420 gIsMultiPlaneV1 = getImageEffectHostDescription()->isMultiPlanar;
3421 #endif
3422 #if defined(OFX_EXTENSIONS_NUKE) && defined(OFX_EXTENSIONS_NATRON)
3423 gIsMultiPlaneV2 = getImageEffectHostDescription()->supportsDynamicChoices && gIsMultiPlaneV1;
3424 if ((gIsMultiPlaneV1 || gIsMultiPlaneV2) && (plugin == eDistortionPluginSTMap || plugin == eDistortionPluginIDistort)) {
3425 // This enables fetching different planes from the input.
3426 // Generally the user will read a multi-layered EXR file in the Reader node and then use the shuffle
3427 // to redirect the plane's channels into RGBA color plane.
3428
3429 desc.setIsMultiPlanar(true);
3430 }
3431 #endif
3432 if (plugin == eDistortionPluginLensDistortion) {
3433 desc.setOverlayInteractDescriptor(new GeneratorOverlayDescriptor);
3434 }
3435 if ( (plugin == eDistortionPluginLensDistortion && this->getMajorVersion() < kPluginVersionLensDistortionMajor) ||
3436 (plugin != eDistortionPluginLensDistortion && this->getMajorVersion() < kPluginVersionMajor) ) {
3437 desc.setIsDeprecated(true);
3438 }
3439 } // >::describe
3440
3441 static void
addWrapOptions(ChoiceParamDescriptor * channel,WrapEnum def)3442 addWrapOptions(ChoiceParamDescriptor* channel,
3443 WrapEnum def)
3444 {
3445 assert(channel->getNOptions() == eWrapClamp);
3446 channel->appendOption(kParamWrapOptionClamp);
3447 assert(channel->getNOptions() == eWrapRepeat);
3448 channel->appendOption(kParamWrapOptionRepeat);
3449 assert(channel->getNOptions() == eWrapMirror);
3450 channel->appendOption(kParamWrapOptionMirror);
3451 channel->setDefault(def);
3452 }
3453
3454 template<DistortionPluginEnum plugin, int majorVersion>
3455 void
describeInContext(ImageEffectDescriptor & desc,ContextEnum context)3456 DistortionPluginFactory<plugin, majorVersion>::describeInContext(ImageEffectDescriptor &desc,
3457 ContextEnum context)
3458 {
3459 #ifdef OFX_EXTENSIONS_NUKE
3460 if ( gIsMultiPlaneV2 && !fetchSuite(kFnOfxImageEffectPlaneSuite, 2, true) ) {
3461 throwHostMissingSuiteException(kFnOfxImageEffectPlaneSuite);
3462 } else if (gIsMultiPlaneV1 && !fetchSuite(kFnOfxImageEffectPlaneSuite, 1, true) ) {
3463 throwHostMissingSuiteException(kFnOfxImageEffectPlaneSuite);
3464 }
3465 #endif
3466
3467 if (plugin == eDistortionPluginSTMap) {
3468 // create the uv clip
3469 // uv clip is defined first, because the output format is taken from the RoD of the first clip in Nuke
3470 ClipDescriptor *uvClip = desc.defineClip(kClipUV);
3471 uvClip->addSupportedComponent(ePixelComponentRGBA);
3472 uvClip->addSupportedComponent(ePixelComponentRGB);
3473 #ifdef OFX_EXTENSIONS_NUKE
3474 uvClip->addSupportedComponent(ePixelComponentXY);
3475 #endif
3476 uvClip->addSupportedComponent(ePixelComponentAlpha);
3477 uvClip->setTemporalClipAccess(false);
3478 uvClip->setSupportsTiles(kSupportsTiles);
3479 uvClip->setIsMask(false);
3480 uvClip->setOptional(false);
3481 }
3482 // create the mandated source clip
3483 ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName);
3484 srcClip->addSupportedComponent(ePixelComponentRGBA);
3485 srcClip->addSupportedComponent(ePixelComponentRGB);
3486 #ifdef OFX_EXTENSIONS_NUKE
3487 srcClip->addSupportedComponent(ePixelComponentXY);
3488 #endif
3489 srcClip->addSupportedComponent(ePixelComponentAlpha);
3490 srcClip->setTemporalClipAccess(false);
3491 srcClip->setSupportsTiles(kSupportsTiles);
3492 #ifdef OFX_EXTENSIONS_NUKE
3493 srcClip->setCanTransform(true); // we can concatenate transforms upwards on srcClip only
3494 #endif
3495 srcClip->setIsMask(false);
3496 if (plugin == eDistortionPluginLensDistortion) {
3497 // in LensDistrortion, if Output Mode is set to STMap, the size is taken from the project size
3498 srcClip->setOptional(true);
3499 }
3500 if (plugin == eDistortionPluginIDistort) {
3501 // create the uv clip
3502 ClipDescriptor *uvClip = desc.defineClip(kClipUV);
3503 uvClip->addSupportedComponent(ePixelComponentRGBA);
3504 uvClip->addSupportedComponent(ePixelComponentRGB);
3505 #ifdef OFX_EXTENSIONS_NUKE
3506 uvClip->addSupportedComponent(ePixelComponentXY);
3507 #endif
3508 uvClip->addSupportedComponent(ePixelComponentAlpha);
3509 uvClip->setTemporalClipAccess(false);
3510 uvClip->setSupportsTiles(kSupportsTiles);
3511 uvClip->setIsMask(false);
3512 }
3513
3514 // create the mandated output clip
3515 ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName);
3516 dstClip->addSupportedComponent(ePixelComponentRGBA);
3517 dstClip->addSupportedComponent(ePixelComponentRGB);
3518 #ifdef OFX_EXTENSIONS_NUKE
3519 dstClip->addSupportedComponent(ePixelComponentXY);
3520 #endif
3521 dstClip->addSupportedComponent(ePixelComponentAlpha);
3522 dstClip->setSupportsTiles(kSupportsTiles);
3523
3524 ClipDescriptor *maskClip = (context == eContextPaint) ? desc.defineClip("Brush") : desc.defineClip("Mask");
3525 maskClip->addSupportedComponent(ePixelComponentAlpha);
3526 maskClip->setTemporalClipAccess(false);
3527 if (context != eContextPaint) {
3528 maskClip->setOptional(true);
3529 }
3530 maskClip->setSupportsTiles(kSupportsTiles);
3531 maskClip->setIsMask(true);
3532
3533 // make some pages and to things in
3534 PageParamDescriptor *page = desc.definePageParam("Controls");
3535
3536 {
3537 BooleanParamDescriptor* param = desc.defineBooleanParam(kParamProcessR);
3538 param->setLabelAndHint(kParamProcessRLabel);
3539 param->setDefault(true);
3540 #ifdef OFX_EXTENSIONS_NUKE
3541 param->setLayoutHint(eLayoutHintNoNewLine, 1);
3542 #endif
3543 if (page) {
3544 page->addChild(*param);
3545 }
3546 }
3547 {
3548 BooleanParamDescriptor* param = desc.defineBooleanParam(kParamProcessG);
3549 param->setLabelAndHint(kParamProcessGLabel);
3550 param->setDefault(true);
3551 #ifdef OFX_EXTENSIONS_NUKE
3552 param->setLayoutHint(eLayoutHintNoNewLine, 1);
3553 #endif
3554 if (page) {
3555 page->addChild(*param);
3556 }
3557 }
3558 {
3559 BooleanParamDescriptor* param = desc.defineBooleanParam(kParamProcessB);
3560 param->setLabelAndHint(kParamProcessBLabel);
3561 param->setDefault(true);
3562 #ifdef OFX_EXTENSIONS_NUKE
3563 param->setLayoutHint(eLayoutHintNoNewLine, 1);
3564 #endif
3565 if (page) {
3566 page->addChild(*param);
3567 }
3568 }
3569 {
3570 BooleanParamDescriptor* param = desc.defineBooleanParam(kParamProcessA);
3571 param->setLabelAndHint(kParamProcessALabel);
3572 param->setDefault(true);
3573 if (page) {
3574 page->addChild(*param);
3575 }
3576 }
3577
3578 if ( (plugin == eDistortionPluginIDistort) ||
3579 ( plugin == eDistortionPluginSTMap) ) {
3580 std::vector<std::string> clipsForChannels(1);
3581 clipsForChannels[0] = kClipUV;
3582
3583 if (gIsMultiPlaneV2) {
3584 {
3585 ChoiceParamDescriptor* param = MultiPlane::Factory::describeInContextAddPlaneChannelChoice(desc, page, clipsForChannels, kParamChannelU, kParamChannelULabel);
3586 #ifdef OFX_EXTENSIONS_NUKE
3587 param->setLayoutHint(eLayoutHintNoNewLine, 1);
3588 #endif
3589 param->setDefault(eInputChannelR);
3590 }
3591 {
3592 ChoiceParamDescriptor* param = MultiPlane::Factory::describeInContextAddPlaneChannelChoice(desc, page, clipsForChannels, kParamChannelV, kParamChannelVLabel);
3593 param->setDefault(eInputChannelG);
3594 }
3595 {
3596 ChoiceParamDescriptor* param = MultiPlane::Factory::describeInContextAddPlaneChannelChoice(desc, page, clipsForChannels, kParamChannelA, kParamChannelALabel);
3597 param->setDefault(eInputChannelA);
3598 }
3599 } else {
3600 {
3601 ChoiceParamDescriptor *param = desc.defineChoiceParam(kParamChannelU);
3602 param->setLabelAndHint(kParamChannelULabel);
3603 #ifdef OFX_EXTENSIONS_NUKE
3604 param->setLayoutHint(eLayoutHintNoNewLine, 1);
3605 #endif
3606 MultiPlane::Factory::addInputChannelOptionsRGBA(param, clipsForChannels, true /*addConstants*/, !gIsMultiPlaneV1 /*addOnlyColorPlane*/);
3607 param->setDefault(eInputChannelR);
3608 if (page) {
3609 page->addChild(*param);
3610 }
3611 }
3612 {
3613 ChoiceParamDescriptor *param = desc.defineChoiceParam(kParamChannelV);
3614 param->setLabelAndHint(kParamChannelVLabel);
3615 MultiPlane::Factory::addInputChannelOptionsRGBA(param, clipsForChannels, true /*addConstants*/, !gIsMultiPlaneV1 /*addOnlyColorPlane*/);
3616 param->setDefault(eInputChannelG);
3617 if (page) {
3618 page->addChild(*param);
3619 }
3620 }
3621 {
3622 ChoiceParamDescriptor *param = desc.defineChoiceParam(kParamChannelA);
3623 param->setLabelAndHint(kParamChannelALabel);
3624 MultiPlane::Factory::addInputChannelOptionsRGBA(param, clipsForChannels, true /*addConstants*/, !gIsMultiPlaneV1 /*addOnlyColorPlane*/);
3625 param->setDefault(eInputChannelA);
3626 if (page) {
3627 page->addChild(*param);
3628 }
3629 }
3630 }
3631 {
3632 BooleanParamDescriptor* param = desc.defineBooleanParam(kParamChannelUnpremultUV);
3633 param->setLabelAndHint(kParamChannelUnpremultUVLabel);
3634 param->setDefault(false);
3635 if (page) {
3636 page->addChild(*param);
3637 }
3638 }
3639 {
3640 Double2DParamDescriptor *param = desc.defineDouble2DParam(kParamUVOffset);
3641 param->setLabelAndHint(kParamUVOffsetLabel);
3642 param->setDefault(0., 0.);
3643 param->setDoubleType(eDoubleTypePlain);
3644 param->setRange(-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3645 param->setDisplayRange(0., 0., 1., 1.);
3646 param->setDimensionLabels("U", "V");
3647 param->setUseHostNativeOverlayHandle(false);
3648 if (page) {
3649 page->addChild(*param);
3650 }
3651 }
3652 {
3653 Double2DParamDescriptor *param = desc.defineDouble2DParam(kParamUVScale);
3654 param->setLabelAndHint(kParamUVScaleLabel);
3655 param->setDoubleType(eDoubleTypeScale);
3656 param->setDefault(1., 1.);
3657 param->setRange(-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3658 param->setDisplayRange(0., 0., 100., 100.);
3659 param->setDimensionLabels("U", "V");
3660 param->setUseHostNativeOverlayHandle(false);
3661 if (page) {
3662 page->addChild(*param);
3663 }
3664 }
3665
3666 if (plugin == eDistortionPluginSTMap) {
3667 {
3668 ChoiceParamDescriptor *param = desc.defineChoiceParam(kParamWrapU);
3669 param->setLabelAndHint(kParamWrapULabel);
3670 #ifdef OFX_EXTENSIONS_NUKE
3671 param->setLayoutHint(eLayoutHintNoNewLine, 1);
3672 #endif
3673 addWrapOptions(param, eWrapClamp);
3674 if (page) {
3675 page->addChild(*param);
3676 }
3677 }
3678 {
3679 ChoiceParamDescriptor *param = desc.defineChoiceParam(kParamWrapV);
3680 param->setLabelAndHint(kParamWrapVLabel);
3681 addWrapOptions(param, eWrapClamp);
3682 if (page) {
3683 page->addChild(*param);
3684 }
3685 }
3686 }
3687 }
3688
3689 if (plugin == eDistortionPluginLensDistortion) {
3690 { // Frame format
3691 // extent
3692 {
3693 ChoiceParamDescriptor* param = desc.defineChoiceParam(kParamFormat);
3694 param->setLabelAndHint(kParamFormatLabel);
3695 assert(param->getNOptions() == eGeneratorExtentFormat);
3696 param->appendOption(kParamGeneratorExtentOptionFormat);
3697 assert(param->getNOptions() == eGeneratorExtentSize);
3698 param->appendOption(kParamGeneratorExtentOptionSize);
3699 assert(param->getNOptions() == eGeneratorExtentProject);
3700 param->appendOption(kParamGeneratorExtentOptionProject);
3701 assert(param->getNOptions() == eGeneratorExtentDefault);
3702 param->appendOption(kParamGeneratorExtentOptionDefault);
3703 param->setDefault(eGeneratorExtentDefault);
3704 param->setLayoutHint(eLayoutHintNoNewLine, 1);
3705 param->setAnimates(false);
3706 desc.addClipPreferencesSlaveParam(*param);
3707 if (page) {
3708 page->addChild(*param);
3709 }
3710 }
3711
3712 // recenter
3713 {
3714 PushButtonParamDescriptor* param = desc.definePushButtonParam(kParamGeneratorCenter);
3715 param->setLabel(kParamGeneratorCenterLabel);
3716 param->setHint(kParamGeneratorCenterHint);
3717 param->setLayoutHint(eLayoutHintNoNewLine, 1);
3718 if (page) {
3719 page->addChild(*param);
3720 }
3721 }
3722
3723 // format
3724 {
3725 ChoiceParamDescriptor* param = desc.defineChoiceParam(kParamGeneratorFormat);
3726 param->setLabel(kParamGeneratorFormatLabel);
3727 assert(param->getNOptions() == eParamFormatPCVideo);
3728 param->appendOption(kParamFormatPCVideoLabel, "", kParamFormatPCVideo);
3729 assert(param->getNOptions() == eParamFormatNTSC);
3730 param->appendOption(kParamFormatNTSCLabel, "", kParamFormatNTSC);
3731 assert(param->getNOptions() == eParamFormatPAL);
3732 param->appendOption(kParamFormatPALLabel, "", kParamFormatPAL);
3733 assert(param->getNOptions() == eParamFormatNTSC169);
3734 param->appendOption(kParamFormatNTSC169Label, "", kParamFormatNTSC169);
3735 assert(param->getNOptions() == eParamFormatPAL169);
3736 param->appendOption(kParamFormatPAL169Label, "", kParamFormatPAL169);
3737 assert(param->getNOptions() == eParamFormatHD720);
3738 param->appendOption(kParamFormatHD720Label, "", kParamFormatHD720);
3739 assert(param->getNOptions() == eParamFormatHD);
3740 param->appendOption(kParamFormatHDLabel, "", kParamFormatHD);
3741 assert(param->getNOptions() == eParamFormatUHD4K);
3742 param->appendOption(kParamFormatUHD4KLabel, "", kParamFormatUHD4K);
3743 assert(param->getNOptions() == eParamFormat1kSuper35);
3744 param->appendOption(kParamFormat1kSuper35Label, "", kParamFormat1kSuper35);
3745 assert(param->getNOptions() == eParamFormat1kCinemascope);
3746 param->appendOption(kParamFormat1kCinemascopeLabel, "", kParamFormat1kCinemascope);
3747 assert(param->getNOptions() == eParamFormat2kSuper35);
3748 param->appendOption(kParamFormat2kSuper35Label, "", kParamFormat2kSuper35);
3749 assert(param->getNOptions() == eParamFormat2kCinemascope);
3750 param->appendOption(kParamFormat2kCinemascopeLabel, "", kParamFormat2kCinemascope);
3751 assert(param->getNOptions() == eParamFormat2kDCP);
3752 param->appendOption(kParamFormat2kDCPLabel, "", kParamFormat2kDCP);
3753 assert(param->getNOptions() == eParamFormat4kSuper35);
3754 param->appendOption(kParamFormat4kSuper35Label, "", kParamFormat4kSuper35);
3755 assert(param->getNOptions() == eParamFormat4kCinemascope);
3756 param->appendOption(kParamFormat4kCinemascopeLabel, "", kParamFormat4kCinemascope);
3757 assert(param->getNOptions() == eParamFormat4kDCP);
3758 param->appendOption(kParamFormat4kDCPLabel, "", kParamFormat4kDCP);
3759 assert(param->getNOptions() == eParamFormatSquare256);
3760 param->appendOption(kParamFormatSquare256Label, "", kParamFormatSquare256);
3761 assert(param->getNOptions() == eParamFormatSquare512);
3762 param->appendOption(kParamFormatSquare512Label, "", kParamFormatSquare512);
3763 assert(param->getNOptions() == eParamFormatSquare1k);
3764 param->appendOption(kParamFormatSquare1kLabel, "", kParamFormatSquare1k);
3765 assert(param->getNOptions() == eParamFormatSquare2k);
3766 param->appendOption(kParamFormatSquare2kLabel, "", kParamFormatSquare2k);
3767 param->setDefault(eParamFormatPCVideo);
3768 param->setHint(kParamGeneratorFormatHint);
3769 param->setAnimates(false);
3770 desc.addClipPreferencesSlaveParam(*param);
3771 if (page) {
3772 page->addChild(*param);
3773 }
3774 }
3775
3776 {
3777 int w = 0, h = 0;
3778 double par = -1.;
3779 getFormatResolution(eParamFormatPCVideo, &w, &h, &par);
3780 assert(par != -1);
3781 {
3782 Int2DParamDescriptor* param = desc.defineInt2DParam(kParamGeneratorSize);
3783 param->setLabelAndHint(kParamGeneratorSizeLabel, kParamGeneratorSizeHint);
3784 param->setIsSecretAndDisabled(true);
3785 param->setDefault(w, h);
3786 if (page) {
3787 page->addChild(*param);
3788 }
3789 }
3790
3791 {
3792 DoubleParamDescriptor* param = desc.defineDoubleParam(kParamGeneratorPAR);
3793 param->setLabelAndHint(kParamGeneratorPARLabel, kParamGeneratorPARHint);
3794 param->setIsSecretAndDisabled(true);
3795 param->setRange(0., DBL_MAX);
3796 param->setDisplayRange(0.5, 2.);
3797 param->setDefault(par);
3798 if (page) {
3799 page->addChild(*param);
3800 }
3801 }
3802 }
3803
3804 // btmLeft
3805 {
3806 Double2DParamDescriptor* param = desc.defineDouble2DParam(kParamRectangleInteractBtmLeft);
3807 param->setLabelAndHint(kParamRectangleInteractBtmLeftLabel, "Coordinates of the bottom left corner of the size rectangle.");
3808 param->setDoubleType(eDoubleTypeXYAbsolute);
3809 if ( param->supportsDefaultCoordinateSystem() ) {
3810 param->setDefaultCoordinateSystem(eCoordinatesNormalised); // no need of kParamDefaultsNormalised
3811 } else {
3812 gHostSupportsDefaultCoordinateSystem = false; // no multithread here, see kParamDefaultsNormalised
3813 }
3814 param->setDefault(0., 0.);
3815 param->setRange(-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3816 param->setDisplayRange(-10000, -10000, 10000, 10000); // Resolve requires display range or values are clamped to (-1,1)
3817 param->setIncrement(1.);
3818 param->setLayoutHint(eLayoutHintNoNewLine, 1);
3819 param->setDigits(0);
3820 if (page) {
3821 page->addChild(*param);
3822 }
3823 }
3824
3825 // size
3826 {
3827 Double2DParamDescriptor* param = desc.defineDouble2DParam(kParamRectangleInteractSize);
3828 param->setLabelAndHint(kParamRectangleInteractSizeLabel, "Width and height of the size rectangle.");
3829 param->setDoubleType(eDoubleTypeXY);
3830 if ( param->supportsDefaultCoordinateSystem() ) {
3831 param->setDefaultCoordinateSystem(eCoordinatesNormalised); // no need of kParamDefaultsNormalised
3832 } else {
3833 gHostSupportsDefaultCoordinateSystem = false; // no multithread here, see kParamDefaultsNormalised
3834 }
3835 param->setDefault(1., 1.);
3836 param->setRange(0., 0., DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3837 param->setDisplayRange(0, 0, 10000, 10000); // Resolve requires display range or values are clamped to (-1,1)
3838 param->setIncrement(1.);
3839 param->setDimensionLabels(kParamRectangleInteractSizeDim1, kParamRectangleInteractSizeDim2);
3840 param->setIncrement(1.);
3841 param->setDigits(0);
3842 if (page) {
3843 page->addChild(*param);
3844 }
3845 }
3846
3847 }
3848
3849 {
3850 ChoiceParamDescriptor *param = desc.defineChoiceParam(kParamDistortionModel);
3851 param->setLabelAndHint(kParamDistortionModelLabel);
3852 assert(param->getNOptions() == eDistortionModelNuke);
3853 param->appendOption(kParamDistortionModelOptionNuke);
3854 assert(param->getNOptions() == eDistortionModelPFBarrel);
3855 param->appendOption(kParamDistortionModelOptionPFBarrel);
3856 assert(param->getNOptions() == eDistortionModel3DEClassic);
3857 param->appendOption(kParamDistortionModelOption3DEClassic);
3858 assert(param->getNOptions() == eDistortionModel3DEAnamorphic6);
3859 param->appendOption(kParamDistortionModelOption3DEAnamorphic6);
3860 assert(param->getNOptions() == eDistortionModel3DEFishEye8);
3861 param->appendOption(kParamDistortionModelOption3DEFishEye8);
3862 assert(param->getNOptions() == eDistortionModel3DEStandard);
3863 param->appendOption(kParamDistortionModelOption3DEStandard);
3864 assert(param->getNOptions() == eDistortionModel3DEAnamorphic4);
3865 param->appendOption(kParamDistortionModelOption3DEAnamorphic4);
3866 assert(param->getNOptions() == eDistortionModelPanoTools);
3867 param->appendOption(kParamDistortionModelOptionPanoTools);
3868 if (page) {
3869 page->addChild(*param);
3870 }
3871 }
3872 {
3873 ChoiceParamDescriptor *param = desc.defineChoiceParam(kParamDistortionDirection);
3874 param->setLabelAndHint(kParamDistortionDirectionLabel);
3875 assert(param->getNOptions() == eDirectionDistort);
3876 param->appendOption(kParamDistortionDirectionOptionDistort);
3877 assert(param->getNOptions() == eDirectionUndistort);
3878 param->appendOption(kParamDistortionDirectionOptionUndistort);
3879 param->setDefault((int)eDirectionDistort); // same default as in Nuke, and also the most straightforward (non-iterative) transform for most models
3880 if (page) {
3881 page->addChild(*param);
3882 }
3883 }
3884 {
3885 ChoiceParamDescriptor *param = desc.defineChoiceParam(kParamDistortionOutputMode);
3886 param->setLabelAndHint(kParamDistortionOutputModeLabel);
3887 assert(param->getNOptions() == eOutputModeImage);
3888 param->appendOption(kParamDistortionOutputModeOptionImage);
3889 assert(param->getNOptions() == eOutputModeSTMap);
3890 param->appendOption(kParamDistortionOutputModeOptionSTMap);
3891 if (page) {
3892 page->addChild(*param);
3893 }
3894 }
3895
3896 // Nuke
3897 {
3898 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamK1);
3899 param->setLabelAndHint(kParamK1Label);
3900 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3901 param->setDisplayRange(-0.3, 0.3);
3902 if (page) {
3903 page->addChild(*param);
3904 }
3905 }
3906 {
3907 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamK2);
3908 param->setLabelAndHint(kParamK2Label);
3909 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3910 param->setDisplayRange(-0.1, 0.1);
3911 if (page) {
3912 page->addChild(*param);
3913 }
3914 }
3915 {
3916 Double2DParamDescriptor *param = desc.defineDouble2DParam(kParamCenter);
3917 param->setLabelAndHint(kParamCenterLabel);
3918 param->setRange(-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3919 param->setUseHostNativeOverlayHandle(false);
3920 param->setDoubleType(eDoubleTypePlain);
3921 param->setDisplayRange(-1, -1, 1, 1);
3922 if (page) {
3923 page->addChild(*param);
3924 }
3925 }
3926 {
3927 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamSqueeze);
3928 param->setLabelAndHint(kParamSqueezeLabel);
3929 param->setDefault(1.);
3930 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3931 param->setDisplayRange(0., 1.);
3932 if (page) {
3933 page->addChild(*param);
3934 }
3935 }
3936 {
3937 Double2DParamDescriptor *param = desc.defineDouble2DParam(kParamAsymmetric);
3938 param->setLabelAndHint(kParamAsymmetricLabel);
3939 param->setRange(-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3940 param->setDoubleType(eDoubleTypePlain);
3941 param->setDisplayRange(-0.5, -0.5, 0.5, 0.5);
3942 param->setUseHostNativeOverlayHandle(false);
3943 if (page) {
3944 page->addChild(*param);
3945 }
3946 }
3947
3948 ////////////
3949 // PFBarrel
3950 {
3951 StringParamDescriptor *param = desc.defineStringParam(kParamPFFile);
3952 param->setLabelAndHint(kParamPFFileLabel);
3953 param->setStringType(eStringTypeFilePath);
3954 param->setFilePathExists(true);
3955 #ifdef OFX_EXTENSIONS_NUKE
3956 if (!getImageEffectHostDescription()->isNatron) {
3957 param->setLayoutHint(eLayoutHintNoNewLine, 1);
3958 }
3959 #endif
3960 if (page) {
3961 page->addChild(*param);
3962 }
3963 }
3964 if (!getImageEffectHostDescription()->isNatron) {
3965 // Natron has its own reload button
3966 PushButtonParamDescriptor *param = desc.definePushButtonParam(kParamPFFileReload);
3967 param->setLabelAndHint(kParamPFFileReloadLabel);
3968 if (page) {
3969 page->addChild(*param);
3970 }
3971 }
3972 {
3973 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamPFC3);
3974 param->setLabelAndHint(kParamPFC3Label);
3975 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3976 param->setDisplayRange(-0.5, 0.5);
3977 if (page) {
3978 page->addChild(*param);
3979 }
3980 }
3981 {
3982 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamPFC5);
3983 param->setLabelAndHint(kParamPFC5Label);
3984 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3985 param->setDisplayRange(-0.5, 0.5);
3986 if (page) {
3987 page->addChild(*param);
3988 }
3989 }
3990 {
3991 Double2DParamDescriptor *param = desc.defineDouble2DParam(kParamPFP);
3992 param->setLabelAndHint(kParamPFPLabel);
3993 param->setRange(-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
3994 param->setDisplayRange(0., 0., 1., 1.);
3995 param->setDefault(0.5, 0.5);
3996 param->setDoubleType(eDoubleTypePlain);
3997 param->setUseHostNativeOverlayHandle(false);
3998 if (page) {
3999 page->addChild(*param);
4000 }
4001 }
4002 {
4003 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamPFSqueeze);
4004 param->setLabelAndHint(kParamPFSqueezeLabel);
4005 param->setRange(0.0, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4006 param->setDisplayRange(0.1, 3.);
4007 param->setDefault(1.);
4008 if (page) {
4009 page->addChild(*param);
4010 }
4011 }
4012
4013 ////////////////
4014 // 3DEqualizer
4015 // fov parameters
4016 {
4017 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_xa_fov_unit);
4018 param->setLabelAndHint(kParam3DE4_xa_fov_unitLabel);
4019 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4020 param->setDisplayRange(0., 1.);
4021 param->setDefault(0.);
4022 if (page) {
4023 page->addChild(*param);
4024 }
4025 }
4026 {
4027 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_ya_fov_unit);
4028 param->setLabelAndHint(kParam3DE4_ya_fov_unitLabel);
4029 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4030 param->setDisplayRange(0., 1.);
4031 param->setDefault(0.);
4032 if (page) {
4033 page->addChild(*param);
4034 }
4035 }
4036 {
4037 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_xb_fov_unit);
4038 param->setLabelAndHint(kParam3DE4_xb_fov_unitLabel);
4039 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4040 param->setDisplayRange(0., 1.);
4041 param->setDefault(1.);
4042 if (page) {
4043 page->addChild(*param);
4044 }
4045 }
4046 {
4047 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_yb_fov_unit);
4048 param->setLabelAndHint(kParam3DE4_yb_fov_unitLabel);
4049 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4050 param->setDisplayRange(0., 1.);
4051 param->setDefault(1.);
4052 if (page) {
4053 page->addChild(*param);
4054 }
4055 }
4056 // seven builtin parameters
4057 {
4058 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_focal_length_cm);
4059 param->setLabelAndHint(kParam3DE4_focal_length_cmLabel);
4060 param->setRange(0, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4061 param->setDisplayRange(0.5, 50.);
4062 param->setDefault(1.);
4063 if (page) {
4064 page->addChild(*param);
4065 }
4066 }
4067 {
4068 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_custom_focus_distance_cm);
4069 param->setLabelAndHint(kParam3DE4_custom_focus_distance_cmLabel);
4070 param->setRange(0, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4071 param->setDisplayRange(10, 1000.);
4072 param->setDefault(100.);
4073 if (page) {
4074 page->addChild(*param);
4075 }
4076 }
4077 {
4078 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_filmback_width_cm);
4079 param->setLabelAndHint(kParam3DE4_filmback_width_cmLabel);
4080 param->setRange(0, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4081 param->setDisplayRange(0.1, 10.);
4082 param->setDefault(0.8);
4083 if (page) {
4084 page->addChild(*param);
4085 }
4086 }
4087 {
4088 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_filmback_height_cm);
4089 param->setLabelAndHint(kParam3DE4_filmback_height_cmLabel);
4090 param->setRange(0, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4091 param->setDisplayRange(0.1, 10.);
4092 param->setDefault(0.6);
4093 if (page) {
4094 page->addChild(*param);
4095 }
4096 }
4097 {
4098 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_lens_center_offset_x_cm);
4099 param->setLabelAndHint(kParam3DE4_lens_center_offset_x_cmLabel);
4100 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4101 param->setDisplayRange(-5., 5.);
4102 param->setDefault(0.);
4103 if (page) {
4104 page->addChild(*param);
4105 }
4106 }
4107 {
4108 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_lens_center_offset_y_cm);
4109 param->setLabelAndHint(kParam3DE4_lens_center_offset_y_cmLabel);
4110 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4111 param->setDisplayRange(-5., 5.);
4112 param->setDefault(0.);
4113 if (page) {
4114 page->addChild(*param);
4115 }
4116 }
4117 {
4118 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DE4_pixel_aspect);
4119 param->setLabelAndHint(kParam3DE4_pixel_aspectLabel);
4120 param->setRange(0., DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4121 param->setDisplayRange(0.25, 4.);
4122 param->setDefault(1.);
4123 if (page) {
4124 page->addChild(*param);
4125 }
4126 }
4127 // 3DE Classic model
4128 {
4129 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEDistortion);
4130 param->setLabelAndHint(kParam3DEDistortionLabel);
4131 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4132 param->setDisplayRange(-0.5, 0.5);
4133 param->setDefault(0.);
4134 if (page) {
4135 page->addChild(*param);
4136 }
4137 }
4138 {
4139 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEAnamorphicSqueeze);
4140 param->setLabelAndHint(kParam3DEAnamorphicSqueezeLabel);
4141 param->setRange(0., DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4142 param->setDisplayRange(0.25, 4.);
4143 param->setDefault(1.);
4144 if (page) {
4145 page->addChild(*param);
4146 }
4147 }
4148 {
4149 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECurvatureX);
4150 param->setLabelAndHint(kParam3DECurvatureXLabel);
4151 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4152 param->setDisplayRange(-0.5, 0.5);
4153 param->setDefault(0.);
4154 if (page) {
4155 page->addChild(*param);
4156 }
4157 }
4158 {
4159 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECurvatureY);
4160 param->setLabelAndHint(kParam3DECurvatureYLabel);
4161 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4162 param->setDisplayRange(-0.5, 0.5);
4163 param->setDefault(0.);
4164 if (page) {
4165 page->addChild(*param);
4166 }
4167 }
4168 {
4169 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEQuarticDistortion);
4170 param->setLabelAndHint(kParam3DEQuarticDistortionLabel);
4171 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4172 param->setDisplayRange(-0.5, 0.5);
4173 param->setDefault(0.);
4174 if (page) {
4175 page->addChild(*param);
4176 }
4177 }
4178 // 3DE Radial Standard Degree 4
4179 {
4180 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEDistortionDegree2);
4181 param->setLabelAndHint(kParam3DEDistortionDegree2Label);
4182 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4183 param->setDisplayRange(-0.5, 0.5);
4184 param->setDefault(0.);
4185 if (page) {
4186 page->addChild(*param);
4187 }
4188 }
4189 {
4190 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEUDegree2);
4191 param->setLabelAndHint(kParam3DEUDegree2Label);
4192 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4193 param->setDisplayRange(-0.5, 0.5);
4194 param->setDefault(0.);
4195 if (page) {
4196 page->addChild(*param);
4197 }
4198 }
4199 {
4200 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEVDegree2);
4201 param->setLabelAndHint(kParam3DEVDegree2Label);
4202 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4203 param->setDisplayRange(-0.5, 0.5);
4204 param->setDefault(0.);
4205 if (page) {
4206 page->addChild(*param);
4207 }
4208 }
4209 {
4210 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEQuarticDistortionDegree4);
4211 param->setLabelAndHint(kParam3DEQuarticDistortionDegree4Label);
4212 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4213 param->setDisplayRange(-0.5, 0.5);
4214 param->setDefault(0.);
4215 if (page) {
4216 page->addChild(*param);
4217 }
4218 }
4219 {
4220 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEUDegree4);
4221 param->setLabelAndHint(kParam3DEUDegree4Label);
4222 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4223 param->setDisplayRange(-0.5, 0.5);
4224 param->setDefault(0.);
4225 if (page) {
4226 page->addChild(*param);
4227 }
4228 }
4229 {
4230 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEVDegree4);
4231 param->setLabelAndHint(kParam3DEVDegree4Label);
4232 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4233 param->setDisplayRange(-0.5, 0.5);
4234 param->setDefault(0.);
4235 if (page) {
4236 page->addChild(*param);
4237 }
4238 }
4239 {
4240 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEPhiCylindricDirection);
4241 param->setLabelAndHint(kParam3DEPhiCylindricDirectionLabel);
4242 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4243 param->setDisplayRange(-90., 90.);
4244 param->setDefault(0.);
4245 if (page) {
4246 page->addChild(*param);
4247 }
4248 }
4249 {
4250 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEBCylindricBending);
4251 param->setLabelAndHint(kParam3DEBCylindricBendingLabel);
4252 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4253 param->setDisplayRange(-0.1, 0.1);
4254 param->setDefault(0.);
4255 if (page) {
4256 page->addChild(*param);
4257 }
4258 }
4259 // 3DE4_Anamorphic_Standard_Degree_4 and 3DE4_Anamorphic_Degree_6
4260 {
4261 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECx02Degree2);
4262 param->setLabelAndHint(kParam3DECx02Degree2Label);
4263 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4264 param->setDisplayRange(-0.5, 0.5);
4265 param->setDefault(0.);
4266 if (page) {
4267 page->addChild(*param);
4268 }
4269 }
4270 {
4271 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECy02Degree2);
4272 param->setLabelAndHint(kParam3DECy02Degree2Label);
4273 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4274 param->setDisplayRange(-0.5, 0.5);
4275 param->setDefault(0.);
4276 if (page) {
4277 page->addChild(*param);
4278 }
4279 }
4280 {
4281 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECx22Degree2);
4282 param->setLabelAndHint(kParam3DECx22Degree2Label);
4283 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4284 param->setDisplayRange(-0.5, 0.5);
4285 param->setDefault(0.);
4286 if (page) {
4287 page->addChild(*param);
4288 }
4289 }
4290 {
4291 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECy22Degree2);
4292 param->setLabelAndHint(kParam3DECy22Degree2Label);
4293 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4294 param->setDisplayRange(-0.5, 0.5);
4295 param->setDefault(0.);
4296 if (page) {
4297 page->addChild(*param);
4298 }
4299 }
4300 {
4301 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECx04Degree4);
4302 param->setLabelAndHint(kParam3DECx04Degree4Label);
4303 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4304 param->setDisplayRange(-0.5, 0.5);
4305 param->setDefault(0.);
4306 if (page) {
4307 page->addChild(*param);
4308 }
4309 }
4310 {
4311 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECy04Degree4);
4312 param->setLabelAndHint(kParam3DECy04Degree4Label);
4313 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4314 param->setDisplayRange(-0.5, 0.5);
4315 param->setDefault(0.);
4316 if (page) {
4317 page->addChild(*param);
4318 }
4319 }
4320 {
4321 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECx24Degree4);
4322 param->setLabelAndHint(kParam3DECx24Degree4Label);
4323 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4324 param->setDisplayRange(-0.5, 0.5);
4325 param->setDefault(0.);
4326 if (page) {
4327 page->addChild(*param);
4328 }
4329 }
4330 {
4331 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECy24Degree4);
4332 param->setLabelAndHint(kParam3DECy24Degree4Label);
4333 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4334 param->setDisplayRange(-0.5, 0.5);
4335 param->setDefault(0.);
4336 if (page) {
4337 page->addChild(*param);
4338 }
4339 }
4340 {
4341 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECx44Degree4);
4342 param->setLabelAndHint(kParam3DECx44Degree4Label);
4343 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4344 param->setDisplayRange(-0.5, 0.5);
4345 param->setDefault(0.);
4346 if (page) {
4347 page->addChild(*param);
4348 }
4349 }
4350 {
4351 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECy44Degree4);
4352 param->setLabelAndHint(kParam3DECy44Degree4Label);
4353 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4354 param->setDisplayRange(-0.5, 0.5);
4355 param->setDefault(0.);
4356 if (page) {
4357 page->addChild(*param);
4358 }
4359 }
4360 {
4361 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECx06Degree6);
4362 param->setLabelAndHint(kParam3DECx06Degree6Label);
4363 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4364 param->setDisplayRange(-0.5, 0.5);
4365 param->setDefault(0.);
4366 if (page) {
4367 page->addChild(*param);
4368 }
4369 }
4370 {
4371 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECy06Degree6);
4372 param->setLabelAndHint(kParam3DECy06Degree6Label);
4373 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4374 param->setDisplayRange(-0.5, 0.5);
4375 param->setDefault(0.);
4376 if (page) {
4377 page->addChild(*param);
4378 }
4379 }
4380 {
4381 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECx26Degree6);
4382 param->setLabelAndHint(kParam3DECx26Degree6Label);
4383 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4384 param->setDisplayRange(-0.5, 0.5);
4385 param->setDefault(0.);
4386 if (page) {
4387 page->addChild(*param);
4388 }
4389 }
4390 {
4391 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECy26Degree6);
4392 param->setLabelAndHint(kParam3DECy26Degree6Label);
4393 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4394 param->setDisplayRange(-0.5, 0.5);
4395 param->setDefault(0.);
4396 if (page) {
4397 page->addChild(*param);
4398 }
4399 }
4400 {
4401 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECx46Degree6);
4402 param->setLabelAndHint(kParam3DECx46Degree6Label);
4403 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4404 param->setDisplayRange(-0.5, 0.5);
4405 param->setDefault(0.);
4406 if (page) {
4407 page->addChild(*param);
4408 }
4409 }
4410 {
4411 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECy46Degree6);
4412 param->setLabelAndHint(kParam3DECy46Degree6Label);
4413 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4414 param->setDisplayRange(-0.5, 0.5);
4415 param->setDefault(0.);
4416 if (page) {
4417 page->addChild(*param);
4418 }
4419 }
4420 {
4421 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECx66Degree6);
4422 param->setLabelAndHint(kParam3DECx66Degree6Label);
4423 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4424 param->setDisplayRange(-0.5, 0.5);
4425 param->setDefault(0.);
4426 if (page) {
4427 page->addChild(*param);
4428 }
4429 }
4430 {
4431 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DECy66Degree6);
4432 param->setLabelAndHint(kParam3DECy66Degree6Label);
4433 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4434 param->setDisplayRange(-0.5, 0.5);
4435 param->setDefault(0.);
4436 if (page) {
4437 page->addChild(*param);
4438 }
4439 }
4440 {
4441 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DELensRotation);
4442 param->setLabelAndHint(kParam3DELensRotationLabel);
4443 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4444 param->setDisplayRange(-2., 2.);
4445 param->setDefault(0.);
4446 if (page) {
4447 page->addChild(*param);
4448 }
4449 }
4450 {
4451 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DESqueezeX);
4452 param->setLabelAndHint(kParam3DESqueezeXLabel);
4453 param->setRange(0, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4454 param->setDisplayRange(0.9, 1.1);
4455 param->setDefault(1.);
4456 if (page) {
4457 page->addChild(*param);
4458 }
4459 }
4460 {
4461 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DESqueezeY);
4462 param->setLabelAndHint(kParam3DESqueezeYLabel);
4463 param->setRange(0, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4464 param->setDisplayRange(0.9, 1.1);
4465 param->setDefault(1.);
4466 if (page) {
4467 page->addChild(*param);
4468 }
4469 }
4470 // 3DEFishEye8
4471 {
4472 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEDegree6);
4473 param->setLabelAndHint(kParam3DEDegree6Label);
4474 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4475 param->setDisplayRange(-0.5, 0.5);
4476 param->setDefault(0.);
4477 if (page) {
4478 page->addChild(*param);
4479 }
4480 }
4481 {
4482 DoubleParamDescriptor *param = desc.defineDoubleParam(kParam3DEDegree8);
4483 param->setLabelAndHint(kParam3DEDegree8Label);
4484 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4485 param->setDisplayRange(-0.5, 0.5);
4486 param->setDefault(0.);
4487 if (page) {
4488 page->addChild(*param);
4489 }
4490 }
4491
4492 // PanoTools
4493 {
4494 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamPanoToolsA);
4495 param->setLabelAndHint(kParamPanoToolsALabel);
4496 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4497 param->setDisplayRange(-0.2, 0.2);
4498 if (page) {
4499 page->addChild(*param);
4500 }
4501 }
4502 {
4503 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamPanoToolsB);
4504 param->setLabelAndHint(kParamPanoToolsBLabel);
4505 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4506 param->setDisplayRange(-0.2, 0.2);
4507 if (page) {
4508 page->addChild(*param);
4509 }
4510 }
4511 {
4512 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamPanoToolsC);
4513 param->setLabelAndHint(kParamPanoToolsCLabel);
4514 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4515 param->setDisplayRange(-0.2, 0.2);
4516 if (page) {
4517 page->addChild(*param);
4518 }
4519 }
4520 {
4521 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamPanoToolsD);
4522 param->setLabelAndHint(kParamPanoToolsDLabel);
4523 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4524 param->setDisplayRange(-1000., 1000.);
4525 if (page) {
4526 page->addChild(*param);
4527 }
4528 }
4529 {
4530 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamPanoToolsE);
4531 param->setLabelAndHint(kParamPanoToolsELabel);
4532 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4533 param->setDisplayRange(-1000., 1000.);
4534 if (page) {
4535 page->addChild(*param);
4536 }
4537 }
4538 {
4539 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamPanoToolsG);
4540 param->setLabelAndHint(kParamPanoToolsGLabel);
4541 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4542 param->setDisplayRange(-1000., 1000.);
4543 if (page) {
4544 page->addChild(*param);
4545 }
4546 }
4547 {
4548 DoubleParamDescriptor *param = desc.defineDoubleParam(kParamPanoToolsT);
4549 param->setLabelAndHint(kParamPanoToolsTLabel);
4550 param->setRange(-DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
4551 param->setDisplayRange(-1000., 1000.);
4552 if (page) {
4553 page->addChild(*param);
4554 }
4555 }
4556
4557 }
4558
4559 ofxsFilterDescribeParamsInterpolate2D( desc, page, (plugin == eDistortionPluginSTMap) );
4560 #ifdef OFX_EXTENSIONS_NATRON
4561 if (plugin == eDistortionPluginLensDistortion && majorVersion >= 4 && getImageEffectHostDescription()->isNatron) {
4562 BooleanParamDescriptor *param = desc.defineBooleanParam(kParamCropToFormat);
4563 param->setLabel(kParamCropToFormatLabel);
4564 param->setHint(kParamCropToFormatHint);
4565 param->setDefault(true);
4566 if (page) {
4567 page->addChild(*param);
4568 }
4569 }
4570 #endif
4571 ofxsPremultDescribeParams(desc, page);
4572 ofxsMaskMixDescribeParams(desc, page);
4573 } // >::describeInContext
4574
4575 template<DistortionPluginEnum plugin, int majorVersion>
4576 ImageEffect*
createInstance(OfxImageEffectHandle handle,ContextEnum)4577 DistortionPluginFactory<plugin, majorVersion>::createInstance(OfxImageEffectHandle handle,
4578 ContextEnum /*context*/)
4579 {
4580 return new DistortionPlugin(handle, this->getMajorVersion(), plugin);
4581 }
4582
4583 static DistortionPluginFactory<eDistortionPluginIDistort,kPluginVersionMajor> pIDistort(kPluginIDistortIdentifier, kPluginVersionMajor, kPluginVersionMinor);
4584 static DistortionPluginFactory<eDistortionPluginSTMap,kPluginVersionMajor> pSTMap(kPluginSTMapIdentifier, kPluginVersionMajor, kPluginVersionMinor);
4585 static DistortionPluginFactory<eDistortionPluginLensDistortion,2> pLensDistortion2(kPluginLensDistortionIdentifier, 2, kPluginVersionMinor);
4586 static DistortionPluginFactory<eDistortionPluginLensDistortion,3> pLensDistortion3(kPluginLensDistortionIdentifier, 3, kPluginVersionMinor);
4587 static DistortionPluginFactory<eDistortionPluginLensDistortion,kPluginVersionLensDistortionMajor> pLensDistortion4(kPluginLensDistortionIdentifier, kPluginVersionLensDistortionMajor, kPluginVersionLensDistortionMinor);
4588 mRegisterPluginFactoryInstance(pIDistort)
4589 mRegisterPluginFactoryInstance(pSTMap)
4590 mRegisterPluginFactoryInstance(pLensDistortion2)
4591 mRegisterPluginFactoryInstance(pLensDistortion3)
4592 mRegisterPluginFactoryInstance(pLensDistortion4)
4593
4594 OFXS_NAMESPACE_ANONYMOUS_EXIT
4595