#include <UT/UT_DSOVersion.h>
#include <OP/OP_OperatorTable.h>
#include <CH/CH_LocalVariable.h>
#include <CHOP/CHOP_VariableList.h>
#include <PRM/PRM_Include.h>
#include <UT/UT_Interrupt.h>
#include "CHOP_Blend.h"
using namespace HDK_Sample;
CHOP_SWITCHER(2,"Blend");
static PRM_Name methodItems[] = {
PRM_Name("prop", "Proportional"),
PRM_Name("dif", "Difference"),
PRM_Name(0),
};
static PRM_ChoiceList methodMenu((PRM_ChoiceListType)
(PRM_CHOICELIST_EXCLUSIVE |
PRM_CHOICELIST_REPLACE),
methodItems);
static PRM_Name names[] = {
PRM_Name("method", "Method"),
PRM_Name("firstweight", "Omit First Weight Channel"),
};
PRM_Template
CHOP_Blend::myTemplateList[] =
{
PRM_Template(PRM_SWITCHER, 2, &PRMswitcherName, switcher),
PRM_Template(PRM_ORD, 1, &names[0], PRMoneDefaults,&methodMenu),
PRM_Template(PRM_TOGGLE, 1, &names[1], PRMzeroDefaults),
PRM_Template(),
};
OP_TemplatePair CHOP_Blend::myTemplatePair(
CHOP_Blend::myTemplateList, &CHOP_Node::myTemplatePair);
unsigned
CHOP_Blend::disableParms()
{
unsigned changes = CHOP_Node::disableParms();
changes += enableParm("firstweight", GETDIFFERENCE());
return changes;
}
CH_LocalVariable
CHOP_Blend::myVariableList[] = {
{ 0, 0, 0 }
};
OP_VariablePair CHOP_Blend::myVariablePair(
CHOP_Blend::myVariableList, &CHOP_Node::myVariablePair);
OP_Node *
CHOP_Blend::myConstructor(OP_Network *net,
const char *name,
OP_Operator *op)
{
return new CHOP_Blend(net, name, op);
}
CHOP_Blend::CHOP_Blend( OP_Network *net,
const char *name,
OP_Operator *op)
: CHOP_Node(net, name, op)
{
myParmBase = getParmList()->getParmIndex( names[0].getToken() );
}
CHOP_Blend::~CHOP_Blend()
{
}
const CL_Clip *
CHOP_Blend::getCacheInputClip(int j)
{
return (j>=0 && j<myInputClip.entries()) ?
myInputClip(j) : 0;
}
OP_ERROR
CHOP_Blend::cookMyChop(OP_Context &context)
{
const CL_Clip *blendclip;
const CL_Clip *clip;
const CL_Track *track, *blend;
int num_motion_tracks;
int num_clips;
float weight, *data, *total;
int i,j,k,samples;
float time;
float val;
int difference;
int fweight;
UT_Interrupt *boss = UTgetInterrupt();
short int percent = -1;
int stopped = 0;
float adjust[2] = {1.0f, -1.0f};
const float *src, *w;
difference = GETDIFFERENCE();
if(difference)
fweight = FIRST_WEIGHT();
else
fweight = 0;
blendclip = copyInputAttributes(context);
if(!blendclip)
return error();
num_clips = findInputClips(context, blendclip);
num_motion_tracks = findFirstAvailableTracks(context);
samples = myClip->getTrackLength();
myTotalArray.resize(samples);
myTotalArray.entries(samples);
total = myTotalArray.array();
if(boss->opStart("Blending Channels"))
{
for(i=0; i<num_motion_tracks; i++)
{
myClip->getTrack(i)->constant(0);
data = myClip->getTrack(i)->getData();
myTotalArray.constant(difference ? 1.0f : 0.0f);
for(j=difference?1:0; j<num_clips; j++)
{
clip = getCacheInputClip(j+1);
if(!clip)
continue;
if(difference && fweight)
blend = blendclip->getTrack(j-1);
else
blend = blendclip->getTrack(j);
track = clip->getTrack(i);
if(!track || !blend)
continue;
w = blend->getData();
if (myClip->isSameRange(*clip))
{
src = track->getData();
for(k=0; k<samples; k++)
{
if (w[k])
{
data[k] += w[k]*src[k];
total[k] += w[k]*adjust[difference];
}
}
}
else
{
for(k=0; k<samples; k++)
{
time = myClip->getTime(k + myClip->getStart());
if (w[k])
{
data[k] += w[k] *
clip->evaluateSingleTime(track, time);
total[k] += w[k]*adjust[difference];
}
}
}
if(boss->opInterrupt())
{
stopped = 1;
break;
}
}
if(!stopped)
{
if(!difference)
{
j = myAvailableTracks(i);
if ( j!=-1 && getCacheInputClip(j))
{
track = getCacheInputClip(j)->getTrack(i);
blend = blendclip->getTrack(j);
if(blend)
w = blend->getData();
else
continue;
}
else
track = 0;
for(k=0; k<samples; k++)
{
if(!UTequalZero(total[k], 0.001F))
{
data[k] /= total[k];
}
else
{
if(track && blend)
{
time = myClip->getTime(k + myClip->getStart());
val = clip->evaluateSingleTime(track,time);
data[k] -= w[k]*val;
total[k]-= w[k];
weight = 1.0F - total[k];
total[k]+= weight;
data[k] += weight*val;
data[k] /= total[k];
}
}
}
}
else
{
j = myAvailableTracks(i);
if (j != -1)
{
clip = getCacheInputClip(j);
track = clip ? clip->getTrack(i) : 0;
if (track)
{
if (myClip->isSameRange(*clip))
{
const float *src = track->getData();
for(k=0; k<samples; k++)
data[k] += src[k] * total[k];
}
else
{
for(k=0; k<samples; k++)
{
time= myClip->getTime(k+myClip->getStart());
val = clip->evaluateSingleTime(track, time);
data[k] += val * total[k];
}
}
}
}
if(boss->opInterrupt(percent))
{
stopped = 1;
break;
}
}
}
if(stopped)
break;
}
}
boss->opEnd();
return error();
}
int
CHOP_Blend::findInputClips(OP_Context &context, const CL_Clip *blendclip)
{
int i, num_clips;
num_clips = blendclip->getNumTracks();
if(GETDIFFERENCE() && FIRST_WEIGHT())
num_clips ++;
if (num_clips >= nInputs())
num_clips = nInputs()-1;
myInputClip.resize(num_clips+1);
myInputClip.entries(num_clips+1);
for (i=0; i<=num_clips; i++)
myInputClip(i) = inputClip(i, context);
return num_clips;
}
int
CHOP_Blend::findFirstAvailableTracks(OP_Context &context)
{
const CL_Track *track;
const CL_Clip *clip;
int i, j;
int num_motion_tracks;
num_motion_tracks = 0;
for(i=1; i<nInputs(); i++)
{
clip = inputClip(i, context);
if(!clip)
continue;
if(clip->getNumTracks() > num_motion_tracks)
num_motion_tracks = clip->getNumTracks();
}
myAvailableTracks.resize(num_motion_tracks);
myAvailableTracks.entries(num_motion_tracks);
for(i=0; i<num_motion_tracks; i++)
{
track = 0;
j = 1;
while( !track && j<nInputs())
{
clip = inputClip(j, context);
if(!clip)
{
j++;
continue;
}
track = clip->getTrack(i);
if(!track)
j++;
}
myAvailableTracks(i) = track ? j: -1;
}
for(i=0; i<num_motion_tracks; i++)
{
j = myAvailableTracks(i);
if (j == -1)
continue;
track = inputClip(j, context)->getTrack(i);
if (track)
myClip->dupTrackInfo(track);
}
return num_motion_tracks;
}
void newChopOperator(OP_OperatorTable *table)
{
table->addOperator(new OP_Operator("hdk_blend",
"HDK Blend",
CHOP_Blend::myConstructor,
&CHOP_Blend::myTemplatePair,
2,
9999,
&CHOP_Blend::myVariablePair));
}