1 /*
2 Software License :
3
4 Copyright (c) 2003, The Open Effects Association Ltd. All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9 * Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following disclaimer in the documentation
13 and/or other materials provided with the distribution.
14 * Neither the name The Open Effects Association Ltd, nor the names of its
15 contributors may be used to endorse or promote products derived from this
16 software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 Ofx Example plugin that shows how an overlay is drawn and interacted with.
32
33 It is meant to illustrate certain features of the API, as opposed to being a perfectly
34 crafted piece of image processing software.
35
36 Note, that the default bitdepths and components are specified for the source (RGBA + A, 8 + 16 + 32) and that
37 this plugin does absolutely no image processing, it assumes the isIdentity action will be called before a render
38 and so do nothing.
39 */
40
41 #ifdef WIN32
42 #include <windows.h>
43 #endif
44
45 #include <cstring>
46 #ifdef __APPLE__
47 #include <OpenGL/gl.h>
48 #else
49 #include <GL/gl.h>
50 #endif
51 #include <cmath>
52 #include <stdexcept>
53 #include <new>
54 #include "ofxImageEffect.h"
55 #include "ofxMemory.h"
56 #include "ofxMultiThread.h"
57
58 #include "../include/ofxUtilities.H" // example support utils
59
60 #if defined __APPLE__ || defined linux || defined __DragonFly__
61 # define EXPORT __attribute__((visibility("default")))
62 #elif defined _WIN32
63 # define EXPORT OfxExport
64 #else
65 # error Not building on your operating system quite yet
66 #endif
67
68 #define kPointParam "point"
69
70 // pointers to various bits of the host
71 OfxHost *gHost;
72 OfxImageEffectSuiteV1 *gEffectHost = 0;
73 OfxPropertySuiteV1 *gPropHost = 0;
74 OfxParameterSuiteV1 *gParamHost = 0;
75 OfxMemorySuiteV1 *gMemoryHost = 0;
76 OfxMultiThreadSuiteV1 *gThreadHost = 0;
77 OfxMessageSuiteV1 *gMessageSuite = 0;
78 OfxInteractSuiteV1 *gInteractHost = 0;
79
80
81 // we are always identity as we are just a hack example plugin
82 static OfxStatus
isIdentity(OfxImageEffectHandle,OfxPropertySetHandle,OfxPropertySetHandle outArgs)83 isIdentity(OfxImageEffectHandle /*pluginInstance*/,
84 OfxPropertySetHandle /*inArgs*/,
85 OfxPropertySetHandle outArgs)
86 {
87 // set the property in the out args indicating which is the identity clip
88 gPropHost->propSetString(outArgs, kOfxPropName, 0, kOfxImageEffectSimpleSourceClipName);
89 return kOfxStatOK;
90 }
91
92 // the process code that the host sees
render(OfxImageEffectHandle,OfxPropertySetHandle,OfxPropertySetHandle)93 static OfxStatus render(OfxImageEffectHandle /*instance*/,
94 OfxPropertySetHandle /*inArgs*/,
95 OfxPropertySetHandle /*outArgs*/)
96 {
97 // do nothing as this should never be called as isIdentity should always be trapped
98 return kOfxStatOK;
99 }
100
101 ////////////////////////////////////////////////////////////////////////////////
102 // the interaction routines
103 struct MyInteractData {
104 bool selected;
105 OfxParamHandle pointParam;
106
MyInteractDataMyInteractData107 explicit MyInteractData(OfxParamHandle pParam)
108 : selected(false)
109 , pointParam(pParam)
110 {
111 }
112 };
113
114 // get the interact data from an interact instance
115 static MyInteractData *
getInteractData(OfxInteractHandle interactInstance)116 getInteractData(OfxInteractHandle interactInstance)
117 {
118 void *dataV = ofxuGetInteractInstanceData(interactInstance);
119 return (MyInteractData *) dataV;
120 }
121
122 // creation of an interact instance
123 static OfxStatus
interactDescribe(OfxInteractHandle)124 interactDescribe(OfxInteractHandle /*interactDescriptor*/)
125 {
126
127 // and we are good
128 return kOfxStatOK;
129 }
130
131 // creation of an interact instance
132 static OfxStatus
interactCreateInstance(OfxImageEffectHandle pluginInstance,OfxInteractHandle interactInstance)133 interactCreateInstance(OfxImageEffectHandle pluginInstance,
134 OfxInteractHandle interactInstance)
135 {
136 // get the parameter set for this effect
137 OfxParamSetHandle paramSet;
138 gEffectHost->getParamSet(pluginInstance, ¶mSet);
139
140 // fetch a handle to the point param from the parameter set
141 OfxParamHandle pointParam;
142 gParamHost->paramGetHandle(paramSet, kPointParam, &pointParam, 0);
143
144 // make my interact's instance data
145 MyInteractData *data = new MyInteractData(pointParam);
146
147 // and set the interact's data pointer
148 ofxuSetInteractInstanceData(interactInstance, (void *) data);
149
150 OfxPropertySetHandle interactProps;
151 gInteractHost->interactGetPropertySet(interactInstance, &interactProps);
152
153 // slave this interact to the point param so redraws are triggered cleanly
154 gPropHost->propSetString(interactProps, kOfxInteractPropSlaveToParam, 0, kPointParam);
155
156 return kOfxStatOK;
157 }
158
159 // destruction of an interact instance
160 static OfxStatus
interactDestroyInstance(OfxImageEffectHandle,OfxInteractHandle interactInstance)161 interactDestroyInstance(OfxImageEffectHandle /*pluginInstance*/,
162 OfxInteractHandle interactInstance)
163 {
164 MyInteractData *data = getInteractData(interactInstance);
165 delete data;
166 return kOfxStatOK;
167 }
168
169 // size of the cross hair in screen pixels
170 #define kXHairSize 10
171
172 // draw an interact instance
173 static OfxStatus
interactDraw(OfxImageEffectHandle pluginInstance,OfxInteractHandle interactInstance,OfxPropertySetHandle drawArgs)174 interactDraw(OfxImageEffectHandle pluginInstance,
175 OfxInteractHandle interactInstance,
176 OfxPropertySetHandle drawArgs)
177 {
178 // get my private interact data
179 MyInteractData *data = getInteractData(interactInstance);
180
181 // get the size of a pixel in the current projection
182 double pixelScale[2];
183 ofxuGetInteractPixelScale(drawArgs, pixelScale);
184
185 // get my param's value
186 double x, y;
187 gParamHost->paramGetValue(data->pointParam, &x, &y);
188
189 // make the xhair a constant size on screen by scaling by the pixel scale
190 float dx = kXHairSize * pixelScale[0];
191 float dy = kXHairSize * pixelScale[1];
192
193 // if the we have selected the Xhair, draw it highlit
194 if(data->selected)
195 glColor3f(1, 1, 1);
196 else
197 glColor3f(1, 0, 0);
198
199 // Draw a cross hair, the current coordinate system aligns with the image plane.
200 glPushMatrix();
201
202 glTranslated(x, y, 0);
203
204 glBegin(GL_LINES);
205
206 glVertex2f(-dx, 0);
207 glVertex2f(dx, 0);
208
209 glVertex2f(0, -dy);
210 glVertex2f(0, dy);
211
212 glEnd();
213
214
215 glPopMatrix();
216
217 return kOfxStatOK;
218 }
219
220 // function reacting to pen motion
221 static OfxStatus
interactPenMotion(OfxImageEffectHandle pluginInstance,OfxInteractHandle interactInstance,OfxPropertySetHandle inArgs)222 interactPenMotion(OfxImageEffectHandle pluginInstance,
223 OfxInteractHandle interactInstance,
224 OfxPropertySetHandle inArgs)
225 {
226 // get my data handle
227 MyInteractData *data = getInteractData(interactInstance);
228
229 // Have we grabbed on a pen down already?
230 if(data->selected) {
231 // get the pen position
232 OfxPointD penPos = {0., 0.};
233 gPropHost->propGetDoubleN(inArgs, kOfxInteractPropPenPosition, 2, &penPos.x);
234
235 // set the value of the 'point' param
236 gParamHost->paramSetValue(data->pointParam, penPos.x, penPos.y);
237 return kOfxStatOK;
238 }
239 return kOfxStatReplyDefault;
240 }
241
242 static OfxStatus
interactPenDown(OfxImageEffectHandle pluginInstance,OfxInteractHandle interactInstance,OfxPropertySetHandle inArgs)243 interactPenDown(OfxImageEffectHandle pluginInstance,
244 OfxInteractHandle interactInstance,
245 OfxPropertySetHandle inArgs)
246 {
247 // get my data handle
248 MyInteractData *data = getInteractData(interactInstance);
249
250 // get the point param's value
251 double x, y;
252 gParamHost->paramGetValue(data->pointParam, &x, &y);
253
254 // get the size of a pixel on screen
255 double pixelScale[2];
256 ofxuGetInteractPixelScale(inArgs, pixelScale);
257
258 // see if the pen is within 5 screen pixels of the point, in which case, select it
259 double penPos[2];
260 gPropHost->propGetDoubleN(inArgs, kOfxInteractPropPenPosition, 2, penPos);
261 if(fabs(x - penPos[0]) < 5 * pixelScale[0] && fabs(y - penPos[1]) < 5 * pixelScale[1]) {
262 data->selected = true;
263 return kOfxStatOK;
264 }
265 return kOfxStatReplyDefault;
266 }
267
268 static OfxStatus
interactPenUp(OfxImageEffectHandle,OfxInteractHandle interactInstance,OfxPropertySetHandle)269 interactPenUp(OfxImageEffectHandle /*pluginInstance*/,
270 OfxInteractHandle interactInstance,
271 OfxPropertySetHandle /*inArgs*/)
272 {
273 // get my data handle
274 MyInteractData *data = getInteractData(interactInstance);
275
276 if(data->selected) {
277 // pen's gone up, deselect
278 data->selected = false;
279 return kOfxStatOK;
280 }
281 return kOfxStatReplyDefault;
282 }
283
284 ////////////////////////////////////////////////////////////////////////////////
285 // the entry point for the overlay
286 static OfxStatus
overlayMain(const char * action,const void * handle,OfxPropertySetHandle inArgs,OfxPropertySetHandle)287 overlayMain(const char *action, const void *handle, OfxPropertySetHandle inArgs, OfxPropertySetHandle /*outArgs*/)
288 {
289 OfxInteractHandle interact = (OfxInteractHandle ) handle;
290
291 OfxPropertySetHandle props;
292 gInteractHost->interactGetPropertySet(interact, &props);
293
294 if(strcmp(action, kOfxActionDescribe) == 0) {
295 return interactDescribe(interact);
296 }
297 else {
298 // fetch the effect instance from the interact
299 OfxImageEffectHandle pluginInstance;
300 gPropHost->propGetPointer(props, kOfxPropEffectInstance, 0, (void **) &pluginInstance);
301
302 if(strcmp(action, kOfxActionCreateInstance) == 0) {
303 return interactCreateInstance(pluginInstance, interact);
304 }
305 else if(strcmp(action, kOfxActionDestroyInstance) == 0) {
306 return interactDestroyInstance(pluginInstance, interact);
307 }
308 else if(strcmp(action, kOfxInteractActionDraw) == 0) {
309 return interactDraw(pluginInstance, interact, inArgs);
310 }
311 else if(strcmp(action, kOfxInteractActionPenMotion) == 0) {
312 return interactPenMotion(pluginInstance, interact, inArgs);
313 }
314 else if(strcmp(action, kOfxInteractActionPenDown) == 0) {
315 return interactPenDown(pluginInstance, interact, inArgs);
316 }
317 else if(strcmp(action, kOfxInteractActionPenUp) == 0) {
318 return interactPenUp(pluginInstance, interact, inArgs);
319 }
320 return kOfxStatReplyDefault;
321 }
322 return kOfxStatReplyDefault;
323 }
324
325 ////////////////////////////////////////////////////////////////////////////////
326 // the plugin's description routine
327 static OfxStatus
describe(OfxImageEffectHandle effect)328 describe(OfxImageEffectHandle effect)
329 {
330 // fetch the host APIs
331 OfxStatus stat;
332 if((stat = ofxuFetchHostSuites()) != kOfxStatOK)
333 return stat;
334
335 // see if the host supports overlays
336 int supportsOverlays;
337 gPropHost->propGetInt(gHost->host, kOfxImageEffectPropSupportsOverlays, 0, &supportsOverlays);
338 if(supportsOverlays == 0)
339 return kOfxStatErrMissingHostFeature;
340
341 // get the property handle for the plugin
342 OfxPropertySetHandle effectProps;
343 gEffectHost->getPropertySet(effect, &effectProps);
344
345 // define the plugin to the host
346 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 0, kOfxBitDepthByte);
347 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 1, kOfxBitDepthShort);
348 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 2, kOfxBitDepthFloat);
349
350 // set the bit depths the plugin can handle
351 gPropHost->propSetString(effectProps, kOfxPropLabel, 0, "OFX Overlay Example");
352 gPropHost->propSetString(effectProps, kOfxImageEffectPluginPropGrouping, 0, "OFX Example");
353
354 // define the contexts we can be used in
355 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 0, kOfxImageEffectContextFilter);
356
357 // set the property that is the overlay's main entry point for the plugin
358 gPropHost->propSetPointer(effectProps, kOfxImageEffectPluginPropOverlayInteractV1, 0, (void *) overlayMain);
359
360 return kOfxStatOK;
361 }
362
363 static OfxStatus
describeInContext(OfxImageEffectHandle effect,OfxPropertySetHandle)364 describeInContext(OfxImageEffectHandle effect, OfxPropertySetHandle /*inArgs*/)
365 {
366 // define the single source clip
367 OfxPropertySetHandle props;
368 gEffectHost->clipDefine(effect, kOfxImageEffectSimpleSourceClipName, &props);
369 gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
370 gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
371
372 // define the output clip
373 gEffectHost->clipDefine(effect, kOfxImageEffectOutputClipName, &props);
374 gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
375 gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
376
377 // fetch the parameter set from the effect
378 OfxParamSetHandle paramSet;
379 gEffectHost->getParamSet(effect, ¶mSet);
380
381 // define the 2D point we are going to draw an overlay for
382 gParamHost->paramDefine(paramSet, kOfxParamTypeDouble2D, kPointParam, &props);
383 gPropHost->propSetString(props, kOfxParamPropDoubleType, 0, kOfxParamDoubleTypeXYAbsolute);
384 gPropHost->propSetString(props, kOfxParamPropDefaultCoordinateSystem, 0, kOfxParamCoordinatesNormalised);
385 gPropHost->propSetDouble(props, kOfxParamPropDefault, 0, 0.5);
386 gPropHost->propSetDouble(props, kOfxParamPropDefault, 1, 0.5);
387 gPropHost->propSetString(props, kOfxParamPropHint, 0, "Point attached to overlay crosshair");
388 gPropHost->propSetString(props, kOfxParamPropScriptName, 0, "point");
389 gPropHost->propSetString(props, kOfxPropLabel, 0, "Point");
390
391 return kOfxStatOK;
392 }
393
394 ////////////////////////////////////////////////////////////////////////////////
395 // The main function
396 static OfxStatus
pluginMain(const char * action,const void * handle,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)397 pluginMain(const char *action, const void *handle, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs)
398 {
399 try {
400 // cast to appropriate type
401 OfxImageEffectHandle effect = (OfxImageEffectHandle ) handle;
402
403 if(strcmp(action, kOfxActionDescribe) == 0) {
404 return describe(effect);
405 }
406 else if(strcmp(action, kOfxImageEffectActionDescribeInContext) == 0) {
407 return describeInContext(effect, inArgs);
408 }
409 else if(strcmp(action, kOfxImageEffectActionIsIdentity) == 0) {
410 return isIdentity(effect, inArgs, outArgs);
411 }
412 else if(strcmp(action, kOfxImageEffectActionRender) == 0) {
413 return render(effect, inArgs, outArgs);
414 }
415 } catch (std::bad_alloc) {
416 // catch memory
417 //std::cout << "OFX Plugin Memory error." << std::endl;
418 return kOfxStatErrMemory;
419 } catch ( const std::exception& e ) {
420 // standard exceptions
421 //std::cout << "OFX Plugin error: " << e.what() << std::endl;
422 return kOfxStatErrUnknown;
423 } catch (int err) {
424 // ho hum, gone wrong somehow
425 return err;
426 } catch ( ... ) {
427 // everything else
428 //std::cout << "OFX Plugin error" << std::endl;
429 return kOfxStatErrUnknown;
430 }
431
432 // other actions to take the default value
433 return kOfxStatReplyDefault;
434 }
435
436 // function to set the host structure
437 static void
setHostFunc(OfxHost * hostStruct)438 setHostFunc(OfxHost *hostStruct)
439 {
440 gHost = hostStruct;
441 }
442
443 ////////////////////////////////////////////////////////////////////////////////
444 // the plugin struct
445 static OfxPlugin basicPlugin =
446 {
447 kOfxImageEffectPluginApi,
448 1,
449 "uk.co.thefoundry.BasicOverlayPlugin",
450 1,
451 0,
452 setHostFunc,
453 pluginMain
454 };
455
456 // the two mandated functions
457 EXPORT OfxPlugin *
OfxGetPlugin(int nth)458 OfxGetPlugin(int nth)
459 {
460 if(nth == 0)
461 return &basicPlugin;
462 return 0;
463 }
464
465 EXPORT int
OfxGetNumberOfPlugins(void)466 OfxGetNumberOfPlugins(void)
467 {
468 return 1;
469 }
470
471
472