tahoma2d/toonz/sources/common/tfx/binaryFx.cpp

719 lines
20 KiB
C++
Raw Normal View History

2016-03-19 06:57:51 +13:00
// TnzCore includes
#include "tstream.h"
#include "trop.h"
#include "tflash.h"
// TnzBase includes
#include "tdoubleparam.h"
#include "tnotanimatableparam.h"
#include "tfxparam.h"
#include "trasterfx.h"
#include "tbasefx.h"
//******************************************************************************************
// Local namespace
//******************************************************************************************
2016-06-15 18:43:10 +12:00
namespace {
void makeRectCoherent(TRectD &rect, const TPointD &pos) {
rect -= pos;
rect.x0 = tfloor(rect.x0);
rect.y0 = tfloor(rect.y0);
rect.x1 = tceil(rect.x1);
rect.y1 = tceil(rect.y1);
rect += pos;
2016-03-19 06:57:51 +13:00
}
}
//******************************************************************************************
// TImageCombinationFx declaration
//******************************************************************************************
2016-06-15 18:43:10 +12:00
class TImageCombinationFx : public TBaseRasterFx {
TFxPortDG m_group;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
TImageCombinationFx();
virtual ~TImageCombinationFx() {}
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
// Virtual interface for heirs
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
//! The raster processing function that must be reimplemented to perform the
//! fx
virtual void process(const TRasterP &up, const TRasterP &down,
double frame) = 0;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
//! Whether the 'up' rasters of process() invocations must be allocated to
//! entirely cover the 'down' counterpart. Should be enabled if the process()
//! function affects 'down' pixels when the 'up's are fully transparent.
virtual bool requiresFullRect() { return false; }
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
// Low-level TRasterFx-related functions
2016-03-19 06:57:51 +13:00
2016-06-19 20:06:29 +12:00
int dynamicPortGroupsCount() const override { return 1; }
const TFxPortDG *dynamicPortGroup(int g) const override {
2016-06-15 18:43:10 +12:00
return (g == 0) ? &m_group : 0;
}
2016-03-19 06:57:51 +13:00
2016-06-20 14:23:05 +12:00
bool canHandle(const TRenderSettings &info, double frame) override {
return true;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int getMemoryRequirement(const TRectD &rect, double frame,
2016-06-19 20:06:29 +12:00
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
// At max the memory of another tile with the same infos may be allocated
// apart from
// the externally supplied one.
return TRasterFx::memorySize(rect, info.m_bpp);
}
2016-03-19 06:57:51 +13:00
2016-06-20 14:23:05 +12:00
bool doGetBBox(double frame, TRectD &bBox,
const TRenderSettings &info) override;
2016-03-19 06:57:51 +13:00
2016-06-20 14:23:05 +12:00
void doDryCompute(TRectD &rect, double frame,
const TRenderSettings &info) override;
void doCompute(TTile &tile, double frame,
const TRenderSettings &info) override;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
void compatibilityTranslatePort(int majorVersion, int minorVersion,
2016-06-19 20:06:29 +12:00
std::string &portName) override;
2016-03-19 06:57:51 +13:00
2016-06-19 20:06:29 +12:00
int getPreferredInputPort() override { return 1; }
2016-03-19 06:57:51 +13:00
};
//******************************************************************************************
// TImageCombinationFx implementation
//******************************************************************************************
2016-06-15 18:43:10 +12:00
TImageCombinationFx::TImageCombinationFx() : m_group("Source", 2) {
addInputPort("Source1", new TRasterFxPort, 0);
addInputPort("Source2", new TRasterFxPort, 0);
setName(L"ImageCombinationFx");
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
bool TImageCombinationFx::doGetBBox(double frame, TRectD &bBox,
const TRenderSettings &info) {
bBox = TRectD();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int p, pCount = getInputPortCount();
for (p = 0; p != pCount; ++p) {
TRasterFxPort *port = static_cast<TRasterFxPort *>(getInputPort(p));
TRectD inputBBox;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
bool hasInput = (port && port->isConnected())
? (*port)->doGetBBox(frame, inputBBox, info)
: false;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (hasInput) bBox += inputBBox;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
return (bBox.getLx() >= 0) && (bBox.getLy() >= 0);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void TImageCombinationFx::doCompute(TTile &tile, double frame,
const TRenderSettings &info) {
int p, pCount = getInputPortCount();
TRasterFxPort *port = 0;
// Skip empty ports
for (p = pCount - 1; p >= 0;
--p) // Reverse iteration - bottom ports have high indices
{
port = static_cast<TRasterFxPort *>(getInputPort(p));
if (port && port->getFx()) break;
}
// If there is no input, clear and return
if (p < 0) {
tile.getRaster()
->clear(); // Probably not necessary unless externally invocation
return; // deliberately soiled tile - however, should be rare anyway.
}
// Calculate the tiles' geometries
const TRect &tileRect(tile.getRaster()->getBounds());
const TDimension &tileSize(tileRect.getSize());
TRectD tileRectD(tile.m_pos, TDimensionD(tileSize.lx, tileSize.ly));
// Render the first viable port directly on tile
(*port)->compute(tile, frame,
info); // Should we do it only if the bbox is not empty?
// Then, render each subsequent port and process() it on top of tile
bool canRestrict = !requiresFullRect();
for (--p; p >= 0; --p) {
port = static_cast<TRasterFxPort *>(getInputPort(p));
if (!(port && port->getFx())) // Skip empty ports
continue;
// Will allocate a new tile to calculate the input contribution - so, if
// possible
// we'll restrict allocation to the input port's bbox
TRectD computeRect(tileRectD);
if (canRestrict) {
TRectD inBBox;
(*port)->getBBox(frame, inBBox, info);
computeRect *= inBBox;
makeRectCoherent(
computeRect,
tile.m_pos); // Make it coherent with tile's pixel geometry
}
// Calculate the input port and perform processing
TDimension computeSize(tround(computeRect.getLx()),
tround(computeRect.getLy()));
if ((computeSize.lx > 0) && (computeSize.ly > 0)) {
TTile inTile; // Observe its locality - not incidental
(*port)->allocateAndCompute(inTile, computeRect.getP00(), computeSize,
tile.getRaster(), frame, info);
// Invoke process() to deal with the actual fx processing
TRasterP up(inTile.getRaster()), down(tile.getRaster());
if (canRestrict) {
// Extract from tile the part corresponding to inTile
TRect downRect(convert(computeRect.getP00() - tile.m_pos), computeSize);
down = down->extract(downRect);
}
assert(up->getSize() == down->getSize());
process(up, down, frame); // This is the point with the max concentration
// of allocated resources
}
}
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void TImageCombinationFx::doDryCompute(TRectD &rect, double frame,
const TRenderSettings &info) {
// Mere copy of doCompute(), stripped of the actual computations
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int p, pCount = getInputPortCount();
TRasterFxPort *port = 0;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
for (p = pCount - 1; p >= 0; --p) {
port = static_cast<TRasterFxPort *>(getInputPort(p));
if (port && port->getFx()) break;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (p < 0) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
(*port)->dryCompute(rect, frame, info);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
bool canRestrict = !requiresFullRect();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
for (--p; p >= 0; --p) {
port = static_cast<TRasterFxPort *>(getInputPort(p));
if (!(port && port->getFx())) continue;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TRectD computeRect(rect);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (canRestrict) {
TRectD inBBox;
(*port)->getBBox(frame, inBBox, info);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
computeRect *= inBBox;
makeRectCoherent(computeRect, rect.getP00());
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TDimension computeSize(tround(computeRect.getLx()),
tround(computeRect.getLy()));
if ((computeSize.lx > 0) && (computeSize.ly > 0))
(*port)->dryCompute(computeRect, frame, info);
}
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void TImageCombinationFx::compatibilityTranslatePort(int major, int minor,
std::string &portName) {
if (VersionNumber(major, minor) < VersionNumber(1, 20)) {
if (portName == "Up")
portName = "Source1";
else if (portName == "Down")
portName = "Source2";
}
2016-03-19 06:57:51 +13:00
}
//******************************************************************************************
// TImageCombinationFx heir classes
//******************************************************************************************
2016-06-15 18:43:10 +12:00
class OverFx : public TImageCombinationFx {
FX_DECLARATION(OverFx)
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
OverFx() { setName(L"OverFx"); }
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
TRop::over(down, up);
}
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class AddFx : public TImageCombinationFx {
FX_DECLARATION(AddFx)
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TDoubleParamP m_value;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
AddFx() : m_value(100.0) { bindParam(this, "value", m_value); }
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
double value = m_value->getValue(frame) / 100.0;
if (value != 1.0)
TRop::add(up, down, down, value);
else
TRop::add(up, down, down);
}
2016-06-19 20:06:29 +12:00
TFxPort *getXsheetPort() const override { return getInputPort(1); }
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class ColorDodgeFx : public TImageCombinationFx {
FX_DECLARATION(AddFx)
2016-03-19 06:57:51 +13:00
public:
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
TRop::colordodge(up, down, down);
}
2016-06-19 20:06:29 +12:00
TFxPort *getXsheetPort() const override { return getInputPort(1); }
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class ColorBurnFx : public TImageCombinationFx {
FX_DECLARATION(AddFx)
2016-03-19 06:57:51 +13:00
public:
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
TRop::colorburn(up, down, down);
}
2016-06-19 20:06:29 +12:00
TFxPort *getXsheetPort() const override { return getInputPort(1); }
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class ScreenFx : public TImageCombinationFx {
FX_DECLARATION(AddFx)
2016-03-19 06:57:51 +13:00
public:
2016-06-19 20:06:29 +12:00
bool requiresFullRect() override { return true; }
2016-03-19 06:57:51 +13:00
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
TRop::screen(up, down, down);
}
2016-03-19 06:57:51 +13:00
2016-06-19 20:06:29 +12:00
TFxPort *getXsheetPort() const override { return getInputPort(1); }
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class SubFx : public TImageCombinationFx {
FX_DECLARATION(SubFx)
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TBoolParamP m_matte;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
SubFx() : m_matte(false) { bindParam(this, "matte", m_matte); }
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
TRop::sub(up, down, down, m_matte->getValue());
}
2016-06-19 20:06:29 +12:00
TFxPort *getXsheetPort() const override { return getInputPort(1); }
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class MultFx : public TImageCombinationFx {
FX_DECLARATION(MultFx)
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TDoubleParamP m_value;
TBoolParamP m_matte;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
MultFx() : m_value(0.0), m_matte(false) {
bindParam(this, "value", m_value);
bindParam(this, "matte", m_matte);
}
2016-06-19 20:06:29 +12:00
bool requiresFullRect() override { return m_matte->getValue(); }
2016-06-15 18:43:10 +12:00
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
TRop::mult(up, down, down, m_value->getValue(frame), m_matte->getValue());
}
2016-06-19 20:06:29 +12:00
TFxPort *getXsheetPort() const override { return getInputPort(1); }
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class MinFx : public TImageCombinationFx {
FX_DECLARATION(MinFx)
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TBoolParamP m_matte;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
MinFx() : m_matte(true) { bindParam(this, "matte", m_matte); }
2016-06-19 20:06:29 +12:00
bool requiresFullRect() override { return true; }
2016-06-15 18:43:10 +12:00
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
TRop::ropmin(up, down, down, m_matte->getValue());
}
2016-06-19 20:06:29 +12:00
TFxPort *getXsheetPort() const override { return getInputPort(1); }
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class MaxFx : public TImageCombinationFx {
FX_DECLARATION(MaxFx)
2016-03-19 06:57:51 +13:00
public:
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
TRop::ropmax(up, down, down);
}
2016-06-19 20:06:29 +12:00
TFxPort *getXsheetPort() const override { return getInputPort(1); }
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class LinearBurnFx : public TImageCombinationFx {
FX_DECLARATION(LinearBurnFx)
2016-03-19 06:57:51 +13:00
public:
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
TRop::linearburn(up, down, down);
}
2016-06-19 20:06:29 +12:00
TFxPort *getXsheetPort() const override { return getInputPort(1); }
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
// This Fx is probably unused...!
class OverlayFx : public TImageCombinationFx {
FX_DECLARATION(OverlayFx)
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
OverlayFx() {}
~OverlayFx() {}
2016-03-19 06:57:51 +13:00
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
TRop::overlay(up, down, down);
}
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class BlendFx : public TImageCombinationFx {
FX_DECLARATION(BlendFx)
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TDoubleParamP m_value;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
BlendFx() : m_value(0.0) {
bindParam(this, "value", m_value);
m_value->setValueRange(0.0, 100.0);
}
2016-06-19 20:06:29 +12:00
bool requiresFullRect() override { return true; }
2016-06-15 18:43:10 +12:00
2016-06-20 14:23:05 +12:00
void process(const TRasterP &up, const TRasterP &down,
double frame) override {
2016-06-15 18:43:10 +12:00
double value = 0.01 * m_value->getValue(frame);
UCHAR matteValue = (UCHAR)(value * 255.0 + 0.5);
TRop::crossDissolve(up, down, down, matteValue);
}
2016-06-19 20:06:29 +12:00
TFxPort *getXsheetPort() const override { return getInputPort(1); }
2016-03-19 06:57:51 +13:00
};
//******************************************************************************************
// Matte Fxs definition
//******************************************************************************************
2016-06-15 18:43:10 +12:00
class InFx : public TBaseRasterFx {
FX_DECLARATION(InFx)
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TRasterFxPort m_source, m_matte;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
InFx() {
addInputPort("Source", m_source);
addInputPort("Matte", m_matte);
setName(L"InFx");
}
~InFx() {}
2016-06-20 14:23:05 +12:00
bool doGetBBox(double frame, TRectD &bbox,
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
if (m_matte.isConnected() && m_source.isConnected()) {
bool ret = m_matte->doGetBBox(frame, bbox, info);
if (bbox == TConsts::infiniteRectD)
return m_source->doGetBBox(frame, bbox, info);
else
return ret;
}
bbox = TRectD();
return false;
}
2016-06-20 14:23:05 +12:00
bool canHandle(const TRenderSettings &info, double frame) override {
return true;
}
2016-06-15 18:43:10 +12:00
2016-06-20 14:23:05 +12:00
void doCompute(TTile &tile, double frame,
const TRenderSettings &ri) override {
2016-06-15 18:43:10 +12:00
// This fx is not visible if either the source or the matte tiles are empty.
// It's because only source is visible, and only where matte is opaque.
if (!(m_source.isConnected() && m_matte.isConnected())) return;
TTile srcTile;
m_source->allocateAndCompute(srcTile, tile.m_pos,
tile.getRaster()->getSize(), tile.getRaster(),
frame, ri);
m_matte->compute(tile, frame, ri);
TRop::ropin(srcTile.getRaster(), tile.getRaster(), tile.getRaster());
}
2016-06-20 14:23:05 +12:00
void doDryCompute(TRectD &rect, double frame,
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
if (!(m_source.isConnected() && m_matte.isConnected())) return;
m_source->dryCompute(rect, frame, info);
m_matte->dryCompute(rect, frame, info);
}
int getMemoryRequirement(const TRectD &rect, double frame,
2016-06-19 20:06:29 +12:00
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
return TRasterFx::memorySize(rect, info.m_bpp);
}
2016-06-19 20:06:29 +12:00
void compute(TFlash &flash, int frame) override {
2016-06-15 18:43:10 +12:00
if (m_matte.isConnected()) {
flash.pushMatrix();
flash.beginMask();
((TRasterFxP)(m_matte.getFx()))->compute(flash, frame);
flash.endMask();
flash.popMatrix();
}
if (m_source.isConnected()) {
flash.pushMatrix();
flash.enableMask();
((TRasterFxP)(m_source.getFx()))->compute(flash, frame);
flash.disableMask();
flash.popMatrix();
}
}
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class OutFx : public TBaseRasterFx {
FX_DECLARATION(OutFx)
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TRasterFxPort m_source, m_matte;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
OutFx() {
addInputPort("Source", m_source);
addInputPort("Matte", m_matte);
setName(L"OutFx");
}
~OutFx() {}
2016-06-20 14:23:05 +12:00
bool doGetBBox(double frame, TRectD &bbox,
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
if (m_source.isConnected()) return m_source->doGetBBox(frame, bbox, info);
return false;
}
2016-06-20 14:23:05 +12:00
bool canHandle(const TRenderSettings &info, double frame) override {
return true;
}
2016-06-15 18:43:10 +12:00
2016-06-20 14:23:05 +12:00
void doCompute(TTile &tile, double frame,
const TRenderSettings &ri) override {
2016-06-15 18:43:10 +12:00
// If there is no source, do nothing
if (!m_source.isConnected()) return;
// Here, source is visible where matte is transparent. So if there is
// no matte, just build source.
if (!m_matte.isConnected()) {
m_source->compute(tile, frame, ri);
return;
}
TTile srcTile;
m_source->allocateAndCompute(srcTile, tile.m_pos,
tile.getRaster()->getSize(), tile.getRaster(),
frame, ri);
m_matte->compute(tile, frame, ri);
TRop::ropout(srcTile.getRaster(), tile.getRaster(), tile.getRaster());
}
2016-06-20 14:23:05 +12:00
void doDryCompute(TRectD &rect, double frame,
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
if (!m_source.isConnected()) return;
if (!m_matte.isConnected()) {
m_source->dryCompute(rect, frame, info);
return;
}
m_source->dryCompute(rect, frame, info);
m_matte->dryCompute(rect, frame, info);
}
int getMemoryRequirement(const TRectD &rect, double frame,
2016-06-19 20:06:29 +12:00
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
return TRasterFx::memorySize(rect, info.m_bpp);
}
2016-03-19 06:57:51 +13:00
};
//==================================================================
2016-06-15 18:43:10 +12:00
class AtopFx : public TBaseRasterFx {
FX_DECLARATION(AtopFx)
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TRasterFxPort m_up, m_dn;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
AtopFx() {
addInputPort("Up", m_up);
addInputPort("Down", m_dn);
}
2016-03-19 06:57:51 +13:00
2016-06-20 14:23:05 +12:00
bool canHandle(const TRenderSettings &info, double frame) override {
return true;
}
2016-03-19 06:57:51 +13:00
2016-06-20 14:23:05 +12:00
bool doGetBBox(double frame, TRectD &bBox,
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
bBox = TRectD();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
{
TRectD inputBBox;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
bool hasInput =
m_up.isConnected() ? m_up->doGetBBox(frame, inputBBox, info) : false;
if (hasInput) bBox += inputBBox;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
{
TRectD inputBBox;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
bool hasInput =
m_dn.isConnected() ? m_dn->doGetBBox(frame, inputBBox, info) : false;
if (hasInput) bBox += inputBBox;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
return (bBox.getLx() >= 0) && (bBox.getLy() >= 0);
}
2016-03-19 06:57:51 +13:00
2016-06-20 14:23:05 +12:00
void doCompute(TTile &tile, double frame,
const TRenderSettings &ri) override {
2016-06-15 18:43:10 +12:00
// Here it's just like matte in, but the matte is visible under up.
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (!m_dn.isConnected()) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (!m_up.isConnected()) {
m_dn->compute(tile, frame, ri);
return;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TTile upTile;
m_up->allocateAndCompute(upTile, tile.m_pos, tile.getRaster()->getSize(),
tile.getRaster(), frame, ri);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
m_dn->compute(tile, frame, ri);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TRop::atop(upTile.getRaster(), tile.getRaster(), tile.getRaster());
}
2016-03-19 06:57:51 +13:00
2016-06-20 14:23:05 +12:00
void doDryCompute(TRectD &rect, double frame,
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
if (!m_dn.isConnected()) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (!m_up.isConnected()) {
m_dn->dryCompute(rect, frame, info);
return;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
m_up->dryCompute(rect, frame, info);
m_dn->dryCompute(rect, frame, info);
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int getMemoryRequirement(const TRectD &rect, double frame,
2016-06-19 20:06:29 +12:00
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
return TRasterFx::memorySize(rect, info.m_bpp);
}
2016-03-19 06:57:51 +13:00
};
//==================================================================
//=======================
// Fx identifiers
//-----------------------
FX_IDENTIFIER(OverFx, "overFx")
FX_IDENTIFIER(AddFx, "addFx")
FX_IDENTIFIER(SubFx, "subFx")
FX_IDENTIFIER(MultFx, "multFx")
FX_IDENTIFIER(InFx, "inFx")
FX_IDENTIFIER(OutFx, "outFx")
FX_IDENTIFIER(AtopFx, "atopFx")
2016-06-15 18:43:10 +12:00
// FX_IDENTIFIER(XorFx, "xorFx")
2016-03-19 06:57:51 +13:00
FX_IDENTIFIER(MinFx, "minFx")
FX_IDENTIFIER(MaxFx, "maxFx")
FX_IDENTIFIER(LinearBurnFx, "linearBurnFx")
FX_IDENTIFIER(OverlayFx, "overlayFx")
FX_IDENTIFIER(BlendFx, "blendFx")
FX_IDENTIFIER(ColorDodgeFx, "colorDodgeFx")
FX_IDENTIFIER(ColorBurnFx, "colorBurnFx")
FX_IDENTIFIER(ScreenFx, "screenFx")