Files
oak-editor/third_party/openfx/Support/Plugins/MultiBundle/multibundle2.cpp
T

432 lines
12 KiB
C++

#ifdef _WINDOWS
#include <windows.h>
#endif
#ifdef __APPLE__
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
#include <cassert>
#include "ofxsImageEffect.h"
#include "ofxsMultiThread.h"
#include "../include/ofxsProcessing.H"
#include "multibundle2.h"
static const OfxPointD kBoxSize = {20, 20};
class DotExampleInteract : public OFX::OverlayInteract
{
protected :
enum StateEnum {
eInActive,
ePoised,
ePicked
};
StateEnum _state;
OFX::Double2DParam* position_;
public :
DotExampleInteract(OfxInteractHandle handle, OFX::ImageEffect* effect) : OFX::OverlayInteract(handle), _state(eInActive)
{
position_ = effect->fetchDouble2DParam("position");
}
virtual bool draw(const OFX::DrawArgs &args);
virtual bool penMotion(const OFX::PenArgs &args);
virtual bool penDown(const OFX::PenArgs &args);
virtual bool penUp(const OFX::PenArgs &args);
};
template <class T>
inline T Absolute(T a)
{
return (a < 0) ? -a : a;
}
class DotGeneratorBase : public OFX::ImageProcessor
{
public :
DotGeneratorBase(OFX::ImageEffect &instance) : OFX::ImageProcessor(instance), _radius(0.0f), _positionx(0.0f), _positiony(0.0f)
{
_colour[0] = _colour[1] = _colour[2] = _colour[3] = 0;
}
void setRadius(float v) { _radius = v; }
void setR(float v) { _colour[0] = v;}
void setG(float v) { _colour[1] = v;}
void setB(float v) { _colour[2] = v;}
void setA(float v) { _colour[3] = v;}
void setColour(double r, double g, double b, double a)
{
setR((float)r);
setG((float)g);
setB((float)b);
setA((float)a);
}
void setPosition(float x, float y)
{
_positionx = x;
_positiony = y;
}
protected:
float _radius;
float _colour[4];
float _positionx;
float _positiony;
};
template <class PIX, int nComponents, int max>
class DotGenerator : public DotGeneratorBase {
public :
DotGenerator(OFX::ImageEffect &instance): DotGeneratorBase(instance){}
void multiThreadProcessImages(OfxRectI procWindow)
{
float radiusSq = _radius * _radius;
for(int y = procWindow.y1; y < procWindow.y2; y++)
{
if(_effect.abort())
break;
PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y);
for(int x = procWindow.x1; x < procWindow.x2; x++)
{
float radsq = (x - _positionx)*(x - _positionx) + (y - _positiony)*(y - _positiony);
float val = radsq/radiusSq;
for(int c = 0; c < nComponents; c++)
{
dstPix[c] = val < 1.0f ? PIX((1.0f-val)*max) : PIX(0);
dstPix[c] = (PIX)(dstPix[c] * _colour[c]);
}
dstPix += nComponents;
}
}
}
};
class DotExamplePlugin : public OFX::ImageEffect
{
protected:
OFX::Clip *dstClip_;
OFX::DoubleParam *radius_;
OFX::RGBAParam *colour_;
OFX::Double2DParam* position_;
public:
DotExamplePlugin(OfxImageEffectHandle handle): ImageEffect(handle), dstClip_(0), radius_(0) , colour_(0), position_(0)
{
dstClip_ = fetchClip(kOfxImageEffectOutputClipName);
radius_ = fetchDoubleParam("radius");
colour_ = fetchRGBAParam("colour");
position_ = fetchDouble2DParam("position");
}
virtual void render(const OFX::RenderArguments &args);
void setupAndProcess(DotGeneratorBase &, const OFX::RenderArguments &args);
bool getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod);
template<class ARGS>
void getPositionInPixels(double& x, double& y, const ARGS& args);
template<class ARGS>
void getPositionInCanonical(double& x, double& y, const ARGS& args);
};
template<class ARGS>
void DotExamplePlugin::getPositionInCanonical(double& x, double& y, const ARGS& args)
{
position_->getValueAtTime(args.time, x, y);
}
template<class ARGS>
void DotExamplePlugin::getPositionInPixels(double& x, double& y, const ARGS& args)
{
double xpos, ypos;
getPositionInCanonical(xpos, ypos, args);
x = (xpos * args.renderScale.x) /getProjectPixelAspectRatio();
y = ypos * args.renderScale.y;
}
void DotExamplePlugin::setupAndProcess(DotGeneratorBase &processor, const OFX::RenderArguments &args)
{
std::unique_ptr<OFX::Image> dst(dstClip_->fetchImage(args.time));
//OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth();
//OFX::PixelComponentEnum dstComponents = dst->getPixelComponents();
double rad = radius_->getValueAtTime(args.time);
processor.setRadius((float)(rad));
double r, g, b, a;
colour_->getValueAtTime(args.time, r, g, b, a);
processor.setColour(r,g,b,a);
processor.setDstImg(dst.get());
processor.setRenderWindow(args.renderWindow);
double xpospixel, ypospixel;
getPositionInPixels(xpospixel, ypospixel, args);
float fieldScaler = (args.fieldToRender == OFX::eFieldLower || args.fieldToRender == OFX::eFieldUpper)? 0.5f: 1.0f;
ypospixel *= fieldScaler;
processor.setPosition((float)xpospixel, (float)ypospixel);
processor.process();
}
bool DotExamplePlugin::getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod)
{
double r = radius_->getValueAtTime(args.time);
double x, y;
position_->getValueAtTime(args.time, x, y);
rod.x1 = x - r;
rod.y1 = y - r;
rod.x2 = x + r;
rod.y2 = y + r;
return true;
}
void DotExamplePlugin::render(const OFX::RenderArguments &args)
{
OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth();
OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents();
if(dstComponents == OFX::ePixelComponentRGBA)
{
switch(dstBitDepth)
{
case OFX::eBitDepthUByte :
{
DotGenerator<unsigned char, 4, 255> fred(*this);
setupAndProcess(fred, args);
}
break;
case OFX::eBitDepthUShort :
{
DotGenerator<unsigned short, 4, 65535> fred(*this);
setupAndProcess(fred, args);
}
break;
case OFX::eBitDepthFloat :
{
DotGenerator<float, 4, 1> fred(*this);
setupAndProcess(fred, args);
}
break;
default :
OFX::throwSuiteStatusException(kOfxStatErrUnsupported);
}
}
else
{
switch(dstBitDepth)
{
case OFX::eBitDepthUByte :
{
DotGenerator<unsigned char, 1, 255> fred(*this);
setupAndProcess(fred, args);
}
break;
case OFX::eBitDepthUShort :
{
DotGenerator<unsigned short, 1, 65535> fred(*this);
setupAndProcess(fred, args);
}
break;
case OFX::eBitDepthFloat :
{
DotGenerator<float, 1, 1> fred(*this);
setupAndProcess(fred, args);
}
break;
default :
OFX::throwSuiteStatusException(kOfxStatErrUnsupported);
}
}
}
bool DotExampleInteract::draw(const OFX::DrawArgs &args)
{
OfxRGBColourF col;
col.r = 0.5f;
col.g = 0.0f;
switch(_state)
{
case eInActive :
col.b = 0.0f;
break;
case ePoised :
col.b = 0.5f;
break;
case ePicked :
col.b = 1.0f;
break;
}
float dx = (float)(kBoxSize.x * args.pixelScale.x);
float dy = (float)(kBoxSize.y * args.pixelScale.y);
double xpos = 0., ypos = 0.;
DotExamplePlugin* plug = dynamic_cast<DotExamplePlugin*>(_effect);
assert(plug);
if (plug) {
plug->getPositionInCanonical(xpos, ypos, args);
}
glPushMatrix();
glColor3f(col.r, col.g, col.b);
glTranslated(xpos, ypos, 0);
glBegin(GL_POLYGON);
glVertex2f(-dx, -dy);
glVertex2f(-dx, dy);
glVertex2f( dx, dy);
glVertex2f( dx, -dy);
glEnd();
glPopMatrix();
glColor3f(1.0f - col.r, 1.0f - col.g, 1.0f - col.b);
glTranslated(xpos, ypos, 0);
glBegin(GL_LINE_LOOP);
glVertex2f(-dx, -dy);
glVertex2f(-dx, dy);
glVertex2f( dx, dy);
glVertex2f( dx, -dy);
glEnd();
glPopMatrix();
return true;
}
bool DotExampleInteract::penMotion(const OFX::PenArgs &args)
{
float dx = (float)(kBoxSize.x * args.pixelScale.x);
float dy = (float)(kBoxSize.y * args.pixelScale.y);
OfxPointD penPos = args.penPosition;
switch(_state)
{
case eInActive :
case ePoised :
{
StateEnum newState;
double xpos = 0., ypos = 0.;
DotExamplePlugin* plug = dynamic_cast<DotExamplePlugin*>(_effect);
if (plug) {
plug->getPositionInCanonical(xpos, ypos, args);
}
penPos.x -= xpos;
penPos.y -= ypos;
if(Absolute(penPos.x) < dx && Absolute(penPos.y) < dy)
{
newState = ePoised;
}
else
{
newState = eInActive;
}
if(_state != newState)
{
_state = newState;
_effect->redrawOverlays();
}
}
break;
case ePicked :
{
position_->setValueAtTime(args.time, args.penPosition.x, args.penPosition.y);
_effect->redrawOverlays();
}
break;
}
return _state != eInActive;
}
bool DotExampleInteract::penDown(const OFX::PenArgs &args)
{
penMotion(args);
if(_state == ePoised)
{
_state = ePicked;
_effect->redrawOverlays();
}
return _state == ePicked;
}
bool DotExampleInteract::penUp(const OFX::PenArgs &args)
{
if(_state == ePicked)
{
_state = ePoised;
penMotion(args);
_effect->redrawOverlays();
return true;
}
return false;
}
using namespace OFX;
class DotExampleOverlayDescriptor : public DefaultEffectOverlayDescriptor<DotExampleOverlayDescriptor, DotExampleInteract> {};
void DotExamplePluginFactory::describe(OFX::ImageEffectDescriptor &desc)
{
desc.setLabels("Dot Generator", "Dot Generator", "Dot Generator");
desc.setPluginGrouping("OFX Example (Support)");
desc.addSupportedContext(eContextGenerator);
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);
desc.setRenderTwiceAlways(false);
desc.setOverlayInteractDescriptor( new DotExampleOverlayDescriptor );
}
void DotExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum /*context*/)
{
// there has to be an input clip, even for generators
ClipDescriptor* srcClip = desc.defineClip( kOfxImageEffectSimpleSourceClipName );
srcClip->addSupportedComponent( OFX::ePixelComponentRGBA );
srcClip->addSupportedComponent( OFX::ePixelComponentAlpha );
srcClip->setSupportsTiles(true);
srcClip->setOptional(true);
ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName);
dstClip->addSupportedComponent(ePixelComponentRGBA);
dstClip->addSupportedComponent(ePixelComponentAlpha);
dstClip->setSupportsTiles(true);
dstClip->setFieldExtraction(eFieldExtractSingle);
DoubleParamDescriptor *param = desc.defineDoubleParam("radius");
param->setLabels("Radius", "Radius", "Radius");
param->setScriptName("radius");
param->setHint("The radius of the dot produced.");
param->setDoubleType(eDoubleTypeX);
param->setDefaultCoordinateSystem(eCoordinatesNormalised);
param->setDefault(0.02);
//param->setRange(0, 1);
param->setIncrement(1);
param->setDisplayRange(0, 1);
param->setAnimates(true);
RGBAParamDescriptor *param2 = desc.defineRGBAParam("colour");
param2->setAnimates(true);
param2->setLabels("Colour", "Colour", "Colour");
param2->setHint("The colour of the dot produced.");
param2->setScriptName("colour");
param2->setDefault(1.0, 1.0, 1.0, 1.0);
Double2DParamDescriptor* param3 = desc.defineDouble2DParam("position");
param3->setLabels("Dot Position", "Dot Position", "Dot Position");
param3->setDoubleType(eDoubleTypeXY);
param3->setDefaultCoordinateSystem(eCoordinatesNormalised);
param3->setAnimates(true);
param3->setDimensionLabels("X", "Y");
param3->setDefault(0.5, 0.5);
PageParamDescriptor *page = desc.definePageParam("Controls");
page->addChild(*param);
page->addChild(*param2);
page->addChild(*param3);
}
ImageEffect* DotExamplePluginFactory::createInstance(OfxImageEffectHandle handle, OFX::ContextEnum /*context*/)
{
return new DotExamplePlugin(handle);
}