#ifdef _WINDOWS
#include <windows.h>
#endif
#ifdef __APPLE__
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
#include <stdio.h>
#include "ofxsImageEffect.h"
class ColourInteract : public OFX::ParamInteract
{
protected:
enum State
{
eDefault,
ePoised,
eDragging
};
State _state;
double _radius;
public:
ColourInteract(OfxInteractHandle handle, OFX::ImageEffect* effect, const std::string& paramName):
OFX::ParamInteract(handle, effect), _state(eDefault), _radius(5.0)
{
_param = effect->fetchRGBParam(paramName);
}
virtual bool draw(const OFX::DrawArgs &args)
{
OfxPointI size = getInteractSize();
glBegin (GL_POLYGON);
glColor3f (0.0f, 0.0f, 0.0f);
glVertex2f (-0.5f, -0.5f);
glColor3f (1.0f, 0.0f, 0.0f);
glVertex2f (-0.5f, size.y-0.5f);
glColor3f (0.0f, 1.0f, 0.0f);
glVertex2f (size.x - 0.5f, size.y - 0.5f);
glColor3f (0.0f, 0.0f, 1.0f);
glVertex2f (size.x - 0.5f, -0.5f);
glEnd();
double r,g,b,x,y;
_param->getValueAtTime(args.time, r, g, b);
positionFromColour(r, g, b, x, y);
glColor3f(1.0f, 1.0f, 1.0f);
if(_state==ePoised)
glColor3f(0.5f, 0.5f, 0.5f);
glBegin(GL_POLYGON);
glVertex2d(x - _radius, y - _radius);
glVertex2d(x - _radius, y + _radius);
glVertex2d(x + _radius, y + _radius);
glVertex2d(x + _radius, y - _radius);
glEnd();
return true;
}
bool hitTest(double posx, double posy, double time) const
{
double r,g,b,x,y;
_param->getValueAtTime(time, r, g, b);
positionFromColour(r, g, b, x, y);
if(posx > x - _radius &&
posy > y - _radius &&
posx < x + _radius &&
posy < y + _radius)
return true;
return false;
}
void positionFromColour(double r, double g, double b, double& x, double& y) const
{
x = (b/(g+b)) * 100.0 - 0.5;
y = (r/(g+r)) * 100.0 - 0.5;
}
void colourFromPosition(double x, double y, double& r, double& g, double& b) const
{
x += 0.5;
y += 0.5;
x = x*0.01;
y = y*0.01;
r = y * ( 1.0 - x);
b = x * ( 1.0 - y);
g = (1.0 - x) * (1.0 - y);
}
virtual bool penMotion(const OFX::PenArgs &args)
{
if(_state != eDragging)
{
if(hitTest(args.penPosition.x, args.penPosition.y, args.time))
{
_state = ePoised;
requestRedraw();
return true;
}
}
else
{
double r,g,b;
colourFromPosition(args.penPosition.x, args.penPosition.y, r, g, b);
_param->setValueAtTime(args.time, r, g, b);
requestRedraw();
return true;
}
_state = eDefault;
requestRedraw();
return false;
}
virtual bool penDown(const OFX::PenArgs &args)
{
if(hitTest(args.penPosition.x, args.penPosition.y, args.time))
{
_state = eDragging;
return true;
}
return false;
}
virtual bool penUp(const OFX::PenArgs &)
{
_state = ePoised;
requestRedraw();
return true;
}
virtual ~ColourInteract(){}
protected:
OFX::RGBParam* _param;
};
template<int INSTANCECOUNT>
class ColourInteractDescriptor : public OFX::DefaultParamInteractDescriptor<ColourInteractDescriptor<INSTANCECOUNT>, ColourInteract>
{
public:
using OFX::DefaultParamInteractDescriptor<ColourInteractDescriptor<INSTANCECOUNT>,ColourInteract>::setInteractSizeAspect;
using OFX::DefaultParamInteractDescriptor<ColourInteractDescriptor<INSTANCECOUNT>,ColourInteract>::setInteractMinimumSize;
using OFX::DefaultParamInteractDescriptor<ColourInteractDescriptor<INSTANCECOUNT>,ColourInteract>::setInteractPreferredSize;
virtual void describe()
{
setInteractSizeAspect(1.0);
setInteractMinimumSize(50, 50);
setInteractPreferredSize(100, 100);
}
};
class BasePlugin : public OFX::ImageEffect {
protected :
OFX::Clip *dstClip_;
public :
BasePlugin(OfxImageEffectHandle handle)
: ImageEffect(handle)
, dstClip_(0)
{
dstClip_ = fetchClip(kOfxImageEffectOutputClipName);
}
};
class GeneratorPlugin : public BasePlugin {
public :
GeneratorPlugin(OfxImageEffectHandle handle)
: BasePlugin(handle)
{}
virtual void render(const OFX::RenderArguments &args);
};
class FilterPlugin : public BasePlugin {
protected :
OFX::Clip *srcClip_;
public :
FilterPlugin(OfxImageEffectHandle handle)
: BasePlugin(handle)
, srcClip_(0)
{
srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName);
}
virtual void render(const OFX::RenderArguments &args);
};
class GeneralPlugin : public FilterPlugin {
protected :
OFX::Clip *extraClip_;
public :
GeneralPlugin(OfxImageEffectHandle handle)
: FilterPlugin(handle)
, extraClip_(0)
{
extraClip_ = fetchClip("Extra");
}
};
using namespace OFX;
class PropTesterPluginFactory : public OFX::PluginFactoryHelper<PropTesterPluginFactory>
{
public:
PropTesterPluginFactory():OFX::PluginFactoryHelper<PropTesterPluginFactory>("net.sf.openfx.propertyTester", 1, 0){}
virtual void describe(OFX::ImageEffectDescriptor &desc);
virtual void describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum context);
virtual OFX::ImageEffect* createInstance(OfxImageEffectHandle handle, OFX::ContextEnum context);
};
namespace OFX
{
namespace Plugin
{
void getPluginIDs(OFX::PluginFactoryArray &ids)
{
static PropTesterPluginFactory p;
ids.push_back(&p);
}
}
}
void PropTesterPluginFactory::describe(OFX::ImageEffectDescriptor &desc)
{
desc.setLabels("Prop Tester", "Prop Tester", "Property Tester");
desc.setPluginGrouping("OFX Test");
desc.addSupportedContext(eContextGenerator);
desc.addSupportedContext(eContextFilter);
desc.addSupportedContext(eContextGeneral);
desc.addSupportedBitDepth(eBitDepthUByte);
desc.addSupportedBitDepth(eBitDepthUShort);
desc.addSupportedBitDepth(eBitDepthFloat);
desc.setSingleInstance(false);
desc.setHostFrameThreading(false);
desc.setSupportsMultiResolution(true);
desc.setSupportsTiles(true);
desc.setTemporalClipAccess(false);
desc.setRenderTwiceAlways(false);
desc.setSupportsMultipleClipPARs(false);
}
static
void describeStringParam(OFX::ImageEffectDescriptor &desc, const std::string &name, StringTypeEnum strType, PageParamDescriptor *page)
{
StringParamDescriptor *param = desc.defineStringParam(name);
param->setDefault(name);
param->setScriptName(name);
param->setHint("A string parameter");
param->setLabels(name, name, name);
param->setStringType(strType);
page->addChild(*param);
}
static
void describeDoubleParam(OFX::ImageEffectDescriptor &desc, const std::string &name, DoubleTypeEnum doubleType,
double min, double max, PageParamDescriptor *page)
{
DoubleParamDescriptor *param = desc.defineDoubleParam(name);
param->setLabels(name, name, name);
param->setScriptName(name);
param->setHint("A double parameter");
param->setDefault(0);
param->setRange(min, max);
param->setDisplayRange(min, max);
param->setDoubleType(doubleType);
page->addChild(*param);
}
static
void describe2DDoubleParam(OFX::ImageEffectDescriptor &desc, const std::string &name, DoubleTypeEnum doubleType,
double min, double max, PageParamDescriptor *page)
{
Double2DParamDescriptor *param = desc.defineDouble2DParam(name);
param->setLabels(name, name, name);
param->setScriptName(name);
param->setHint("A 2D double parameter");
param->setDefault(0, 0);
param->setRange(min, min, max, max);
param->setDisplayRange(min, min, max, max);
param->setDoubleType(doubleType);
page->addChild(*param);
}
static
void describe3DDoubleParam(OFX::ImageEffectDescriptor &desc, const std::string &name, DoubleTypeEnum doubleType,
double min, double max, PageParamDescriptor *page)
{
Double3DParamDescriptor *param = desc.defineDouble3DParam(name);
param->setLabels(name, name, name);
param->setScriptName(name);
param->setHint("A 3D double parameter");
param->setDefault(0, 0, 0);
param->setRange(min, min, min, max, max, max);
param->setDisplayRange(min, min, min, max, max, max);
param->setDoubleType(doubleType);
page->addChild(*param);
}
void PropTesterPluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum context)
{
if(context == eContextGeneral) {
ClipDescriptor *srcClip = desc.defineClip("Extra");
srcClip->addSupportedComponent(ePixelComponentRGBA);
srcClip->setTemporalClipAccess(false);
srcClip->setOptional(false);
srcClip->setSupportsTiles(true);
srcClip->setIsMask(false);
}
if(context == eContextFilter || context == eContextGeneral) {
ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName);
srcClip->addSupportedComponent(ePixelComponentRGBA);
srcClip->setTemporalClipAccess(false);
srcClip->setSupportsTiles(true);
srcClip->setIsMask(false);
}
ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName);
dstClip->addSupportedComponent(ePixelComponentRGBA);
dstClip->setTemporalClipAccess(false);
dstClip->setSupportsTiles(true);
dstClip->setIsMask(false);
PageParamDescriptor *page1 = desc.definePageParam("page1");
PageParamDescriptor *page2 = desc.definePageParam("page2");
PageParamDescriptor *page3 = desc.definePageParam("page3");
IntParamDescriptor *iParam = desc.defineIntParam("Int");
iParam->setLabels("Int", "Int", "Int");
iParam->setScriptName("int");
iParam->setHint("An integer parameter");
iParam->setDefault(0);
iParam->setRange(-100, 100);
iParam->setDisplayRange(-100, 100);
page1->addChild(*iParam);
Int2DParamDescriptor *i2DParam = desc.defineInt2DParam("Int2D");
i2DParam->setLabels("Int2D", "Int2D", "Int2D");
i2DParam->setScriptName("int2D");
i2DParam->setHint("A 2D integer parameter");
i2DParam->setDefault(0, 0);
i2DParam->setRange(-100, -100, 100, 100);
i2DParam->setDisplayRange(-100, -100, 100, 100);
page1->addChild(*i2DParam);
Int3DParamDescriptor *i3DParam = desc.defineInt3DParam("Int3D");
i3DParam->setLabels("Int3D", "Int3D", "Int2D");
i3DParam->setScriptName("int3D");
i3DParam->setHint("A 3D integer parameter");
i3DParam->setDefault(0, 0, 0);
i3DParam->setRange(-100, -100, -100, 100, 100, 100);
i3DParam->setDisplayRange(-100, -100, -100, 100, 100, 100);
page1->addChild(*i3DParam);
page1->addChild(PageParamDescriptor::gSkipColumn);
BooleanParamDescriptor *boolean = desc.defineBooleanParam("bool");
boolean->setLabels("bool", "bool", "bool");
boolean->setDefault(false);
page1->addChild(*boolean);
ChoiceParamDescriptor *choice = desc.defineChoiceParam("choice");
choice->setLabels("choice", "choice", "choice");
choice->appendOption("This", "This");
choice->appendOption("That", "That");
choice->appendOption("The Other", "The Other");
choice->resetOptions();
choice->appendOption("Tom", "Tom");
choice->appendOption("Dick", "Dick");
choice->appendOption("Harry", "Harry");
choice->setDefault(0);
page1->addChild(*choice);
page1->addChild(PageParamDescriptor::gSkipColumn);
PushButtonParamDescriptor *push = desc.definePushButtonParam("push");
push->setLabels("push me", "push me", "push me Big Nose");
page1->addChild(*push);
CustomParamDescriptor *custom = desc.defineCustomParam("custom");
custom->setLabels("custom", "custom", "custom");
custom->setDefault("wibble");
RGBAParamDescriptor *rgba = desc.defineRGBAParam("rgba");
rgba->setLabels("rgba", "rgba", "rgba");
rgba->setDefault(0, 0, 0, 1);
page1->addChild(*rgba);
RGBParamDescriptor *rgba2 = desc.defineRGBParam("rgbaCustom");
rgba2->setLabels("RGB Custom", "RGB Custom", "RGB Custom");
rgba2->setDefault(0, 1, 1);
rgba2->setInteractDescriptor(new ColourInteractDescriptor<0>);
page1->addChild(*rgba2);
RGBParamDescriptor *rgba3 = desc.defineRGBParam("rgbaCustom2");
rgba3->setLabels("RGB Custom 2", "RGB Custom 2", "RGB Custom 2");
rgba3->setDefault(1, 0, 1);
rgba3->setInteractDescriptor(new ColourInteractDescriptor<1>);
page1->addChild(*rgba3);
page1->addChild(PageParamDescriptor::gSkipRow);
RGBParamDescriptor *rgb = desc.defineRGBParam("rgb");
rgb->setLabels("rgb", "rgb", "rgb");
rgb->setDefault(0, 0, 0);
page1->addChild(*rgb);
describeDoubleParam(desc, "double", eDoubleTypePlain, -100, 100, page2);
describeDoubleParam(desc, "angle", eDoubleTypeAngle, -100, 100, page2);
describeDoubleParam(desc, "scale", eDoubleTypeScale, -1, 1, page2);
describeDoubleParam(desc, "time", eDoubleTypeTime, -100, 100, page2);
describeDoubleParam(desc, "absoluteTime", eDoubleTypeAbsoluteTime, 0, 1000, page2);
describeDoubleParam(desc, "X_Value", eDoubleTypeX, -1, 1, page2);
describeDoubleParam(desc, "Y_Value", eDoubleTypeY, -1, 1, page2);
describeDoubleParam(desc, "X_Position", eDoubleTypeXAbsolute, -1, 1, page2);
describeDoubleParam(desc, "Y_Position", eDoubleTypeYAbsolute, -1, 1, page2);
page2->addChild(PageParamDescriptor::gSkipColumn);
describe2DDoubleParam(desc, "double2D", eDoubleTypePlain, -100, 100, page2);
describe2DDoubleParam(desc, "angle2D", eDoubleTypeAngle, -100, 100, page2);
describe2DDoubleParam(desc, "scale2D", eDoubleTypeScale, -1, 1, page2);
describe2DDoubleParam(desc, "XY_Value", eDoubleTypeXY, -1, 1, page2);
describe2DDoubleParam(desc, "XY_Position", eDoubleTypeXYAbsolute, -1, 1, page2);
page2->addChild(PageParamDescriptor::gSkipColumn);
describe3DDoubleParam(desc, "double3D", eDoubleTypePlain, -100, 100, page2);
describe3DDoubleParam(desc, "angle3D", eDoubleTypeAngle, -100, 100, page2);
describe3DDoubleParam(desc, "scale3D", eDoubleTypeScale, -1, 1, page2);
describeStringParam(desc, "singleLine", eStringTypeSingleLine, page3);
describeStringParam(desc, "multiLine", eStringTypeMultiLine, page3);
describeStringParam(desc, "filePath", eStringTypeFilePath, page3);
describeStringParam(desc, "dirPath", eStringTypeDirectoryPath, page3);
describeStringParam(desc, "label", eStringTypeLabel, page3);
}
ImageEffect* PropTesterPluginFactory::createInstance(OfxImageEffectHandle handle, ContextEnum context)
{
if(context == eContextFilter)
return new FilterPlugin(handle);
else if(context == eContextGenerator)
return new GeneratorPlugin(handle);
else if(context == eContextGeneral)
return new GeneralPlugin(handle);
return NULL; }
void
GeneratorPlugin::render(const OFX::RenderArguments &args)
{
OFX::Image *dst = 0;
try {
dst = dstClip_->fetchImage(args.time);
}
catch(...) {
delete dst;
throw;
}
delete dst;
}
void
FilterPlugin::render(const OFX::RenderArguments &args)
{
OFX::Image *src = 0, *dst = 0;
try {
src = srcClip_->fetchImage(args.time);
dst = dstClip_->fetchImage(args.time);
}
catch(...) {
delete src;
delete dst;
throw;
}
delete src;
delete dst;
}