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, &paramSet);
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, &paramSet);
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