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 Transform & DirBlur plugins.
21 */
22
23 #define _USE_MATH_DEFINES
24 #include <cmath> // tan, atan2
25 #include <cstring> // strerror
26 #include <cstdio> // fopen, fclose
27 #include <cstdlib> // atoi, atof
28 #include <cerrno> // errno
29 #include <iostream>
30
31 #include "ofxsTransform3x3.h"
32 #include "ofxsCoords.h"
33 #include "ofxsThreadSuite.h"
34 #include "ofxsGenerator.h"
35 #include "ofxsFormatResolution.h"
36 #include "ofxsFileOpen.h"
37
38 using namespace OFX;
39 using std::string;
40
41 #define kCameraAxis "axis"
42 #define kCameraAxisLabel "Axis"
43
44 #define kCameraCam "cam"
45 #define kCameraCamLabel "Cam"
46
47 #define kGroupCard "card"
48 #define kGroupCardLabel "Card"
49
50
51 //#define kParamTransformAmount "transformAmount"
52 //#define kParamTransformAmountLabel "Amount"
53 //#define kParamTransformAmountHint "Amount of transform to apply (excluding the extra matrix, which is always applied). 0 means the transform is identity, 1 means to apply the full transform."
54
55 #define kParamTransformInteractive "interactive"
56 #define kParamTransformInteractiveLabel "Interactive Update"
57 #define kParamTransformInteractiveHint "If checked, update the parameter values during interaction with the image viewer, else update the values when pen is released."
58
59 OFXS_NAMESPACE_ANONYMOUS_ENTER
60
61 #define kPluginName "Card3DOFX"
62 #define kPluginGrouping "Transform"
63 #define kPluginDescription "Card3D.\n" \
64 "This effect applies a transform that corresponds to projection the source image onto a 3D card in space. The 3D card is positionned with relative to the Axis position, and the Camera position may also be given. The Axis may be used to apply the same global motion to several cards.\n" \
65 "This plugin concatenates transforms.\n" \
66 "http://opticalenquiry.com/nuke/index.php?title=Card3D"
67
68 #define kPluginIdentifier "net.sf.openfx.Card3D"
69 #define kPluginVersionMajor 1 // Incrementing this number means that you have broken backwards compatibility of the plug-in.
70 #define kPluginVersionMinor 0 // Increment this when you have fixed a bug or made it faster.
71
72 #define kParamSrcClipChanged "srcClipChanged"
73
74 #define kParamCamEnable "camEnable"
75 #define kParamCamEnableLabel "Enable Camera", "Enable the camera projection parameters."
76
77 #define kParamLensInFocal "lensInFocal"
78 #define kParamLensInFocalLabel "Lens-In Focal", "The focal length of the camera that took the picture on the card. The card is scaled so that at distance 1 (which is the default card Z) it occupies the field of view corresponding to lensInFocal and lensInHAperture."
79
80 #define kParamLensInHAperture "lensInHAperture"
81 #define kParamLensInHApertureLabel "Lens-In H.Aperture", "The horizontal aperture (or sensor/film back width) of the camera that took the picture on the card. The card is scaled so that at distance 1 (which is the default card Z) it occupies the field of view corresponding to lensInFocal and lensInHAperture."
82
83 #define kParamOutputFormat "format"
84 #define kParamOutputFormatLabel "Output Format", "Desired format for the output sequence."
85
86 // Some hosts (e.g. Resolve) may not support normalized defaults (setDefaultCoordinateSystem(eCoordinatesNormalised))
87 #define kParamDefaultsNormalised "defaultsNormalised"
88
89 static bool gHostSupportsDefaultCoordinateSystem = true; // for kParamDefaultsNormalised
90
91 ////////////////////////////////////////////////////////////////////////////////
92 // BEGIN CameraParm
93
94 // Camera Projection parameters
95
96
97 #define kParamCameraProjectionGroup "Projection"
98 #define kParamCameraProjectionGroupLabel "Projection"
99
100 #define kParamCameraProjectionMode kNukeOfxCameraParamProjectionMode
101 #define kParamCameraProjectionModeLabel "Projection"
102 #define kParamCameraProjectionModeOptionPerspective "Perspective", "Perspective projection.", "perspective"
103 #define kParamCameraProjectionModeOptionOrthographic "Orthographic", "Orthographic projection", "orthographic"
104 //#define kParamCameraProjectionModeOptionUV "UV", "UV projection", "uv" // used in Nuke to compute uv coordinates instead of pixel values
105 //#define kParamCameraProjectionModeOptionSpherical "Spherical", "Spherical projection." , "spherical"
106 enum CameraProjectionModeEnum {
107 eCameraProjectionModePerspective = 0,
108 eCameraProjectionModeOrthographic,
109 eCameraProjectionModeUV,
110 eCameraProjectionModeSpherical,
111 };
112 /* other camera projections from nona http://hugin.sourceforge.net/docs/nona/nona.txt
113 see also http://wiki.panotools.org/Projections http://wiki.panotools.org/Fisheye
114 # 0 - rectilinear (for printing and viewing) [R = f.tan(theta)] http://wiki.panotools.org/Rectilinear_Projection
115 # 1 - Cylindrical (for Printing and QTVR) http://wiki.panotools.org/Cylindrical_Projection
116 # 2 - Equirectangular ( for Spherical panos), default http://wiki.panotools.org/Equirectangular_Projection
117 # 3 - full-frame fisheye [R = f.theta], e.g. Peleng 8mm f/3.5 Fisheye
118 # 4 - Stereographic [R = 2f.tan(theta/2)], e.g. Samyang 8 mm f/3.5
119 # 5 - Mercator http://wiki.panotools.org/Projections#Mercator_projection
120 # 6 - Transverse Mercator
121 # 7 - Sinusoidal http://wiki.panotools.org/Projections#Sinusoidal_projection
122 # 8 - Lambert Cylindrical Equal Area
123 # 9 - Lambert Equal Area Azimuthal
124 # 10 - Albers Equal Area Conic
125 # 11 - Miller Cylindrical http://wiki.panotools.org/Projections#Miller_projection
126 # 12 - Panini (obsolete non-Panini projection)
127 # 13 - Architectural (Miller above the horizon, Lambert Equal Area below
128 # 14 - Orthographic [R = f.sin(theta)], e.g. Yasuhara - MADOKA 180 circle fisheye lens
129 # 15 - Equisolid (equal-area fisheye) [R=2f.sin(theta/2)], e. g. Sigma 8mm f/4.0 AF EX, Olympus 8mm F2.8, Nikon 6mm F2.8, Nikon 8mm F2.8 (also convex mirror)
130 # 16 - Equirectangular Panini (standard Panini, covered by Panini General)
131 # 17 - Biplane
132 # 18 - Triplane
133 # 19 - Panini General http://wiki.panotools.org/The_General_Panini_Projection has 3 parameters: http://wiki.panotools.org/The_General_Panini_Projection#Parameters
134 # 20 - Thoby Projection [R = k1.f.sin(k2.theta) k1=1.47 k2=0.713], e.g. AF DX Fisheye-Nikkor 10.5mm f/2.8G ED
135 # 21 - Hammer-Aitoff Projection
136
137 lens may be:
138 # 0 - rectilinear (normal lenses)
139 # 1 - Panoramic (Scanning cameras like Noblex)
140 # 2 - Circular fisheye
141 # 3 - full-frame fisheye
142 # 4 - PSphere, equirectangular
143 # 8 - orthographic fisheye
144 # 10 - stereographic fisheye
145 # 21 - Equisolid fisheye
146 # 20 - Fisheye Thoby (Nikkor 10.5)
147
148 lens supported by videostitch studio:
149 2 - Equirectangular
150 4 - Stereographic
151 0 - Rectilinear
152 ??? Circular fisheye
153 3 - Full-frame fisheye
154
155 */
156 #define kParamCameraFocalLength kNukeOfxCameraParamFocalLength
157 #define kParamCameraFocalLengthLabel "Focal Length", "The camera focal length, in arbitrary units (usually either millimeters or 35 mm equivalent focal length). haperture and vaperture must be expressed in the same units."
158 #define kParamCameraHorizontalAperture kNukeOfxCameraParamHorizontalAperture
159 #define kParamCameraHorizontalApertureLabel "Horiz. Aperture", "The camera horizontal aperture (or film back width), in the same units as the focal length. In the case of scanned film, this can be obtained as image_width * scanner_pitch."
160 #define kParamCameraVerticalAperture kNukeOfxCameraParamVerticalAperture
161 #define kParamCameraVerticalApertureLabel "Vert. Aperture", "The camera vertical aperture (or film back height), in the same units as the focal length. This does not affect the projection (which is computed from haperture and the image aspect ratio), but it is used to compute the focal length from vertical FOV when importing chan files, using the formula: focal = 0.5 * vaperture / tan(vfov/2). It is thus best set as: haperture = vaperture * image_width/image_height. In the case of scanned film, this can be obtained as image_height * scanner_pitch."
162 #define kParamCameraNear kNukeOfxCameraParamNear
163 #define kParamCameraNearLabel "Near"
164 #define kParamCameraFar kNukeOfxCameraParamFar
165 #define kParamCameraFarLabel "Far"
166 #define kParamCameraWindowTranslate kNukeOfxCameraParamWindowTranslate
167 #define kParamCameraWindowTranslateLabel "Window Translate", "The camera window (or film back) is translated by this fraction of the horizontal aperture, without changing the position of the camera center. This can be used to model tilt-shift or perspective-control lens."
168 #define kParamCameraWindowScale kNukeOfxCameraParamWindowScale
169 #define kParamCameraWindowScaleLabel "Window Scale", "Scale the camera window (or film back)."
170 #define kParamCameraWindowRoll kNukeOfxCameraParamWindowRoll
171 #define kParamCameraWindowRollLabel "Window Roll", "Rotation (in degrees) of the camera window (or film back) around the z axis."
172 #define kParamCameraFocalPoint kNukeOfxCameraParamFocalPoint
173 #define kParamCameraFocalPointLabel "Focus Distance", "Focus distance of the camera (used for depth-of-field effects)."
174 #define kParamCameraFStop "fstop"
175 #define kParamCameraFStopLabel "F-Stop", "F-stop (relative aperture) of the camera (used for depth-of-field effects)."
176
177 class CameraParam {
178 friend class PosMatParam;
179
180 std::string _prefix;
181 ChoiceParam* _camProjectionMode;
182 DoubleParam* _camFocalLength;
183 DoubleParam* _camHAperture;
184 DoubleParam* _camVAperture;
185 DoubleParam* _camNear;
186 DoubleParam* _camFar;
187 Double2DParam* _camWinTranslate;
188 Double2DParam* _camWinScale;
189 DoubleParam* _camWinRoll;
190 DoubleParam* _camFocusDistance;
191 DoubleParam* _camFStop;
192 bool _enabled;
193
194 public:
CameraParam(OFX::ImageEffect * parent,const std::string & prefix)195 CameraParam(OFX::ImageEffect* parent, const std::string& prefix)
196 : _prefix(prefix)
197 , _camProjectionMode(NULL)
198 , _camFocalLength(NULL)
199 , _camHAperture(NULL)
200 , _camVAperture(NULL)
201 , _camNear(NULL)
202 , _camFar(NULL)
203 , _camWinTranslate(NULL)
204 , _camWinScale(NULL)
205 , _camWinRoll(NULL)
206 , _camFocusDistance(NULL)
207 , _camFStop(NULL)
208 , _enabled(true)
209 {
210 _camProjectionMode = parent->fetchChoiceParam(prefix + kParamCameraProjectionMode);
211 _camFocalLength = parent->fetchDoubleParam(prefix + kParamCameraFocalLength);
212 _camHAperture = parent->fetchDoubleParam(prefix + kParamCameraHorizontalAperture);
213 if (parent->paramExists(prefix + kParamCameraVerticalAperture)) {
214 _camVAperture = parent->fetchDoubleParam(prefix + kParamCameraVerticalAperture);
215 }
216 if (parent->paramExists(prefix + kParamCameraNear)) {
217 _camNear = parent->fetchDoubleParam(prefix + kParamCameraNear);
218 }
219 if (parent->paramExists(prefix + kParamCameraFar)) {
220 _camFar = parent->fetchDoubleParam(prefix + kParamCameraFar);
221 }
222 _camWinTranslate = parent->fetchDouble2DParam(prefix + kParamCameraWindowTranslate);
223 _camWinScale = parent->fetchDouble2DParam(prefix + kParamCameraWindowScale);
224 _camWinRoll = parent->fetchDoubleParam(prefix + kParamCameraWindowRoll);
225 if (parent->paramExists(prefix + kParamCameraFocalPoint)) {
226 _camFocusDistance = parent->fetchDoubleParam(prefix + kParamCameraFocalPoint);
227 }
228 if (parent->paramExists(prefix + kParamCameraFStop)) {
229 _camFStop = parent->fetchDoubleParam(prefix + kParamCameraFStop);
230 }
231 }
232
233 void getValueAtTime(double time,
234 CameraProjectionModeEnum& projectionMode,
235 double& focalLength,
236 double& hAperture,
237 double& winTranslateU,
238 double& winTranslateV,
239 double& winScaleU,
240 double& winScaleV,
241 double& winRoll) const;
242
243 static void getMatrix(const Matrix4x4& pos,
244 CameraProjectionModeEnum projectionMode,
245 double focalLength,
246 double hAperture,
247 double winTranslateU,
248 double winTranslateV,
249 double winScaleU,
250 double winScaleV,
251 double winRoll,
252 Matrix3x3* mat);
253
254 static void define(ImageEffectDescriptor &desc,
255 PageParamDescriptor *page,
256 GroupParamDescriptor *group,
257 const std::string prefix);
258
setEnabled(bool enabled)259 void setEnabled(bool enabled) { _enabled = enabled; update(); }
260
261 private:
262
update()263 void update()
264 {
265 _camProjectionMode->setEnabled(_enabled);
266 _camFocalLength->setEnabled(_enabled);
267 _camHAperture->setEnabled(_enabled);
268 if (_camVAperture) {
269 _camVAperture->setEnabled(_enabled);
270 }
271 if (_camNear) {
272 _camNear->setEnabled(_enabled);
273 }
274 if (_camFar) {
275 _camFar->setEnabled(_enabled);
276 }
277 _camWinTranslate->setEnabled(_enabled);
278 _camWinScale->setEnabled(_enabled);
279 _camWinRoll->setEnabled(_enabled);
280 if (_camFocusDistance) {
281 _camFocusDistance->setEnabled(_enabled);
282 }
283 if (_camFStop) {
284 _camFStop->setEnabled(_enabled);
285 }
286 }
287 };
288
289
290
291 void
define(ImageEffectDescriptor & desc,PageParamDescriptor * page,GroupParamDescriptor * group,const std::string prefix)292 CameraParam::define(ImageEffectDescriptor &desc,
293 PageParamDescriptor *page,
294 GroupParamDescriptor *group,
295 const std::string prefix)
296 {
297 {
298 ChoiceParamDescriptor* param = desc.defineChoiceParam(prefix + kParamCameraProjectionMode);
299 param->setLabel(kParamCameraProjectionModeLabel);
300 assert(param->getNOptions() == eCameraProjectionModePerspective);
301 param->appendOption(kParamCameraProjectionModeOptionPerspective);
302 assert(param->getNOptions() == eCameraProjectionModeOrthographic);
303 param->appendOption(kParamCameraProjectionModeOptionOrthographic);
304 /*
305 assert(param->getNOptions() == eCameraProjectionModeUV);
306 param->appendOption(kParamCameraProjectionModeOptionUV);
307 assert(param->getNOptions() == eCameraProjectionModeSpherical);
308 param->appendOption(kParamCameraProjectionModeOptionSpherical);
309 //*/
310 param->setDefault(eCameraProjectionModePerspective);
311 param->setAnimates(false);
312 if (group) {
313 param->setParent(*group);
314 }
315 if (page) {
316 page->addChild(*param);
317 }
318 }
319 {
320 DoubleParamDescriptor* param = desc.defineDoubleParam(prefix + kParamCameraFocalLength);
321 param->setLabelAndHint(kParamCameraFocalLengthLabel);
322 param->setRange(1e-8, DBL_MAX);
323 param->setDisplayRange(5, 100);
324 param->setDefault(50.);
325 if (group) {
326 param->setParent(*group);
327 }
328 if (page) {
329 page->addChild(*param);
330 }
331 }
332 {
333 DoubleParamDescriptor* param = desc.defineDoubleParam(prefix + kParamCameraHorizontalAperture);
334 param->setLabelAndHint(kParamCameraHorizontalApertureLabel);
335 param->setRange(1e-8, DBL_MAX);
336 param->setDisplayRange(0.1, 50);
337 param->setDefault(24.576);
338 if (group) {
339 param->setParent(*group);
340 }
341 if (page) {
342 page->addChild(*param);
343 }
344 }
345 {
346 DoubleParamDescriptor* param = desc.defineDoubleParam(prefix + kParamCameraVerticalAperture);
347 param->setLabelAndHint(kParamCameraVerticalApertureLabel);
348 param->setRange(1e-8, DBL_MAX);
349 param->setDisplayRange(0.1, 50);
350 param->setDefault(18.672);
351 if (group) {
352 param->setParent(*group);
353 }
354 if (page) {
355 page->addChild(*param);
356 }
357 }
358 /*
359 {
360 DoubleParamDescriptor* param = desc.defineDoubleParam(prefix + kParamCameraNear);
361 param->setLabelAndHint(kParamCameraNearLabel);
362 param->setRange(1e-8, DBL_MAX);
363 param->setDisplayRange(0.1, 10);
364 param->setDefault(0.1);
365 if (group) {
366 param->setParent(*group);
367 }
368 if (page) {
369 page->addChild(*param);
370 }
371 }
372 {
373 DoubleParamDescriptor* param = desc.defineDoubleParam(prefix + kParamCameraFar);
374 param->setLabelAndHint(kParamCameraFarLabel);
375 param->setRange(1e-8, DBL_MAX);
376 param->setDisplayRange(11, 10000);
377 param->setDefault(10000);
378 if (group) {
379 param->setParent(*group);
380 }
381 if (page) {
382 page->addChild(*param);
383 }
384 }
385 //*/
386 {
387 Double2DParamDescriptor* param = desc.defineDouble2DParam(prefix + kParamCameraWindowTranslate);
388 param->setLabelAndHint(kParamCameraWindowTranslateLabel);
389 param->setRange(-1, -1, 1, 1);
390 param->setDisplayRange(-1, -1, 1, 1);
391 param->setDoubleType(eDoubleTypePlain);
392 if (group) {
393 param->setParent(*group);
394 }
395 if (page) {
396 page->addChild(*param);
397 }
398 }
399 {
400 Double2DParamDescriptor* param = desc.defineDouble2DParam(prefix + kParamCameraWindowScale);
401 param->setLabelAndHint(kParamCameraWindowScaleLabel);
402 param->setRange(1e-8, 1e-8, DBL_MAX, DBL_MAX);
403 param->setDisplayRange(0.1, 0.1, 10, 10);
404 param->setDefault(1, 1);
405 param->setDoubleType(eDoubleTypeScale);
406 if (group) {
407 param->setParent(*group);
408 }
409 if (page) {
410 page->addChild(*param);
411 }
412 }
413 {
414 DoubleParamDescriptor* param = desc.defineDoubleParam(prefix + kParamCameraWindowRoll);
415 param->setLabelAndHint(kParamCameraWindowRollLabel);
416 param->setRange(-DBL_MAX, DBL_MAX);
417 param->setDisplayRange(-45, 45);
418 param->setDoubleType(eDoubleTypeAngle);
419 if (group) {
420 param->setParent(*group);
421 }
422 if (page) {
423 page->addChild(*param);
424 }
425 }
426 /*
427 {
428 DoubleParamDescriptor* param = desc.defineDoubleParam(prefix + kParamCameraFocalPoint);
429 param->setLabelAndHint(kParamCameraFocalPointLabel);
430 param->setRange(1e-8, DBL_MAX);
431 param->setDisplayRange(0.1, 10);
432 param->setDefault(2);
433 if (group) {
434 param->setParent(*group);
435 }
436 if (page) {
437 page->addChild(*subgroup);
438 }
439 }
440 {
441 DoubleParamDescriptor* param = desc.defineDoubleParam(prefix + kParamCameraFStop);
442 param->setLabelAndHint(kParamCameraFStopLabel);
443 param->setRange(1e-8, DBL_MAX);
444 param->setDisplayRange(0.1, 30);
445 param->setDefault(16);
446 if (group) {
447 param->setParent(*group);
448 }
449 if (page) {
450 page->addChild(*param);
451 }
452 }
453 //*/
454 }
455
456 void
getValueAtTime(double time,CameraProjectionModeEnum & projectionMode,double & focalLength,double & hAperture,double & winTranslateU,double & winTranslateV,double & winScaleU,double & winScaleV,double & winRoll) const457 CameraParam::getValueAtTime(double time,
458 CameraProjectionModeEnum& projectionMode,
459 double& focalLength,
460 double& hAperture,
461 double& winTranslateU,
462 double& winTranslateV,
463 double& winScaleU,
464 double& winScaleV,
465 double& winRoll) const
466 {
467 projectionMode = (CameraProjectionModeEnum)_camProjectionMode->getValueAtTime(time);
468 focalLength = _camFocalLength->getValueAtTime(time);
469 hAperture = _camHAperture->getValueAtTime(time);
470 _camWinTranslate->getValueAtTime(time, winTranslateU, winTranslateV);
471 _camWinScale->getValueAtTime(time, winScaleU, winScaleV);
472 winRoll = _camWinRoll->getValueAtTime(time);
473 }
474
475 void
getMatrix(const Matrix4x4 & pos,const CameraProjectionModeEnum projectionMode,const double focalLength,const double hAperture,const double winTranslateU,const double winTranslateV,const double winScaleU,const double winScaleV,const double winRoll,Matrix3x3 * mat)476 CameraParam::getMatrix(const Matrix4x4& pos,
477 const CameraProjectionModeEnum projectionMode,
478 const double focalLength,
479 const double hAperture,
480 const double winTranslateU,
481 const double winTranslateV,
482 const double winScaleU,
483 const double winScaleV,
484 const double winRoll,
485 Matrix3x3* mat)
486 {
487 // apply camera params
488 double a = hAperture / std::max(1e-8, focalLength);
489 #pragma message WARN("make sure the standard camera matrix gives z > 0 in orthographic and projective cases")
490 (*mat)(0,0) = -pos(0,0); (*mat)(0,1) = -pos(0,1); (*mat)(0,2) = -pos(0,3);
491 (*mat)(1,0) = -pos(1,0); (*mat)(1,1) = -pos(1,1); (*mat)(1,2) = -pos(1,3);
492 if (projectionMode == eCameraProjectionModePerspective) {
493 // divide by Z
494 (*mat)(2,0) = -a * pos(2,0); (*mat)(2,1) = -a * pos(2,1); (*mat)(2,2) = -a * pos(2,3);
495 } else {
496 // orthographic
497 (*mat)(2,0) = a * pos(3,0); (*mat)(2,1) = a * pos(3,1); (*mat)(2,2) = a * pos(3,3);
498 }
499 // apply winTranslate
500 (*mat)(0,0) += (*mat)(2,0) * winTranslateU / 2.;
501 (*mat)(1,0) += (*mat)(2,0) * winTranslateV / 2.;
502 (*mat)(0,1) += (*mat)(2,1) * winTranslateU / 2.;
503 (*mat)(1,1) += (*mat)(2,1) * winTranslateV / 2.;
504 (*mat)(0,2) += (*mat)(2,2) * winTranslateU / 2.;
505 (*mat)(1,2) += (*mat)(2,2) * winTranslateV / 2.;
506 // apply winScale
507 (*mat)(0,0) /= winScaleU;
508 (*mat)(0,1) /= winScaleU;
509 (*mat)(0,2) /= winScaleU;
510 (*mat)(1,0) /= winScaleV;
511 (*mat)(1,1) /= winScaleV;
512 (*mat)(1,2) /= winScaleV;
513 // apply winRoll
514 if (winRoll != 0.) {
515 double s = std::sin(winRoll * M_PI / 180.);
516 double c = std::cos(winRoll * M_PI / 180.);
517 *mat = Matrix3x3(c, -s, 0,
518 s, c, 0,
519 0, 0, 1) * *mat;
520 }
521
522 }
523
524 // END CameraParm
525 ////////////////////////////////////////////////////////////////////////////////
526
527 ////////////////////////////////////////////////////////////////////////////////
528 // BEGIN PosMatParm
529
530 enum PosMatTypeEnum {
531 ePosMatAxis = 0,
532 ePosMatCamera,
533 ePosMatCard,
534 };
535
536 #define kParamPosMatFile "File"
537 #define kParamPosMatFileLabel "File", "Import/export data"
538
539 #define kParamPosMatImportFile "ImportFile"
540 #define kParamPosMatImportFileLabel "Import", "Import a chan file created using 3D tracking software, or a txt file created using Boujou."
541 #define kParamPosMatImportFileReload "ImportFileReload"
542 #define kParamPosMatImportFileReloadLabel "Reload", "Reload the file."
543
544 #define kParamPosMatImportFormat "ImportFormat"
545 #define kParamPosMatImportFormatLabel "Import Format", "The format of the file to import."
546 #define kParamPosMatImportFormatOptionChan "chan", "Chan format, each line is FRAME TX TY TZ RX RY RZ VFOV. Can be created using Natron, Nuke, 3D-Equalizer, Maya and other 3D tracking software. Be careful that the rotation order must be exactly the same when exporting and importing the chan file.", "chan"
547 #define kParamPosMatImportFormatOptionBoujou "Boujou", "Boujou text export. In Boujou, after finishing the track and solving, go to Export > Export Camera Solve (Or press F12) > choose where to save the data and give it a name, click he drop down Export Type and make sure it will save as a .txt, then click Save. Each camera line is R(0,0) R(0,1) R(0,2) R(1,0) R(1,1) R(1,2) R(2,0) R(2,1) R(2,2) Tx Ty Tz F(mm).", "boujou"
548 enum ImportFormatEnum {
549 eImportFormatChan = 0,
550 eImportFormatBoujou,
551 };
552
553 #define kParamPosMatExportChan "ExportChan"
554 #define kParamPosMatExportChanLabel "Export", "Export a .chan file which can be used in Natron, Nuke or 3D tracking software, such as 3D-Equalizer, Maya, or Boujou. Be careful that the rotation order must be exactly the same when exporting and importing the chan file."
555
556 #define kParamPosMatExportChanRewrite "ExportChanRewrite"
557 #define kParamPosMatExportChanRewriteLabel "Rewrite", "Rewrite the .chan file."
558
559 #define kParamPosMatTransformOrder "XformOrder"
560 #define kParamPosMatTransformOrderLabel "Transform Order", "Order in which scale (S), rotation (R) and translation (T) are applied."
561 #define kParamPosMatTransformOrderOptionSRT "SRT", "Scale, Rotation, Translation.", "srt"
562 #define kParamPosMatTransformOrderOptionSTR "STR", "Scale, Translation, Rotation.", "str"
563 #define kParamPosMatTransformOrderOptionRST "RST", "Rotation, Scale, Translation.", "rst"
564 #define kParamPosMatTransformOrderOptionRTS "RTS", "Rotation, Translation, Scale.", "rts"
565 #define kParamPosMatTransformOrderOptionTSR "TSR", "Translation, Scale, Rotation.", "tsr"
566 #define kParamPosMatTransformOrderOptionTRS "TRS", "Translation, Rotation, Scale.", "trs"
567 enum PosMatTransformOrderEnum {
568 ePosMatTransformOrderSRT = 0,
569 ePosMatTransformOrderSTR,
570 ePosMatTransformOrderRST,
571 ePosMatTransformOrderRTS,
572 ePosMatTransformOrderTSR,
573 ePosMatTransformOrderTRS,
574 };
575 #define kParamPosMatTransformOrderDefault ePosMatTransformOrderSRT
576
577 #define kParamPosMatRotationOrder "RotOrder"
578 #define kParamPosMatRotationOrderLabel "Rotation Order", "Order in which Euler angles are applied in the rotation."
579 #define kParamPosMatRotationOrderOptionXYZ "XYZ", "Rotation over X axis, then Y and Z.", "xyz"
580 #define kParamPosMatRotationOrderOptionXZY "XZY", "Rotation over X axis, then Z and Y.", "xzy"
581 #define kParamPosMatRotationOrderOptionYXZ "YXZ", "Rotation over Y axis, then X and Z.", "yxz"
582 #define kParamPosMatRotationOrderOptionYZX "YZX", "Rotation over Y axis, then Z and X.", "yzx"
583 #define kParamPosMatRotationOrderOptionZXY "ZXY", "Rotation over Z axis, then X and Y.", "zxy"
584 #define kParamPosMatRotationOrderOptionZYX "ZYX", "Rotation over Z axis, then Y and X.", "zyx"
585 enum PosMatRotationOrderEnum {
586 ePosMatRotationOrderXYZ = 0,
587 ePosMatRotationOrderXZY,
588 ePosMatRotationOrderYXZ,
589 ePosMatRotationOrderYZX,
590 ePosMatRotationOrderZXY,
591 ePosMatRotationOrderZYX,
592 };
593 #define kParamPosMatRotationOrderDefault ePosMatRotationOrderZXY
594
595 #define kParamPosMatTranslate "Translate"
596 #define kParamPosMatTranslateLabel "Translate", "Translation component."
597
598 #define kParamPosMatRotate "Rotate"
599 #define kParamPosMatRotateLabel "Rotate", "Euler angles (in degrees)."
600
601 #define kParamPosMatScale "Scaling"
602 #define kParamPosMatScaleLabel "Scale", "Scale factor over each axis."
603
604 #define kParamPosMatUniformScale "UniformScale"
605 #define kParamPosMatUniformScaleLabel "Uniform Scale", "Scale factor over all axis. It is multiplied by the scale factor over each axis."
606
607 #define kParamPosMatSkew "Skew"
608 #define kParamPosMatSkewLabel "Skew", "Skew over each axis, in degrees."
609
610 #define kParamPosMatPivot "Pivot"
611 #define kParamPosMatPivotLabel "Pivot", "The position of the origin for position, scaling, skewing, and rotation."
612
613 #define kGroupPosMatLocalMatrix "LocalMatrix"
614 #define kGroupPosMatLocalMatrixLabel "Local Matrix"
615
616 #define kParamPosMatUseMatrix "UseMatrix"
617 #define kParamPosMatUseMatrixLabel "Specify Matrix", "Check to specify manually all the values for the position matrix."
618
619 #define kParamPosMatMatrix "Matrix"
620 #define kParamPosMatMatrixLabel "", "Matrix coefficient."
621
622
623 class PosMatParam {
624 ImageEffect* _effect;
625 Clip* _srcClip;
626 std::string _prefix;
627 GroupParam* _fileGroup;
628 StringParam* _importFile;
629 PushButtonParam* _importFileReload;
630 ChoiceParam* _importFormat;
631 StringParam* _exportChan;
632 PushButtonParam* _exportChanRewrite;
633 ChoiceParam* _transformOrder;
634 ChoiceParam* _rotationOrder;
635 Double3DParam* _translate;
636 Double3DParam* _rotate;
637 Double3DParam* _scale;
638 DoubleParam* _uniformScale;
639 Double3DParam* _skew;
640 Double3DParam* _pivot;
641 GroupParam* _localMatrix;
642 BooleanParam* _useMatrix;
643 DoubleParam* _matrix[4][4];
644 GroupParam* _projectionGroup;
645 CameraParam* _projection;
646 bool _enabled;
647 PosMatTypeEnum _type;
648
649 public:
PosMatParam(OFX::ImageEffect * parent,const std::string & prefix,PosMatTypeEnum type)650 PosMatParam(OFX::ImageEffect* parent, const std::string& prefix, PosMatTypeEnum type)
651 : _effect(parent)
652 , _srcClip(NULL)
653 , _prefix(prefix)
654 , _fileGroup(NULL)
655 , _importFile(NULL)
656 , _importFileReload(NULL)
657 , _importFormat(NULL)
658 , _exportChan(NULL)
659 , _exportChanRewrite(NULL)
660 , _transformOrder(NULL)
661 , _rotationOrder(NULL)
662 , _translate(NULL)
663 , _rotate(NULL)
664 , _scale(NULL)
665 , _uniformScale(NULL)
666 , _skew(NULL)
667 , _pivot(NULL)
668 , _localMatrix(NULL)
669 , _useMatrix(NULL)
670 , _projectionGroup(NULL)
671 , _projection(NULL)
672 , _enabled(true)
673 , _type(type)
674 {
675 _srcClip = _effect->fetchClip(kOfxImageEffectSimpleSourceClipName);
676 _fileGroup = _effect->fetchGroupParam(prefix + kParamPosMatFile);
677 _importFile = _effect->fetchStringParam(prefix + kParamPosMatImportFile);
678 if (_effect->paramExists(prefix + kParamPosMatImportFileReload)) {
679 _importFileReload = _effect->fetchPushButtonParam(prefix + kParamPosMatImportFileReload);
680 }
681 _importFormat = _effect->fetchChoiceParam(prefix + kParamPosMatImportFormat);
682 _exportChan = _effect->fetchStringParam(prefix + kParamPosMatExportChan);
683 if (_effect->paramExists(prefix + kParamPosMatExportChanRewrite)) {
684 _exportChanRewrite = _effect->fetchPushButtonParam(prefix + kParamPosMatExportChanRewrite);
685 }
686 _transformOrder = _effect->fetchChoiceParam(prefix + kParamPosMatTransformOrder);
687 _rotationOrder = _effect->fetchChoiceParam(prefix + kParamPosMatRotationOrder);
688 _translate = _effect->fetchDouble3DParam(prefix + kParamPosMatTranslate);
689 _rotate = _effect->fetchDouble3DParam(prefix + kParamPosMatRotate);
690 _scale = _effect->fetchDouble3DParam(prefix + kParamPosMatScale);
691 _uniformScale = _effect->fetchDoubleParam(prefix + kParamPosMatUniformScale);
692 _skew = _effect->fetchDouble3DParam(prefix + kParamPosMatSkew);
693 _pivot = _effect->fetchDouble3DParam(prefix + kParamPosMatPivot);
694 _localMatrix = _effect->fetchGroupParam(prefix + kGroupPosMatLocalMatrix);
695 _useMatrix = _effect->fetchBooleanParam(prefix + kParamPosMatUseMatrix);
696 for (int i = 0; i < 4; ++i) {
697 for (int j = 0; j < 4; ++j) {
698 _matrix[i][j] = _effect->fetchDoubleParam(prefix + kParamPosMatMatrix + (char)('1' + i) + (char)('1' + j));
699 }
700 }
701 if (_type == ePosMatCamera) {
702 _projectionGroup = _effect->fetchGroupParam(kCameraCam kParamCameraProjectionGroup);
703 _projection = new CameraParam(_effect, kCameraCam);
704 }
705 update();
706 }
707
~PosMatParam()708 virtual ~PosMatParam()
709 {
710 delete _projection;
711 }
712
713 void changedParam(const InstanceChangedArgs &args, const std::string ¶mName);
714
715 void getMatrix(double time, Matrix4x4* mat) const;
716
717 static void define(ImageEffectDescriptor &desc,
718 PageParamDescriptor *page,
719 GroupParamDescriptor *group,
720 const std::string prefix,
721 PosMatTypeEnum type);
722
setEnabled(bool enabled)723 void setEnabled(bool enabled) { _enabled = enabled; update(); }
724
getProjection()725 const CameraParam& getProjection() { assert(_projection); return *_projection; }
726
727 private:
728
729 /// update visibility/enabledness
update()730 void update()
731 {
732 bool useMatrix = _useMatrix->getValue();
733 _fileGroup->setEnabled(_enabled && !useMatrix);
734 _importFile->setEnabled(_enabled && !useMatrix);
735 if (_importFileReload) {
736 _importFileReload->setEnabled(_enabled && !useMatrix);
737 }
738 _exportChan->setEnabled(_enabled && !useMatrix);
739 if (_exportChanRewrite) {
740 _exportChanRewrite->setEnabled(_enabled && !useMatrix);
741 }
742 _transformOrder->setEnabled(_enabled && !useMatrix);
743 _rotationOrder->setEnabled(_enabled && !useMatrix);
744 _translate->setEnabled(_enabled && !useMatrix);
745 _rotate->setEnabled(_enabled && !useMatrix);
746 _scale->setEnabled(_enabled && !useMatrix);
747 _uniformScale->setEnabled(_enabled && !useMatrix);
748 _skew->setEnabled(_enabled && !useMatrix);
749 _pivot->setEnabled(_enabled && !useMatrix);
750 _localMatrix->setEnabled(_enabled);
751 _useMatrix->setEnabled(_enabled);
752 for (int i = 0; i < 4; ++i) {
753 for (int j = 0; j < 4; ++j) {
754 _matrix[i][j]->setEnabled(_enabled && useMatrix);
755 }
756 }
757 if (_projectionGroup) {
758 _projectionGroup->setEnabled(_enabled);
759 }
760 if (_projection) {
761 _projection->setEnabled(_enabled);
762 }
763 }
764
765 void importChan();
766
767 void importBoujou();
768
769 void exportChan();
770
771 struct ChanLine {
772 int frame;
773 double tx, ty, tz, rx, ry, rz, vfov;
774
ChanLinePosMatParam::ChanLine775 ChanLine()
776 : frame(-1)
777 , tx(0)
778 , ty(0)
779 , tz(0)
780 , rx(0)
781 , ry(0)
782 , rz(0)
783 , vfov(0)
784 {
785 }
786 };
787 };
788
789 static std::string
trim(std::string const & str)790 trim(std::string const & str)
791 {
792 const std::string whitespace = " \t\f\v\n\r";
793 std::size_t first = str.find_first_not_of(whitespace);
794
795 // If there is no non-whitespace character, both first and last will be std::string::npos (-1)
796 // There is no point in checking both, since if either doesn't work, the
797 // other won't work, either.
798 if (first == std::string::npos) {
799 return "";
800 }
801
802 std::size_t last = str.find_last_not_of(whitespace);
803
804 return str.substr(first, last - first + 1);
805 }
806
807 void
importChan()808 PosMatParam::importChan()
809 {
810 string filename;
811 _importFile->getValue(filename);
812 if ( filename.empty() ) {
813 // no filename, do nothing
814 return;
815 }
816 FILE* f = fopen_utf8(filename.c_str(), "r");
817 if (!f) {
818 _effect->sendMessage(Message::eMessageError, "", "Cannot read " + filename + ": " + std::strerror(errno), false);
819
820 return;
821 }
822 std::list<ChanLine> lines;
823 char buf[1024];
824
825 while (std::fgets(buf, sizeof buf, f) != NULL) {
826 const string bufstr( trim(buf) );
827 if (bufstr.size() > 0 && bufstr[0] != '#') {
828 const char* b = bufstr.c_str();
829 ChanLine l;
830 bool err = false;
831 if (_type == ePosMatCamera) {
832 int ret = std::sscanf(b, "%d%lf%lf%lf%lf%lf%lf%lf",
833 &l.frame, &l.tx, &l.ty, &l.tz, &l.rx, &l.ry, &l.rz, &l.vfov);
834 if (ret == 8) {
835 lines.push_back(l);
836 } else {
837 err = true;
838 }
839 } else {
840 int ret = std::sscanf(b, "%d%lf%lf%lf%lf%lf%lf",
841 &l.frame, &l.tx, &l.ty, &l.tz, &l.rx, &l.ry, &l.rz);
842 if (ret == 7) {
843 lines.push_back(l);
844 } else {
845 err = true;
846 }
847 }
848 if (err) {
849 std::fclose(f);
850 _effect->sendMessage(Message::eMessageError, "", "Chan import error: Cannot parse line from " + filename + ": '" + bufstr + "'", false);
851
852 return;
853 }
854 }
855 }
856 std::fclose(f);
857 _effect->beginEditBlock(kParamPosMatImportFile);
858 _translate->deleteAllKeys();
859 _rotate->deleteAllKeys();
860 if (_type == ePosMatCamera && _projection && _projection->_camFocalLength) {
861 _projection->_camFocalLength->deleteAllKeys();
862 }
863 for (std::list<ChanLine>::const_iterator it = lines.begin(); it != lines.end(); ++it) {
864 _translate->setValueAtTime(it->frame, it->tx, it->ty, it->tz);
865 _rotate->setValueAtTime(it->frame, it->rx, it->ry, it->rz);
866 if (_type == ePosMatCamera && _projection && _projection->_camFocalLength) {
867 double vaperture = _projection->_camVAperture->getValueAtTime(it->frame);
868 double focal = 0.5 * vaperture / std::tan(0.5 * (it->vfov * M_PI / 180));
869
870 _projection->_camFocalLength->setValueAtTime(it->frame, focal);
871 }
872 }
873 _effect->endEditBlock();
874 }
875
876 // importBoujou.
877 //
878 // Credits:
879 // - Ivan Busquets' importBoujou.py
880 // http://www.nukepedia.com/python/import/export/importboujou
881 // - Blenders' import_boujou.py
882 // https://wiki.blender.org/index.php/Extensions:2.4/Py/Scripts/Manual/Import/Boujou
883 // https://sourceforge.net/projects/boujouimport/
884 void
importBoujou()885 PosMatParam::importBoujou()
886 {
887 string filename;
888 _importFile->getValue(filename);
889 if ( filename.empty() ) {
890 // no filename, do nothing
891 return;
892 }
893 FILE* f = fopen_utf8(filename.c_str(), "r");
894 if (!f) {
895 _effect->sendMessage(Message::eMessageError, "", "Cannot read " + filename + ": " + std::strerror(errno), false);
896
897 return;
898 }
899 bool foundOffset = false;
900 int offsetFrame = 1;
901 bool foundStart = false;
902 int startFrame;
903 double haperture = 0;
904 double vaperture = 0;
905 std::list<ChanLine> lines;
906 char buf[1024];
907 int i = 1; // line number
908
909 while (std::fgets(buf, sizeof buf, f) != NULL) {
910 if (i == 1) {
911 const string b( trim(buf) );
912 const string h("# boujou export: text");
913 if (b != h) {
914 _effect->sendMessage(Message::eMessageError, "", "Boujou import error: incorrect file header on first line, expected '" + h + "', got '" + b + "'", false);
915
916 std::fclose(f);
917 return;
918 }
919 }
920
921 std::stringstream ss(buf); // Insert the string into a stream
922
923 std::vector<string> line; // Create vector to hold our words
924
925 // split using whitespace
926 while (ss >> buf) {
927 line.push_back(buf);
928 }
929
930 if (line.size() == 0) {
931 continue;
932 }
933 // # boujou export: text
934 // # Copyright (c) 2009, Vicon Motion Systems
935 // # boujou Version: 5.0.0 47534
936 // # Creation date : Thu Mar 17 17:30:38 2011
937 // # The image sequence file name was C:/Users/Nate's/Videos/final.mp4
938 // # boujou frame 0 is image sequence file 1000
939 // # boujou frame 100 is image sequence file 1100
940 // # One boujou frame for every image sequence frame
941 // # Exporting camera data for boujou frames 65 to 100
942 // # First boujou frame indexed to animation frame 1
943 //
944 //
945 // #The Camera (One line per time frame)
946 // #Image Size 1920 1080
947 // #Filmback Size 14.7574 8.3007
948 // #Line Format: Camera Rotation Matrix (9 numbers - 1st row, 2nd row, 3rd row) Camera Translation (3 numbers) Focal Length (mm)
949 // #rotation applied before translation
950 // #R(0,0) R(0,1) R(0,2) R(1,0) R(1,1) R(1,2) R(2,0) R(2,1) R(2,2) TxTy Tz F(mm)
951 // ...
952 //
953 // #3D Scene Points
954 // #x y z
955 // ...
956 // #End of boujou export file
957
958 if (!foundOffset) {
959 // # Exporting camera data for boujou frames 65 to 100
960 if (line.size() == 10 && line[0] == "#" && line[1] == "Exporting" && line[line.size() - 2] == "to") {
961 offsetFrame = std::atoi(line[line.size() - 3].c_str());
962 foundOffset = true;
963 }
964 }
965 if (!foundStart) {
966 // # First boujou frame indexed to animation frame 1
967 if (line.size() == 9 && line[0] == "#" && line[1] == "First" && line[2] == "boujou" && line[3] == "frame") {
968 startFrame = std::atoi(line[line.size() - 1].c_str()) + offsetFrame;
969 foundStart = true;
970 }
971 }
972
973 // #Filmback Size 14.7574 8.3007
974 if (line.size() == 4 && line[0] == "#Filmback") {
975 haperture = std::atof(line[2].c_str());
976 vaperture = std::atof(line[3].c_str());
977 }
978
979 if (foundOffset && foundStart && line.size() == 13 && buf[0] != '#') {
980 ChanLine l;
981 //bool err = false;
982 l.frame = startFrame;
983 l.vfov = std::atof(line[12].c_str());
984 l.tx = std::atof(line[9].c_str());
985 l.ty = std::atof(line[10].c_str());
986 l.tz = std::atof(line[11].c_str());
987 double rot00 = std::atof(line[0].c_str());
988 double rot01 = std::atof(line[1].c_str());
989 double rot02 = std::atof(line[2].c_str());
990 double rot10 = std::atof(line[3].c_str());
991 //double rot11 = std::atof(line[4].c_str());
992 //double rot12 = std::atof(line[5].c_str());
993 double rot20 = std::atof(line[6].c_str());
994 double rot21 = std::atof(line[7].c_str());
995 double rot22 = std::atof(line[8].c_str());
996 if (rot00 == 0 && rot10 == 0) {
997 l.rx = std::atan2(-rot01, -rot02) * 180. / M_PI;
998 l.ry = 90.;
999 l.rz = 0.;
1000 } else {
1001 l.rx = std::atan2(rot21, -rot22) * 180. / M_PI;
1002 l.ry = -std::asin(rot20) * 180. / M_PI;
1003 l.rz = std::atan2(rot10,rot00) * 180. / M_PI;
1004 }
1005 lines.push_back(l);
1006 ++startFrame;
1007 }
1008 ++i;
1009 }
1010 std::fclose(f);
1011 _effect->beginEditBlock(kParamPosMatImportFile);
1012 _translate->deleteAllKeys();
1013 _rotate->deleteAllKeys();
1014 if (_type == ePosMatCamera && _projection) {
1015 if (_projection->_camFocalLength) {
1016 _projection->_camFocalLength->deleteAllKeys();
1017 }
1018 if (_projection->_camHAperture && haperture != 0.) {
1019 _projection->_camHAperture->deleteAllKeys();
1020 _projection->_camHAperture->setValue(haperture);
1021 }
1022 if (_projection->_camVAperture && vaperture != 0.) {
1023 _projection->_camVAperture->deleteAllKeys();
1024 _projection->_camVAperture->setValue(vaperture);
1025 }
1026 }
1027 for (std::list<ChanLine>::const_iterator it = lines.begin(); it != lines.end(); ++it) {
1028 _translate->setValueAtTime(it->frame, it->tx, it->ty, it->tz);
1029 _rotate->setValueAtTime(it->frame, it->rx, it->ry, it->rz);
1030 if (_type == ePosMatCamera && _projection && _projection->_camFocalLength) {
1031 // it-vfov contains focal in Boujou
1032 double focal = it->vfov;
1033 //double vaperture = _projection->_camVAperture->getValueAtTime(it->frame);
1034 //double focal = 0.5 * vaperture / std::tan(0.5 * (it->vfov * M_PI / 180));
1035
1036 _projection->_camFocalLength->setValueAtTime(it->frame, focal);
1037 }
1038 }
1039 _effect->endEditBlock();
1040 }
1041
1042 void
exportChan()1043 PosMatParam::exportChan()
1044 {
1045 string filename;
1046 _importFile->getValue(filename);
1047 if ( filename.empty() ) {
1048 // no filename, do nothing
1049 return;
1050 }
1051 FILE* f = fopen_utf8(filename.c_str(), "w");
1052 if (!f) {
1053 _effect->sendMessage(Message::eMessageError, "", "Cannot write " + filename + ": " + std::strerror(errno), false);
1054 return;
1055 }
1056 OfxRangeD r = _srcClip->getFrameRange();
1057 for (int t = (int)r.min; t <= (int)r.max; ++t) {
1058 ChanLine l;
1059 l.frame = t;
1060 _translate->getValueAtTime(t, l.tx, l.ty, l.tz);
1061 _rotate->getValueAtTime(t, l.rx, l.ry, l.rz);
1062 if (_type == ePosMatCamera && _projection && _projection->_camVAperture) {
1063 double vaperture = _projection->_camVAperture->getValueAtTime(t);
1064 double focal = _projection->_camFocalLength->getValueAtTime(t);
1065 l.vfov = 2 * std::atan2(0.5 * vaperture, focal) * 180 / M_PI;
1066 std::fprintf(f, "%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\n",
1067 t, l.tx, l.ty, l.tz, l.rx, l.ry, l.rz, l.vfov);
1068 } else {
1069 std::fprintf(f, "%d\t%g\t%g\t%g\t%g\t%g\t%g\n",
1070 t, l.tx, l.ty, l.tz, l.rx, l.ry, l.rz);
1071 }
1072 }
1073 std::fclose(f);
1074 }
1075
1076 void
define(ImageEffectDescriptor & desc,PageParamDescriptor * page,GroupParamDescriptor * group,const std::string prefix,PosMatTypeEnum type)1077 PosMatParam::define(ImageEffectDescriptor &desc,
1078 PageParamDescriptor *page,
1079 GroupParamDescriptor *group,
1080 const std::string prefix,
1081 PosMatTypeEnum type)
1082 {
1083 {
1084 GroupParamDescriptor* subgroup = desc.defineGroupParam(prefix + kParamPosMatFile);
1085 if (subgroup) {
1086 subgroup->setLabelAndHint(kParamPosMatFileLabel);
1087 subgroup->setOpen(false);
1088 if (group) {
1089 subgroup->setParent(*group);
1090 }
1091 if (page) {
1092 page->addChild(*subgroup);
1093 }
1094 }
1095 {
1096 ChoiceParamDescriptor* param = desc.defineChoiceParam(prefix + kParamPosMatImportFormat);
1097 param->setLabelAndHint(kParamPosMatImportFormatLabel);
1098 assert(param->getNOptions() == eImportFormatChan);
1099 param->appendOption(kParamPosMatImportFormatOptionChan);
1100 assert(param->getNOptions() == eImportFormatBoujou);
1101 param->appendOption(kParamPosMatImportFormatOptionBoujou);
1102 if (subgroup) {
1103 param->setParent(*subgroup);
1104 }
1105 if (page) {
1106 page->addChild(*param);
1107 }
1108 }
1109 {
1110 StringParamDescriptor* param = desc.defineStringParam(prefix + kParamPosMatImportFile);
1111 param->setLabelAndHint(kParamPosMatImportFileLabel);
1112 param->setStringType(eStringTypeFilePath);
1113 param->setFilePathExists(true);
1114 param->setAnimates(false);
1115 param->setEvaluateOnChange(false);
1116 if (!OFX::getImageEffectHostDescription()->isNatron) { // Natron already has a reload button
1117 param->setLayoutHint(eLayoutHintNoNewLine, 1);
1118 }
1119 if (subgroup) {
1120 param->setParent(*subgroup);
1121 }
1122 if (page) {
1123 page->addChild(*param);
1124 }
1125
1126 }
1127 if (!OFX::getImageEffectHostDescription()->isNatron) { // Natron already has a reload button
1128 PushButtonParamDescriptor* param = desc.definePushButtonParam(prefix + kParamPosMatImportFileReload);
1129 param->setLabelAndHint(kParamPosMatImportFileReloadLabel);
1130 if (subgroup) {
1131 param->setParent(*subgroup);
1132 }
1133 if (page) {
1134 page->addChild(*param);
1135 }
1136
1137 }
1138 {
1139 StringParamDescriptor* param = desc.defineStringParam(prefix + kParamPosMatExportChan);
1140 param->setLabelAndHint(kParamPosMatExportChanLabel);
1141 param->setStringType(eStringTypeFilePath);
1142 param->setFilePathExists(false);
1143 param->setAnimates(false);
1144 param->setEvaluateOnChange(false);
1145 if (!OFX::getImageEffectHostDescription()->isNatron) { // Natron already has a rewrite button
1146 param->setLayoutHint(eLayoutHintNoNewLine, 1);
1147 }
1148 if (subgroup) {
1149 param->setParent(*subgroup);
1150 }
1151 if (page) {
1152 page->addChild(*param);
1153 }
1154
1155 }
1156 if (!OFX::getImageEffectHostDescription()->isNatron) { // Natron already has a rewrite button
1157 PushButtonParamDescriptor* param = desc.definePushButtonParam(prefix + kParamPosMatExportChanRewrite);
1158 param->setLabelAndHint(kParamPosMatExportChanRewriteLabel);
1159 if (subgroup) {
1160 param->setParent(*subgroup);
1161 }
1162 if (page) {
1163 page->addChild(*param);
1164 }
1165
1166 }
1167 }
1168 {
1169 ChoiceParamDescriptor* param = desc.defineChoiceParam(prefix + kParamPosMatTransformOrder);
1170 param->setLabelAndHint(kParamPosMatTransformOrderLabel);
1171 assert(param->getNOptions() == ePosMatTransformOrderSRT);
1172 param->appendOption(kParamPosMatTransformOrderOptionSRT);
1173 assert(param->getNOptions() == ePosMatTransformOrderSTR);
1174 param->appendOption(kParamPosMatTransformOrderOptionSTR);
1175 assert(param->getNOptions() == ePosMatTransformOrderRST);
1176 param->appendOption(kParamPosMatTransformOrderOptionRST);
1177 assert(param->getNOptions() == ePosMatTransformOrderRTS);
1178 param->appendOption(kParamPosMatTransformOrderOptionRTS);
1179 assert(param->getNOptions() == ePosMatTransformOrderTSR);
1180 param->appendOption(kParamPosMatTransformOrderOptionTSR);
1181 assert(param->getNOptions() == ePosMatTransformOrderTRS);
1182 param->appendOption(kParamPosMatTransformOrderOptionTRS);
1183 param->setDefault(kParamPosMatTransformOrderDefault);
1184 if (group) {
1185 param->setParent(*group);
1186 }
1187 if (page) {
1188 page->addChild(*param);
1189 }
1190 }
1191 {
1192 ChoiceParamDescriptor* param = desc.defineChoiceParam(prefix + kParamPosMatRotationOrder);
1193 param->setLabelAndHint(kParamPosMatRotationOrderLabel);
1194 assert(param->getNOptions() == ePosMatRotationOrderXYZ);
1195 param->appendOption(kParamPosMatRotationOrderOptionXYZ);
1196 assert(param->getNOptions() == ePosMatRotationOrderXZY);
1197 param->appendOption(kParamPosMatRotationOrderOptionXZY);
1198 assert(param->getNOptions() == ePosMatRotationOrderYXZ);
1199 param->appendOption(kParamPosMatRotationOrderOptionYXZ);
1200 assert(param->getNOptions() == ePosMatRotationOrderYZX);
1201 param->appendOption(kParamPosMatRotationOrderOptionYZX);
1202 assert(param->getNOptions() == ePosMatRotationOrderZXY);
1203 param->appendOption(kParamPosMatRotationOrderOptionZXY);
1204 assert(param->getNOptions() == ePosMatRotationOrderZYX);
1205 param->appendOption(kParamPosMatRotationOrderOptionZYX);
1206 param->setDefault(kParamPosMatRotationOrderDefault);
1207 if (group) {
1208 param->setParent(*group);
1209 }
1210 if (page) {
1211 page->addChild(*param);
1212 }
1213 }
1214 {
1215 Double3DParamDescriptor* param = desc.defineDouble3DParam(prefix + kParamPosMatTranslate);
1216 param->setLabelAndHint(kParamPosMatTranslateLabel);
1217 param->setRange(-DBL_MAX, -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX, DBL_MAX);
1218 param->setDisplayRange(-10., -10., -10., 10., 10., 10.);
1219 param->setDefault(0, 0, (type == ePosMatCard) ? -1 : 0.);
1220 if (group) {
1221 param->setParent(*group);
1222 }
1223 if (page) {
1224 page->addChild(*param);
1225 }
1226 }
1227 {
1228 Double3DParamDescriptor* param = desc.defineDouble3DParam(prefix + kParamPosMatRotate);
1229 param->setLabelAndHint(kParamPosMatRotateLabel);
1230 param->setRange(-DBL_MAX, -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX, DBL_MAX);
1231 param->setDisplayRange(-180., -180., -180., 180., 180., 180.);
1232 param->setDefault(0., 0., 0.);
1233 param->setDoubleType(eDoubleTypeAngle);
1234 if (group) {
1235 param->setParent(*group);
1236 }
1237 if (page) {
1238 page->addChild(*param);
1239 }
1240 }
1241 {
1242 Double3DParamDescriptor* param = desc.defineDouble3DParam(prefix + kParamPosMatScale);
1243 param->setLabelAndHint(kParamPosMatScaleLabel);
1244 param->setRange(-DBL_MAX, -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX, DBL_MAX);
1245 param->setDisplayRange(0.01, 0.01, 0.01, 10., 10., 10.);
1246 param->setDefault(1., 1., 1.);
1247 param->setDoubleType(eDoubleTypeScale);
1248 if (group) {
1249 param->setParent(*group);
1250 }
1251 if (page) {
1252 page->addChild(*param);
1253 }
1254 }
1255 {
1256 DoubleParamDescriptor* param = desc.defineDoubleParam(prefix + kParamPosMatUniformScale);
1257 param->setLabelAndHint(kParamPosMatUniformScaleLabel);
1258 param->setRange(-DBL_MAX, DBL_MAX);
1259 param->setDisplayRange(0.01, 10.);
1260 param->setDefault(1.);
1261 param->setDoubleType(eDoubleTypeScale);
1262 if (group) {
1263 param->setParent(*group);
1264 }
1265 if (page) {
1266 page->addChild(*param);
1267 }
1268 }
1269 {
1270 Double3DParamDescriptor* param = desc.defineDouble3DParam(prefix + kParamPosMatSkew);
1271 param->setLabelAndHint(kParamPosMatSkewLabel);
1272 param->setRange(-DBL_MAX, -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX, DBL_MAX);
1273 param->setDisplayRange(-1., -1., -1., 1., 1., 1.);
1274 param->setDefault(0., 0., 0.);
1275 if (group) {
1276 param->setParent(*group);
1277 }
1278 if (page) {
1279 page->addChild(*param);
1280 }
1281 }
1282 {
1283 Double3DParamDescriptor* param = desc.defineDouble3DParam(prefix + kParamPosMatPivot);
1284 param->setLabelAndHint(kParamPosMatPivotLabel);
1285 param->setRange(-DBL_MAX, -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX, DBL_MAX);
1286 param->setDisplayRange(-10., -10., -10., 10., 10., 10.);
1287 param->setDefault(0., 0., 0.);
1288 if (group) {
1289 param->setParent(*group);
1290 }
1291 if (page) {
1292 page->addChild(*param);
1293 }
1294 }
1295 {
1296 GroupParamDescriptor* subgroup = desc.defineGroupParam(prefix + kGroupPosMatLocalMatrix);
1297 if (subgroup) {
1298 subgroup->setLabel(kGroupPosMatLocalMatrixLabel);
1299 subgroup->setOpen(false);
1300 if (group) {
1301 subgroup->setParent(*group);
1302 }
1303 if (page) {
1304 page->addChild(*subgroup);
1305 }
1306 }
1307 {
1308 BooleanParamDescriptor* param = desc.defineBooleanParam(prefix + kParamPosMatUseMatrix);
1309 param->setLabelAndHint(kParamPosMatUseMatrixLabel);
1310 param->setAnimates(false);
1311 param->setEvaluateOnChange(false);
1312 if (subgroup) {
1313 param->setParent(*subgroup);
1314 }
1315 if (page) {
1316 page->addChild(*param);
1317 }
1318 }
1319 for (int i = 0; i < 4; ++i) {
1320 for (int j = 0; j < 4; ++j) {
1321 DoubleParamDescriptor* param = desc.defineDoubleParam(prefix + kParamPosMatMatrix + (char)('1' + i) + (char)('1' + j));
1322 param->setLabelAndHint(kParamPosMatMatrixLabel);
1323 param->setRange(-DBL_MAX, DBL_MAX);
1324 param->setDisplayRange(-1., 1.);
1325 param->setDefault(i == j ? 1. : (i == 2 && j == 3) ? -1. : 0.);
1326 if (j < 3) {
1327 param->setLayoutHint(eLayoutHintNoNewLine, 1);
1328 }
1329 if (subgroup) {
1330 param->setParent(*subgroup);
1331 }
1332 if (page) {
1333 page->addChild(*param);
1334 }
1335 }
1336 }
1337 }
1338 if (type == ePosMatCamera) {
1339 GroupParamDescriptor* subgroup = desc.defineGroupParam(kCameraCam kParamCameraProjectionGroup);
1340 if (subgroup) {
1341 subgroup->setLabel(kCameraCamLabel " " kParamCameraProjectionGroupLabel);
1342 subgroup->setOpen(false);
1343 if (group) {
1344 subgroup->setParent(*group);
1345 }
1346 if (page) {
1347 page->addChild(*subgroup);
1348 }
1349 }
1350
1351 CameraParam::define(desc, page, subgroup, kCameraCam);
1352 }
1353 }
1354
1355 void
getMatrix(const double t,Matrix4x4 * mat) const1356 PosMatParam::getMatrix(const double t, Matrix4x4* mat) const
1357 {
1358 if (_useMatrix->getValueAtTime(t)) {
1359 for (int i = 0; i < 4; ++i) {
1360 for (int j = 0; j < 4; ++j) {
1361 (*mat)(i,j) = _matrix[i][j]->getValueAtTime(t);
1362 }
1363 }
1364
1365 return;
1366 }
1367
1368
1369 PosMatTransformOrderEnum transformOrder = (PosMatTransformOrderEnum)_transformOrder->getValueAtTime(t);
1370 PosMatRotationOrderEnum rotationOrder = (PosMatRotationOrderEnum)_rotationOrder->getValueAtTime(t);
1371
1372 Matrix4x4 T;
1373 T(0,0) = T(1,1) = T(2,2) = T(3,3) = 1.;
1374 _translate->getValueAtTime(t, T(0,3), T(1,3), T(2,3));
1375
1376 double theta[3];
1377 _rotate->getValueAtTime(t, theta[0], theta[1], theta[2]);
1378 Matrix4x4 R;
1379 if (theta[0] == 0. && theta[1] == 0. && theta[2] == 0.) {
1380 R(0,0) = R(1,1) = R(2,2) = R(3,3) = 1.;
1381 } else {
1382 Matrix4x4 Rx, Ry, Rz;
1383 Rx(3,3) = Ry(3,3) = Rz(3,3) = 1.;
1384 {
1385 double s = std::sin(theta[0] * M_PI / 180.);
1386 double c = std::cos(theta[0] * M_PI / 180.);
1387 Rx(0,0) = 1.;
1388 Rx(1,1) = c; Rx(1,2) = -s;
1389 Rx(2,1) = s; Rx(2,2) = c;
1390 }
1391 {
1392 double s = std::sin(theta[1] * M_PI / 180.);
1393 double c = std::cos(theta[1] * M_PI / 180.);
1394 Ry(1,1) = 1.;
1395 Ry(2,2) = c; Ry(2,0) = -s;
1396 Ry(0,2) = s; Ry(0,0) = c;
1397 }
1398 {
1399 double s = std::sin(theta[2] * M_PI / 180.);
1400 double c = std::cos(theta[2] * M_PI / 180.);
1401 Rz(2,2) = 1.;
1402 Rz(0,0) = c; Rz(0,1) = -s;
1403 Rz(1,0) = s; Rz(1,1) = c;
1404 }
1405 switch (rotationOrder) {
1406 case ePosMatRotationOrderXYZ:
1407 R = Rz * Ry * Rx;
1408 break;
1409 case ePosMatRotationOrderXZY:
1410 R = Ry * Rz * Rx;
1411 break;
1412 case ePosMatRotationOrderYXZ:
1413 R = Rz * Rx * Ry;
1414 break;
1415 case ePosMatRotationOrderYZX:
1416 R = Rx * Rz * Ry;
1417 break;
1418 case ePosMatRotationOrderZXY:
1419 default:
1420 R = Ry * Rx * Rz;
1421 break;
1422 case ePosMatRotationOrderZYX:
1423 R = Rx * Ry * Rz;
1424 break;
1425 }
1426 }
1427
1428 // in Nuke, skew is just before the rotation, xhatever the RTS order is (strange, but true)
1429 double skew[3];
1430 _skew->getValueAtTime(t, skew[0], skew[1], skew[2]);
1431 if (skew[0] != 0. ||
1432 skew[1] != 0. ||
1433 skew[2] != 0.) {
1434 Matrix4x4 K;
1435 K(0,1) = std::tan(skew[0] * M_PI / 180.);
1436 K(1,0) = std::tan(skew[1] * M_PI / 180.);
1437 K(1,2) = std::tan(skew[2] * M_PI / 180.);
1438 K(0,0) = K(1,1) = K(2,2) = K(3,3) = 1;
1439 R = R * K;
1440 }
1441
1442 Matrix4x4 S;
1443 S(3,3) = 1.;
1444 _scale->getValueAtTime(t, S(0,0), S(1,1), S(2,2));
1445 {
1446 double uniformScale = _uniformScale->getValueAtTime(t);
1447 S(0,0) *= uniformScale;
1448 S(1,1) *= uniformScale;
1449 S(2,2) *= uniformScale;
1450
1451 }
1452
1453 switch (transformOrder) {
1454 case ePosMatTransformOrderSRT:
1455 default:
1456 *mat = T * R * S;
1457 break;
1458 case ePosMatTransformOrderSTR:
1459 *mat = R * T * S;
1460 break;
1461 case ePosMatTransformOrderRST:
1462 *mat = T * S * R;
1463 break;
1464 case ePosMatTransformOrderRTS:
1465 *mat = S * T * R;
1466 break;
1467 case ePosMatTransformOrderTSR:
1468 *mat = R * S * T;
1469 break;
1470 case ePosMatTransformOrderTRS:
1471 *mat = S * R * T;
1472 break;
1473 }
1474
1475
1476 // pivot
1477 double pivot[3];
1478 _pivot->getValueAtTime(t, pivot[0], pivot[1], pivot[2]);
1479 if (pivot[0] != 0. ||
1480 pivot[1] != 0. ||
1481 pivot[2] != 0.) {
1482 // (reuse the T matrix)
1483 T(0,3) = pivot[0];
1484 T(1,3) = pivot[1];
1485 T(2,3) = pivot[2];
1486 Matrix4x4 P;
1487 P(0,3) = -pivot[0];
1488 P(1,3) = -pivot[1];
1489 P(2,3) = -pivot[2];
1490 P(0,0) = P(1,1) = P(2,2) = P(3,3) = 1;
1491 *mat = T * *mat * P;
1492 }
1493 }
1494
1495 void
changedParam(const InstanceChangedArgs & args,const std::string & paramName)1496 PosMatParam::changedParam(const InstanceChangedArgs &args,
1497 const std::string ¶mName)
1498 {
1499 if (paramName.compare(0, _prefix.length(), _prefix) != 0) {
1500 return;
1501 }
1502 const double t = args.time;
1503 if ( args.reason == eChangeUserEdit &&
1504 (paramName == _importFile->getName() ||
1505 (_importFileReload && paramName == _importFileReload->getName()) ) ) {
1506 ImportFormatEnum format = (ImportFormatEnum)_importFormat->getValue();
1507 switch (format) {
1508 case eImportFormatChan:
1509 importChan();
1510 break;
1511 case eImportFormatBoujou:
1512 importBoujou();
1513 break;
1514 }
1515 } else if ( args.reason == eChangeUserEdit &&
1516 (paramName == _exportChan->getName() ||
1517 (_exportChanRewrite && paramName == _exportChanRewrite->getName()) ) ) {
1518 exportChan();
1519 } else if ( paramName == _useMatrix->getName() ) {
1520 update();
1521 } else if (paramName == _transformOrder->getName() ||
1522 paramName == _rotationOrder->getName() ||
1523 paramName == _translate->getName() ||
1524 paramName == _rotate->getName() ||
1525 paramName == _scale->getName() ||
1526 paramName == _uniformScale->getName() ||
1527 paramName == _skew->getName() ||
1528 paramName == _pivot->getName() ||
1529 paramName == _useMatrix->getName()) {
1530 bool useMatrix = _useMatrix->getValueAtTime(t);
1531 if (!useMatrix) {
1532 Matrix4x4 mat;
1533 getMatrix(t, &mat);
1534 for (int i = 0; i < 4; ++i) {
1535 for (int j = 0; j < 4; ++j) {
1536 _matrix[i][j]->setValue( mat(i,j) );
1537 }
1538 }
1539 }
1540 }
1541 }
1542
1543 // END PosMatParm
1544 ////////////////////////////////////////////////////////////////////////////////
1545
1546
1547 ////////////////////////////////////////////////////////////////////////////////
1548 /** @brief The plugin that does our work */
1549 class Card3DPlugin
1550 : public Transform3x3Plugin
1551 {
1552 public:
1553 /** @brief ctor */
Card3DPlugin(OfxImageEffectHandle handle)1554 Card3DPlugin(OfxImageEffectHandle handle)
1555 : Transform3x3Plugin(handle, false, eTransform3x3ParamsTypeMotionBlur)
1556 //, _transformAmount(NULL)
1557 , _interactive(NULL)
1558 , _srcClipChanged(NULL)
1559 , _axisCamera(NULL)
1560 , _camCamera(NULL)
1561 , _axisPosMat(NULL)
1562 , _camEnable(NULL)
1563 , _camPosMat(NULL)
1564 , _card(this, kGroupCard, ePosMatCard)
1565 , _lensInFocal(NULL)
1566 , _lensInHAperture(NULL)
1567 , _extent(NULL)
1568 , _format(NULL)
1569 , _formatSize(NULL)
1570 , _formatPar(NULL)
1571 , _btmLeft(NULL)
1572 , _size(NULL)
1573 , _recenter(NULL)
1574 {
1575 if (getImageEffectHostDescription()->supportsCamera) {
1576 _axisCamera = fetchCamera(kCameraAxis);
1577 _camCamera = fetchCamera(kCameraCam);
1578 } else {
1579 _axisPosMat = new PosMatParam(this, kCameraAxis, ePosMatAxis);
1580 _camEnable = fetchBooleanParam(kParamCamEnable);
1581 _camPosMat = new PosMatParam(this, kCameraCam, ePosMatCamera);
1582 }
1583 _lensInFocal = fetchDoubleParam(kParamLensInFocal);
1584 _lensInHAperture = fetchDoubleParam(kParamLensInHAperture);
1585 _extent = fetchChoiceParam(kParamOutputFormat);
1586 _format = fetchChoiceParam(kParamGeneratorFormat);
1587 _formatSize = fetchInt2DParam(kParamGeneratorSize);
1588 _formatPar= fetchDoubleParam(kParamGeneratorPAR);
1589 _btmLeft = fetchDouble2DParam(kParamRectangleInteractBtmLeft);
1590 _size = fetchDouble2DParam(kParamRectangleInteractSize);
1591 _recenter = fetchPushButtonParam(kParamGeneratorCenter);
1592
1593 //_transformAmount = fetchDoubleParam(kParamTransformAmount);
1594 _interactive = fetchBooleanParam(kParamTransformInteractive);
1595 assert(_interactive);
1596 _srcClipChanged = fetchBooleanParam(kParamSrcClipChanged);
1597 assert(_srcClipChanged);
1598
1599 // honor kParamDefaultsNormalised
1600 if ( paramExists(kParamDefaultsNormalised) ) {
1601 // Some hosts (e.g. Resolve) may not support normalized defaults (setDefaultCoordinateSystem(eCoordinatesNormalised))
1602 // handle these ourselves!
1603 BooleanParam* param = fetchBooleanParam(kParamDefaultsNormalised);
1604 assert(param);
1605 bool normalised = param->getValue();
1606 if (normalised) {
1607 OfxPointD size = getProjectExtent();
1608 OfxPointD origin = getProjectOffset();
1609 OfxPointD p;
1610 // we must denormalise all parameters for which setDefaultCoordinateSystem(eCoordinatesNormalised) couldn't be done
1611 beginEditBlock(kParamDefaultsNormalised);
1612 p = _btmLeft->getValue();
1613 _btmLeft->setValue(p.x * size.x + origin.x, p.y * size.y + origin.y);
1614 p = _size->getValue();
1615 _size->setValue(p.x * size.x, p.y * size.y);
1616 param->setValue(false);
1617 endEditBlock();
1618 }
1619 }
1620
1621 // finally...
1622 syncPrivateData();
1623 }
1624
~Card3DPlugin()1625 ~Card3DPlugin()
1626 {
1627 delete _axisPosMat;
1628 delete _camPosMat;
1629 }
1630
1631 private:
1632 //virtual bool getRegionOfDefinition(const RegionOfDefinitionArguments &args, OfxRectD &rod) OVERRIDE FINAL;
1633 virtual void getClipPreferences(ClipPreferencesSetter &clipPreferences) OVERRIDE FINAL;
1634 virtual bool isIdentity(double time) OVERRIDE FINAL;
1635 virtual bool getInverseTransformCanonical(double time, int view, double amount, bool invert, Matrix3x3* invtransform) const OVERRIDE FINAL;
1636
1637 virtual void changedParam(const InstanceChangedArgs &args, const std::string ¶mName) OVERRIDE FINAL;
1638
1639 /** @brief called when a clip has just been changed in some way (a rewire maybe) */
1640 virtual void changedClip(const InstanceChangedArgs &args, const std::string &clipName) OVERRIDE FINAL;
1641 /** @brief The sync private data action, called when the effect needs to sync any private data to persistent parameters */
1642 virtual void syncPrivateData(void) OVERRIDE FINAL;
1643
1644 void updateVisibility();
1645
1646 bool getOutputFormat(double time,
1647 const OfxPointD& renderScale,
1648 OfxRectI *format,
1649 double *par) const;
1650 // NON-GENERIC
1651 //DoubleParam* _transformAmount;
1652 BooleanParam* _interactive;
1653 BooleanParam* _srcClipChanged; // set to true the first time the user connects src
1654 Camera* _axisCamera;
1655 Camera* _camCamera;
1656 PosMatParam* _axisPosMat;
1657 BooleanParam* _camEnable;
1658 PosMatParam* _camPosMat;
1659 PosMatParam _card;
1660 DoubleParam* _lensInFocal;
1661 DoubleParam* _lensInHAperture;
1662
1663 // format params
1664 ChoiceParam* _extent;
1665 ChoiceParam* _format;
1666 Int2DParam* _formatSize;
1667 DoubleParam* _formatPar;
1668 Double2DParam* _btmLeft;
1669 Double2DParam* _size;
1670 PushButtonParam *_recenter;
1671 };
1672
1673 void
syncPrivateData()1674 Card3DPlugin::syncPrivateData()
1675 {
1676 updateVisibility();
1677 }
1678
1679 // returns true if fixed format (i.e. not the input RoD) and setFormat can be called in getClipPrefs
1680 bool
getOutputFormat(double,const OfxPointD & renderScale,OfxRectI * format,double * par) const1681 Card3DPlugin::getOutputFormat(double /*time*/,
1682 const OfxPointD& renderScale,
1683 OfxRectI *format,
1684 double *par) const
1685 {
1686 GeneratorExtentEnum extent = (GeneratorExtentEnum)_extent->getValue();
1687
1688 switch (extent) {
1689 case eGeneratorExtentFormat: {
1690 int w, h;
1691 _formatSize->getValue(w, h);
1692 *par = _formatPar->getValue();
1693 format->x1 = format->y1 = 0;
1694 format->x2 = std::ceil(w * renderScale.x);
1695 format->y2 = std::ceil(h * renderScale.y);
1696
1697 return true;
1698 break;
1699 }
1700 case eGeneratorExtentSize: {
1701 OfxRectD rod;
1702 _size->getValue(rod.x2, rod.y2);
1703 _btmLeft->getValue(rod.x1, rod.y1);
1704 rod.x2 += rod.x1;
1705 rod.y2 += rod.y1;
1706 *par = _srcClip ? _srcClip->getPixelAspectRatio() : 1.;
1707 Coords::toPixelNearest(rod, renderScale, *par, format);
1708
1709 return true;
1710 break;
1711 }
1712 case eGeneratorExtentProject: {
1713 OfxRectD rod;
1714 OfxPointD siz = getProjectSize();
1715 OfxPointD off = getProjectOffset();
1716 rod.x1 = off.x;
1717 rod.x2 = off.x + siz.x;
1718 rod.y1 = off.y;
1719 rod.y2 = off.y + siz.y;
1720 *par = getProjectPixelAspectRatio();
1721 Coords::toPixelNearest(rod, renderScale, *par, format);
1722
1723 return true;
1724 break;
1725 }
1726 case eGeneratorExtentDefault:
1727 default:
1728 assert(false);
1729 /*
1730 if ( _srcClip && _srcClip->isConnected() ) {
1731 format->x1 = format->y1 = format->x2 = format->y2 = 0; // default value
1732 _srcClip->getFormat(*format);
1733 *par = _srcClip->getPixelAspectRatio();
1734 if ( OFX::Coords::rectIsEmpty(*format) ) {
1735 // no format is available, use the RoD instead
1736 const OfxRectD& srcRod = _srcClip->getRegionOfDefinition(time);
1737 Coords::toPixelNearest(srcRod, renderScale, *par, format);
1738 }
1739 } else {
1740 // default to Project Size
1741 OfxRectD srcRoD;
1742 OfxPointD siz = getProjectSize();
1743 OfxPointD off = getProjectOffset();
1744 srcRoD.x1 = off.x;
1745 srcRoD.x2 = off.x + siz.x;
1746 srcRoD.y1 = off.y;
1747 srcRoD.y2 = off.y + siz.y;
1748 *par = getProjectPixelAspectRatio();
1749 Coords::toPixelNearest(srcRoD, renderScale, *par, format);
1750 }
1751 */
1752 return false;
1753 break;
1754 }
1755 return false;
1756 }
1757
1758 #if 0 // getRoD is done by ofxsTransform3x3
1759 bool
1760 Card3DPlugin::getRegionOfDefinition(const RegionOfDefinitionArguments &args, OfxRectD &rod)
1761 {
1762 const double time = args.time;
1763 OfxRectI format = {0, 1, 0, 1};
1764 double par = 1.;
1765 getOutputFormat(time, args.renderScale, &format, &par);
1766 const OfxPointD rs1 = {1., 1.};
1767 OFX::Coords::toCanonical(format, rs1, par, &rod);
1768
1769 return true;
1770 }
1771 #endif
1772
1773 void
getClipPreferences(ClipPreferencesSetter & clipPreferences)1774 Card3DPlugin::getClipPreferences(ClipPreferencesSetter &clipPreferences)
1775 {
1776 //We have to do this because the processing code does not support varying components for uvClip and srcClip
1777 PixelComponentEnum dstPixelComps = getDefaultOutputClipComponents();
1778
1779 if (_srcClip) {
1780 clipPreferences.setClipComponents(*_srcClip, dstPixelComps);
1781 }
1782 OfxRectI format;
1783 double par;
1784 OfxPointD renderScale = {1., 1.};
1785
1786 // we pass 0 as time, since anyway the input RoD is never used, thanks to the test on the return value
1787 bool setFormat = getOutputFormat(0, renderScale, &format, &par);
1788 if (setFormat) {
1789 clipPreferences.setOutputFormat(format);
1790 clipPreferences.setPixelAspectRatio(*_dstClip, par);
1791 }
1792 }
1793
1794 // overridden is identity
1795 bool
isIdentity(double)1796 Card3DPlugin::isIdentity(double /*time*/)
1797 {
1798 // NON-GENERIC
1799 //double amount = _transformAmount->getValueAtTime(time);
1800 //if (amount == 0.) {
1801 // return true;
1802 //}
1803
1804 return false;
1805 }
1806
1807 bool
getInverseTransformCanonical(double time,int view,double,bool invert,Matrix3x3 * invtransform) const1808 Card3DPlugin::getInverseTransformCanonical(double time,
1809 int view,
1810 double /*amount*/,
1811 bool invert,
1812 Matrix3x3* invtransform) const
1813 {
1814 Matrix4x4 axis;
1815 if (_axisCamera) {
1816 if (_axisCamera->isConnected()) {
1817 _axisCamera->getParameter(kNukeOfxCameraParamPositionMatrix, time, view, &axis(0,0), 16);
1818 } else {
1819 axis(0, 0) = axis(1,1) = axis(2,2) = axis(3,3) = 1.;
1820 }
1821 } else {
1822 _axisPosMat->getMatrix(time, &axis);
1823 }
1824 Matrix4x4 cam;
1825 CameraProjectionModeEnum camProjectionMode = eCameraProjectionModePerspective;
1826 double camFocal = 1.;
1827 double camHAperture = 1.; // only the ratio focal/haperture matters for card3d
1828 double camWinTranslate[2] = {0., 0.};
1829 double camWinScale[2] = {1., 1.};
1830 double camWinRoll = 0.;
1831 if (_camCamera) {
1832 if (_camCamera->isConnected()) {
1833 _camCamera->getParameter(kNukeOfxCameraParamPositionMatrix, time, view, &cam(0,0), 16);
1834 double projectionMode;
1835 _camCamera->getParameter(kNukeOfxCameraParamProjectionMode, time, view, &projectionMode, 1);
1836 camProjectionMode = (CameraProjectionModeEnum)((int)projectionMode);
1837 _camCamera->getParameter(kNukeOfxCameraParamFocalLength, time, view, &camFocal, 1);
1838 _camCamera->getParameter(kNukeOfxCameraParamHorizontalAperture, time, view, &camHAperture, 1);
1839 _camCamera->getParameter(kNukeOfxCameraParamWindowTranslate, time, view, camWinTranslate, 2);
1840 _camCamera->getParameter(kNukeOfxCameraParamWindowScale, time, view, camWinScale, 2);
1841 _camCamera->getParameter(kNukeOfxCameraParamWindowRoll, time, view, &camWinRoll, 1);
1842 }
1843 } else if (_camEnable->getValueAtTime(time)) {
1844 _camPosMat->getMatrix(time, &cam);
1845 _camPosMat->getProjection().getValueAtTime(time, camProjectionMode, camFocal, camHAperture, camWinTranslate[0], camWinTranslate[1], camWinScale[0], camWinScale[1], camWinRoll);
1846 } else {
1847 cam(0,0) = cam(1,1) = cam(2,2) = cam(3,3) = 1.;
1848 }
1849 Matrix4x4 card;
1850 _card.getMatrix(time, &card);
1851
1852
1853 // compose matrices
1854 Matrix4x4 invCam;
1855 if ( !cam.inverse(&invCam) ) {
1856 invCam(0,0) = invCam(1,1) = invCam(2,2) = invCam(3,3) = 1.;
1857 }
1858 Matrix4x4 pos = invCam * axis * card;
1859
1860 // apply camera params
1861 Matrix3x3 mat;
1862 CameraParam::getMatrix(pos, camProjectionMode, camFocal, camHAperture, camWinTranslate[0], camWinTranslate[1], camWinScale[0], camWinScale[1], camWinRoll, &mat);
1863
1864 double lensInFocal = _lensInFocal->getValueAtTime(time);
1865 double lensInHAperture = _lensInHAperture->getValueAtTime(time);
1866 double a = lensInHAperture / std::max(1e-8, lensInFocal);
1867 mat(0,0) *= a;
1868 mat(1,0) *= a;
1869 mat(2,0) *= a;
1870 mat(0,1) *= a;
1871 mat(1,1) *= a;
1872 mat(2,1) *= a;
1873
1874 // mat is the direct transform, from source coords to output coords.
1875 // it is normalized for coordinates in (-0.5,0.5)x(-0.5*h/w,0.5*h/w) with y from to to bottom
1876
1877 // get the input format (Natron only) or the input RoD (others)
1878 OfxRectD srcFormatCanonical;
1879 {
1880 OfxRectI srcFormat;
1881 _srcClip->getFormat(srcFormat);
1882 double par = _srcClip->getPixelAspectRatio();
1883 if ( OFX::Coords::rectIsEmpty(srcFormat) ) {
1884 // no format is available, use the RoD instead
1885 srcFormatCanonical = _srcClip->getRegionOfDefinition(time);
1886 } else {
1887 const OfxPointD rs1 = {1., 1.};
1888 Coords::toCanonical(srcFormat, rs1, par, &srcFormatCanonical);
1889 }
1890 }
1891
1892 OfxRectI dstFormat = {0, 1, 0, 1};
1893 double dstPar = 1.;
1894 const OfxPointD rs1 = {1., 1.};
1895 getOutputFormat(time, rs1, &dstFormat, &dstPar);
1896 OfxRectD dstFormatCanonical;
1897 OFX::Coords::toCanonical(dstFormat, rs1, dstPar, &dstFormatCanonical);
1898
1899 Matrix3x3 N; // normalize source
1900 {
1901 double w = srcFormatCanonical.x2 - srcFormatCanonical.x1;
1902 //double h = srcFormatCanonical.y2 - srcFormatCanonical.y1;
1903 if (w == 0.) {
1904 return false;
1905 }
1906 N(0,0) = 1./w;
1907 N(0,2) = -(srcFormatCanonical.x1 + srcFormatCanonical.x2) / (2. * w);
1908 N(1,1) = 1./w;
1909 N(1,2) = -(srcFormatCanonical.y1 + srcFormatCanonical.y2) / (2. * w);
1910 N(2,2) = 1.;
1911 }
1912
1913 Matrix3x3 D; // denormalize output
1914 {
1915 double w = dstFormatCanonical.x2 - dstFormatCanonical.x1;
1916 //double h = dstFormatCanonical.y2 - dstFormatCanonical.y1;
1917 D(0,0) = -w;
1918 D(0,2) = (dstFormatCanonical.x1 + dstFormatCanonical.x2) / 2.;
1919 D(1,1) = -w;
1920 D(1,2) = (dstFormatCanonical.y1 + dstFormatCanonical.y2) / 2.;
1921 D(2,2) = 1.;
1922 }
1923
1924 mat = D * mat * N;
1925
1926 if (invert) {
1927 (*invtransform) = mat;
1928 } else {
1929 if ( !mat.inverse(invtransform) ) {
1930 return false;
1931 }
1932 }
1933
1934 return true;
1935 } // Card3DPlugin::getInverseTransformCanonical
1936
1937
1938 void
updateVisibility()1939 Card3DPlugin::updateVisibility()
1940 {
1941 if (_camEnable) {
1942 bool enabled = _camEnable->getValue();
1943 _camPosMat->setEnabled(enabled);
1944 }
1945 {
1946 GeneratorExtentEnum extent = (GeneratorExtentEnum)_extent->getValue();
1947 bool hasFormat = (extent == eGeneratorExtentFormat);
1948 bool hasSize = (extent == eGeneratorExtentSize);
1949
1950 _format->setIsSecretAndDisabled(!hasFormat);
1951 _size->setIsSecretAndDisabled(!hasSize);
1952 _recenter->setIsSecretAndDisabled(!hasSize);
1953 _btmLeft->setIsSecretAndDisabled(!hasSize);
1954 }
1955 }
1956
1957 void
changedParam(const InstanceChangedArgs & args,const std::string & paramName)1958 Card3DPlugin::changedParam(const InstanceChangedArgs &args,
1959 const std::string ¶mName)
1960 {
1961 //const double time = args.time;
1962 if ( (paramName == kParamPremult) && (args.reason == eChangeUserEdit) ) {
1963 _srcClipChanged->setValue(true);
1964 } else if (paramName == kParamCamEnable) {
1965 updateVisibility();
1966 } else if (paramName == kParamOutputFormat) {
1967 updateVisibility();
1968 } else if (paramName == kParamGeneratorFormat) {
1969 //the host does not handle the format itself, do it ourselves
1970 EParamFormat format = (EParamFormat)_format->getValue();
1971 int w = 0, h = 0;
1972 double par = -1;
1973 getFormatResolution(format, &w, &h, &par);
1974 assert(par != -1);
1975 _formatPar->setValue(par);
1976 _formatSize->setValue(w, h);
1977 } else if (paramName == kParamGeneratorCenter) {
1978 Clip* srcClip = _srcClip;
1979 OfxRectD srcRoD;
1980 if ( srcClip && srcClip->isConnected() ) {
1981 srcRoD = srcClip->getRegionOfDefinition(args.time);
1982 } else {
1983 OfxPointD siz = getProjectSize();
1984 OfxPointD off = getProjectOffset();
1985 srcRoD.x1 = off.x;
1986 srcRoD.x2 = off.x + siz.x;
1987 srcRoD.y1 = off.y;
1988 srcRoD.y2 = off.y + siz.y;
1989 }
1990 OfxPointD center;
1991 center.x = (srcRoD.x2 + srcRoD.x1) / 2.;
1992 center.y = (srcRoD.y2 + srcRoD.y1) / 2.;
1993
1994 OfxRectD rectangle;
1995 _size->getValue(rectangle.x2, rectangle.y2);
1996 _btmLeft->getValue(rectangle.x1, rectangle.y1);
1997 rectangle.x2 += rectangle.x1;
1998 rectangle.y2 += rectangle.y1;
1999
2000 OfxRectD newRectangle;
2001 newRectangle.x1 = center.x - (rectangle.x2 - rectangle.x1) / 2.;
2002 newRectangle.y1 = center.y - (rectangle.y2 - rectangle.y1) / 2.;
2003 newRectangle.x2 = newRectangle.x1 + (rectangle.x2 - rectangle.x1);
2004 newRectangle.y2 = newRectangle.y1 + (rectangle.y2 - rectangle.y1);
2005
2006 _size->setValue(newRectangle.x2 - newRectangle.x1, newRectangle.y2 - newRectangle.y1);
2007 _btmLeft->setValue(newRectangle.x1, newRectangle.y1);
2008 } else {
2009 if (_axisPosMat) {
2010 _axisPosMat->changedParam(args, paramName);
2011 }
2012 if (_camPosMat) {
2013 _camPosMat->changedParam(args, paramName);
2014 }
2015 _card.changedParam(args, paramName);
2016 Transform3x3Plugin::changedParam(args, paramName);
2017 }
2018 }
2019
2020 void
changedClip(const InstanceChangedArgs & args,const std::string & clipName)2021 Card3DPlugin::changedClip(const InstanceChangedArgs &args,
2022 const std::string &clipName)
2023 {
2024 if ( (clipName == kOfxImageEffectSimpleSourceClipName) &&
2025 _srcClip && _srcClip->isConnected() &&
2026 ( args.reason == eChangeUserEdit) ) {
2027 //resetCenter(args.time);
2028 }
2029 }
2030
2031 mDeclarePluginFactory(Card3DPluginFactory, {ofxsThreadSuiteCheck();}, {});
2032
2033
2034 void
describe(ImageEffectDescriptor & desc)2035 Card3DPluginFactory::describe(ImageEffectDescriptor &desc)
2036 {
2037 // basic labels
2038 desc.setLabel(kPluginName);
2039 desc.setPluginGrouping(kPluginGrouping);
2040 desc.setPluginDescription(kPluginDescription);
2041
2042 Transform3x3Describe(desc, false);
2043
2044 //desc.setOverlayInteractDescriptor(new TransformOverlayDescriptorOldParams);
2045 }
2046
2047
2048
2049 void
describeInContext(ImageEffectDescriptor & desc,ContextEnum context)2050 Card3DPluginFactory::describeInContext(ImageEffectDescriptor &desc,
2051 ContextEnum context)
2052 {
2053 // make some pages and to things in
2054 PageParamDescriptor *page = Transform3x3DescribeInContextBegin(desc, context, false);
2055
2056 if (getImageEffectHostDescription()->supportsCamera) {
2057 {
2058 CameraDescriptor* camera = desc.defineCamera(kCameraCam);
2059 camera->setLabel(kCameraCamLabel);
2060 camera->setOptional(true);
2061 }
2062 {
2063 CameraDescriptor* camera = desc.defineCamera(kCameraAxis);
2064 camera->setLabel(kCameraAxisLabel);
2065 camera->setOptional(true);
2066 }
2067 } else {
2068 {
2069 GroupParamDescriptor* group = desc.defineGroupParam(kCameraAxis);
2070 group->setLabel(kCameraAxisLabel);
2071 group->setOpen(false);
2072 if (page) {
2073 page->addChild(*group);
2074 }
2075 PosMatParam::define(desc, page, group, kCameraAxis, ePosMatAxis);
2076 }
2077 {
2078 GroupParamDescriptor* group = desc.defineGroupParam(kCameraCam);
2079 if (group) {
2080 group->setLabel(kCameraCamLabel);
2081 group->setOpen(false);
2082 if (page) {
2083 page->addChild(*group);
2084 }
2085 }
2086 {
2087 BooleanParamDescriptor* param = desc.defineBooleanParam(kParamCamEnable);
2088 param->setLabelAndHint(kParamCamEnableLabel);
2089 param->setDefault(false);
2090 param->setAnimates(false);
2091 if (group) {
2092 param->setParent(*group);
2093 }
2094 if (page) {
2095 page->addChild(*param);
2096 }
2097 }
2098
2099 PosMatParam::define(desc, page, group, kCameraCam, ePosMatCamera);
2100 }
2101 }
2102
2103 PosMatParam::define(desc, page, /*group=*/NULL, /*prefix=*/kGroupCard, ePosMatCard);
2104
2105 {
2106 DoubleParamDescriptor* param = desc.defineDoubleParam(kParamLensInFocal);
2107 param->setLabelAndHint(kParamLensInFocalLabel);
2108 param->setDefault(1.);
2109 param->setRange(1e-8, DBL_MAX);
2110 param->setDisplayRange(1e-8, 1.);
2111 if (page) {
2112 page->addChild(*param);
2113 }
2114 }
2115
2116 {
2117 DoubleParamDescriptor* param = desc.defineDoubleParam(kParamLensInHAperture);
2118 param->setLabelAndHint(kParamLensInHApertureLabel);
2119 param->setDefault(1.);
2120 param->setRange(1e-8, DBL_MAX);
2121 param->setDisplayRange(1e-8, 1.);
2122 param->setLayoutHint(eLayoutHintDivider);
2123 if (page) {
2124 page->addChild(*param);
2125 }
2126 }
2127
2128 { // Frame format
2129 // extent
2130 {
2131 ChoiceParamDescriptor* param = desc.defineChoiceParam(kParamOutputFormat);
2132 param->setLabelAndHint(kParamOutputFormatLabel);
2133 assert(param->getNOptions() == eGeneratorExtentFormat);
2134 param->appendOption(kParamGeneratorExtentOptionFormat);
2135 assert(param->getNOptions() == eGeneratorExtentSize);
2136 param->appendOption(kParamGeneratorExtentOptionSize);
2137 assert(param->getNOptions() == eGeneratorExtentProject);
2138 param->appendOption(kParamGeneratorExtentOptionProject);
2139 //assert(param->getNOptions() == eGeneratorExtentDefault);
2140 //param->appendOption(kParamGeneratorExtentOptionDefault);
2141 param->setDefault(eGeneratorExtentProject);
2142 param->setLayoutHint(eLayoutHintNoNewLine, 1);
2143 param->setAnimates(false);
2144 desc.addClipPreferencesSlaveParam(*param);
2145 if (page) {
2146 page->addChild(*param);
2147 }
2148 }
2149
2150 // recenter
2151 {
2152 PushButtonParamDescriptor* param = desc.definePushButtonParam(kParamGeneratorCenter);
2153 param->setLabel(kParamGeneratorCenterLabel);
2154 param->setHint(kParamGeneratorCenterHint);
2155 param->setLayoutHint(eLayoutHintNoNewLine, 1);
2156 if (page) {
2157 page->addChild(*param);
2158 }
2159 }
2160
2161 // format
2162 {
2163 ChoiceParamDescriptor* param = desc.defineChoiceParam(kParamGeneratorFormat);
2164 param->setLabel(kParamGeneratorFormatLabel);
2165 assert(param->getNOptions() == eParamFormatPCVideo);
2166 param->appendOption(kParamFormatPCVideoLabel, "", kParamFormatPCVideo);
2167 assert(param->getNOptions() == eParamFormatNTSC);
2168 param->appendOption(kParamFormatNTSCLabel, "", kParamFormatNTSC);
2169 assert(param->getNOptions() == eParamFormatPAL);
2170 param->appendOption(kParamFormatPALLabel, "", kParamFormatPAL);
2171 assert(param->getNOptions() == eParamFormatNTSC169);
2172 param->appendOption(kParamFormatNTSC169Label, "", kParamFormatNTSC169);
2173 assert(param->getNOptions() == eParamFormatPAL169);
2174 param->appendOption(kParamFormatPAL169Label, "", kParamFormatPAL169);
2175 assert(param->getNOptions() == eParamFormatHD720);
2176 param->appendOption(kParamFormatHD720Label, "", kParamFormatHD720);
2177 assert(param->getNOptions() == eParamFormatHD);
2178 param->appendOption(kParamFormatHDLabel, "", kParamFormatHD);
2179 assert(param->getNOptions() == eParamFormatUHD4K);
2180 param->appendOption(kParamFormatUHD4KLabel, "", kParamFormatUHD4K);
2181 assert(param->getNOptions() == eParamFormat1kSuper35);
2182 param->appendOption(kParamFormat1kSuper35Label, "", kParamFormat1kSuper35);
2183 assert(param->getNOptions() == eParamFormat1kCinemascope);
2184 param->appendOption(kParamFormat1kCinemascopeLabel, "", kParamFormat1kCinemascope);
2185 assert(param->getNOptions() == eParamFormat2kSuper35);
2186 param->appendOption(kParamFormat2kSuper35Label, "", kParamFormat2kSuper35);
2187 assert(param->getNOptions() == eParamFormat2kCinemascope);
2188 param->appendOption(kParamFormat2kCinemascopeLabel, "", kParamFormat2kCinemascope);
2189 assert(param->getNOptions() == eParamFormat2kDCP);
2190 param->appendOption(kParamFormat2kDCPLabel, "", kParamFormat2kDCP);
2191 assert(param->getNOptions() == eParamFormat4kSuper35);
2192 param->appendOption(kParamFormat4kSuper35Label, "", kParamFormat4kSuper35);
2193 assert(param->getNOptions() == eParamFormat4kCinemascope);
2194 param->appendOption(kParamFormat4kCinemascopeLabel, "", kParamFormat4kCinemascope);
2195 assert(param->getNOptions() == eParamFormat4kDCP);
2196 param->appendOption(kParamFormat4kDCPLabel, "", kParamFormat4kDCP);
2197 assert(param->getNOptions() == eParamFormatSquare256);
2198 param->appendOption(kParamFormatSquare256Label, "", kParamFormatSquare256);
2199 assert(param->getNOptions() == eParamFormatSquare512);
2200 param->appendOption(kParamFormatSquare512Label, "", kParamFormatSquare512);
2201 assert(param->getNOptions() == eParamFormatSquare1k);
2202 param->appendOption(kParamFormatSquare1kLabel, "", kParamFormatSquare1k);
2203 assert(param->getNOptions() == eParamFormatSquare2k);
2204 param->appendOption(kParamFormatSquare2kLabel, "", kParamFormatSquare2k);
2205 param->setDefault(eParamFormatPCVideo);
2206 param->setHint(kParamGeneratorFormatHint);
2207 param->setAnimates(false);
2208 desc.addClipPreferencesSlaveParam(*param);
2209 if (page) {
2210 page->addChild(*param);
2211 }
2212 }
2213
2214 {
2215 int w = 0, h = 0;
2216 double par = -1.;
2217 getFormatResolution(eParamFormatPCVideo, &w, &h, &par);
2218 assert(par != -1);
2219 {
2220 Int2DParamDescriptor* param = desc.defineInt2DParam(kParamGeneratorSize);
2221 param->setLabel(kParamGeneratorSizeLabel);
2222 param->setHint(kParamGeneratorSizeHint);
2223 param->setIsSecretAndDisabled(true);
2224 param->setDefault(w, h);
2225 if (page) {
2226 page->addChild(*param);
2227 }
2228 }
2229
2230 {
2231 DoubleParamDescriptor* param = desc.defineDoubleParam(kParamGeneratorPAR);
2232 param->setLabel(kParamGeneratorPARLabel);
2233 param->setHint(kParamGeneratorPARHint);
2234 param->setIsSecretAndDisabled(true);
2235 param->setRange(0., DBL_MAX);
2236 param->setDisplayRange(0.5, 2.);
2237 param->setDefault(par);
2238 if (page) {
2239 page->addChild(*param);
2240 }
2241 }
2242 }
2243
2244 // btmLeft
2245 {
2246 Double2DParamDescriptor* param = desc.defineDouble2DParam(kParamRectangleInteractBtmLeft);
2247 param->setLabel(kParamRectangleInteractBtmLeftLabel);
2248 param->setDoubleType(eDoubleTypeXYAbsolute);
2249 if ( param->supportsDefaultCoordinateSystem() ) {
2250 param->setDefaultCoordinateSystem(eCoordinatesNormalised); // no need of kParamDefaultsNormalised
2251 } else {
2252 gHostSupportsDefaultCoordinateSystem = false; // no multithread here, see kParamDefaultsNormalised
2253 }
2254 param->setDefault(0., 0.);
2255 param->setRange(-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
2256 param->setDisplayRange(-10000, -10000, 10000, 10000); // Resolve requires display range or values are clamped to (-1,1)
2257 param->setIncrement(1.);
2258 param->setLayoutHint(eLayoutHintNoNewLine, 1);
2259 param->setHint("Coordinates of the bottom left corner of the size rectangle.");
2260 param->setDigits(0);
2261 if (page) {
2262 page->addChild(*param);
2263 }
2264 }
2265
2266 // size
2267 {
2268 Double2DParamDescriptor* param = desc.defineDouble2DParam(kParamRectangleInteractSize);
2269 param->setLabel(kParamRectangleInteractSizeLabel);
2270 param->setDoubleType(eDoubleTypeXY);
2271 if ( param->supportsDefaultCoordinateSystem() ) {
2272 param->setDefaultCoordinateSystem(eCoordinatesNormalised); // no need of kParamDefaultsNormalised
2273 } else {
2274 gHostSupportsDefaultCoordinateSystem = false; // no multithread here, see kParamDefaultsNormalised
2275 }
2276 param->setDefault(1., 1.);
2277 param->setRange(0., 0., DBL_MAX, DBL_MAX); // Resolve requires range and display range or values are clamped to (-1,1)
2278 param->setDisplayRange(0, 0, 10000, 10000); // Resolve requires display range or values are clamped to (-1,1)
2279 param->setIncrement(1.);
2280 param->setDimensionLabels(kParamRectangleInteractSizeDim1, kParamRectangleInteractSizeDim2);
2281 param->setHint("Width and height of the size rectangle.");
2282 param->setIncrement(1.);
2283 param->setDigits(0);
2284 if (page) {
2285 page->addChild(*param);
2286 }
2287 }
2288
2289 }
2290
2291 Transform3x3DescribeInContextEnd(desc, context, page, false, Transform3x3Plugin::eTransform3x3ParamsTypeMotionBlur);
2292
2293 {
2294 BooleanParamDescriptor* param = desc.defineBooleanParam(kParamSrcClipChanged);
2295 param->setDefault(false);
2296 param->setIsSecretAndDisabled(true);
2297 param->setAnimates(false);
2298 param->setEvaluateOnChange(false);
2299 if (page) {
2300 page->addChild(*param);
2301 }
2302 }
2303
2304 // interactive
2305 {
2306 BooleanParamDescriptor* param = desc.defineBooleanParam(kParamTransformInteractive);
2307 param->setLabel(kParamTransformInteractiveLabel);
2308 param->setHint(kParamTransformInteractiveHint);
2309 param->setEvaluateOnChange(false);
2310 if (page) {
2311 page->addChild(*param);
2312 }
2313 }
2314 }
2315
2316 ImageEffect*
createInstance(OfxImageEffectHandle handle,ContextEnum)2317 Card3DPluginFactory::createInstance(OfxImageEffectHandle handle,
2318 ContextEnum /*context*/)
2319 {
2320 return new Card3DPlugin(handle);
2321 }
2322
2323
2324 static Card3DPluginFactory p1(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
2325 mRegisterPluginFactoryInstance(p1)
2326
2327 OFXS_NAMESPACE_ANONYMOUS_EXIT
2328