#include <UT/UT_DSOVersion.h>
#include <OP/OP_OperatorTable.h>
#include <PRM/PRM_Include.h>
#include <SYS/SYS_Floor.h>
#include <SYS/SYS_Math.h>
#include <TIL/TIL_Plane.h>
#include <TIL/TIL_Region.h>
#include <TIL/TIL_Tile.h>
#include <COP2/COP2_CookAreaInfo.h>
#include "COP2_MultiInputWipe.h"
using namespace HDK_Sample;
COP_MULTI_SWITCHER(5, "Blend");
static PRM_Name names[] =
{
PRM_Name("fadera", "A Fader"),
PRM_Name("faderb", "B Fader"),
PRM_Name("boostval", "Overexposure Boost"),
PRM_Name("bloomblur", "Bloom Blur"),
PRM_Name("fademode", "Fade Rate"),
};
#define FADE_LINEAR 0
#define FADE_SQUARE 1
#define FADE_ROOT 2
static PRM_Name fadeItems[] =
{
PRM_Name("linear", "Linear"),
PRM_Name("squared", "Squared"),
PRM_Name("root", "Square Root"),
PRM_Name(0),
};
static PRM_ChoiceList fadeMenu((PRM_ChoiceListType)
(PRM_CHOICELIST_EXCLUSIVE | PRM_CHOICELIST_REPLACE), fadeItems);
static PRM_Range wipeRange(PRM_RANGE_RESTRICTED, 0.0f,
PRM_RANGE_RESTRICTED, 1.0f);
static PRM_Range boostRange(PRM_RANGE_UI, 0.0f, PRM_RANGE_UI, 1.0f);
static PRM_Range blurRange(PRM_RANGE_RESTRICTED, 0.0f, PRM_RANGE_UI, 20.0f);
static PRM_Default boostValue(0.9);
static PRM_Default boostBlur(9);
PRM_Template
COP2_MultiInputWipe::myTemplateList[] =
{
PRM_Template(PRM_SWITCHER, 2, &PRMswitcherName, switcher),
PRM_Template(PRM_FLT, TOOL_PARM, 1, &names[0], PRMoneDefaults, 0,
&wipeRange),
PRM_Template(PRM_FLT, TOOL_PARM, 1, &names[1], PRMzeroDefaults, 0,
&wipeRange),
PRM_Template(PRM_FLT, TOOL_PARM, 1, &names[2], &boostValue, 0,
&boostRange),
PRM_Template(PRM_FLT, TOOL_PARM, 1, &names[3], &boostBlur, 0,
&blurRange),
PRM_Template(PRM_ORD, POPUP_PARM, 1, &names[4], PRMoneDefaults,
&fadeMenu),
PRM_Template(),
};
OP_TemplatePair COP2_MultiInputWipe::myTemplatePair(
COP2_MultiInputWipe::myTemplateList,
&COP2_MultiBase::myTemplatePair );
OP_VariablePair COP2_MultiInputWipe::myVariablePair( 0,
&COP2_Node::myVariablePair );
const char * COP2_MultiInputWipe::myInputLabels[] =
{
"Wipe A",
"Wipe B",
0
};
OP_Node *
COP2_MultiInputWipe::myConstructor( OP_Network *net,
const char *name,
OP_Operator *op)
{
return new COP2_MultiInputWipe(net, name, op);
}
COP2_MultiInputWipe::COP2_MultiInputWipe(OP_Network *parent,
const char *name,
OP_Operator *entry)
: COP2_MultiBase(parent, name, entry)
{
}
COP2_MultiInputWipe::~COP2_MultiInputWipe()
{
}
namespace HDK_Sample {
class cop2_MultiInputWipeData : public COP2_ContextData
{
public:
cop2_MultiInputWipeData() {}
virtual ~cop2_MultiInputWipeData() {}
float myFaderA;
float myFaderB;
float myBoostA;
float myBoostB;
int myBlurRadA;
int myBlurRadB;
float myBlurA;
float myBlurB;
bool myPassA;
bool myPassB;
};
}
COP2_ContextData *
COP2_MultiInputWipe::newContextData(const TIL_Plane *, int , float t,
int xres, int , int , int )
{
cop2_MultiInputWipeData *data = new cop2_MultiInputWipeData();
int fademode;
float blur;
float boost;
data->myFaderA = evalFloat("fadera",0,t);
data->myFaderB = evalFloat("faderb",0,t);
fademode = evalInt("fademode", 0, t);
if(fademode == FADE_SQUARE)
{
data->myFaderA *= data->myFaderA;
data->myFaderB *= data->myFaderB;
}
else if(fademode == FADE_ROOT)
{
data->myFaderA = SYSsqrt(data->myFaderA);
data->myFaderB = SYSsqrt(data->myFaderB);
}
data->myPassA = (data->myFaderA == 1.0f && data->myFaderB == 0.0f);
data->myPassB = (data->myFaderB == 1.0f && data->myFaderA == 0.0f);
boost = evalFloat("boostval", 0, t) * 0.5f;
data->myBoostA = data->myFaderB * boost;
data->myBoostB = data->myFaderA * boost;
blur = evalFloat("bloomblur", 0, t) * getXScaleFactor(xres);
data->myBlurA = data->myFaderB * blur;
data->myBlurB = data->myFaderA * blur;
data->myBlurRadA = (int)SYSceil(data->myBlurA * 0.5f);
data->myBlurRadB = (int)SYSceil(data->myBlurB * 0.5f);
return data;
}
void
COP2_MultiInputWipe::computeImageBounds(COP2_Context &context)
{
cop2_MultiInputWipeData *data =
static_cast<cop2_MultiInputWipeData *>(context.data());
bool init = false;
int x1,y1,x2,y2;
int ix1, ix2, iy1, iy2;
x1 = 0;
y1 = 0;
x2 = context.myXres-1;
y2 = context.myYres-1;
for(int i=0; i<nInputs(); i++)
{
if(getInputBounds(i, context, ix1, iy1, ix2, iy2))
{
if(!init)
{
x1 = ix1;
y1 = iy1;
x2 = ix2;
y2 = iy2;
init = true;
}
else
{
if(ix1 < x1) x1 = ix1;
if(ix2 > x2) x2 = ix2;
if(iy1 < y1) y1 = iy1;
if(iy2 > y2) y2 = iy2;
}
}
}
if(!data->myPassA && !data->myPassB)
{
int brad = SYSmax(data->myBlurRadA, data->myBlurRadB);
x1 -= brad;
y1 -= brad;
x2 += brad;
y2 += brad;
}
context.setImageBounds(x1,y1,x2,y2);
}
void
COP2_MultiInputWipe::getInputDependenciesForOutputArea(
COP2_CookAreaInfo &output_area,
const COP2_CookAreaList &input_areas,
COP2_CookAreaList &needed_areas)
{
cop2_MultiInputWipeData *cdata;
COP2_Context *context;
COP2_CookAreaInfo *area;
if (getBypass())
{
area = makeOutputAreaDependOnMyPlane(0, output_area, input_areas,
needed_areas);
return;
}
context = output_area.getNodeContextData();
cdata = static_cast<cop2_MultiInputWipeData *>(context->data());
if(!cdata->myPassB)
{
area = makeOutputAreaDependOnMyPlane(0, output_area, input_areas,
needed_areas);
if(area)
area->expandNeededArea( cdata->myBlurRadA, cdata->myBlurRadA,
cdata->myBlurRadA, cdata->myBlurRadA);
}
if(!cdata->myPassA)
{
area = makeOutputAreaDependOnMyPlane(1, output_area, input_areas,
needed_areas);
if(area)
area->expandNeededArea( cdata->myBlurRadB, cdata->myBlurRadB,
cdata->myBlurRadB, cdata->myBlurRadB);
}
}
int
COP2_MultiInputWipe::passThrough(COP2_Context &context,
const TIL_Plane *plane, int,
int, float t,
int xstart, int ystart)
{
cop2_MultiInputWipeData *data =
static_cast<cop2_MultiInputWipeData *>(context.data());
const TIL_Sequence *inputseq = 0;
if(data->myPassA)
inputseq = inputInfo(0);
else if(data->myPassB)
inputseq = inputInfo(1);
if(inputseq)
{
const TIL_Plane *inputplane = inputseq->getPlane(plane->getName());
if(inputplane)
{
int xres,yres;
int ixres, iyres;
mySequence.getRes(xres,yres);
inputseq->getRes(ixres,iyres);
if(plane->isCompatible(*inputplane) &&
ixres == xres && iyres == yres &&
inputseq->getImageIndex(t) != -1 &&
isTileAlignedWithInput(0,context, xstart,ystart))
{
return 1;
}
}
}
return 0;
}
void
COP2_MultiInputWipe::passThroughTiles(COP2_Context &context,
const TIL_Plane *plane, int array_index,
float t, int xstart, int ystart,
TIL_TileList *&tiles,
int block, bool *mask, bool *blocked)
{
cop2_MultiInputWipeData *data =
static_cast<cop2_MultiInputWipeData *>(context.data());
bool iblocked = false;
if(data->myPassA)
{
tiles = passInputTile(0,context, plane, array_index, t, xstart,
ystart, block, &iblocked, mask);
}
else if(data->myPassB)
{
tiles = passInputTile(1, context, plane, array_index, t, xstart,
ystart, block, &iblocked, mask);
}
if(!tiles && iblocked && blocked)
*blocked = true;
}
OP_ERROR
COP2_MultiInputWipe::cookMyTile(COP2_Context &context, TIL_TileList *tilelist)
{
cop2_MultiInputWipeData *data =
static_cast<cop2_MultiInputWipeData *>(context.data());
TIL_Region *aregion, *bregion;
int arad, brad;
TIL_Plane fpplane(*context.myPlane);
bool init = false;
arad = data->myBlurRadA;
brad = data->myBlurRadB;
fpplane.setScoped(1);
fpplane.setFormat(TILE_FLOAT32);
if(data->myFaderA != 0.0f)
{
aregion = inputRegion(0, context, &fpplane, 0, context.myTime,
tilelist->myX1 - arad,
tilelist->myY1 - arad,
tilelist->myX2 + arad,
tilelist->myY2 + arad, TIL_HOLD);
if(aregion)
{
boostAndBlur(tilelist, aregion, data->myFaderA,
data->myBoostA, arad, data->myBlurA, false);
init = true;
releaseRegion(aregion);
}
}
if(data->myFaderB != 0.0f)
{
bregion = inputRegion(1, context, &fpplane, 0, context.myTime,
tilelist->myX1 - brad,
tilelist->myY1 - brad,
tilelist->myX2 + brad,
tilelist->myY2 + brad, TIL_HOLD);
if(bregion)
{
boostAndBlur(tilelist, bregion, data->myFaderB,
data->myBoostB, brad, data->myBlurB, init);
init = true;
releaseRegion(bregion);
}
}
if(!init)
tilelist->clearToBlack();
return error();
}
void
COP2_MultiInputWipe::boostAndBlur(TIL_TileList *tiles, TIL_Region *input,
float fade, float boost, int rad, float blur,
bool add)
{
int ti, x,y, i,j, idx;
int w,h;
int stride;
TIL_Tile *itr;
float *src, *scan;
float vedge;
float sum, hsum;
float *dest = NULL;
bool alloced = false;
const float iblur = fade / ((1.0f + blur) * (1.0f + blur));
const float edge = 1.0f - (rad - blur * 0.5f);
w = tiles->myX2 - tiles->myX1 + 1;
h = tiles->myY2 - tiles->myY1 + 1;
stride = w + rad * 2;
if(boost != 0.0f)
{
for(i=0; i<PLANE_MAX_VECTOR_SIZE; i++)
{
src = (float *) input->getImageData(i);
if(src)
for(y=0; y<(h+rad*2) * stride; y++)
*src++ += boost;
}
}
if(!add)
{
dest = new float[w*h];
alloced = true;
}
FOR_EACH_UNCOOKED_TILE(tiles, itr, ti)
{
src = ((float *) input->getImageData(ti)) + rad;
if(add)
{
if(getTileInFP(tiles, dest, ti))
alloced = true;
}
else
{
memset(dest, 0, sizeof(float)*w*h);
}
for(idx=0, y=0; y<h; y++)
{
for(x=0; x<w; x++, idx++)
{
sum = 0.0f;
scan = src+x;
for(i=-rad; i<=rad; i++)
{
vedge = (i == -rad || i == rad) ? edge : 1.0f;
hsum = scan[-rad] * edge;
if(rad)
hsum += scan[rad] * edge;
for(j=-rad+1; j<rad; j++)
hsum += scan[j];
sum += hsum * vedge;
scan += stride;
}
dest[idx] += sum * iblur;
}
src += stride;
}
writeFPtoTile(tiles, dest, ti);
}
if(alloced)
delete [] dest;
}
void
newCop2Operator(OP_OperatorTable *table)
{
table->addOperator(new OP_Operator("hdk_multiwipe",
"HDK Multi Input Wipe",
COP2_MultiInputWipe::myConstructor,
&COP2_MultiInputWipe::myTemplatePair,
2,
2,
&COP2_MultiInputWipe::myVariablePair,
0,
COP2_MultiInputWipe::myInputLabels));
}