#include <cstring>
#include <stdexcept>
#include <new>
#include "ofxImageEffect.h"
#include "ofxMemory.h"
#include "ofxMultiThread.h"
#include "../include/ofxUtilities.H"
#if defined __APPLE__ || defined linux || defined __FreeBSD__
# define EXPORT __attribute__((visibility("default")))
#elif defined _WIN32
# define EXPORT OfxExport
#else
# error Not building on your operating system quite yet
#endif
template <class T> inline T Maximum(T a, T b) {return a > b ? a : b;}
template <class T> inline T Minimum(T a, T b) {return a < b ? a : b;}
OfxHost *gHost;
OfxImageEffectSuiteV1 *gEffectHost = 0;
OfxPropertySuiteV1 *gPropHost = 0;
OfxParameterSuiteV1 *gParamHost = 0;
OfxMemorySuiteV1 *gMemoryHost = 0;
OfxMultiThreadSuiteV1 *gThreadHost = 0;
OfxMessageSuiteV1 *gMessageSuite = 0;
OfxInteractSuiteV1 *gInteractHost = 0;
int gHostSupportsMultipleBitDepths = false;
enum ContextEnum {
eIsGenerator,
eIsFilter,
eIsGeneral
};
struct MyInstanceData {
ContextEnum context;
OfxImageClipHandle sourceClip;
OfxImageClipHandle outputClip;
OfxParamHandle corner1Param;
OfxParamHandle corner2Param;
OfxParamHandle colourParam;
};
static MyInstanceData *
getMyInstanceData(OfxImageEffectHandle effect)
{
MyInstanceData *myData = (MyInstanceData *) ofxuGetEffectInstanceData(effect);
return myData;
}
static OfxStatus
createInstance(OfxImageEffectHandle effect)
{
OfxPropertySetHandle effectProps;
gEffectHost->getPropertySet(effect, &effectProps);
OfxParamSetHandle paramSet;
gEffectHost->getParamSet(effect, ¶mSet);
MyInstanceData *myData = new MyInstanceData;
char *context = 0;
gPropHost->propGetString(effectProps, kOfxImageEffectPropContext, 0, &context);
if(strcmp(context, kOfxImageEffectContextGenerator) == 0) {
myData->context = eIsGenerator;
}
else if(strcmp(context, kOfxImageEffectContextFilter) == 0) {
myData->context = eIsFilter;
}
else {
myData->context = eIsGeneral;
}
gParamHost->paramGetHandle(paramSet, "corner1", &myData->corner1Param, 0);
gParamHost->paramGetHandle(paramSet, "corner2", &myData->corner2Param, 0);
gParamHost->paramGetHandle(paramSet, "colour", &myData->colourParam, 0);
if( myData->context != eIsGenerator)
gEffectHost->clipGetHandle(effect, kOfxImageEffectSimpleSourceClipName, &myData->sourceClip, 0);
gEffectHost->clipGetHandle(effect, kOfxImageEffectOutputClipName, &myData->outputClip, 0);
gPropHost->propSetPointer(effectProps, kOfxPropInstanceData, 0, (void *) myData);
return kOfxStatOK;
}
static OfxStatus
destroyInstance(OfxImageEffectHandle effect)
{
MyInstanceData *myData = getMyInstanceData(effect);
if(myData)
delete myData;
return kOfxStatOK;
}
static void
getCannonicalRect(OfxImageEffectHandle effect, double time, OfxRectD &rect)
{
MyInstanceData *myData = getMyInstanceData(effect);
OfxPointD c1, c2;
gParamHost->paramGetValueAtTime(myData->corner1Param, time, &c1.x, &c1.y);
gParamHost->paramGetValueAtTime(myData->corner2Param, time, &c2.x, &c2.y);
rect.x1 = Minimum(c1.x, c2.x);
rect.y1 = Minimum(c1.y, c2.y);
rect.x2 = Maximum(c1.x, c2.x);
rect.y2 = Maximum(c1.y, c2.y);
}
OfxStatus
getSpatialRoD(OfxImageEffectHandle effect, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs)
{
MyInstanceData *myData = getMyInstanceData(effect);
OfxTime time;
gPropHost->propGetDouble(inArgs, kOfxPropTime, 0, &time);
OfxRectD rod;
getCannonicalRect(effect, time, rod);
if(myData->context != eIsGenerator){
OfxRectD sourceRoD;
gEffectHost->clipGetRegionOfDefinition(myData->sourceClip, time, &sourceRoD);
if(ofxuInfiniteRectInX(sourceRoD)) {
rod.x1 = kOfxFlagInfiniteMin;
rod.x2 = kOfxFlagInfiniteMax;
}
else {
rod.x1 = Minimum(rod.x1, sourceRoD.x1);
rod.x2 = Maximum(rod.x2, sourceRoD.x2);
}
if(ofxuInfiniteRectInY(sourceRoD)) {
rod.y1 = kOfxFlagInfiniteMin;
rod.y2 = kOfxFlagInfiniteMax;
}
else {
rod.y1 = Minimum(rod.y1, sourceRoD.y1);
rod.y2 = Maximum(rod.y2, sourceRoD.y2);
}
}
gPropHost->propSetDoubleN(outArgs, kOfxImageEffectPropRegionOfDefinition, 4, &rod.x1);
return kOfxStatOK;
}
OfxStatus
getSpatialRoI(OfxImageEffectHandle effect, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs)
{
MyInstanceData *myData = getMyInstanceData(effect);
if(myData->context != eIsGenerator){
OfxRectD roi;
gPropHost->propGetDoubleN(inArgs, kOfxImageEffectPropRegionOfInterest, 4, &roi.x1);
gPropHost->propSetDoubleN(outArgs, "OfxImageClipPropRoI_Source", 4, &roi.x1);
return kOfxStatOK;
}
else return kOfxStatReplyDefault;
}
static OfxStatus
isIdentity(OfxImageEffectHandle effect,
OfxPropertySetHandle inArgs,
OfxPropertySetHandle outArgs)
{
MyInstanceData *myData = getMyInstanceData(effect);
if(myData->context != eIsGenerator){
OfxTime time;
OfxRectI renderWindow;
gPropHost->propGetDouble(inArgs, kOfxPropTime, 0, &time);
gPropHost->propGetIntN(inArgs, kOfxImageEffectPropRenderWindow, 4, &renderWindow.x1);
OfxRectD rect;
getCannonicalRect(effect, time, rect);
OfxRGBAColourD col;
gParamHost->paramGetValueAtTime(myData->colourParam, time, &col.r, &col.g, &col.b, &col.a);
if(col.a <= 0.0 || rect.x1 > renderWindow.x2 || rect.y1 > renderWindow.y2 ||
rect.x2 < renderWindow.x1 || rect.y2 < renderWindow.y1) {
gPropHost->propSetString(outArgs, kOfxPropName, 0, kOfxImageEffectSimpleSourceClipName);
return kOfxStatOK;
}
}
return kOfxStatReplyDefault;
}
template <class T> inline T
Clamp(T v, int min, int max)
{
if(v < T(min)) return T(min);
if(v > T(max)) return T(max);
return v;
}
static inline int
Lerp(int a, int b, float v)
{
return int(a + (b - a) * v);
}
static inline float
Lerp(float a, float b, float v)
{
return float(a + (b - a) * v);
}
template <class PIX> inline PIX *
pixelAddress(PIX *img, OfxRectI rect, int x, int y, int bytesPerLine)
{
if(x < rect.x1 || x >= rect.x2 || y < rect.y1 || y > rect.y2)
return 0;
PIX *pix = (PIX *) (((char *) img) + (y - rect.y1) * bytesPerLine);
pix += x - rect.x1;
return pix;
}
class Processor {
protected :
OfxImageEffectHandle effect;
OfxRGBAColourD colour;
OfxRectI position;
bool unpremultiplied;
void *srcV, *dstV;
OfxRectI srcRect, dstRect;
OfxRectI window;
int srcBytesPerLine, dstBytesPerLine;
public :
Processor(OfxImageEffectHandle eff,
OfxRectI pos,
OfxRGBAColourD col,
bool unpremult,
void *src, OfxRectI sRect, int sBytesPerLine,
void *dst, OfxRectI dRect, int dBytesPerLine,
OfxRectI win)
: effect(eff)
, colour(col)
, position(pos)
, unpremultiplied(unpremult)
, srcV(src)
, dstV(dst)
, srcRect(sRect)
, dstRect(dRect)
, window(win)
, srcBytesPerLine(sBytesPerLine)
, dstBytesPerLine(dBytesPerLine)
{}
static void multiThreadProcessing(unsigned int threadId, unsigned int nThreads, void *arg);
virtual void doProcessing(OfxRectI window) = 0;
void process(void);
};
void
Processor::multiThreadProcessing(unsigned int threadId, unsigned int nThreads, void *arg)
{
Processor *proc = (Processor *) arg;
unsigned int dy = proc->window.y2 - proc->window.y1;
unsigned int y1 = proc->window.y1 + threadId * dy/nThreads;
unsigned int y2 = proc->window.y1 + Minimum((threadId + 1) * dy/nThreads, dy);
OfxRectI win = proc->window;
win.y1 = y1; win.y2 = y2;
proc->doProcessing(win);
}
void
Processor::process(void)
{
unsigned int nThreads;
gThreadHost->multiThreadNumCPUs(&nThreads);
gThreadHost->multiThread(multiThreadProcessing, nThreads, (void *) this);
}
template <class PIX, int max, int isFloat>
class ProcessRGBA : public Processor{
public :
ProcessRGBA(OfxImageEffectHandle eff,
OfxRectI pos,
OfxRGBAColourD col,
bool unpremult,
void *src, OfxRectI sRect, int sBytesPerLine,
void *dst, OfxRectI dRect, int dBytesPerLine,
OfxRectI win)
: Processor(eff,
pos, col, unpremult,
src, sRect, sBytesPerLine,
dst, dRect, dBytesPerLine,
win)
{
}
void doProcessing(OfxRectI procWindow)
{
PIX *src = (PIX *) srcV;
PIX *dst = (PIX *) dstV;
PIX black;
black.r = black.g = black.b = black.a = 0;
PIX value, premultValue;
if(isFloat) {
value.r = colour.r * max;
value.g = colour.g * max;
value.b = colour.b * max;
value.a = colour.a * max;
premultValue.r = colour.r * max * colour.a;
premultValue.g = colour.g * max * colour.a;
premultValue.b = colour.b * max * colour.a;
premultValue.a = colour.a * max * colour.a;
}
else {
value.r = Clamp(colour.r * max, 0, max);
value.g = Clamp(colour.g * max, 0, max);
value.b = Clamp(colour.b * max, 0, max);
value.a = Clamp(colour.a * max, 0, max);
premultValue.r = Clamp(colour.r * max * colour.a, 0, max);
premultValue.g = Clamp(colour.g * max * colour.a, 0, max);
premultValue.b = Clamp(colour.b * max * colour.a, 0, max);
premultValue.a = Clamp(colour.a * max * colour.a, 0, max);
}
for(int y = procWindow.y1; y < procWindow.y2; y++) {
if(gEffectHost->abort(effect)) break;
PIX *dstPix = pixelAddress(dst, dstRect, procWindow.x1, y, dstBytesPerLine);
for(int x = procWindow.x1; x < procWindow.x2; x++) {
PIX *srcPix = 0;
if(src)
srcPix = pixelAddress(src, srcRect, x, y, srcBytesPerLine);
if(x < position.x1 || x >= position.x2 || y < position.y1 || y >= position.y2) {
*dstPix = srcPix ? *srcPix : black;
if(srcPix)
srcPix++;
}
else {
if(srcPix) {
if(unpremultiplied) {
float a = srcPix->a + value.a - (srcPix->a * value.a)/max;
float r, g, b;
if(srcPix->a == 0) {
r = g = b = 0;
}
else {
r = Lerp(srcPix->r * max/srcPix->a, value.r, colour.a) * a/max;
g = Lerp(srcPix->g * max/srcPix->a, value.g, colour.a) * a/max;
b = Lerp(srcPix->b * max/srcPix->a, value.b, colour.a) * a/max;
}
if(isFloat) {
dstPix->r = r;
dstPix->g = g;
dstPix->b = b;
dstPix->a = a;
}
else {
dstPix->r = Clamp(r, 0, max);
dstPix->g = Clamp(g, 0, max);
dstPix->b = Clamp(b, 0, max);
dstPix->a = Clamp(a, 0, max);
}
}
else {
if(isFloat) {
dstPix->r = Lerp(srcPix->r, value.r, colour.a);
dstPix->g = Lerp(srcPix->g, value.g, colour.a);
dstPix->b = Lerp(srcPix->b, value.b, colour.a);
dstPix->a = srcPix->a + value.a - (srcPix->a * value.a)/max;
}
else {
dstPix->r = Clamp(int(Lerp(srcPix->r, value.r, colour.a)), 0, max);
dstPix->g = Clamp(int(Lerp(srcPix->g, value.g, colour.a)), 0, max);
dstPix->b = Clamp(int(Lerp(srcPix->b, value.b, colour.a)), 0, max);
dstPix->a = Clamp(int(srcPix->a + value.a - (srcPix->a * value.a)/max), 0, max);
}
}
srcPix++;
}
else {
if(unpremultiplied)
*dstPix = premultValue;
else
*dstPix = value;
}
}
dstPix++;
}
}
}
};
template <class PIX, int max, int isFloat>
class ProcessAlpha : public Processor {
public :
ProcessAlpha(OfxImageEffectHandle inst,
OfxRectI pos,
OfxRGBAColourD col,
void *src, OfxRectI sRect, int sBytesPerLine,
void *dst, OfxRectI dRect, int dBytesPerLine,
OfxRectI win)
: Processor(inst,
pos, col, 1,
src, sRect, sBytesPerLine,
dst, dRect, dBytesPerLine,
win)
{
}
void doProcessing(OfxRectI procWindow)
{
PIX *src = (PIX *) srcV;
PIX *dst = (PIX *) dstV;
PIX value;
if(isFloat) {
value = colour.a * max;
}
else {
value = Clamp(colour.a * max, 0, max);
}
for(int y = procWindow.y1; y < procWindow.y2; y++) {
if(gEffectHost->abort(effect)) break;
PIX *dstPix = pixelAddress(dst, dstRect, procWindow.x1, y, dstBytesPerLine);
for(int x = procWindow.x1; x < procWindow.x2; x++) {
PIX *srcPix = 0;
if(src)
srcPix = pixelAddress(src, srcRect, x, y, srcBytesPerLine);
if(x < position.x1 || x >= position.x2 || y < position.y1 || y >= position.y2) {
*dstPix = srcPix ? *srcPix : 0;
if(srcPix)
srcPix++;
}
else {
if(srcPix) {
if(isFloat) {
*dstPix = *srcPix + value - *srcPix * value;
}
else {
*dstPix = Clamp(int(*srcPix + value - *srcPix * value), 0, max);
}
srcPix++;
}
else {
*dstPix = value;
}
}
dstPix++;
}
}
}
};
static OfxStatus render(OfxImageEffectHandle effect,
OfxPropertySetHandle inArgs,
OfxPropertySetHandle )
{
OfxTime time;
OfxRectI renderWindow;
OfxStatus status = kOfxStatOK;
gPropHost->propGetDouble(inArgs, kOfxPropTime, 0, &time);
gPropHost->propGetIntN(inArgs, kOfxImageEffectPropRenderWindow, 4, &renderWindow.x1);
MyInstanceData *myData = getMyInstanceData(effect);
OfxPropertySetHandle sourceImg = NULL, outputImg = NULL;
int srcRowBytes = 0, srcBitDepth, dstRowBytes, dstBitDepth;
bool srcIsAlpha, dstIsAlpha;
OfxRectI dstRect, srcRect = {0};
void *src = NULL, *dst;
bool unpremultiplied = false;
try {
outputImg = ofxuGetImage(myData->outputClip, time, dstRowBytes, dstBitDepth, dstIsAlpha, dstRect, dst);
if(outputImg == NULL) throw OfxuNoImageException();
if(myData->context != eIsGenerator) {
sourceImg = ofxuGetImage(myData->sourceClip, time, srcRowBytes, srcBitDepth, srcIsAlpha, srcRect, src);
if(sourceImg == NULL) throw OfxuNoImageException();
unpremultiplied = ofxuIsUnPremultiplied(myData->sourceClip);
}
OfxPointD renderScale;
gPropHost->propGetDoubleN(inArgs, kOfxImageEffectPropRenderScale, 2, &renderScale.x);
double fieldScale = 1.0;
char *field;
gPropHost->propGetString(outputImg, kOfxImagePropField, 0, &field);
if(strcmp(field, kOfxImageFieldLower) == 0 || strcmp(field, kOfxImageFieldUpper) == 0)
fieldScale = 0.5;
double pixelAspectRatio;
gPropHost->propGetDouble(outputImg, kOfxImagePropPixelAspectRatio, 0, &pixelAspectRatio);
OfxRectD rect;
getCannonicalRect(effect, time, rect);
OfxRectI rectI;
rectI.x1 = int(rect.x1 * renderScale.x / pixelAspectRatio);
rectI.x2 = int(rect.x2 * renderScale.x / pixelAspectRatio);
rectI.y1 = int(rect.y1 * renderScale.y * fieldScale);
rectI.y2 = int(rect.y2 * renderScale.y * fieldScale);
OfxRGBAColourD colour;
gParamHost->paramGetValueAtTime(myData->colourParam, time, &colour.r, &colour.g, &colour.b, &colour.a);
if(!dstIsAlpha) {
switch(dstBitDepth) {
case 8 : {
ProcessRGBA<OfxRGBAColourB, 255, 0> fred(effect, rectI, colour, unpremultiplied,
src, srcRect, srcRowBytes,
dst, dstRect, dstRowBytes,
renderWindow);
fred.process();
}
break;
case 16 : {
ProcessRGBA<OfxRGBAColourS, 65535, 0> fred(effect, rectI, colour, unpremultiplied,
src, srcRect, srcRowBytes,
dst, dstRect, dstRowBytes,
renderWindow);
fred.process();
}
break;
case 32 : {
ProcessRGBA<OfxRGBAColourF, 1, 1> fred(effect, rectI, colour, unpremultiplied,
src, srcRect, srcRowBytes,
dst, dstRect, dstRowBytes,
renderWindow);
fred.process();
break;
}
}
}
else {
switch(dstBitDepth) {
case 8 : {
ProcessAlpha<unsigned char, 255, 0> fred(effect, rectI, colour,
src, srcRect, srcRowBytes,
dst, dstRect, dstRowBytes,
renderWindow);
fred.process();
}
break;
case 16 : {
ProcessAlpha<unsigned short, 65535, 0> fred(effect, rectI, colour,
src, srcRect, srcRowBytes,
dst, dstRect, dstRowBytes,
renderWindow);
fred.process();
}
break;
case 32 : {
ProcessAlpha<float, 1, 1> fred(effect, rectI, colour,
src, srcRect, srcRowBytes,
dst, dstRect, dstRowBytes,
renderWindow);
fred.process();
}
break;
}
}
}
catch(OfxuNoImageException &ex) {
if(!gEffectHost->abort(effect)) {
status = kOfxStatFailed;
}
}
if(sourceImg)
gEffectHost->clipReleaseImage(sourceImg);
if(outputImg)
gEffectHost->clipReleaseImage(outputImg);
return status;
}
static OfxStatus
getClipPreferences(OfxImageEffectHandle effect, OfxPropertySetHandle , OfxPropertySetHandle outArgs)
{
MyInstanceData *myData = getMyInstanceData(effect);
if(myData->context == eIsGenerator) {
gPropHost->propSetString(outArgs, kOfxImageEffectPropPreMultiplication, 0, kOfxImagePreMultiplied);
}
else {
OfxPropertySetHandle clipProps;
gEffectHost->clipGetPropertySet(myData->sourceClip, &clipProps);
char *premult;
gPropHost->propGetString(clipProps, kOfxImageEffectPropPreMultiplication, 0, &premult);
gPropHost->propSetString(outArgs, kOfxImageEffectPropPreMultiplication, 0, premult);
}
return kOfxStatOK;
}
static OfxStatus
describeInContext(OfxImageEffectHandle effect, OfxPropertySetHandle inArgs)
{
char *context;
gPropHost->propGetString(inArgs, kOfxImageEffectPropContext, 0, &context);
bool isGeneratorContext = strcmp(context, kOfxImageEffectContextGenerator) == 0;
OfxPropertySetHandle clipProps;
gEffectHost->clipDefine(effect, kOfxImageEffectOutputClipName, &clipProps);
gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
gPropHost->propSetString(clipProps, kOfxImageClipPropFieldExtraction, 0, kOfxImageFieldSingle);
if(!isGeneratorContext) {
gEffectHost->clipDefine(effect, kOfxImageEffectSimpleSourceClipName, &clipProps);
gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
gPropHost->propSetString(clipProps, kOfxImageClipPropFieldExtraction, 0, kOfxImageFieldSingle);
}
OfxParamSetHandle paramSet;
gEffectHost->getParamSet(effect, ¶mSet);
OfxPropertySetHandle paramProps;
gParamHost->paramDefine(paramSet, kOfxParamTypeDouble2D, "corner1", ¶mProps);
gPropHost->propSetString(paramProps, kOfxParamPropDoubleType, 0, kOfxParamDoubleTypeXYAbsolute);
gPropHost->propSetString(paramProps, kOfxParamPropDefaultCoordinateSystem, 0, kOfxParamCoordinatesNormalised);
gPropHost->propSetDouble(paramProps, kOfxParamPropDefault, 0, 0.4);
gPropHost->propSetDouble(paramProps, kOfxParamPropDefault, 1, 0.4);
gPropHost->propSetString(paramProps, kOfxParamPropHint, 0, "A corner of the rectangle to draw");
gPropHost->propSetString(paramProps, kOfxPropLabel, 0, "Corner 1");
gParamHost->paramDefine(paramSet, kOfxParamTypeDouble2D, "corner2", ¶mProps);
gPropHost->propSetString(paramProps, kOfxParamPropDoubleType, 0, kOfxParamDoubleTypeXYAbsolute);
gPropHost->propSetString(paramProps, kOfxParamPropDefaultCoordinateSystem, 0, kOfxParamCoordinatesNormalised);
gPropHost->propSetDouble(paramProps, kOfxParamPropDefault, 0, 0.6);
gPropHost->propSetDouble(paramProps, kOfxParamPropDefault, 1, 0.6);
gPropHost->propSetString(paramProps, kOfxParamPropHint, 0, "A corner of the rectangle to draw");
gPropHost->propSetString(paramProps, kOfxPropLabel, 0, "Corner 2");
gPropHost->propSetDouble(paramProps, kOfxParamPropDefault, 0, 0);
gPropHost->propSetDouble(paramProps, kOfxParamPropDefault, 1, 0);
gPropHost->propSetDouble(paramProps, kOfxParamPropDefault, 2, 0);
gPropHost->propSetDouble(paramProps, kOfxParamPropDefault, 3, 1);
gParamHost->paramDefine(paramSet, kOfxParamTypeRGBA, "colour", ¶mProps);
gPropHost->propSetString(paramProps, kOfxParamPropHint, 0, "The colour of the rectangle");
gPropHost->propSetString(paramProps, kOfxParamPropScriptName, 0, "colour");
gPropHost->propSetString(paramProps, kOfxPropLabel, 0, "Colour");
return kOfxStatOK;
}
static OfxStatus
describe(OfxImageEffectHandle effect)
{
OfxStatus stat;
if((stat = ofxuFetchHostSuites()) != kOfxStatOK)
return stat;
OfxPropertySetHandle effectProps;
gEffectHost->getPropertySet(effect, &effectProps);
gPropHost->propSetInt(effectProps, kOfxImageEffectPluginPropFieldRenderTwiceAlways, 0, 0);
gPropHost->propSetInt(effectProps, kOfxImageEffectPropSupportsMultipleClipDepths, 0, 0);
gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 0, kOfxBitDepthByte);
gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 1, kOfxBitDepthShort);
gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 2, kOfxBitDepthFloat);
gPropHost->propSetString(effectProps, kOfxPropLabel, 0, "OFX Rectangle");
gPropHost->propSetString(effectProps, kOfxImageEffectPluginPropGrouping, 0, "OFX Example");
gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 0, kOfxImageEffectContextGenerator);
gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 1, kOfxImageEffectContextFilter);
gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 2, kOfxImageEffectContextGeneral);
return kOfxStatOK;
}
static OfxStatus
pluginMain(const char *action, const void *handle, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs)
{
try {
OfxImageEffectHandle effect = (OfxImageEffectHandle ) handle;
if(strcmp(action, kOfxActionDescribe) == 0) {
return describe(effect);
}
else if(strcmp(action, kOfxImageEffectActionDescribeInContext) == 0) {
return describeInContext(effect, inArgs);
}
else if(strcmp(action, kOfxActionCreateInstance) == 0) {
return createInstance(effect);
}
else if(strcmp(action, kOfxActionDestroyInstance) == 0) {
return destroyInstance(effect);
}
else if(strcmp(action, kOfxImageEffectActionIsIdentity) == 0) {
return isIdentity(effect, inArgs, outArgs);
}
else if(strcmp(action, kOfxImageEffectActionRender) == 0) {
return render(effect, inArgs, outArgs);
}
else if(strcmp(action, kOfxImageEffectActionGetRegionOfDefinition) == 0) {
return getSpatialRoD(effect, inArgs, outArgs);
}
else if(strcmp(action, kOfxImageEffectActionGetRegionsOfInterest) == 0) {
return getSpatialRoI(effect, inArgs, outArgs);
}
else if(strcmp(action, kOfxImageEffectActionGetClipPreferences) == 0) {
return getClipPreferences(effect, inArgs, outArgs);
}
} catch (std::bad_alloc) {
return kOfxStatErrMemory;
} catch ( const std::exception& e ) {
return kOfxStatErrUnknown;
} catch (int err) {
return err;
} catch ( ... ) {
return kOfxStatErrUnknown;
}
return kOfxStatReplyDefault;
}
static void
setHostFunc(OfxHost *hostStruct)
{
gHost = hostStruct;
}
static OfxPlugin basicPlugin =
{
kOfxImageEffectPluginApi,
1,
"uk.co.thefoundry.GeneratorExample",
1,
0,
setHostFunc,
pluginMain
};
EXPORT OfxPlugin *
OfxGetPlugin(int nth)
{
if(nth == 0)
return &basicPlugin;
return 0;
}
EXPORT int
OfxGetNumberOfPlugins(void)
{
return 1;
}