#include <cstring>
#include <stdexcept>
#include <new>
#include "ofxImageEffect.h"
#include "ofxMemory.h"
#include "ofxMultiThread.h"
#include "ofxPixels.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
OfxHost *gHost;
OfxImageEffectSuiteV1 *gEffectHost = 0;
OfxPropertySuiteV1 *gPropHost = 0;
inline OfxRGBAColourB *
pixelAddress(OfxRGBAColourB *img, OfxRectI rect, int x, int y, int bytesPerLine)
{
if(x < rect.x1 || x >= rect.x2 || y < rect.y1 || y > rect.y2)
return 0;
OfxRGBAColourB *pix = (OfxRGBAColourB *) (((char *) img) + (y - rect.y1) * bytesPerLine);
pix += x - rect.x1;
return pix;
}
class NoImageEx {};
static OfxStatus render(OfxImageEffectHandle instance,
OfxPropertySetHandle inArgs,
OfxPropertySetHandle )
{
OfxTime time;
OfxRectI renderWindow;
OfxStatus status = kOfxStatOK;
gPropHost->propGetDouble(inArgs, kOfxPropTime, 0, &time);
gPropHost->propGetIntN(inArgs, kOfxImageEffectPropRenderWindow, 4, &renderWindow.x1);
OfxImageClipHandle outputClip;
gEffectHost->clipGetHandle(instance, kOfxImageEffectOutputClipName, &outputClip, 0);
OfxPropertySetHandle outputImg = NULL, sourceImg = NULL;
try {
OfxPropertySetHandle outputImg;
if(gEffectHost->clipGetImage(outputClip, time, NULL, &outputImg) != kOfxStatOK) {
throw NoImageEx();
}
int dstRowBytes;
OfxRectI dstRect;
void *dstPtr;
gPropHost->propGetInt(outputImg, kOfxImagePropRowBytes, 0, &dstRowBytes);
gPropHost->propGetIntN(outputImg, kOfxImagePropBounds, 4, &dstRect.x1);
gPropHost->propGetInt(outputImg, kOfxImagePropRowBytes, 0, &dstRowBytes);
gPropHost->propGetPointer(outputImg, kOfxImagePropData, 0, &dstPtr);
OfxImageClipHandle sourceClip;
gEffectHost->clipGetHandle(instance, kOfxImageEffectSimpleSourceClipName, &sourceClip, 0);
if (gEffectHost->clipGetImage(sourceClip, time, NULL, &sourceImg) != kOfxStatOK) {
throw NoImageEx();
}
int srcRowBytes;
OfxRectI srcRect;
void *srcPtr;
gPropHost->propGetInt(sourceImg, kOfxImagePropRowBytes, 0, &srcRowBytes);
gPropHost->propGetIntN(sourceImg, kOfxImagePropBounds, 4, &srcRect.x1);
gPropHost->propGetInt(sourceImg, kOfxImagePropRowBytes, 0, &srcRowBytes);
gPropHost->propGetPointer(sourceImg, kOfxImagePropData, 0, &srcPtr);
OfxRGBAColourB *src = (OfxRGBAColourB *) srcPtr;
OfxRGBAColourB *dst = (OfxRGBAColourB *) dstPtr;
for(int y = renderWindow.y1; y < renderWindow.y2; y++) {
if(gEffectHost->abort(instance)) break;
OfxRGBAColourB *dstPix = pixelAddress(dst, dstRect, renderWindow.x1, y, dstRowBytes);
for(int x = renderWindow.x1; x < renderWindow.x2; x++) {
OfxRGBAColourB *srcPix = pixelAddress(src, srcRect, x, y, srcRowBytes);
if(srcPix) {
dstPix->r = 255 - srcPix->r;
dstPix->g = 255 - srcPix->g;
dstPix->b = 255 - srcPix->b;
dstPix->a = 255 - srcPix->a;
}
else {
dstPix->r = 0;
dstPix->g = 0;
dstPix->b = 0;
dstPix->a = 0;
}
dstPix++;
}
}
}
catch(NoImageEx &) {
if(!gEffectHost->abort(instance)) {
status = kOfxStatFailed;
}
}
if(sourceImg)
gEffectHost->clipReleaseImage(sourceImg);
if(outputImg)
gEffectHost->clipReleaseImage(outputImg);
return status;
}
static OfxStatus
describeInContext( OfxImageEffectHandle effect, OfxPropertySetHandle )
{
OfxPropertySetHandle props;
gEffectHost->clipDefine(effect, kOfxImageEffectOutputClipName, &props);
gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
gEffectHost->clipDefine(effect, kOfxImageEffectSimpleSourceClipName, &props);
gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
return kOfxStatOK;
}
static OfxStatus
describe(OfxImageEffectHandle effect)
{
OfxPropertySetHandle effectProps;
gEffectHost->getPropertySet(effect, &effectProps);
gPropHost->propSetInt(effectProps, kOfxImageEffectPropSupportsMultipleClipDepths, 0, 0);
gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 0, kOfxBitDepthByte);
gPropHost->propSetString(effectProps, kOfxPropLabel, 0, "OFX Invert Example");
gPropHost->propSetString(effectProps, kOfxImageEffectPluginPropGrouping, 0, "OFX Example");
gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 0, kOfxImageEffectContextFilter);
return kOfxStatOK;
}
static OfxStatus
onLoad(void)
{
if(!gHost) return kOfxStatErrMissingHostFeature;
gEffectHost = (OfxImageEffectSuiteV1 *) gHost->fetchSuite(gHost->host, kOfxImageEffectSuite, 1);
gPropHost = (OfxPropertySuiteV1 *) gHost->fetchSuite(gHost->host, kOfxPropertySuite, 1);
if(!gEffectHost || !gPropHost)
return kOfxStatErrMissingHostFeature;
return kOfxStatOK;
}
static OfxStatus
pluginMain(const char *action, const void *handle, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs)
{
try {
OfxImageEffectHandle effect = (OfxImageEffectHandle) handle;
if(strcmp(action, kOfxActionLoad) == 0) {
return onLoad();
}
else if(strcmp(action, kOfxActionDescribe) == 0) {
return describe(effect);
}
else if(strcmp(action, kOfxImageEffectActionDescribeInContext) == 0) {
return describeInContext(effect, inArgs);
}
else if(strcmp(action, kOfxImageEffectActionRender) == 0) {
return render(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.OfxInvertExample",
1,
0,
setHostFunc,
pluginMain
};
EXPORT OfxPlugin *
OfxGetPlugin(int nth)
{
if(nth == 0)
return &basicPlugin;
return 0;
}
EXPORT int
OfxGetNumberOfPlugins(void)
{
return 1;
}