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 /*
32   Ofx Example plugin that shows how a plugin can manipulate pixel depths.
33 
34   It is meant to illustrate certain features of the API, as opposed to being a perfectly
35   crafted piece of image processing software.
36 
37   The main features are
38     - how to map pixel depths
39  */
40 #include <cstring>
41 #include <stdexcept>
42 #include <new>
43 #include "ofxImageEffect.h"
44 #include "ofxMemory.h"
45 #include "ofxMultiThread.h"
46 
47 #include "../include/ofxUtilities.H" // example support utils
48 
49 #if defined __APPLE__ || defined linux || defined __DragonFly__
50 #  define EXPORT __attribute__((visibility("default")))
51 #elif defined _WIN32
52 #  define EXPORT OfxExport
53 #else
54 #  error Not building on your operating system quite yet
55 #endif
56 
57 // Message id for the message posted when we don't have enough bits
58 #define kMessageNotEnoughBits "MessageIDNotEnoughBits"
59 
Maximum(T a,T b)60 template <class T> inline T Maximum(T a, T b) {return a > b ? a : b;}
Minimum(T a,T b)61 template <class T> inline T Minimum(T a, T b) {return a < b ? a : b;}
62 
63 
64 static bool gSupportsBytes  = false;
65 static bool gSupportsShorts = false;
66 static bool gSupportsFloats = false;
67 static int gDepthParamToBytes[3]; // maps the value of the bit depth param to a host supported bit depth
68 
69 // pointers64 to various bits of the host
70 OfxHost               *gHost;
71 OfxImageEffectSuiteV1 *gEffectHost = 0;
72 OfxPropertySuiteV1    *gPropHost = 0;
73 OfxParameterSuiteV1   *gParamHost = 0;
74 OfxMemorySuiteV1      *gMemoryHost = 0;
75 OfxMultiThreadSuiteV1 *gThreadHost = 0;
76 OfxMessageSuiteV1     *gMessageSuite = 0;
77 OfxInteractSuiteV1    *gInteractHost = 0;
78 
79 // private instance data type
80 struct MyInstanceData {
81   // handles to the clips we deal with
82   OfxImageClipHandle sourceClip;
83   OfxImageClipHandle outputClip;
84 
85   // handles to a our parameters
86   OfxParamHandle depthParam;
87 };
88 
89 
90 // Convinience wrapper to get private data
91 static MyInstanceData *
getMyInstanceData(OfxImageEffectHandle effect)92 getMyInstanceData(OfxImageEffectHandle effect)
93 {
94   MyInstanceData *myData = (MyInstanceData *) ofxuGetEffectInstanceData(effect);
95   return myData;
96 }
97 
98 
99 /** @brief Called at load */
100 
101 //  instance construction
102 static OfxStatus
createInstance(OfxImageEffectHandle effect)103 createInstance(OfxImageEffectHandle effect)
104 {
105   // get a pointer to the effect properties
106   OfxPropertySetHandle effectProps;
107   gEffectHost->getPropertySet(effect, &effectProps);
108 
109   // get a pointer to the effect's parameter set
110   OfxParamSetHandle paramSet;
111   gEffectHost->getParamSet(effect, &paramSet);
112 
113   MyInstanceData *myData = new MyInstanceData;
114 
115   // cache away param handles
116   gParamHost->paramGetHandle(paramSet, "depth", &myData->depthParam, 0);
117 
118   // cache away clip handles
119   gEffectHost->clipGetHandle(effect, "Source", &myData->sourceClip, 0);
120   gEffectHost->clipGetHandle(effect, "Output", &myData->outputClip, 0);
121 
122   ofxuSetEffectInstanceData(effect, (void *) myData);
123 
124   return kOfxStatOK;
125 }
126 
127 // instance destruction
128 static OfxStatus
destroyInstance(OfxImageEffectHandle effect)129 destroyInstance(OfxImageEffectHandle effect)
130 {
131   // get my instance data
132   MyInstanceData *myData = getMyInstanceData(effect);
133 
134   // and delete it
135   if(myData)
136     delete myData;
137   return kOfxStatOK;
138 }
139 
140 // are the settings of the effect performing an identity operation
141 static OfxStatus
isIdentity(OfxImageEffectHandle effect,OfxPropertySetHandle,OfxPropertySetHandle outArgs)142 isIdentity(OfxImageEffectHandle  effect,
143 	   OfxPropertySetHandle /*inArgs*/,
144 	   OfxPropertySetHandle outArgs)
145 {
146   // retrieve any instance data associated with this effect
147   MyInstanceData *myData = getMyInstanceData(effect);
148 
149   // get the render window and the time from the inArgs
150   //OfxTime time;
151   //OfxRectI renderWindow;
152 
153   // get the src depth
154   int srcDepth = ofxuGetClipPixelDepth(myData->sourceClip);
155 
156   // get the dst depth
157   int dstDepth = ofxuGetClipPixelDepth(myData->outputClip);
158 
159   // if the depths are the same we have no work to do!
160   if(srcDepth == dstDepth) {
161     // set the property in the out args indicating which is the identity clip
162     gPropHost->propSetString(outArgs, kOfxPropName, 0, "Source");
163     return kOfxStatOK;
164   }
165 
166   // In this case do the default, which in this case is to render
167   return kOfxStatReplyDefault;
168 }
169 
170 ////////////////////////////////////////////////////////////////////////////////
171 // rendering routines
172 template <class T> inline T
Clamp(T v,int min,int max)173 Clamp(T v, int min, int max)
174 {
175   if(v < T(min)) return T(min);
176   if(v > T(max)) return T(max);
177   return v;
178 }
179 
180 // look up a pixel in the image, does bounds checking to see if it is in the image rectangle
181 template <class PIX> inline PIX *
pixelAddress(PIX * img,OfxRectI rect,int x,int y,int bytesPerLine)182 pixelAddress(PIX *img, OfxRectI rect, int x, int y, int bytesPerLine)
183 {
184   if(x < rect.x1 || x >= rect.x2 || y < rect.y1 || y > rect.y2)
185     return 0;
186   PIX *pix = (PIX *) (((char *) img) + (y - rect.y1) * bytesPerLine);
187   pix += x - rect.x1;
188   return pix;
189 }
190 
191 ////////////////////////////////////////////////////////////////////////////////
192 // base class to process images with
193 class Processor {
194 protected :
195   OfxImageEffectHandle instance;
196   int nComponents;
197   void *srcV, *dstV;
198   OfxRectI srcRect, dstRect;
199   int srcBytesPerLine, dstBytesPerLine;
200   OfxRectI  window;
201 
202 public :
Processor(const Processor & p)203   Processor(const Processor &p)
204     : instance(p.instance)
205     , nComponents(p.nComponents)
206     , srcV(p.srcV)
207     , dstV(p.dstV)
208     , srcRect(p.srcRect)
209     , dstRect(p.dstRect)
210     , srcBytesPerLine(p.srcBytesPerLine)
211     , dstBytesPerLine(p.dstBytesPerLine)
212     , window(p.window)
213   {}
214 
Processor(OfxImageEffectHandle inst,int nComps,void * src,OfxRectI sRect,int sBytesPerLine,void * dst,OfxRectI dRect,int dBytesPerLine,OfxRectI win)215   Processor(OfxImageEffectHandle inst, int nComps,
216             void *src, OfxRectI sRect, int sBytesPerLine,
217             void *dst, OfxRectI dRect, int dBytesPerLine,
218             OfxRectI  win)
219     : instance(inst)
220     , nComponents(nComps)
221     , srcV(src)
222     , dstV(dst)
223     , srcRect(sRect)
224     , dstRect(dRect)
225     , srcBytesPerLine(sBytesPerLine)
226     , dstBytesPerLine(dBytesPerLine)
227     , window(win)
228   {}
229 
230   static void multiThreadProcessing(unsigned int threadId, unsigned int nThreads, void *arg);
231   virtual void doProcessing(OfxRectI window);
232   void process(void);
233 };
234 
235 // function call once for each thread by the host
236 void
multiThreadProcessing(unsigned int threadId,unsigned int nThreads,void * arg)237 Processor::multiThreadProcessing(unsigned int threadId, unsigned int nThreads, void *arg)
238 {
239   Processor *proc = (Processor *) arg;
240 
241   // slice the y range into the number of threads it has
242   unsigned int dy = proc->window.y2 - proc->window.y1;
243   unsigned int y1 = proc->window.y1 + threadId * dy/nThreads;
244   unsigned int y2 = proc->window.y1 + Minimum((threadId + 1) * dy/nThreads, dy);
245 
246   OfxRectI win = proc->window;
247   win.y1 = y1; win.y2 = y2;
248 
249   // and render that thread on each
250   proc->doProcessing(win);
251 }
252 
253 // function to kick off rendering across multiple CPUs
254 void
process(void)255 Processor::process(void)
256 {
257   unsigned int nThreads;
258   gThreadHost->multiThreadNumCPUs(&nThreads);
259   gThreadHost->multiThread(multiThreadProcessing, nThreads, (void *) this);
260 }
261 
262 void
doProcessing(OfxRectI)263 Processor::doProcessing(OfxRectI /*window*/)
264 {
265 }
266 
267 // template to do the RGBA processing
268 template <class SRCPIX, int kSrcMax, int srcIsFloat,
269 	  class DSTPIX, int kDstMax, int dstIsFloat>
270 class ProcessPix : public Processor {
271  public :
ProcessPix(const Processor & p)272   ProcessPix(const Processor &p)
273     : Processor(p)
274   {
275     process();
276   }
277 
doProcessing(OfxRectI procWindow)278   void doProcessing(OfxRectI procWindow)
279   {
280     SRCPIX *src = (SRCPIX *) srcV;
281     DSTPIX *dst = (DSTPIX *) dstV;
282 
283     float scaleF;
284     scaleF = float(kDstMax)/float(kSrcMax);
285 
286     for(int y = procWindow.y1; y < procWindow.y2; y++) {
287       if(gEffectHost->abort(instance)) break;
288 
289       DSTPIX *dstPix = pixelAddress(dst, dstRect, procWindow.x1, y, dstBytesPerLine);
290 
291       for(int x = procWindow.x1; x < procWindow.x2; x++) {
292 
293         // if a generator, we have no source
294         SRCPIX *srcPix = pixelAddress(src, srcRect, x, y, srcBytesPerLine);
295 
296         // change my pixel depths
297         if(srcPix) {
298           for(int c = 0; c < nComponents; c++) {
299             if(dstIsFloat)
300               dstPix[c] = srcPix[c] * scaleF;
301             else if (srcIsFloat)
302               dstPix[c] = Clamp(srcPix[c] * scaleF, 0, kDstMax);
303             else
304               dstPix[c] = Clamp(srcPix[c] * kDstMax/kSrcMax, 0, kDstMax);
305           }
306           srcPix += nComponents;
307         }
308         else {
309           for(int c = 0; c < nComponents; c++)
310             dstPix[c] = 0;
311         }
312         dstPix += nComponents;
313       }
314     }
315   }
316 
317 };
318 
319 // the process code  that the host sees
render(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs,OfxPropertySetHandle)320 static OfxStatus render(OfxImageEffectHandle effect,
321                         OfxPropertySetHandle inArgs,
322                         OfxPropertySetHandle /*outArgs*/)
323 {
324   // get the render window and the time from the inArgs
325   OfxTime time;
326   OfxRectI renderWindow;
327   OfxStatus status = kOfxStatOK;
328 
329   gPropHost->propGetDouble(inArgs, kOfxPropTime, 0, &time);
330   gPropHost->propGetIntN(inArgs, kOfxImageEffectPropRenderWindow, 4, &renderWindow.x1);
331 
332   // retrieve any instance data associated with this effect
333   MyInstanceData *myData = getMyInstanceData(effect);
334 
335   // property handles and members of each image
336   // in reality, we would put this in a struct as the C++ support layer does
337   OfxPropertySetHandle sourceImg = NULL, outputImg = NULL;
338   int srcRowBytes, srcBitDepth, dstRowBytes, dstBitDepth;
339   bool srcIsAlpha, dstIsAlpha;
340   OfxRectI dstRect, srcRect;
341   void *src, *dst;
342 
343   try {
344     outputImg = ofxuGetImage(myData->outputClip, time, dstRowBytes, dstBitDepth, dstIsAlpha, dstRect, dst);
345     if(outputImg == NULL) throw OfxuNoImageException();
346 
347     sourceImg = ofxuGetImage(myData->sourceClip, time, srcRowBytes, srcBitDepth, srcIsAlpha, srcRect, src);
348     if(sourceImg == NULL) throw OfxuNoImageException();
349 
350     int nComponents = dstIsAlpha ? 1 : 4;
351 
352     // set up the processor that we pass to the individual constructors
353     Processor proc(effect, nComponents,
354                    src, srcRect, srcRowBytes,
355                    dst, dstRect, dstRowBytes,
356                    renderWindow);
357 
358     // now instantiate the templated processor depending on src and dest pixel types, 9 cases in all
359     switch(dstBitDepth) {
360     case 8 : {
361       switch(srcBitDepth) {
362       case 8 :  {ProcessPix<unsigned char,  255,   0, unsigned char, 255, 0> pixProc(proc); break;}
363       case 16 : {ProcessPix<unsigned short, 65535, 0, unsigned char, 255, 0> pixProc(proc); break;}
364       case 32 : {ProcessPix<float,          1,     1, unsigned char, 255, 0> pixProc(proc); break;}
365       }
366     }
367       break;
368 
369     case 16 : {
370       switch(srcBitDepth) {
371       case 8 :  {ProcessPix<unsigned char,  255,   0, unsigned short, 65535, 0> pixProc(proc); break;}
372       case 16 : {ProcessPix<unsigned short, 65535, 0, unsigned short, 65535, 0> pixProc(proc); break;}
373       case 32 : {ProcessPix<float,          1,     1, unsigned short, 65535, 0> pixProc(proc); break;}
374       }
375     }
376       break;
377 
378     case 32 : {
379       switch(srcBitDepth) {
380       case 8 :  {ProcessPix<unsigned char,  255,   0, float, 1, 1> pixProc(proc); break;}
381       case 16 : {ProcessPix<unsigned short, 65535, 0, float, 1, 1> pixProc(proc); break;}
382       case 32 : {ProcessPix<float,          1,     1, float, 1, 1> pixProc(proc); break;}
383       }
384     }
385       break;
386     }
387   }
388   catch(OfxuNoImageException &ex) {
389     // if we were interrupted, the failed fetch is fine, just return kOfxStatOK
390     // otherwise, something wierd happened
391     if(!gEffectHost->abort(effect)) {
392       status = kOfxStatFailed;
393     }
394   }
395 
396   // release the data pointers;
397   if(sourceImg)
398     gEffectHost->clipReleaseImage(sourceImg);
399   if(outputImg)
400     gEffectHost->clipReleaseImage(outputImg);
401 
402   return status;
403 }
404 
405 // Set our clip preferences
406 static OfxStatus
getClipPreferences(OfxImageEffectHandle effect,OfxPropertySetHandle,OfxPropertySetHandle outArgs)407 getClipPreferences(OfxImageEffectHandle effect,
408 		   OfxPropertySetHandle /*inArgs*/,
409 		   OfxPropertySetHandle outArgs)
410 {
411   // retrieve any instance data associated with this effect
412   MyInstanceData *myData = getMyInstanceData(effect);
413 
414   // fetch the depth parameter value
415   int depthVal;
416   gParamHost->paramGetValue(myData->depthParam, &depthVal);
417 
418   // and set the output depths based on that
419   switch(gDepthParamToBytes[depthVal]) {
420   // byte
421   case 8 : gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, kOfxBitDepthByte); break;
422   // short
423   case 16 : gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, kOfxBitDepthShort); break;
424   // float
425   case 32 : gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, kOfxBitDepthFloat); break;
426   }
427 
428   return kOfxStatOK;
429 }
430 
431 
432 //  describe the plugin in context
433 static OfxStatus
describeInContext(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs)434 describeInContext(OfxImageEffectHandle effect, OfxPropertySetHandle inArgs)
435 {
436   // get the context from the inArgs handle
437   const char *context = NULL;
438   gPropHost->propGetString(inArgs, kOfxImageEffectPropContext, 0, &context);
439   //bool isGeneratorContext = strcmp(context, kOfxImageEffectContextGenerator) == 0;
440 
441   OfxPropertySetHandle clipProps;
442   // define the single output clip in both contexts
443   gEffectHost->clipDefine(effect, "Output", &clipProps);
444 
445   // set the component types we can handle on out output
446   gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
447   gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
448   gPropHost->propSetString(clipProps, kOfxImageClipPropFieldExtraction, 0, kOfxImageFieldSingle);
449 
450   // define the single source clip in filter and general contexts
451   gEffectHost->clipDefine(effect, "Source", &clipProps);
452 
453   // set the component types we can handle on our main input
454   gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
455   gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
456   gPropHost->propSetString(clipProps, kOfxImageClipPropFieldExtraction, 0, kOfxImageFieldSingle);
457 
458   ////////////////////////////////////////////////////////////////////////////////
459   // define the parameters for this context
460   OfxParamSetHandle paramSet;
461   gEffectHost->getParamSet(effect, &paramSet);
462 
463   //OfxParamHandle param;
464   OfxPropertySetHandle paramProps;
465 
466   // single choice parameter
467   gParamHost->paramDefine(paramSet, kOfxParamTypeChoice, "depth", &paramProps);
468   gPropHost->propSetString(paramProps, kOfxParamPropHint, 0, "What pixel depth to convert the image to");
469   gPropHost->propSetString(paramProps, kOfxPropLabel, 0, "Depth");
470 
471   // set the options, depending on the bit depths the host supports
472   int i = 0;
473   if(gSupportsBytes)  gPropHost->propSetString(paramProps, kOfxParamPropChoiceOption, i++, "Byte");
474   if(gSupportsShorts) gPropHost->propSetString(paramProps, kOfxParamPropChoiceOption, i++, "Short");
475   if(gSupportsFloats) gPropHost->propSetString(paramProps, kOfxParamPropChoiceOption, i++, "Float");
476 
477   // we convert things to 8 bits by default
478   gPropHost->propSetInt(paramProps, kOfxParamPropDefault, 0, 0);
479 
480   // say that the pixel depth affects the clip preferences
481   OfxPropertySetHandle effectProps;
482   gEffectHost->getPropertySet(effect, &effectProps);
483   gPropHost->propSetString(effectProps, kOfxImageEffectPropClipPreferencesSlaveParam, 0, "depth");
484 
485   return kOfxStatOK;
486 }
487 
488 ////////////////////////////////////////////////////////////////////////////////
489 // the plugin's description routine
490 static OfxStatus
describe(OfxImageEffectHandle effect)491 describe(OfxImageEffectHandle  effect)
492 {
493   // first fetch the host APIs, this cannot be done before this call
494   OfxStatus stat;
495   if((stat = ofxuFetchHostSuites()) != kOfxStatOK)
496     return stat;
497 
498   int hostSupportsMultipleDepths;
499   // record a few host features
500   gPropHost->propGetInt(gHost->host, kOfxImageEffectPropSupportsMultipleClipDepths, 0, &hostSupportsMultipleDepths);
501 
502   // see how many bit depths the host supports, this affects our parameter values
503   int nHostDepths;
504   gPropHost->propGetDimension(gHost->host, kOfxImageEffectPropSupportedPixelDepths, &nHostDepths);
505 
506   // If the host cannot support multiple bit depths on in and out clips or it only supports 1 bit depth
507   // we cant do any work, so refuse to load and explain why.
508   if(!hostSupportsMultipleDepths || nHostDepths == 1) {
509     // post a message
510     // - disabled, because posting a message within describe() crashes Nuke 6
511     //gMessageSuite->message(effect, kOfxMessageError, kMessageNotEnoughBits,
512 	//		   "OFX GeneratorExample : cannot run on this application because the it does not allow effects to change the bit depth of images.");
513 
514     // and refuse to load
515     // - disabled, because Nuke 6 still loads it - it's better to load it even if it's non-functional
516     //return kOfxStatErrMissingHostFeature;
517   }
518 
519   // get the property handle for the plugin
520   OfxPropertySetHandle effectProps;
521   gEffectHost->getPropertySet(effect, &effectProps);
522 
523   // We can render both fields in a fielded image in one hit as there is no animation and no spatially dependant parameters
524   gPropHost->propSetInt(effectProps, kOfxImageEffectPluginPropFieldRenderTwiceAlways, 0, 0);
525 
526   // say we can support multiple pixel depths on in and out
527   gPropHost->propSetInt(effectProps, kOfxImageEffectPropSupportsMultipleClipDepths, 0, 1);
528 
529   // set the bit depths the plugin can handle
530   gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 0, kOfxBitDepthByte);
531   gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 1, kOfxBitDepthShort);
532   gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 2, kOfxBitDepthFloat);
533 
534   // figure which bit depths are supported
535   int i;
536   for(i = 0; i < nHostDepths; i++) {
537     const char *depthStr = NULL;
538     gPropHost->propGetString(gHost->host, kOfxImageEffectPropSupportedPixelDepths, i, &depthStr);
539     int nBits = ofxuMapPixelDepth(depthStr);
540     switch(nBits) {
541     case 8  : gSupportsBytes  = true; break;
542     case 16 : gSupportsShorts = true; break;
543     case 32 : gSupportsFloats = true; break;
544     }
545   }
546 
547   // now set a mapping from parameter value to bit depth
548   i = 0;
549   if(gSupportsBytes)  gDepthParamToBytes[i++] = 8;
550   if(gSupportsShorts) gDepthParamToBytes[i++] = 16;
551   if(gSupportsFloats) gDepthParamToBytes[i++] = 32;
552 
553   // set some labels and the group it belongs to
554   gPropHost->propSetString(effectProps, kOfxPropLabel, 0, "OFX Depth Converter");
555   gPropHost->propSetString(effectProps, kOfxImageEffectPluginPropGrouping, 0, "OFX Example");
556 
557   // define the contexts we can be used in
558   gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 0, kOfxImageEffectContextFilter);
559   gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 1, kOfxImageEffectContextGeneral);
560 
561   return kOfxStatOK;
562 }
563 
564 ////////////////////////////////////////////////////////////////////////////////
565 // The main function
566 static OfxStatus
pluginMain(const char * action,const void * handle,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)567 pluginMain(const char *action,  const void *handle, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs)
568 {
569   try {
570   // cast to appropriate type
571   OfxImageEffectHandle effect = (OfxImageEffectHandle ) handle;
572 
573   if(strcmp(action, kOfxActionDescribe) == 0) {
574     return describe(effect);
575   }
576   else if(strcmp(action, kOfxImageEffectActionDescribeInContext) == 0) {
577     return describeInContext(effect, inArgs);
578   }
579   else if(strcmp(action, kOfxActionCreateInstance) == 0) {
580     return createInstance(effect);
581   }
582   else if(strcmp(action, kOfxActionDestroyInstance) == 0) {
583     return destroyInstance(effect);
584   }
585   else if(strcmp(action, kOfxImageEffectActionIsIdentity) == 0) {
586     return isIdentity(effect, inArgs, outArgs);
587   }
588   else if(strcmp(action, kOfxImageEffectActionRender) == 0) {
589     return render(effect, inArgs, outArgs);
590   }
591   else if(strcmp(action, kOfxImageEffectActionGetClipPreferences) == 0) {
592     return getClipPreferences(effect, inArgs, outArgs);
593   }
594   } catch (std::bad_alloc) {
595     // catch memory
596     //std::cout << "OFX Plugin Memory error." << std::endl;
597     return kOfxStatErrMemory;
598   } catch ( const std::exception& e ) {
599     // standard exceptions
600     //std::cout << "OFX Plugin error: " << e.what() << std::endl;
601     return kOfxStatErrUnknown;
602   } catch (int err) {
603     // ho hum, gone wrong somehow
604     return err;
605   } catch ( ... ) {
606     // everything else
607     //std::cout << "OFX Plugin error" << std::endl;
608     return kOfxStatErrUnknown;
609   }
610 
611   // other actions to take the default value
612   return kOfxStatReplyDefault;
613 }
614 
615 // function to set the host structure
616 static void
setHostFunc(OfxHost * hostStruct)617 setHostFunc(OfxHost *hostStruct)
618 {
619   gHost         = hostStruct;
620 }
621 
622 ////////////////////////////////////////////////////////////////////////////////
623 // the plugin struct
624 static OfxPlugin basicPlugin =
625 {
626   kOfxImageEffectPluginApi,
627   1,
628   "uk.co.thefoundry.DepthConverterExample",
629   1,
630   0,
631   setHostFunc,
632   pluginMain
633 };
634 
635 // the two mandated functions
636 EXPORT OfxPlugin *
OfxGetPlugin(int nth)637 OfxGetPlugin(int nth)
638 {
639   if(nth == 0)
640     return &basicPlugin;
641   return 0;
642 }
643 
644 EXPORT int
OfxGetNumberOfPlugins(void)645 OfxGetNumberOfPlugins(void)
646 {
647   return 1;
648 }
649