1 /*
2 Software License :
3
4 Copyright (c) 2012, 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 /*
32 Direct GPU processing using OpenGL
33 */
34 #include <cstdio>
35 #include <cstring>
36 #include <cstdarg>
37 #ifdef __APPLE__
38 #include <OpenGL/gl.h>
39 #else
40 #include <GL/gl.h>
41 #endif
42 #include <stdexcept>
43 #include <new>
44
45 #include "ofxImageEffect.h"
46 #include "ofxMemory.h"
47 #include "ofxMultiThread.h"
48 #include "ofxOpenGLRender.h"
49
50 #include "../include/ofxUtilities.H" // example support utils
51
52 #if defined __APPLE__ || defined linux || defined __DragonFly__
53 # define EXPORT __attribute__((visibility("default")))
54 #elif defined _WIN32
55 # define EXPORT OfxExport
56 #else
57 # error Not building on your operating system quite yet
58 #endif
59
60 // pointers64 to various bits of the host
61 OfxHost *gHost;
62 OfxImageEffectSuiteV1 *gEffectHost = 0;
63 OfxPropertySuiteV1 *gPropHost = 0;
64 OfxParameterSuiteV1 *gParamHost = 0;
65 OfxMemorySuiteV1 *gMemoryHost = 0;
66 OfxMultiThreadSuiteV1 *gThreadHost = 0;
67 OfxMessageSuiteV1 *gMessageSuite = 0;
68 OfxInteractSuiteV1 *gInteractHost = 0;
69 OfxImageEffectOpenGLRenderSuiteV1 *gOpenGLSuite = 0;
70
71 // some flags about the host's behaviour
72 int gHostSupportsMultipleBitDepths = false;
73 int gHostSupportsOpenGL = false;
74
75 /*
76 #define CHECK_STATUS(args) check_status_fun args
77
78 static void
79 check_status_fun(int status, int expected, const char *name)
80 {
81 if (status != expected) {
82 fprintf(stderr, "OFX error in %s: expected status %d, got %d\n",
83 name, expected, status);
84 }
85 }
86 */
87
88 #define DPRINT(args) print_dbg args
print_dbg(const char * fmt,...)89 void print_dbg(const char *fmt, ...)
90 {
91 char msg[1024];
92 va_list ap;
93
94 va_start(ap, fmt);
95 vsnprintf(msg, 1023, fmt, ap);
96 fwrite(msg, sizeof(char), strlen(msg), stderr);
97 fflush(stderr);
98 #ifdef _WIN32
99 OutputDebugString(msg);
100 #endif
101 va_end(ap);
102 }
103
104 // private instance data type
105 struct MyInstanceData {
106 bool isGeneralEffect;
107
108 // handles to the clips we deal with
109 OfxImageClipHandle sourceClip;
110 OfxImageClipHandle outputClip;
111
112 // handles to our parameters
113 OfxParamHandle scaleParam;
114 OfxParamHandle sourceScaleParam;
115 };
116
117 /* mandatory function to set up the host structures */
118
119
120 // Convinience wrapper to get private data
121 static MyInstanceData *
getMyInstanceData(OfxImageEffectHandle effect)122 getMyInstanceData( OfxImageEffectHandle effect)
123 {
124 // get the property handle for the plugin
125 OfxPropertySetHandle effectProps;
126 gEffectHost->getPropertySet(effect, &effectProps);
127
128 // get my data pointer out of that
129 MyInstanceData *myData = 0;
130 gPropHost->propGetPointer(effectProps, kOfxPropInstanceData, 0,
131 (void **) &myData);
132 return myData;
133 }
134
135 /** @brief Called at load */
136 static OfxStatus
onLoad(void)137 onLoad(void)
138 {
139 return kOfxStatOK;
140 }
141
142 /** @brief Called before unload */
143 static OfxStatus
onUnLoad(void)144 onUnLoad(void)
145 {
146 return kOfxStatOK;
147 }
148
149 // instance construction
150 static OfxStatus
createInstance(OfxImageEffectHandle effect)151 createInstance( OfxImageEffectHandle effect)
152 {
153 // get a pointer to the effect properties
154 OfxPropertySetHandle effectProps;
155 gEffectHost->getPropertySet(effect, &effectProps);
156
157 // get a pointer to the effect's parameter set
158 OfxParamSetHandle paramSet;
159 gEffectHost->getParamSet(effect, ¶mSet);
160
161 // make my private instance data
162 MyInstanceData *myData = new MyInstanceData;
163 const char *context = NULL;
164
165 // is this instance a general effect ?
166 gPropHost->propGetString(effectProps, kOfxImageEffectPropContext, 0, &context);
167 myData->isGeneralEffect = context && (strcmp(context, kOfxImageEffectContextGeneral) == 0);
168
169 // cache away our param handles
170 gParamHost->paramGetHandle(paramSet, "scale", &myData->scaleParam, 0);
171 gParamHost->paramGetHandle(paramSet, "source_scale", &myData->sourceScaleParam, 0);
172
173 // cache away our clip handles
174 gEffectHost->clipGetHandle(effect, kOfxImageEffectSimpleSourceClipName, &myData->sourceClip, 0);
175 gEffectHost->clipGetHandle(effect, kOfxImageEffectOutputClipName, &myData->outputClip, 0);
176
177 // set my private instance data
178 gPropHost->propSetPointer(effectProps, kOfxPropInstanceData, 0, (void *) myData);
179
180 return kOfxStatOK;
181 }
182
183 // instance destruction
184 static OfxStatus
destroyInstance(OfxImageEffectHandle effect)185 destroyInstance( OfxImageEffectHandle effect)
186 {
187 // get my instance data
188 MyInstanceData *myData = getMyInstanceData(effect);
189
190 // and delete it
191 if(myData)
192 delete myData;
193 return kOfxStatOK;
194 }
195
196 // tells the host what region we are capable of filling
197 OfxStatus
getSpatialRoD(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)198 getSpatialRoD( OfxImageEffectHandle effect, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs)
199 {
200 // retrieve any instance data associated with this effect
201 MyInstanceData *myData = getMyInstanceData(effect);
202
203 OfxTime time;
204 gPropHost->propGetDouble(inArgs, kOfxPropTime, 0, &time);
205
206 // my RoD is the same as my input's
207 OfxRectD rod;
208 gEffectHost->clipGetRegionOfDefinition(myData->sourceClip, time, &rod);
209
210 // set the rod in the out args
211 gPropHost->propSetDoubleN(outArgs, kOfxImageEffectPropRegionOfDefinition, 4, &rod.x1);
212
213 return kOfxStatOK;
214 }
215
216 // tells the host how much of the input we need to fill the given window
217 OfxStatus
getSpatialRoI(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)218 getSpatialRoI( OfxImageEffectHandle effect, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs)
219 {
220 // get the RoI the effect is interested in from inArgs
221 OfxRectD roi;
222 gPropHost->propGetDoubleN(inArgs, kOfxImageEffectPropRegionOfInterest, 4, &roi.x1);
223
224 // the input needed is the same as the output, so set that on the source clip
225 gPropHost->propSetDoubleN(outArgs, "OfxImageClipPropRoI_Source", 4, &roi.x1);
226
227 // retrieve any instance data associated with this effect
228 MyInstanceData *myData = getMyInstanceData(effect);
229 (void)myData;
230
231 return kOfxStatOK;
232 }
233
234 // Tells the host how many frames we can fill, only called in the general context.
235 // This is actually redundant as this is the default behaviour, but for illustrative
236 // purposes.
237 OfxStatus
getTemporalDomain(OfxImageEffectHandle effect,OfxPropertySetHandle,OfxPropertySetHandle outArgs)238 getTemporalDomain( OfxImageEffectHandle effect, OfxPropertySetHandle /*inArgs*/, OfxPropertySetHandle outArgs)
239 {
240 MyInstanceData *myData = getMyInstanceData(effect);
241
242 double sourceRange[2];
243
244 // get the frame range of the source clip
245 OfxPropertySetHandle props; gEffectHost->clipGetPropertySet(myData->sourceClip, &props);
246 gPropHost->propGetDoubleN(props, kOfxImageEffectPropFrameRange, 2, sourceRange);
247
248 // set it on the out args
249 gPropHost->propSetDoubleN(outArgs, kOfxImageEffectPropFrameRange, 2, sourceRange);
250
251 return kOfxStatOK;
252 }
253
254
255 // Set our clip preferences
256 static OfxStatus
getClipPreferences(OfxImageEffectHandle effect,OfxPropertySetHandle,OfxPropertySetHandle outArgs)257 getClipPreferences( OfxImageEffectHandle effect, OfxPropertySetHandle /*inArgs*/, OfxPropertySetHandle outArgs)
258 {
259 // retrieve any instance data associated with this effect
260 MyInstanceData *myData = getMyInstanceData(effect);
261
262 // get the component type and bit depth of our main input
263 int bitDepth;
264 bool isRGBA;
265 ofxuClipGetFormat(myData->sourceClip, bitDepth, isRGBA, true); // get the unmapped clip component
266
267 // get the strings used to label the various bit depths
268 const char *bitDepthStr = bitDepth == 8 ? kOfxBitDepthByte : (bitDepth == 16 ? kOfxBitDepthShort : kOfxBitDepthFloat);
269 const char *componentStr = isRGBA ? kOfxImageComponentRGBA : kOfxImageComponentAlpha;
270
271 // set out output to be the same same as the input, component and bitdepth
272 gPropHost->propSetString(outArgs, "OfxImageClipPropComponents_Output", 0, componentStr);
273 if(gHostSupportsMultipleBitDepths)
274 gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, bitDepthStr);
275
276 return kOfxStatOK;
277 }
278
279 // are the settings of the effect performing an identity operation
280 static OfxStatus
isIdentity(OfxImageEffectHandle,OfxPropertySetHandle,OfxPropertySetHandle)281 isIdentity( OfxImageEffectHandle /*effect*/,
282 OfxPropertySetHandle /*inArgs*/,
283 OfxPropertySetHandle /*outArgs*/)
284 {
285 // In this case do the default, which in this case is to render
286 return kOfxStatReplyDefault;
287 }
288
289 ////////////////////////////////////////////////////////////////////////////////
290 // function called when the instance has been changed by anything
291 static OfxStatus
instanceChanged(OfxImageEffectHandle,OfxPropertySetHandle,OfxPropertySetHandle)292 instanceChanged( OfxImageEffectHandle /*effect*/,
293 OfxPropertySetHandle /*inArgs*/,
294 OfxPropertySetHandle /*outArgs*/)
295 {
296 // don't trap any others
297 return kOfxStatReplyDefault;
298 }
299
300 ////////////////////////////////////////////////////////////////////////////////
301 // rendering routines
302
303 // Is image handle a GPU texture?
304 /*
305 static bool image_is_texture(OfxPropertySetHandle image)
306 {
307 int tmp;
308 return (gOpenGLSuite != NULL) &&
309 (gPropHost->propGetInt(image, kOfxImageEffectPropOpenGLTextureIndex, 0, &tmp) == kOfxStatOK);
310 }
311 */
312
313 // Render to texture: see http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/
314
315
316 // the process code that the host sees
render(OfxImageEffectHandle instance,OfxPropertySetHandle inArgs,OfxPropertySetHandle)317 static OfxStatus render( OfxImageEffectHandle instance,
318 OfxPropertySetHandle inArgs,
319 OfxPropertySetHandle /*outArgs*/)
320 {
321 // get the render window and the time from the inArgs
322 OfxTime time;
323 OfxRectI renderWindow;
324 OfxStatus status = kOfxStatOK;
325
326 gPropHost->propGetDouble(inArgs, kOfxPropTime, 0, &time);
327 gPropHost->propGetIntN(inArgs, kOfxImageEffectPropRenderWindow, 4, &renderWindow.x1);
328
329 // Retrieve instance data associated with this effect
330 MyInstanceData *myData = getMyInstanceData(instance);
331
332 // property handles and members of each image
333 OfxPropertySetHandle sourceImg = NULL, outputImg = NULL;
334 int gl_enabled = 0;
335 int source_texture_index = -1, source_texture_target = -1;
336 int output_texture_index = -1, output_texture_target = -1;
337 const char *tmps = NULL;
338
339 DPRINT(("render: openGLSuite %s\n", gOpenGLSuite ? "found" : "not found"));
340 if (gOpenGLSuite) {
341 gPropHost->propGetInt(inArgs, kOfxImageEffectPropOpenGLEnabled, 0, &gl_enabled);
342 DPRINT(("render: openGL rendering %s\n", gl_enabled ? "enabled" : "DISABLED"));
343 }
344 DPRINT(("Render: window = [%d, %d - %d, %d]\n",
345 renderWindow.x1, renderWindow.y1,
346 renderWindow.x2, renderWindow.y2));
347
348 // For this test, we only process in OpenGL mode.
349 if (!gl_enabled) {
350 return kOfxStatErrImageFormat;
351 }
352
353 // get the output image texture
354 status = gOpenGLSuite->clipLoadTexture(myData->outputClip, time, NULL, NULL, &outputImg);
355 DPRINT(("openGL: clipLoadTexture (output) returns status %d\n", status));
356 if (status != kOfxStatOK) {
357 return status;
358 }
359 status = gPropHost->propGetInt(outputImg, kOfxImageEffectPropOpenGLTextureIndex,
360 0, &output_texture_index);
361 if (status != kOfxStatOK) {
362 return status;
363 }
364 status = gPropHost->propGetInt(outputImg, kOfxImageEffectPropOpenGLTextureTarget,
365 0, &output_texture_target);
366 if (status != kOfxStatOK) {
367 return status;
368 }
369 status = gPropHost->propGetString(outputImg, kOfxImageEffectPropPixelDepth, 0, &tmps);
370 if (status != kOfxStatOK) {
371 return status;
372 }
373 DPRINT(("openGL: output texture index %d, target %d, depth %s\n",
374 output_texture_index, output_texture_target, tmps));
375
376 status = gOpenGLSuite->clipLoadTexture(myData->sourceClip, time, NULL, NULL, &sourceImg);
377 DPRINT(("openGL: clipLoadTexture (source) returns status %d\n", status));
378 if (status != kOfxStatOK) {
379 return status;
380 }
381
382 status = gPropHost->propGetInt(sourceImg, kOfxImageEffectPropOpenGLTextureIndex,
383 0, &source_texture_index);
384 if (status != kOfxStatOK) {
385 return status;
386 }
387 status = gPropHost->propGetInt(sourceImg, kOfxImageEffectPropOpenGLTextureTarget,
388 0, &source_texture_target);
389 if (status != kOfxStatOK) {
390 return status;
391 }
392 status = gPropHost->propGetString(sourceImg, kOfxImageEffectPropPixelDepth, 0, &tmps);
393 if (status != kOfxStatOK) {
394 return status;
395 }
396 DPRINT(("openGL: source texture index %d, target %d, depth %s\n",
397 source_texture_index, source_texture_target, tmps));
398 // XXX: check status for errors
399
400 // get the scale parameter
401 double scale = 1;
402 double source_scale = 1;
403 gParamHost->paramGetValueAtTime(myData->scaleParam, time, &scale);
404 gParamHost->paramGetValueAtTime(myData->sourceScaleParam, time, &source_scale);
405
406 float w = (renderWindow.x2 - renderWindow.x1);
407 float h = (renderWindow.y2 - renderWindow.y1);
408
409 glPushAttrib(GL_ALL_ATTRIB_BITS);
410 glDisable(GL_BLEND);
411
412 // Draw black into dest to start
413 glBegin(GL_QUADS);
414 glColor4f(0, 0, 0, 1); //Set the colour to opaque black
415 glVertex2f(0, 0);
416 glVertex2f(0, h);
417 glVertex2f(w, h);
418 glVertex2f(w, 0);
419 glEnd();
420
421 //
422 // Copy source texture to output by drawing a big textured quad
423 //
424
425 // set up texture (how much of this is needed?)
426 glEnable(source_texture_target);
427 glBindTexture(source_texture_target, source_texture_index);
428 glTexParameteri(source_texture_target, GL_TEXTURE_WRAP_S, GL_REPEAT);
429 glTexParameteri(source_texture_target, GL_TEXTURE_WRAP_T, GL_REPEAT);
430 glTexParameteri(source_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
431 glTexParameteri(source_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
432 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
433
434 // textures are oriented with Y up (standard orientation)
435 float tymin = 0;
436 float tymax = 1;
437
438 // now draw the textured quad containing the source
439 glBegin(GL_QUADS);
440 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
441 glBegin (GL_QUADS);
442 glTexCoord2f (0, tymin);
443 glVertex2f (0, 0);
444 glTexCoord2f (1.0, tymin);
445 glVertex2f (w * source_scale, 0);
446 glTexCoord2f (1.0, tymax);
447 glVertex2f (w * source_scale, h * source_scale);
448 glTexCoord2f (0, tymax);
449 glVertex2f (0, h * source_scale);
450 glEnd ();
451
452 glDisable(source_texture_target);
453
454 // Now draw some stuff on top of it to show we really did something
455 #define WIDTH 200
456 #define HEIGHT 100
457 glBegin(GL_QUADS);
458 glColor3f(1.0f, 0, 0); //Set the colour to red
459 glVertex2f(10, 10);
460 glVertex2f(10, HEIGHT * scale);
461 glVertex2f(WIDTH * scale, HEIGHT * scale);
462 glVertex2f(WIDTH * scale, 10);
463 glEnd();
464
465 // done; clean up.
466 glPopAttrib();
467
468 // release the data pointers
469 if(sourceImg)
470 gOpenGLSuite->clipFreeTexture(sourceImg);
471 if(outputImg)
472 gOpenGLSuite->clipFreeTexture(outputImg);
473
474 return status;
475 }
476
477 // convience function to define parameters
478 static void
defineParam(OfxParamSetHandle effectParams,const char * name,const char * label,const char * scriptName,const char * hint,const char * parent)479 defineParam( OfxParamSetHandle effectParams,
480 const char *name,
481 const char *label,
482 const char *scriptName,
483 const char *hint,
484 const char *parent)
485 {
486 OfxPropertySetHandle props;
487 gParamHost->paramDefine(effectParams, kOfxParamTypeDouble, name, &props);
488
489 // say we are a scaling parameter
490 gPropHost->propSetString(props, kOfxParamPropDoubleType, 0, kOfxParamDoubleTypeScale);
491 gPropHost->propSetDouble(props, kOfxParamPropDefault, 0, 1.0);
492 gPropHost->propSetDouble(props, kOfxParamPropMin, 0, 0.0);
493 gPropHost->propSetDouble(props, kOfxParamPropDisplayMin, 0, 0.0);
494 //gPropHost->propSetDouble(props, kOfxParamPropDisplayMax, 0, 100.0);
495 gPropHost->propSetDouble(props, kOfxParamPropIncrement, 0, 0.01);
496 gPropHost->propSetString(props, kOfxParamPropHint, 0, hint);
497 gPropHost->propSetString(props, kOfxParamPropScriptName, 0, scriptName);
498 gPropHost->propSetString(props, kOfxPropLabel, 0, label);
499 if(parent)
500 gPropHost->propSetString(props, kOfxParamPropParent, 0, parent);
501 }
502
503 // describe the plugin in context
504 static OfxStatus
describeInContext(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs)505 describeInContext( OfxImageEffectHandle effect, OfxPropertySetHandle inArgs)
506 {
507 // get the context from the inArgs handle
508 const char *context = NULL;
509 gPropHost->propGetString(inArgs, kOfxImageEffectPropContext, 0, &context);
510 //bool isGeneralContext = strcmp(context, kOfxImageEffectContextGeneral) == 0;
511
512 OfxPropertySetHandle props;
513 // define the single output clip in both contexts
514 gEffectHost->clipDefine(effect, kOfxImageEffectOutputClipName, &props);
515
516 // set the component types we can handle on out output
517 gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
518 gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
519
520 // define the single source clip in both contexts
521 gEffectHost->clipDefine(effect, kOfxImageEffectSimpleSourceClipName, &props);
522
523 // set the component types we can handle on our main input
524 gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
525 gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
526
527 ////////////////////////////////////////////////////////////////////////////////
528 // define the parameters for this context
529 // fetch the parameter set from the effect
530 OfxParamSetHandle paramSet;
531 gEffectHost->getParamSet(effect, ¶mSet);
532
533 // overall scale param
534 defineParam(paramSet, "scale", "scale", "scale",
535 "Scales the red rect", 0);
536 defineParam(paramSet, "source_scale", "source_scale", "source_scale",
537 "Scales the source image", 0);
538
539 // make a page of controls and add my parameters to it
540 gParamHost->paramDefine(paramSet, kOfxParamTypePage, "Main", &props);
541 gPropHost->propSetString(props, kOfxParamPropPageChild, 0, "scale");
542 gPropHost->propSetString(props, kOfxParamPropPageChild, 1, "source_scale");
543 return kOfxStatOK;
544 }
545
546 ////////////////////////////////////////////////////////////////////////////////
547 // the plugin's description routine
548 static OfxStatus
describe(OfxImageEffectHandle effect)549 describe(OfxImageEffectHandle effect)
550 {
551 // first fetch the host APIs, this cannot be done before this call
552 OfxStatus stat;
553 if((stat = ofxuFetchHostSuites()) != kOfxStatOK)
554 return stat;
555
556 gOpenGLSuite =
557 (OfxImageEffectOpenGLRenderSuiteV1 *)gHost->fetchSuite(gHost->host, kOfxOpenGLRenderSuite, 1);
558
559 // record a few host features
560 gPropHost->propGetInt(gHost->host, kOfxImageEffectPropSupportsMultipleClipDepths, 0, &gHostSupportsMultipleBitDepths);
561
562 // get the property handle for the plugin
563 OfxPropertySetHandle effectProps;
564 gEffectHost->getPropertySet(effect, &effectProps);
565
566 // We can render both fields in a fielded images in one hit if there is no animation
567 // So set the flag that allows us to do this
568 gPropHost->propSetInt(effectProps, kOfxImageEffectPluginPropFieldRenderTwiceAlways, 0, 0);
569
570 // say we can support multiple pixel depths and let the clip preferences action deal with it all.
571 gPropHost->propSetInt(effectProps, kOfxImageEffectPropSupportsMultipleClipDepths, 0, 1);
572
573 // set the bit depths the plugin can handle
574 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 0, kOfxBitDepthByte);
575 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 1, kOfxBitDepthShort);
576 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 2, kOfxBitDepthFloat);
577
578 // set some labels and the group it belongs to
579 gPropHost->propSetString(effectProps, kOfxPropLabel, 0, "OFX OpenGL Example");
580 gPropHost->propSetString(effectProps, kOfxImageEffectPluginPropGrouping, 0, "OFX Example");
581
582 // define the contexts we can be used in
583 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 0, kOfxImageEffectContextFilter);
584 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 1, kOfxImageEffectContextGeneral);
585
586 // we support OpenGL rendering (could also say "needed" here)
587 gPropHost->propSetString(effectProps, kOfxImageEffectPropOpenGLRenderSupported, 0, "true");
588
589 {
590 const char *s = NULL;
591 stat = gPropHost->propGetString(gHost->host, kOfxImageEffectPropOpenGLRenderSupported, 0, &s);
592 DPRINT(("Host has OpenGL render support: %s (stat=%d)\n", s, stat));
593 gHostSupportsOpenGL = stat == 0 && !strcmp(s, "true");
594 }
595
596 // we support all the OpenGL bit depths
597 gPropHost->propSetString(effectProps, kOfxOpenGLPropPixelDepth, 0, kOfxBitDepthByte);
598 gPropHost->propSetString(effectProps, kOfxOpenGLPropPixelDepth, 1, kOfxBitDepthShort);
599 gPropHost->propSetString(effectProps, kOfxOpenGLPropPixelDepth, 2, kOfxBitDepthFloat);
600
601 return kOfxStatOK;
602 }
603
604 ////////////////////////////////////////////////////////////////////////////////
605 // The main function
606 static OfxStatus
pluginMain(const char * action,const void * handle,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)607 pluginMain(const char *action, const void *handle, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs)
608 {
609 try {
610 // cast to appropriate type
611 OfxImageEffectHandle effect = (OfxImageEffectHandle) handle;
612
613 if(strcmp(action, kOfxActionDescribe) == 0) {
614 return describe(effect);
615 }
616 else if(strcmp(action, kOfxImageEffectActionDescribeInContext) == 0) {
617 return describeInContext(effect, inArgs);
618 }
619 else if(strcmp(action, kOfxActionLoad) == 0) {
620 return onLoad();
621 }
622 else if(strcmp(action, kOfxActionUnload) == 0) {
623 return onUnLoad();
624 }
625 else if(strcmp(action, kOfxActionCreateInstance) == 0) {
626 return createInstance(effect);
627 }
628 else if(strcmp(action, kOfxActionDestroyInstance) == 0) {
629 return destroyInstance(effect);
630 }
631 else if(strcmp(action, kOfxImageEffectActionIsIdentity) == 0) {
632 return isIdentity(effect, inArgs, outArgs);
633 }
634 else if(strcmp(action, kOfxImageEffectActionRender) == 0) {
635 return render(effect, inArgs, outArgs);
636 }
637 else if(strcmp(action, kOfxImageEffectActionGetRegionOfDefinition) == 0) {
638 return getSpatialRoD(effect, inArgs, outArgs);
639 }
640 else if(strcmp(action, kOfxImageEffectActionGetRegionsOfInterest) == 0) {
641 return getSpatialRoI(effect, inArgs, outArgs);
642 }
643 else if(strcmp(action, kOfxImageEffectActionGetClipPreferences) == 0) {
644 return getClipPreferences(effect, inArgs, outArgs);
645 }
646 else if(strcmp(action, kOfxActionInstanceChanged) == 0) {
647 return instanceChanged(effect, inArgs, outArgs);
648 }
649 else if(strcmp(action, kOfxImageEffectActionGetTimeDomain) == 0) {
650 return getTemporalDomain(effect, inArgs, outArgs);
651 }
652 } catch (std::bad_alloc) {
653 // catch memory
654 //std::cout << "OFX Plugin Memory error." << std::endl;
655 return kOfxStatErrMemory;
656 } catch ( const std::exception& e ) {
657 // standard exceptions
658 //std::cout << "OFX Plugin error: " << e.what() << std::endl;
659 return kOfxStatErrUnknown;
660 } catch (int err) {
661 // ho hum, gone wrong somehow
662 return err;
663 } catch ( ... ) {
664 // everything else
665 //std::cout << "OFX Plugin error" << std::endl;
666 return kOfxStatErrUnknown;
667 }
668
669 // other actions to take the default value
670 return kOfxStatReplyDefault;
671 }
672
673 // function to set the host structure
674 static void
setHostFunc(OfxHost * hostStruct)675 setHostFunc(OfxHost *hostStruct)
676 {
677 gHost = hostStruct;
678 }
679
680 ////////////////////////////////////////////////////////////////////////////////
681 // the plugin struct
682 static OfxPlugin basicPlugin =
683 {
684 kOfxImageEffectPluginApi,
685 1,
686 "com.genarts:OpenGLSamplePlugin",
687 1,
688 0,
689 setHostFunc,
690 pluginMain
691 };
692
693 // the two mandated functions
694 EXPORT OfxPlugin *
OfxGetPlugin(int nth)695 OfxGetPlugin(int nth)
696 {
697 if(nth == 0)
698 return &basicPlugin;
699 return 0;
700 }
701
702 EXPORT int
OfxGetNumberOfPlugins(void)703 OfxGetNumberOfPlugins(void)
704 {
705 return 1;
706 }
707