b3bd842e04
This patch used -Wmissing-declarations warning to show functions and symbols that had no declarations, and either: - Make static - Add to header This helps avoid possability that declarations and functions get out of sync. And ensures all source files reference headers correctly. It also makes sure functions defined with extern "C", have this defined in the header. An error found in calligraph.h while writing this patch. This has been applied to toonzlib, to avoid making very large global changes. If accepted, -Wmissing-declarations warning could be added to CMake.
1913 lines
61 KiB
C++
1913 lines
61 KiB
C++
|
||
|
||
// TnzCore includes
|
||
#include "tsystem.h"
|
||
#include "tstream.h"
|
||
#include "tthreadmessage.h"
|
||
#include "tconvert.h"
|
||
#include "tstopwatch.h"
|
||
#include "tlevel_io.h"
|
||
#include "tflash.h"
|
||
#include "trasterimage.h"
|
||
#include "ttoonzimage.h"
|
||
#include "tvectorimage.h"
|
||
#include "timagecache.h"
|
||
#include "timageinfo.h"
|
||
#include "tropcm.h"
|
||
#include "tofflinegl.h"
|
||
#include "tvectorrenderdata.h"
|
||
|
||
// TnzBase includes
|
||
#include "ttzpimagefx.h"
|
||
#include "trasterfx.h"
|
||
#include "tzeraryfx.h"
|
||
#include "trenderer.h"
|
||
#include "tfxcachemanager.h"
|
||
|
||
// TnzLib includes
|
||
#include "toonz/toonzscene.h"
|
||
#include "toonz/txsheet.h"
|
||
#include "toonz/txshlevelcolumn.h"
|
||
#include "toonz/txshpalettecolumn.h"
|
||
#include "toonz/txshzeraryfxcolumn.h"
|
||
#include "toonz/txshlevel.h"
|
||
#include "toonz/txshcell.h"
|
||
#include "toonz/txshsimplelevel.h"
|
||
#include "toonz/txshpalettelevel.h"
|
||
#include "toonz/txshleveltypes.h"
|
||
#include "toonz/levelset.h"
|
||
#include "toonz/txshchildlevel.h"
|
||
#include "toonz/fxdag.h"
|
||
#include "toonz/tcolumnfxset.h"
|
||
#include "toonz/stage.h"
|
||
#include "toonz/fill.h"
|
||
#include "toonz/tstageobjectid.h"
|
||
#include "toonz/tstageobject.h"
|
||
#include "toonz/levelproperties.h"
|
||
#include "toonz/imagemanager.h"
|
||
#include "toonz/toonzimageutils.h"
|
||
#include "toonz/tvectorimageutils.h"
|
||
#include "toonz/preferences.h"
|
||
#include "toonz/dpiscale.h"
|
||
#include "imagebuilders.h"
|
||
|
||
// 4.6 compatibility - sandor fxs
|
||
#include "toonz4.6/raster.h"
|
||
#include "sandor_fxs/blend.h"
|
||
extern "C" {
|
||
#include "sandor_fxs/calligraph.h"
|
||
#include "sandor_fxs/patternmap.h"
|
||
}
|
||
|
||
#include "toonz/tcolumnfx.h"
|
||
|
||
//****************************************************************************************
|
||
// Preliminaries
|
||
//****************************************************************************************
|
||
|
||
#ifdef _WIN32
|
||
template class DV_EXPORT_API TFxDeclarationT<TLevelColumnFx>;
|
||
template class DV_EXPORT_API TFxDeclarationT<TZeraryColumnFx>;
|
||
template class DV_EXPORT_API TFxDeclarationT<TXsheetFx>;
|
||
template class DV_EXPORT_API TFxDeclarationT<TOutputFx>;
|
||
#endif
|
||
|
||
TFxDeclarationT<TLevelColumnFx> columnFxInfo(TFxInfo("Toonz_columnFx", true));
|
||
TFxDeclarationT<TPaletteColumnFx> paletteColumnFxInfo(
|
||
TFxInfo("Toonz_paletteColumnFx", true));
|
||
TFxDeclarationT<TZeraryColumnFx> zeraryColumnFxInfo(
|
||
TFxInfo("Toonz_zeraryColumnFx", true));
|
||
TFxDeclarationT<TXsheetFx> infoTXsheetFx(TFxInfo("Toonz_xsheetFx", true));
|
||
TFxDeclarationT<TOutputFx> infoTOutputFx(TFxInfo("Toonz_outputFx", true));
|
||
|
||
//****************************************************************************************
|
||
// Local namespace - misc functions
|
||
//****************************************************************************************
|
||
|
||
namespace {
|
||
|
||
void setMaxMatte(TRasterP r) {
|
||
TRaster32P r32 = (TRaster32P)r;
|
||
|
||
TRaster64P r64 = (TRaster64P)r;
|
||
|
||
if (r32)
|
||
for (int i = 0; i < r32->getLy(); i++) {
|
||
TPixel *pix = r32->pixels(i);
|
||
for (int j = 0; j < r32->getLx(); j++, pix++) pix->m = 255;
|
||
}
|
||
else if (r64)
|
||
for (int i = 0; i < r64->getLy(); i++) {
|
||
TPixel64 *pix = r64->pixels(i);
|
||
for (int j = 0; j < r64->getLx(); j++, pix++) pix->m = 65535;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------------------------------------
|
||
|
||
char *strsave(const char *t) {
|
||
char *s;
|
||
s = (char *)malloc(
|
||
strlen(t) +
|
||
1); // I'm almost sure that this malloc is LEAKED! Please, check that !
|
||
strcpy(s, t);
|
||
return s;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
inline TRect myConvert(const TRectD &r) {
|
||
return TRect(tfloor(r.x0), tfloor(r.y0), tceil(r.x1), tceil(r.y1));
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
inline TRect myConvert(const TRectD &r, TPointD &dp) {
|
||
TRect ri(tfloor(r.x0), tfloor(r.y0), tceil(r.x1), tceil(r.y1));
|
||
dp.x = r.x0 - ri.x0;
|
||
dp.y = r.y0 - ri.y0;
|
||
assert(dp.x >= 0 && dp.y >= 0);
|
||
return ri;
|
||
}
|
||
|
||
//--------------------------------------------------
|
||
|
||
// Currently used on debug only
|
||
inline QString traduce(const TRectD &rect) {
|
||
return "[" + QString::number(rect.x0) + " " + QString::number(rect.y0) + " " +
|
||
QString::number(rect.x1) + " " + QString::number(rect.y1) + "]";
|
||
}
|
||
|
||
//--------------------------------------------------
|
||
|
||
// Currently used on debug only
|
||
inline QString traduce(const TRectD &rect, const TRenderSettings &info) {
|
||
return "[" + QString::number(rect.x0) + " " + QString::number(rect.y0) + " " +
|
||
QString::number(rect.x1) + " " + QString::number(rect.y1) +
|
||
"]; aff = (" + QString::number(info.m_affine.a11, 'f') + " " +
|
||
QString::number(info.m_affine.a12, 'f') + " " +
|
||
QString::number(info.m_affine.a13, 'f') + " " +
|
||
QString::number(info.m_affine.a21, 'f') + " " +
|
||
QString::number(info.m_affine.a22, 'f') + " " +
|
||
QString::number(info.m_affine.a23, 'f') + ")";
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
inline int colorDistance(const TPixel32 &c0, const TPixel32 &c1) {
|
||
return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) +
|
||
(c0.b - c1.b) * (c0.b - c1.b);
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::string getAlias(TXsheet *xsh, double frame, const TRenderSettings &info) {
|
||
TFxSet *fxs = xsh->getFxDag()->getTerminalFxs();
|
||
std::string alias;
|
||
|
||
// Add the alias for each
|
||
for (int i = 0; i < fxs->getFxCount(); ++i) {
|
||
TRasterFx *fx = dynamic_cast<TRasterFx *>(fxs->getFx(i));
|
||
assert(fx);
|
||
if (!fx) continue;
|
||
|
||
alias += fx->getAlias(frame, info) + ";";
|
||
}
|
||
|
||
return alias;
|
||
}
|
||
|
||
} // namespace
|
||
|
||
//****************************************************************************************
|
||
// Local namespace - Colormap (Sandor) Fxs stuff
|
||
//****************************************************************************************
|
||
|
||
static bool vectorMustApplyCmappedFx(const std::vector<TRasterFxRenderDataP> &fxs) {
|
||
std::vector<TRasterFxRenderDataP>::const_iterator ft, fEnd(fxs.end());
|
||
for (ft = fxs.begin(); ft != fEnd; ++ft) {
|
||
PaletteFilterFxRenderData *paletteFilterData =
|
||
dynamic_cast<PaletteFilterFxRenderData *>(ft->getPointer());
|
||
SandorFxRenderData *sandorData =
|
||
dynamic_cast<SandorFxRenderData *>(ft->getPointer());
|
||
|
||
// (Daniele) Sandor fxs perform on raster colormaps *only* - while texture
|
||
// fxs use palette filters to work.
|
||
// In the latter case, vector-to-colormap conversion makes sure that regions
|
||
// are not rendered under full ink
|
||
// pixels (which causes problems**).
|
||
if (sandorData || (paletteFilterData &&
|
||
paletteFilterData->m_type != ::eApplyToInksAndPaints))
|
||
return true;
|
||
|
||
/*
|
||
(Daniele) Disregarding the above reasons - palette filter fxs do not forcibly
|
||
return true.
|
||
|
||
Err... ok, my fault - when I wrote that, I forgot to specify WHICH problems**
|
||
occurred. Whops!
|
||
|
||
Now, it happens that if palette filters DO NOT convert to colormapped forcedly,
|
||
special styles can be
|
||
retained... so, let's see what happens.
|
||
|
||
Will have to inquire further, though...
|
||
*/
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
static bool mustApplySandorFx(const std::vector<TRasterFxRenderDataP> &fxs) {
|
||
std::vector<TRasterFxRenderDataP>::const_iterator ft, fEnd(fxs.end());
|
||
for (ft = fxs.begin(); ft != fEnd; ++ft) {
|
||
SandorFxRenderData *sandorData =
|
||
dynamic_cast<SandorFxRenderData *>(ft->getPointer());
|
||
|
||
if (sandorData) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
static int getEnlargement(const std::vector<TRasterFxRenderDataP> &fxs, double scale) {
|
||
int enlargement = 1;
|
||
|
||
std::vector<TRasterFxRenderDataP>::const_iterator ft, fEnd(fxs.end());
|
||
for (ft = fxs.begin(); ft != fEnd; ++ft) {
|
||
SandorFxRenderData *sandorData =
|
||
dynamic_cast<SandorFxRenderData *>(ft->getPointer());
|
||
|
||
if (sandorData) {
|
||
switch (sandorData->m_type) {
|
||
case BlendTz: {
|
||
// Nothing happen, unless we have color 0 among the blended ones. In
|
||
// such case,
|
||
// we have to enlarge the bbox proportionally to the amount param.
|
||
std::vector<std::string> items;
|
||
std::string indexes = std::string(sandorData->m_argv[0]);
|
||
parseIndexes(indexes, items);
|
||
PaletteFilterFxRenderData paletteFilterData;
|
||
insertIndexes(items, &paletteFilterData);
|
||
|
||
if (!paletteFilterData.m_colors.empty() &&
|
||
*paletteFilterData.m_colors.begin() == 0) {
|
||
BlendTzParams ¶ms = sandorData->m_blendParams;
|
||
enlargement = params.m_amount * scale;
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
case Calligraphic:
|
||
case OutBorder: {
|
||
CalligraphicParams ¶ms = sandorData->m_callParams;
|
||
enlargement = params.m_thickness * scale;
|
||
|
||
break;
|
||
}
|
||
|
||
case ArtAtContour: {
|
||
ArtAtContourParams ¶ms = sandorData->m_contourParams;
|
||
enlargement = std::max(tceil(sandorData->m_controllerBBox.getLx()),
|
||
tceil(sandorData->m_controllerBBox.getLy())) *
|
||
params.m_maxSize;
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return enlargement;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
static void applyPaletteFilter(TPalette *&plt, bool keep, const set<int> &colors,
|
||
const TPalette *srcPlt) {
|
||
if (colors.empty()) return;
|
||
|
||
if (!plt) plt = srcPlt->clone();
|
||
|
||
if (keep) {
|
||
for (int i = 0; i < plt->getStyleCount(); ++i) {
|
||
if (colors.find(i) == colors.end())
|
||
plt->setStyle(i, TPixel32::Transparent);
|
||
}
|
||
} else {
|
||
std::set<int>::const_iterator ct, cEnd(colors.end());
|
||
for (ct = colors.begin(); ct != cEnd; ++ct) {
|
||
TColorStyle *style = plt->getStyle(*ct);
|
||
if (style) plt->setStyle(*ct, TPixel32::Transparent);
|
||
}
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
static TPalette *getPliPalette(const TFilePath &path) {
|
||
TLevelReaderP levelReader = TLevelReaderP(path);
|
||
if (!levelReader.getPointer()) return 0;
|
||
|
||
TLevelP level = levelReader->loadInfo();
|
||
TPalette *plt = level->getPalette();
|
||
|
||
return plt ? plt->clone() : (TPalette *)0;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
inline bool fxLess(TRasterFxRenderDataP a, TRasterFxRenderDataP b) {
|
||
SandorFxRenderData *sandorDataA =
|
||
dynamic_cast<SandorFxRenderData *>(a.getPointer());
|
||
if (!sandorDataA) return false;
|
||
|
||
SandorFxRenderData *sandorDataB =
|
||
dynamic_cast<SandorFxRenderData *>(b.getPointer());
|
||
if (!sandorDataB) return true;
|
||
|
||
int aIndex = sandorDataA->m_type == OutBorder
|
||
? 2
|
||
: sandorDataA->m_type == BlendTz ? 1 : 0;
|
||
int bIndex = sandorDataB->m_type == OutBorder
|
||
? 2
|
||
: sandorDataB->m_type == BlendTz ? 1 : 0;
|
||
|
||
return aIndex < bIndex;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
inline void sortCmappedFxs(std::vector<TRasterFxRenderDataP> &fxs) {
|
||
std::stable_sort(fxs.begin(), fxs.end(), fxLess);
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
static std::vector<int> getAllBut(std::vector<int> &colorIds) {
|
||
assert(TPixelCM32::getMaxInk() == TPixelCM32::getMaxPaint());
|
||
|
||
std::vector<int> curColorIds;
|
||
std::sort(colorIds.begin(), colorIds.end());
|
||
|
||
// Taking all colors EXCEPT those in colorIds
|
||
unsigned int count1 = 0, count2 = 0;
|
||
int size = TPixelCM32::getMaxInk();
|
||
|
||
curColorIds.resize(size + 1 - colorIds.size());
|
||
for (int i = 0; i < size; i++)
|
||
if (count1 < colorIds.size() && colorIds[count1] == i)
|
||
count1++;
|
||
else
|
||
curColorIds[count2++] = i;
|
||
|
||
return curColorIds;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
//! \b IMPORTANT \b NOTE: This function is now written so that the passed Toonz
|
||
//! Image
|
||
//! will be destroyed at the most appropriate time. You should definitely *COPY*
|
||
//! all
|
||
//! necessary informations before calling it - however, since the intent was
|
||
//! that of
|
||
//! optimizing memory usage, please avoid copying the entire image buffer...
|
||
|
||
static TImageP applyCmappedFx(TToonzImageP &ti,
|
||
const std::vector<TRasterFxRenderDataP> &fxs, int frame,
|
||
double scale) {
|
||
TImageP result = ti;
|
||
TTile resultTile; // Just a quick wrapper to the ImageCache
|
||
TPalette *inPalette, *tempPlt;
|
||
TPaletteP filteredPalette;
|
||
TRasterCM32P copyRas;
|
||
std::string cmRasCacheId;
|
||
|
||
// Retrieve the image dpi
|
||
double dpiX, dpiY;
|
||
ti->getDpi(dpiX, dpiY);
|
||
double dpi = (dpiX > 0) ? dpiX / Stage::inch : 1.0;
|
||
|
||
// First, sort the fxs.
|
||
std::vector<TRasterFxRenderDataP> fxsCopy = fxs;
|
||
sortCmappedFxs(fxsCopy);
|
||
|
||
// First, let's deal with all fxs working on palettes
|
||
inPalette = ti->getPalette();
|
||
|
||
std::vector<TRasterFxRenderDataP>::reverse_iterator it;
|
||
for (it = fxsCopy.rbegin(); it != fxsCopy.rend(); ++it) {
|
||
ExternalPaletteFxRenderData *extpltData =
|
||
dynamic_cast<ExternalPaletteFxRenderData *>((*it).getPointer());
|
||
PaletteFilterFxRenderData *PaletteFilterData =
|
||
dynamic_cast<PaletteFilterFxRenderData *>((*it).getPointer());
|
||
if (extpltData && extpltData->m_palette) {
|
||
filteredPalette = extpltData->m_palette->clone();
|
||
filteredPalette->setFrame(frame);
|
||
} else if (PaletteFilterData &&
|
||
PaletteFilterData->m_type == eApplyToInksAndPaints) {
|
||
bool keep = PaletteFilterData->m_keep;
|
||
|
||
set<int> colors;
|
||
colors.insert(PaletteFilterData->m_colors.begin(),
|
||
PaletteFilterData->m_colors.end());
|
||
|
||
// Apply the palette filters
|
||
tempPlt = filteredPalette.getPointer();
|
||
applyPaletteFilter(tempPlt, keep, colors, inPalette);
|
||
filteredPalette = tempPlt;
|
||
|
||
inPalette = filteredPalette.getPointer();
|
||
}
|
||
}
|
||
|
||
if (filteredPalette) {
|
||
// result= ti = ti->clone(); //Is copying truly necessary??
|
||
result = ti = TToonzImageP(ti->getRaster(), ti->getSavebox());
|
||
filteredPalette->setFrame(frame);
|
||
ti->setPalette(filteredPalette.getPointer());
|
||
}
|
||
|
||
// Next, deal with fxs working on colormaps themselves
|
||
bool firstSandorFx = true;
|
||
TRasterCM32P cmRas = ti->getRaster();
|
||
TRect tiSaveBox(ti->getSavebox());
|
||
TPaletteP tiPalette(ti->getPalette());
|
||
ti = 0; // Release the reference to colormap
|
||
|
||
// Now, apply cmapped->cmapped fxs
|
||
for (it = fxsCopy.rbegin(); it != fxsCopy.rend(); ++it) {
|
||
PaletteFilterFxRenderData *PaletteFilterData =
|
||
dynamic_cast<PaletteFilterFxRenderData *>(it->getPointer());
|
||
if (PaletteFilterData &&
|
||
PaletteFilterData->m_type != eApplyToInksAndPaints) {
|
||
std::vector<int> indexes;
|
||
indexes.resize(PaletteFilterData->m_colors.size());
|
||
|
||
set<int>::const_iterator jt = PaletteFilterData->m_colors.begin();
|
||
for (int j = 0; j < (int)indexes.size(); ++j, ++jt) indexes[j] = *jt;
|
||
|
||
if (copyRas == TRasterCM32P())
|
||
copyRas =
|
||
cmRas->clone(); // Pixels are literally cleared on a copy buffer
|
||
|
||
/*-- 処理するIndexを反転 --*/
|
||
if (PaletteFilterData->m_keep) indexes = getAllBut(indexes);
|
||
|
||
/*-- Paintの消去("Lines Including All
|
||
* Areas"のみ、Areaに何も操作をしない) --*/
|
||
if (PaletteFilterData->m_type !=
|
||
eApplyToInksKeepingAllPaints) // se non e'
|
||
// eApplyToInksKeepingAllPaints,
|
||
// sicuramente devo cancellare dei
|
||
// paint
|
||
TRop::eraseColors(
|
||
copyRas, PaletteFilterData->m_type == eApplyToInksDeletingAllPaints
|
||
? 0
|
||
: &indexes,
|
||
false);
|
||
|
||
/*-- Inkの消去 --*/
|
||
if (PaletteFilterData->m_type !=
|
||
eApplyToPaintsKeepingAllInks) // se non e'
|
||
// eApplyToPaintsKeepingAllInks,
|
||
// sicuramente devo cancellare degli
|
||
// ink
|
||
TRop::eraseColors(
|
||
copyRas, PaletteFilterData->m_type == eApplyToPaintsDeletingAllInks
|
||
? 0
|
||
: &indexes,
|
||
true);
|
||
}
|
||
}
|
||
|
||
if (copyRas) {
|
||
cmRas = copyRas;
|
||
result = TToonzImageP(cmRas, tiSaveBox);
|
||
result->setPalette(tiPalette.getPointer());
|
||
}
|
||
|
||
// Finally, apply cmapped->fullcolor fxs
|
||
|
||
// Prefetch all Blend fxs
|
||
std::vector<BlendParam> blendParams;
|
||
for (it = fxsCopy.rbegin(); it != fxsCopy.rend(); ++it) {
|
||
SandorFxRenderData *sandorData =
|
||
dynamic_cast<SandorFxRenderData *>(it->getPointer());
|
||
if (sandorData && sandorData->m_type == BlendTz) {
|
||
BlendParam param;
|
||
|
||
param.intensity =
|
||
std::stod(std::string(sandorData->m_argv[3])) * scale * dpi;
|
||
param.smoothness = sandorData->m_blendParams.m_smoothness;
|
||
param.stopAtCountour = sandorData->m_blendParams.m_noBlending;
|
||
|
||
param.superSampling = sandorData->m_blendParams.m_superSampling;
|
||
|
||
// Build the color indexes
|
||
std::vector<std::string> items;
|
||
std::string indexes = std::string(sandorData->m_argv[0]);
|
||
parseIndexes(indexes, items);
|
||
PaletteFilterFxRenderData paletteFilterData;
|
||
insertIndexes(items, &paletteFilterData);
|
||
|
||
param.colorsIndexes.reserve(paletteFilterData.m_colors.size());
|
||
|
||
std::set<int>::iterator it;
|
||
for (it = paletteFilterData.m_colors.begin();
|
||
it != paletteFilterData.m_colors.end(); ++it)
|
||
param.colorsIndexes.push_back(*it);
|
||
|
||
blendParams.push_back(param);
|
||
}
|
||
}
|
||
|
||
// Apply each sandor
|
||
for (it = fxsCopy.rbegin(); it != fxsCopy.rend(); ++it) {
|
||
SandorFxRenderData *sandorData =
|
||
dynamic_cast<SandorFxRenderData *>(it->getPointer());
|
||
|
||
if (sandorData) {
|
||
// Avoid dealing with specific cases
|
||
if ((sandorData->m_type == BlendTz && blendParams.empty()) ||
|
||
(sandorData->m_type == OutBorder && !firstSandorFx))
|
||
continue;
|
||
|
||
if (!firstSandorFx) {
|
||
// Retrieve the colormap from cache
|
||
cmRas = TToonzImageP(TImageCache::instance()->get(cmRasCacheId, true))
|
||
->getRaster();
|
||
|
||
// Apply a palette filter in order to keep only the colors specified in
|
||
// the sandor argv
|
||
std::vector<std::string> items;
|
||
std::string indexes = std::string(sandorData->m_argv[0]);
|
||
parseIndexes(indexes, items);
|
||
PaletteFilterFxRenderData paletteFilterData;
|
||
insertIndexes(items, &paletteFilterData);
|
||
|
||
filteredPalette = tempPlt = 0;
|
||
applyPaletteFilter(tempPlt, true, paletteFilterData.m_colors,
|
||
tiPalette.getPointer());
|
||
filteredPalette = tempPlt;
|
||
} else {
|
||
// Pass the input colormap to the cache and release its reference as
|
||
// final result
|
||
cmRasCacheId = TImageCache::instance()->getUniqueId();
|
||
TImageCache::instance()->add(cmRasCacheId,
|
||
TToonzImageP(cmRas, tiSaveBox));
|
||
result = 0;
|
||
}
|
||
|
||
// Convert current smart pointers to a 4.6 'fashion'. The former ones are
|
||
// released - so they
|
||
// do not occupy smart object references.
|
||
RASTER *oldRasterIn, *oldRasterOut;
|
||
oldRasterIn = TRop::convertRaster50to46(
|
||
cmRas, filteredPalette ? filteredPalette : tiPalette.getPointer());
|
||
cmRas = TRasterCM32P(0);
|
||
{
|
||
TRaster32P rasterOut(TDimension(oldRasterIn->lx, oldRasterIn->ly));
|
||
oldRasterOut = TRop::convertRaster50to46(rasterOut, 0);
|
||
}
|
||
|
||
switch (sandorData->m_type) {
|
||
case BlendTz: {
|
||
if (blendParams.empty()) continue;
|
||
|
||
// Retrieve the colormap from cache
|
||
cmRas = TToonzImageP(TImageCache::instance()->get(cmRasCacheId, true))
|
||
->getRaster();
|
||
|
||
TToonzImageP ti(cmRas, tiSaveBox);
|
||
ti->setPalette(filteredPalette ? filteredPalette.getPointer()
|
||
: tiPalette.getPointer());
|
||
|
||
TRasterImageP riOut(TImageCache::instance()->get(
|
||
std::string(oldRasterOut->cacheId, oldRasterOut->cacheIdLength),
|
||
true));
|
||
TRaster32P rasterOut = riOut->getRaster();
|
||
|
||
blend(ti, rasterOut, blendParams);
|
||
|
||
blendParams.clear();
|
||
break;
|
||
}
|
||
|
||
case Calligraphic:
|
||
case OutBorder: {
|
||
if (sandorData->m_type == OutBorder && !firstSandorFx) continue;
|
||
|
||
const char *argv[12];
|
||
memcpy(argv, sandorData->m_argv, 12 * sizeof(const char *));
|
||
|
||
double thickness =
|
||
std::stod(std::string(sandorData->m_argv[7])) * scale * dpi;
|
||
argv[7] = strsave(std::to_string(thickness).c_str());
|
||
|
||
calligraph(oldRasterIn, oldRasterOut, sandorData->m_border,
|
||
sandorData->m_argc, argv, sandorData->m_shrink,
|
||
sandorData->m_type == OutBorder);
|
||
|
||
break;
|
||
}
|
||
case ArtAtContour: {
|
||
const char *argv[12];
|
||
memcpy(argv, sandorData->m_argv, 12 * sizeof(const char *));
|
||
|
||
double distance =
|
||
std::stod(std::string(sandorData->m_argv[6])) * scale * dpi;
|
||
argv[6] = strsave(std::to_string(distance).c_str());
|
||
distance = std::stod(std::string(sandorData->m_argv[7])) * scale * dpi;
|
||
argv[7] = strsave(std::to_string(distance).c_str());
|
||
double density =
|
||
std::stod(std::string(sandorData->m_argv[8])) / sq(scale * dpi);
|
||
argv[8] = strsave(std::to_string(density).c_str());
|
||
double size =
|
||
std::stod(std::string(sandorData->m_argv[1])) * scale * dpi;
|
||
argv[1] = strsave(std::to_string(size).c_str());
|
||
size = std::stod(std::string(sandorData->m_argv[2])) * scale * dpi;
|
||
argv[2] = strsave(std::to_string(size).c_str());
|
||
RASTER *imgContour =
|
||
TRop::convertRaster50to46(sandorData->m_controller, 0);
|
||
patternmap(oldRasterIn, oldRasterOut, sandorData->m_border,
|
||
sandorData->m_argc, argv, sandorData->m_shrink, imgContour);
|
||
TRop::releaseRaster46(imgContour);
|
||
|
||
break;
|
||
}
|
||
default:
|
||
assert(false);
|
||
}
|
||
|
||
TRasterImageP riOut(TImageCache::instance()->get(
|
||
std::string(oldRasterOut->cacheId, oldRasterOut->cacheIdLength),
|
||
true));
|
||
TRaster32P rasterOut = riOut->getRaster();
|
||
|
||
TRop::releaseRaster46(oldRasterIn);
|
||
TRop::releaseRaster46(oldRasterOut);
|
||
|
||
if (firstSandorFx) {
|
||
resultTile.setRaster(rasterOut);
|
||
firstSandorFx = false;
|
||
} else
|
||
TRop::over(resultTile.getRaster(), rasterOut);
|
||
}
|
||
}
|
||
|
||
// Release cmRas cache identifier if any
|
||
TImageCache::instance()->remove(cmRasCacheId);
|
||
|
||
if (!result) result = TRasterImageP(resultTile.getRaster());
|
||
|
||
return result;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
static void applyCmappedFx(TVectorImageP &vi,
|
||
const std::vector<TRasterFxRenderDataP> &fxs, int frame) {
|
||
TRasterP ras;
|
||
bool keep = false;
|
||
TPaletteP modPalette;
|
||
set<int> colors;
|
||
std::vector<TRasterFxRenderDataP>::const_iterator it = fxs.begin();
|
||
|
||
// prima tutti gli effetti che agiscono sulla paletta....
|
||
for (; it != fxs.end(); ++it) {
|
||
ExternalPaletteFxRenderData *extpltData =
|
||
dynamic_cast<ExternalPaletteFxRenderData *>((*it).getPointer());
|
||
PaletteFilterFxRenderData *pltFilterData =
|
||
dynamic_cast<PaletteFilterFxRenderData *>((*it).getPointer());
|
||
|
||
if (extpltData && extpltData->m_palette)
|
||
modPalette = extpltData->m_palette->clone();
|
||
else if (pltFilterData) {
|
||
assert(
|
||
pltFilterData->m_type ==
|
||
eApplyToInksAndPaints); // Must have been converted to CM32 otherwise
|
||
|
||
keep = pltFilterData->m_keep;
|
||
colors.insert(pltFilterData->m_colors.begin(),
|
||
pltFilterData->m_colors.end());
|
||
}
|
||
}
|
||
|
||
TPalette *tempPlt = modPalette.getPointer();
|
||
applyPaletteFilter(tempPlt, keep, colors, vi->getPalette());
|
||
modPalette = tempPlt;
|
||
|
||
if (modPalette) {
|
||
vi = vi->clone();
|
||
vi->setPalette(modPalette.getPointer());
|
||
}
|
||
}
|
||
|
||
//****************************************************************************************
|
||
// LevelFxResourceBuilder definition
|
||
//****************************************************************************************
|
||
|
||
class LevelFxBuilder final : public ResourceBuilder {
|
||
TRasterP m_loadedRas;
|
||
TPaletteP m_palette;
|
||
|
||
TXshSimpleLevel *m_sl;
|
||
TFrameId m_fid;
|
||
TRectD m_tileGeom;
|
||
bool m_64bit;
|
||
|
||
TRect m_rasBounds;
|
||
|
||
public:
|
||
LevelFxBuilder(const std::string &resourceName, double frame,
|
||
const TRenderSettings &rs, TXshSimpleLevel *sl, TFrameId fid)
|
||
: ResourceBuilder(resourceName, 0, frame, rs)
|
||
, m_loadedRas()
|
||
, m_palette()
|
||
, m_sl(sl)
|
||
, m_fid(fid)
|
||
, m_64bit(rs.m_bpp == 64) {}
|
||
|
||
void setRasBounds(const TRect &rasBounds) { m_rasBounds = rasBounds; }
|
||
|
||
void compute(const TRectD &tileRect) override {
|
||
// Load the image
|
||
TImageP img(m_sl->getFullsampledFrame(
|
||
m_fid, (m_64bit ? ImageManager::is64bitEnabled : 0) |
|
||
ImageManager::dontPutInCache));
|
||
|
||
if (!img) return;
|
||
|
||
TRasterImageP rimg(img);
|
||
TToonzImageP timg(img);
|
||
|
||
m_loadedRas = rimg ? (TRasterP)rimg->getRaster()
|
||
: timg ? (TRasterP)timg->getRaster() : TRasterP();
|
||
assert(m_loadedRas);
|
||
|
||
if (timg) m_palette = timg->getPalette();
|
||
|
||
assert(tileRect ==
|
||
TRectD(0, 0, m_loadedRas->getLx(), m_loadedRas->getLy()));
|
||
}
|
||
|
||
void simCompute(const TRectD &rect) override {}
|
||
|
||
void upload(TCacheResourceP &resource) override {
|
||
assert(m_loadedRas);
|
||
resource->upload(TPoint(), m_loadedRas);
|
||
if (m_palette) resource->uploadPalette(m_palette);
|
||
}
|
||
|
||
bool download(TCacheResourceP &resource) override {
|
||
// If the image has been loaded in this builder, just use it
|
||
if (m_loadedRas) return true;
|
||
|
||
// If the image has yet to be loaded by this builder, skip without
|
||
// allocating anything
|
||
if (resource->canDownloadAll(m_rasBounds)) {
|
||
m_loadedRas = resource->buildCompatibleRaster(m_rasBounds.getSize());
|
||
resource->downloadPalette(m_palette);
|
||
return resource->downloadAll(TPoint(), m_loadedRas);
|
||
} else
|
||
return false;
|
||
}
|
||
|
||
TImageP getImage() const {
|
||
if (!m_loadedRas) return TImageP();
|
||
|
||
TRasterCM32P cm(m_loadedRas);
|
||
|
||
TImageP result(cm ? TImageP(TToonzImageP(cm, cm->getBounds()))
|
||
: TImageP(TRasterImageP(m_loadedRas)));
|
||
if (m_palette) result->setPalette(m_palette.getPointer());
|
||
|
||
return result;
|
||
}
|
||
};
|
||
|
||
//****************************************************************************************
|
||
// TLevelColumnFx implementation
|
||
//****************************************************************************************
|
||
|
||
TLevelColumnFx::TLevelColumnFx()
|
||
: m_levelColumn(0), m_isCachable(true), m_mutex(), m_offlineContext(0) {
|
||
setName(L"LevelColumn");
|
||
}
|
||
|
||
//--------------------------------------------------
|
||
|
||
TLevelColumnFx::~TLevelColumnFx() {
|
||
if (m_offlineContext) delete m_offlineContext;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
bool TLevelColumnFx::canHandle(const TRenderSettings &info, double frame) {
|
||
// NOTE 1: Currently, it is necessary that level columns return FALSE for
|
||
// raster levels - just a quick way to tell the cache functions that they
|
||
// have to be cached.
|
||
|
||
if (!m_levelColumn) return true;
|
||
|
||
TXshCell cell = m_levelColumn->getCell(m_levelColumn->getFirstRow());
|
||
if (cell.isEmpty()) return true;
|
||
|
||
TXshSimpleLevel *sl = cell.m_level->getSimpleLevel();
|
||
if (!sl) return true;
|
||
|
||
return (sl->getType() == PLI_XSHLEVEL &&
|
||
!vectorMustApplyCmappedFx(info.m_data));
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TAffine TLevelColumnFx::handledAffine(const TRenderSettings &info,
|
||
double frame) {
|
||
if (!m_levelColumn) return TAffine();
|
||
|
||
TXshCell cell = m_levelColumn->getCell(m_levelColumn->getFirstRow());
|
||
if (cell.isEmpty()) return TAffine();
|
||
|
||
TXshSimpleLevel *sl = cell.m_level->getSimpleLevel();
|
||
if (!sl) return TAffine();
|
||
|
||
if (sl->getType() == PLI_XSHLEVEL)
|
||
return vectorMustApplyCmappedFx(info.m_data)
|
||
? TRasterFx::handledAffine(info, frame)
|
||
: info.m_affine;
|
||
|
||
// Accept any translation consistent with the image's pixels geometry
|
||
TImageInfo imageInfo;
|
||
getImageInfo(imageInfo, sl, cell.m_frameId);
|
||
|
||
TPointD pixelsOrigin(-0.5 * imageInfo.m_lx, -0.5 * imageInfo.m_ly);
|
||
|
||
const TAffine &aff = info.m_affine;
|
||
if (aff.a11 != 1.0 || aff.a22 != 1.0 || aff.a12 != 0.0 || aff.a21 != 0.0)
|
||
return TTranslation(-pixelsOrigin);
|
||
|
||
// This is a translation, ok. Just ensure it is consistent.
|
||
TAffine consistentAff(aff);
|
||
|
||
consistentAff.a13 -= pixelsOrigin.x, consistentAff.a23 -= pixelsOrigin.y;
|
||
consistentAff.a13 = tfloor(consistentAff.a13),
|
||
consistentAff.a23 = tfloor(consistentAff.a23);
|
||
consistentAff.a13 += pixelsOrigin.x, consistentAff.a23 += pixelsOrigin.y;
|
||
|
||
return consistentAff;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TFilePath TLevelColumnFx::getPalettePath(int frame) const {
|
||
if (!m_levelColumn) return TFilePath();
|
||
|
||
TXshCell cell = m_levelColumn->getCell(frame);
|
||
if (cell.isEmpty()) return TFilePath();
|
||
|
||
TXshSimpleLevel *sl = cell.m_level->getSimpleLevel();
|
||
if (!sl) return TFilePath();
|
||
|
||
if (sl->getType() == TZP_XSHLEVEL)
|
||
return sl->getScene()->decodeFilePath(
|
||
sl->getPath().withNoFrame().withType("tpl"));
|
||
|
||
if (sl->getType() == PLI_XSHLEVEL)
|
||
return sl->getScene()->decodeFilePath(sl->getPath());
|
||
|
||
return TFilePath();
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TPalette *TLevelColumnFx::getPalette(int frame) const {
|
||
if (!m_levelColumn) return 0;
|
||
|
||
TXshCell cell = m_levelColumn->getCell(frame);
|
||
if (cell.isEmpty()) return 0;
|
||
|
||
TXshSimpleLevel *sl = cell.m_level->getSimpleLevel();
|
||
if (!sl) return 0;
|
||
|
||
return sl->getPalette();
|
||
}
|
||
|
||
//--------------------------------------------------
|
||
|
||
TFx *TLevelColumnFx::clone(bool recursive) const {
|
||
TLevelColumnFx *clonedFx =
|
||
dynamic_cast<TLevelColumnFx *>(TFx::clone(recursive));
|
||
assert(clonedFx);
|
||
clonedFx->m_levelColumn = m_levelColumn;
|
||
clonedFx->m_isCachable = m_isCachable;
|
||
return clonedFx;
|
||
}
|
||
|
||
//--------------------------------------------------
|
||
|
||
void TLevelColumnFx::doDryCompute(TRectD &rect, double frame,
|
||
const TRenderSettings &info) {
|
||
if (!m_levelColumn) return;
|
||
|
||
int row = (int)frame;
|
||
TXshCell cell = m_levelColumn->getCell(row);
|
||
if (cell.isEmpty()) return;
|
||
|
||
TXshSimpleLevel *sl = cell.m_level->getSimpleLevel();
|
||
if (!sl) return;
|
||
|
||
// In case this is a vector level, the image is renderized quickly and
|
||
// directly at the
|
||
// correct resolution. Caching is disabled in such case, at the moment.
|
||
if (sl->getType() == PLI_XSHLEVEL) return;
|
||
|
||
int renderStatus =
|
||
TRenderer::instance().getRenderStatus(TRenderer::renderId());
|
||
|
||
std::string alias = getAlias(frame, TRenderSettings()) + "_image";
|
||
|
||
TImageInfo imageInfo;
|
||
getImageInfo(imageInfo, sl, cell.m_frameId);
|
||
TRectD imgRect(0, 0, imageInfo.m_lx, imageInfo.m_ly);
|
||
|
||
if (renderStatus == TRenderer::FIRSTRUN) {
|
||
ResourceBuilder::declareResource(alias, 0, imgRect, frame, info, false);
|
||
} else {
|
||
LevelFxBuilder builder(alias, frame, info, sl, cell.m_frameId);
|
||
builder.setRasBounds(TRect(0, 0, imageInfo.m_lx - 1, imageInfo.m_ly - 1));
|
||
builder.simBuild(imgRect);
|
||
}
|
||
}
|
||
|
||
//--------------------------------------------------
|
||
|
||
bool isSubsheetChainOnColumn0(TXsheet *topXsheet, TXsheet *subsheet,
|
||
int frame) {
|
||
if (topXsheet == subsheet) return true;
|
||
|
||
const TXshCell cell = topXsheet->getCell(frame, 0);
|
||
if (!cell.m_level) return false;
|
||
TXshChildLevel *cl = cell.m_level->getChildLevel();
|
||
if (!cl) return false;
|
||
return isSubsheetChainOnColumn0(cl->getXsheet(), subsheet, frame);
|
||
}
|
||
|
||
//-----------------------------------------------------
|
||
|
||
void TLevelColumnFx::doCompute(TTile &tile, double frame,
|
||
const TRenderSettings &info) {
|
||
if (!m_levelColumn) return;
|
||
|
||
// Ensure that a corresponding cell and level exists
|
||
int row = (int)frame;
|
||
TXshCell cell = m_levelColumn->getCell(row);
|
||
|
||
if (cell.isEmpty()) return;
|
||
|
||
TXshSimpleLevel *sl = cell.m_level->getSimpleLevel();
|
||
if (!sl) return;
|
||
|
||
TFrameId fid = cell.m_frameId;
|
||
|
||
TImageP img;
|
||
TImageInfo imageInfo;
|
||
|
||
// Now, fetch the image
|
||
if (sl->getType() != PLI_XSHLEVEL) {
|
||
// Raster case
|
||
LevelFxBuilder builder(getAlias(frame, TRenderSettings()) + "_image", frame,
|
||
info, sl, fid);
|
||
|
||
getImageInfo(imageInfo, sl, fid);
|
||
TRectD imgRect(0, 0, imageInfo.m_lx, imageInfo.m_ly);
|
||
|
||
builder.setRasBounds(TRect(0, 0, imageInfo.m_lx - 1, imageInfo.m_ly - 1));
|
||
builder.build(imgRect);
|
||
|
||
img = builder.getImage();
|
||
} else {
|
||
// Vector case (loading is immediate)
|
||
if (!img) {
|
||
img = sl->getFullsampledFrame(
|
||
fid, ((info.m_bpp == 64) ? ImageManager::is64bitEnabled : 0) |
|
||
ImageManager::dontPutInCache);
|
||
}
|
||
}
|
||
|
||
// Extract the required geometry
|
||
TRect tileBounds(tile.getRaster()->getBounds());
|
||
TRectD tileRectD = TRectD(tileBounds.x0, tileBounds.y0, tileBounds.x1 + 1,
|
||
tileBounds.y1 + 1) +
|
||
tile.m_pos;
|
||
|
||
// To be sure, if there is no image, return.
|
||
if (!img) return;
|
||
|
||
TRectD bBox = img->getBBox();
|
||
|
||
// Discriminate image type
|
||
if (TVectorImageP vectorImage = img) {
|
||
// Vector case
|
||
|
||
if (vectorMustApplyCmappedFx(info.m_data)) {
|
||
// Deal separately
|
||
applyTzpFxsOnVector(vectorImage, tile, frame, info);
|
||
} else {
|
||
QMutexLocker m(&m_mutex);
|
||
bBox = info.m_affine * vectorImage->getBBox();
|
||
TDimension size(tile.getRaster()->getSize());
|
||
|
||
TAffine aff = TTranslation(-tile.m_pos.x, -tile.m_pos.y) *
|
||
TScale(1.0 / info.m_shrinkX, 1.0 / info.m_shrinkY) *
|
||
info.m_affine;
|
||
|
||
applyCmappedFx(vectorImage, info.m_data, (int)frame);
|
||
TPalette *vpalette = vectorImage->getPalette();
|
||
assert(vpalette);
|
||
m_isCachable = !vpalette->isAnimated();
|
||
int oldFrame = vpalette->getFrame();
|
||
|
||
TVectorRenderData rd(TVectorRenderData::ProductionSettings(), aff,
|
||
TRect(size), vpalette);
|
||
|
||
if (!m_offlineContext || m_offlineContext->getLx() < size.lx ||
|
||
m_offlineContext->getLy() < size.ly) {
|
||
if (m_offlineContext) delete m_offlineContext;
|
||
m_offlineContext = new TOfflineGL(size);
|
||
}
|
||
|
||
m_offlineContext->makeCurrent();
|
||
m_offlineContext->clear(TPixel32(0, 0, 0, 0));
|
||
|
||
// If level has animated palette, it is necessary to lock palette's color
|
||
// against
|
||
// concurrents TPalette::setFrame.
|
||
if (!m_isCachable) vpalette->mutex()->lock();
|
||
|
||
vpalette->setFrame((int)frame);
|
||
m_offlineContext->draw(vectorImage, rd, true);
|
||
vpalette->setFrame(oldFrame);
|
||
|
||
if (!m_isCachable) vpalette->mutex()->unlock();
|
||
|
||
m_offlineContext->getRaster(tile.getRaster());
|
||
|
||
m_offlineContext->doneCurrent();
|
||
}
|
||
} else {
|
||
// Raster case
|
||
|
||
TRasterP ras;
|
||
TAffine aff;
|
||
|
||
TRasterImageP ri = img;
|
||
TToonzImageP ti = img;
|
||
img = 0;
|
||
|
||
if (ri) {
|
||
// Fullcolor case
|
||
|
||
ras = ri->getRaster();
|
||
ri = 0;
|
||
TRaster32P ras32(ras);
|
||
TRaster64P ras64(ras);
|
||
|
||
// Ensure that ras is either a 32 or 64 fullcolor.
|
||
// Otherwise, we have to convert it.
|
||
if (!ras32 && !ras64) {
|
||
TRasterP tileRas(tile.getRaster());
|
||
TRaster32P tileRas32(tileRas);
|
||
TRaster64P tileRas64(tileRas);
|
||
|
||
if (tileRas32) {
|
||
ras32 = TRaster32P(ras->getLx(), ras->getLy());
|
||
TRop::convert(ras32, ras);
|
||
ras = ras32;
|
||
} else if (tileRas64) {
|
||
ras64 = TRaster64P(ras->getLx(), ras->getLy());
|
||
TRop::convert(ras64, ras);
|
||
ras = ras64;
|
||
} else
|
||
assert(0);
|
||
}
|
||
TXsheet *xsh = m_levelColumn->getLevelColumn()->getXsheet();
|
||
TXsheet *txsh = sl->getScene()->getTopXsheet();
|
||
|
||
LevelProperties *levelProp = sl->getProperties();
|
||
if (Preferences::instance()->isIgnoreAlphaonColumn1Enabled() &&
|
||
m_levelColumn->getIndex() == 0 &&
|
||
isSubsheetChainOnColumn0(txsh, xsh, frame)) {
|
||
TRasterP appRas(ras->clone());
|
||
setMaxMatte(appRas);
|
||
ras = appRas;
|
||
}
|
||
if (levelProp->doPremultiply()) {
|
||
TRasterP appRas = ras->clone();
|
||
TRop::premultiply(appRas);
|
||
ras = appRas;
|
||
}
|
||
if (levelProp->whiteTransp()) {
|
||
TRasterP appRas(ras->clone());
|
||
TRop::whiteTransp(appRas);
|
||
ras = appRas;
|
||
}
|
||
if (levelProp->antialiasSoftness() > 0) {
|
||
TRasterP appRas = ras->create(ras->getLx(), ras->getLy());
|
||
TRop::antialias(ras, appRas, 10, levelProp->antialiasSoftness());
|
||
ras = appRas;
|
||
}
|
||
|
||
if (TXshSimpleLevel::m_fillFullColorRaster) {
|
||
TRasterP appRas(ras->clone());
|
||
FullColorAreaFiller filler(appRas);
|
||
TPaletteP palette = new TPalette();
|
||
int styleId = palette->getPage(0)->addStyle(TPixel32::White);
|
||
FillParameters params;
|
||
params.m_palette = palette.getPointer();
|
||
params.m_styleId = styleId;
|
||
params.m_minFillDepth = 0;
|
||
params.m_maxFillDepth = 15;
|
||
filler.rectFill(appRas->getBounds(), params, false);
|
||
ras = appRas;
|
||
}
|
||
} else if (ti) {
|
||
// Colormap case
|
||
|
||
// Use the imageInfo's dpi
|
||
ti->setDpi(imageInfo.m_dpix, imageInfo.m_dpiy);
|
||
|
||
TImageP newImg = applyTzpFxs(ti, frame, info);
|
||
|
||
ri = newImg;
|
||
ti = newImg;
|
||
|
||
if (ri)
|
||
ras = ri->getRaster();
|
||
else
|
||
ras = ti->getRaster();
|
||
|
||
if (sl->getProperties()->antialiasSoftness() > 0) {
|
||
TRasterP appRas = ras->create(ras->getLx(), ras->getLy());
|
||
TRop::antialias(ras, appRas, 10,
|
||
sl->getProperties()->antialiasSoftness());
|
||
ras = appRas;
|
||
}
|
||
|
||
ri = 0;
|
||
}
|
||
|
||
if (ras) {
|
||
double lx_2 = ras->getLx() / 2.0;
|
||
double ly_2 = ras->getLy() / 2.0;
|
||
|
||
TRenderSettings infoAux(info);
|
||
assert(info.m_affine.isTranslation());
|
||
infoAux.m_data.clear();
|
||
|
||
// Place the output rect in the image's reference
|
||
tileRectD += TPointD(lx_2 - info.m_affine.a13, ly_2 - info.m_affine.a23);
|
||
|
||
// Then, retrieve loaded image's interesting region
|
||
TRectD inTileRectD;
|
||
if (ti) {
|
||
TRect saveBox(ti->getSavebox());
|
||
inTileRectD =
|
||
TRectD(saveBox.x0, saveBox.y0, saveBox.x1 + 1, saveBox.y1 + 1);
|
||
} else {
|
||
TRect rasBounds(ras->getBounds());
|
||
inTileRectD = TRectD(rasBounds.x0, rasBounds.y0, rasBounds.x1 + 1,
|
||
rasBounds.y1 + 1);
|
||
}
|
||
|
||
// And intersect the two
|
||
inTileRectD *= tileRectD;
|
||
|
||
// Should the intersection be void, return
|
||
if (inTileRectD.x0 >= inTileRectD.x1 || inTileRectD.y0 >= inTileRectD.y1)
|
||
return;
|
||
|
||
// Output that intersection in the requested tile
|
||
TRect inTileRect(tround(inTileRectD.x0), tround(inTileRectD.y0),
|
||
tround(inTileRectD.x1) - 1, tround(inTileRectD.y1) - 1);
|
||
TTile inTile(ras->extract(inTileRect),
|
||
inTileRectD.getP00() + TPointD(-lx_2, -ly_2));
|
||
|
||
// Observe that inTile is in the standard reference, ie image's minus the
|
||
// center coordinates
|
||
|
||
if (ti) {
|
||
// In the colormapped case, we have to convert the cmap to fullcolor
|
||
TPalette *palette = ti->getPalette();
|
||
|
||
if (!m_isCachable) palette->mutex()->lock();
|
||
|
||
int prevFrame = palette->getFrame();
|
||
|
||
palette->setFrame((int)frame);
|
||
TTile auxtile(TRaster32P(inTile.getRaster()->getSize()), inTile.m_pos);
|
||
TRop::convert(auxtile, inTile, palette, false, true);
|
||
palette->setFrame(prevFrame);
|
||
|
||
if (!m_isCachable) palette->mutex()->unlock();
|
||
|
||
inTile.setRaster(auxtile.getRaster());
|
||
}
|
||
|
||
TRasterFx::applyAffine(tile, inTile, infoAux);
|
||
}
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TImageP TLevelColumnFx::applyTzpFxs(TToonzImageP &ti, double frame,
|
||
const TRenderSettings &info) {
|
||
double scale = sqrt(fabs(info.m_affine.det()));
|
||
|
||
int prevFrame = ti->getPalette()->getFrame();
|
||
m_isCachable = !ti->getPalette()->isAnimated();
|
||
|
||
if (!m_isCachable) ti->getPalette()->mutex()->lock();
|
||
|
||
TPaletteP palette(ti->getPalette());
|
||
palette->setFrame((int)frame);
|
||
TImageP newImg = applyCmappedFx(ti, info.m_data, (int)frame, scale);
|
||
palette->setFrame(prevFrame);
|
||
|
||
if (!m_isCachable) palette->mutex()->unlock();
|
||
|
||
return newImg;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TLevelColumnFx::applyTzpFxsOnVector(const TVectorImageP &vi, TTile &tile,
|
||
double frame,
|
||
const TRenderSettings &info) {
|
||
TRect tileBounds(tile.getRaster()->getBounds());
|
||
TRectD tileRectD = TRectD(tileBounds.x0, tileBounds.y0, tileBounds.x1 + 1,
|
||
tileBounds.y1 + 1) +
|
||
tile.m_pos;
|
||
|
||
// Info's affine is not the identity only in case the loaded image is a vector
|
||
// one.
|
||
double scale = sqrt(fabs(info.m_affine.det()));
|
||
int enlargement = getEnlargement(info.m_data, scale);
|
||
|
||
// Extract the vector image's groups
|
||
std::vector<TVectorImageP> groupsList;
|
||
getGroupsList(vi, groupsList);
|
||
|
||
// For each group, apply the tzp fxs stored in info. The result is immediately
|
||
// converted
|
||
// to a raster image if necessary.
|
||
unsigned int i;
|
||
for (i = 0; i < groupsList.size(); ++i) {
|
||
TVectorImageP &groupVi = groupsList[i];
|
||
|
||
// Extract the group's bbox.
|
||
TRectD groupBBox(info.m_affine * groupVi->getBBox());
|
||
if (!mustApplySandorFx(info.m_data)) groupBBox *= tileRectD;
|
||
|
||
groupBBox = groupBBox.enlarge(enlargement);
|
||
|
||
if (groupBBox.x0 >= groupBBox.x1 || groupBBox.y0 >= groupBBox.y1) continue;
|
||
|
||
// Ensure that groupBBox and tile have the same integer geometry
|
||
groupBBox -= tile.m_pos;
|
||
groupBBox.x0 = tfloor(groupBBox.x0);
|
||
groupBBox.y0 = tfloor(groupBBox.y0);
|
||
groupBBox.x1 = tceil(groupBBox.x1);
|
||
groupBBox.y1 = tceil(groupBBox.y1);
|
||
groupBBox += tile.m_pos;
|
||
|
||
// Build groupBBox's relative position to the tile
|
||
TPoint groupRelativePosToTile(groupBBox.x0 - tile.m_pos.x,
|
||
groupBBox.y0 - tile.m_pos.y);
|
||
|
||
// Convert the group to a strictly sufficient Toonz image
|
||
TToonzImageP groupTi = ToonzImageUtils::vectorToToonzImage(
|
||
groupVi, info.m_affine, groupVi->getPalette(), groupBBox.getP00(),
|
||
TDimension(groupBBox.getLx(), groupBBox.getLy()), &info.m_data, true);
|
||
|
||
// Apply the tzp fxs to the converted Toonz image
|
||
TImageP groupResult = applyTzpFxs(groupTi, frame, info);
|
||
|
||
// If necessary, convert the result to fullcolor
|
||
TRasterImageP groupRi = groupResult;
|
||
if (!groupRi) {
|
||
groupTi = groupResult;
|
||
assert(groupTi);
|
||
|
||
TRasterP groupTiRas(groupTi->getRaster());
|
||
TRaster32P tempRas(groupTiRas->getSize());
|
||
groupRi = TRasterImageP(tempRas);
|
||
|
||
TRop::convert(tempRas, groupTiRas, groupTi->getPalette());
|
||
}
|
||
|
||
// Over the group image on the output
|
||
TRasterP tileRas(tile.getRaster());
|
||
TRop::over(tileRas, groupRi->getRaster(), groupRelativePosToTile);
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
int TLevelColumnFx::getMemoryRequirement(const TRectD &rect, double frame,
|
||
const TRenderSettings &info) {
|
||
// Sandor fxs are currently considered *VERY* inefficient upon tile
|
||
// subdivision
|
||
if (mustApplySandorFx(info.m_data)) {
|
||
return -1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TLevelColumnFx::getImageInfo(TImageInfo &info, TXshSimpleLevel *sl,
|
||
TFrameId frameId) {
|
||
int type = sl->getType();
|
||
assert(type != PLI_XSHLEVEL);
|
||
if (type == PLI_XSHLEVEL) return;
|
||
|
||
std::string imageId = sl->getImageId(frameId);
|
||
|
||
const TImageInfo *storedInfo =
|
||
ImageManager::instance()->getInfo(imageId, ImageManager::none, 0);
|
||
|
||
if (!storedInfo) // sulle pict caricate info era nullo, ma l'immagine c'e'!
|
||
// con la getFullSampleFrame riprendo l'immagine e ricalcolo la savebox...
|
||
{
|
||
TImageP img;
|
||
if (!(img =
|
||
sl->getFullsampledFrame(frameId, ImageManager::dontPutInCache))) {
|
||
assert(false);
|
||
return;
|
||
}
|
||
|
||
info.m_lx = (int)img->getBBox().getLx();
|
||
info.m_ly = (int)img->getBBox().getLy();
|
||
info.m_x0 = info.m_y0 = 0;
|
||
info.m_x1 = (int)img->getBBox().getP11().x;
|
||
info.m_y1 = (int)img->getBBox().getP11().y;
|
||
} else
|
||
info = *storedInfo;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
bool TLevelColumnFx::doGetBBox(double frame, TRectD &bBox,
|
||
const TRenderSettings &info) {
|
||
// Usual preliminaries (make sure a level/cell exists, etc...)
|
||
if (!m_levelColumn) return false;
|
||
|
||
int row = (int)frame;
|
||
const TXshCell &cell = m_levelColumn->getCell(row);
|
||
if (cell.isEmpty()) return false;
|
||
|
||
TXshLevelP xshl = cell.m_level;
|
||
if (!xshl) return false;
|
||
|
||
TXshSimpleLevel *sl = xshl->getSimpleLevel();
|
||
if (!sl) return false;
|
||
|
||
double dpi = 1.0;
|
||
|
||
// Discriminate for level type
|
||
int type = xshl->getType();
|
||
if (type != PLI_XSHLEVEL) {
|
||
TImageInfo imageInfo;
|
||
getImageInfo(imageInfo, sl, cell.m_frameId);
|
||
|
||
TRect imageSavebox(imageInfo.m_x0, imageInfo.m_y0, imageInfo.m_x1,
|
||
imageInfo.m_y1);
|
||
double cx = 0.5 * imageInfo.m_lx;
|
||
double cy = 0.5 * imageInfo.m_ly;
|
||
double x0 = (imageSavebox.x0 - cx);
|
||
double y0 = (imageSavebox.y0 - cy);
|
||
double x1 = x0 + imageSavebox.getLx();
|
||
double y1 = y0 + imageSavebox.getLy();
|
||
bBox = TRectD(x0, y0, x1, y1);
|
||
|
||
dpi = imageInfo.m_dpix / Stage::inch;
|
||
} else {
|
||
TImageP img = m_levelColumn->getCell(row).getImage(false);
|
||
if (!img) return false;
|
||
bBox = img->getBBox();
|
||
}
|
||
|
||
// Add the enlargement of the bbox due to Tzp render datas
|
||
if (info.m_data.size()) {
|
||
TRectD imageBBox(bBox);
|
||
for (unsigned int i = 0; i < info.m_data.size(); ++i) {
|
||
TRectD enlargedImageBBox = info.m_data[i]->getBBoxEnlargement(imageBBox);
|
||
double enlargement = enlargedImageBBox.x1 - imageBBox.x1;
|
||
bBox += imageBBox.enlarge(enlargement * dpi);
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
const TPersistDeclaration *TLevelColumnFx::getDeclaration() const {
|
||
return &columnFxInfo;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::string TLevelColumnFx::getPluginId() const { return "Toonz_"; }
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TFxTimeRegion TLevelColumnFx::getTimeRegion() const {
|
||
if (!m_levelColumn) return TFxTimeRegion();
|
||
|
||
int first = m_levelColumn->getFirstRow();
|
||
int last = m_levelColumn->getRowCount();
|
||
|
||
return TFxTimeRegion(first, last);
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TLevelColumnFx::setColumn(TXshLevelColumn *column) {
|
||
m_levelColumn = column;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::wstring TLevelColumnFx::getColumnId() const {
|
||
if (!m_levelColumn) return L"Col?";
|
||
return L"Col" + std::to_wstring(m_levelColumn->getIndex() + 1);
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::wstring TLevelColumnFx::getColumnName() const {
|
||
if (!m_levelColumn) return L"";
|
||
int idx = getColumnIndex();
|
||
return ::to_wstring(m_levelColumn->getXsheet()
|
||
->getStageObject(TStageObjectId::ColumnId(idx))
|
||
->getName());
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::string TLevelColumnFx::getAlias(double frame,
|
||
const TRenderSettings &info) const {
|
||
if (!m_levelColumn || m_levelColumn->getCell((int)frame).isEmpty())
|
||
return std::string();
|
||
|
||
const TXshCell &cell = m_levelColumn->getCell((int)frame);
|
||
|
||
TFilePath fp;
|
||
TXshSimpleLevel *sl = cell.getSimpleLevel();
|
||
|
||
if (!sl) {
|
||
// Try with the sub-xsheet case
|
||
TXshChildLevel *childLevel = cell.m_level->getChildLevel();
|
||
if (childLevel) return ::getAlias(childLevel->getXsheet(), frame, info);
|
||
|
||
return std::string();
|
||
}
|
||
|
||
TFilePath path = sl->getPath();
|
||
if (!cell.m_frameId.isNoFrame())
|
||
fp = path.withFrame(cell.m_frameId);
|
||
else
|
||
fp = path;
|
||
|
||
std::string rdata;
|
||
std::vector<TRasterFxRenderDataP>::const_iterator it = info.m_data.begin();
|
||
for (; it != info.m_data.end(); ++it) {
|
||
TRasterFxRenderDataP data = *it;
|
||
if (data) rdata += data->toString();
|
||
}
|
||
|
||
if (sl->getType() == PLI_XSHLEVEL || sl->getType() == TZP_XSHLEVEL) {
|
||
TPalette *palette = cell.getPalette();
|
||
if (palette && palette->isAnimated())
|
||
rdata += "animatedPlt" + std::to_string(frame);
|
||
}
|
||
|
||
if (Preferences::instance()->isIgnoreAlphaonColumn1Enabled()) {
|
||
TXsheet *xsh = m_levelColumn->getLevelColumn()->getXsheet();
|
||
TXsheet *txsh = sl->getScene()->getTopXsheet();
|
||
|
||
if (m_levelColumn->getIndex() == 0 &&
|
||
isSubsheetChainOnColumn0(txsh, xsh, frame))
|
||
rdata += "column_0";
|
||
}
|
||
|
||
return getFxType() + "[" + ::to_string(fp.getWideString()) + "," + rdata +
|
||
"]";
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
int TLevelColumnFx::getColumnIndex() const {
|
||
return m_levelColumn ? m_levelColumn->getIndex() : -1;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TXshColumn *TLevelColumnFx::getXshColumn() const { return m_levelColumn; }
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TLevelColumnFx::compute(TFlash &flash, int frame) {
|
||
if (!m_levelColumn) return;
|
||
|
||
TImageP img = m_levelColumn->getCell(frame).getImage(false);
|
||
if (!img) return;
|
||
|
||
flash.draw(img, 0);
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TAffine TLevelColumnFx::getDpiAff(int frame) {
|
||
if (!m_levelColumn) return TAffine();
|
||
|
||
TXshCell cell = m_levelColumn->getCell(frame);
|
||
if (cell.isEmpty()) return TAffine();
|
||
|
||
TXshSimpleLevel *sl = cell.m_level->getSimpleLevel();
|
||
TFrameId fid = cell.m_frameId;
|
||
|
||
if (sl) return ::getDpiAffine(sl, cell.m_frameId, true);
|
||
|
||
return TAffine();
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TLevelColumnFx::saveData(TOStream &os) {
|
||
assert(m_levelColumn);
|
||
TFx::saveData(os);
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TLevelColumnFx::loadData(TIStream &is) {
|
||
// The internal numeric identifier is set here but not in constructors.
|
||
// This is *intended* as fx cloning needs to retain the original id
|
||
// through the fxs tree deployment procedure happening just before a
|
||
// render process (see scenefx.cpp).
|
||
|
||
TFx::loadData(is);
|
||
setNewIdentifier();
|
||
}
|
||
|
||
//****************************************************************************************
|
||
// TPaletteColumnFx implementation
|
||
//****************************************************************************************
|
||
|
||
TPaletteColumnFx::TPaletteColumnFx() : m_paletteColumn(0) {}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TPaletteColumnFx::~TPaletteColumnFx() {}
|
||
|
||
//--------------------------------------------------
|
||
|
||
TFx *TPaletteColumnFx::clone(bool recursive) const {
|
||
TPaletteColumnFx *clonedFx =
|
||
dynamic_cast<TPaletteColumnFx *>(TFx::clone(recursive));
|
||
assert(clonedFx);
|
||
clonedFx->m_paletteColumn = m_paletteColumn;
|
||
return clonedFx;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TPaletteColumnFx::doCompute(TTile &tile, double frame,
|
||
const TRenderSettings &) {}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
bool TPaletteColumnFx::doGetBBox(double frame, TRectD &bBox,
|
||
const TRenderSettings &info) {
|
||
return false;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TAffine TPaletteColumnFx::getDpiAff(int frame) { return TAffine(); }
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
bool TPaletteColumnFx::canHandle(const TRenderSettings &info, double frame) {
|
||
return false;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TFilePath TPaletteColumnFx::getPalettePath(int frame) const {
|
||
if (!m_paletteColumn) return TFilePath();
|
||
TXshCell cell = m_paletteColumn->getCell(frame);
|
||
if (cell.isEmpty() || cell.m_level->getPaletteLevel() == 0)
|
||
return TFilePath();
|
||
|
||
TXshPaletteLevel *paletteLevel = cell.m_level->getPaletteLevel();
|
||
TFilePath path = paletteLevel->getPath();
|
||
path = paletteLevel->getScene()->decodeFilePath(path);
|
||
return path;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TPalette *TPaletteColumnFx::getPalette(int frame) const {
|
||
if (!m_paletteColumn) return 0;
|
||
TXshCell cell = m_paletteColumn->getCell(frame);
|
||
if (cell.isEmpty() || cell.m_level->getPaletteLevel() == 0) return 0;
|
||
|
||
TXshPaletteLevel *paletteLevel = cell.m_level->getPaletteLevel();
|
||
return paletteLevel->getPalette();
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
const TPersistDeclaration *TPaletteColumnFx::getDeclaration() const {
|
||
return &paletteColumnFxInfo;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::string TPaletteColumnFx::getPluginId() const { return "Toonz_"; }
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TFxTimeRegion TPaletteColumnFx::getTimeRegion() const {
|
||
int first = 0;
|
||
int last = 11;
|
||
return TFxTimeRegion(first, last);
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::wstring TPaletteColumnFx::getColumnName() const {
|
||
if (!m_paletteColumn) return L"Col?";
|
||
return L"Col" + std::to_wstring(m_paletteColumn->getIndex() + 1);
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::wstring TPaletteColumnFx::getColumnId() const {
|
||
if (!m_paletteColumn) return L"Col?";
|
||
return L"Col" + std::to_wstring(m_paletteColumn->getIndex() + 1);
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::string TPaletteColumnFx::getAlias(double frame,
|
||
const TRenderSettings &info) const {
|
||
TFilePath palettePath = getPalettePath(frame);
|
||
return "TPaletteColumnFx[" + ::to_string(palettePath.getWideString()) + "]";
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TPaletteColumnFx::compute(TFlash &flash, int frame) {}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
int TPaletteColumnFx::getColumnIndex() const {
|
||
return m_paletteColumn ? m_paletteColumn->getIndex() : -1;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TXshColumn *TPaletteColumnFx::getXshColumn() const { return m_paletteColumn; }
|
||
|
||
//****************************************************************************************
|
||
// TZeraryColumnFx implementation
|
||
//****************************************************************************************
|
||
|
||
TZeraryColumnFx::TZeraryColumnFx() : m_zeraryFxColumn(0), m_fx(0) {
|
||
setName(L"ZeraryColumn");
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TZeraryColumnFx::~TZeraryColumnFx() {
|
||
if (m_zeraryFxColumn) m_zeraryFxColumn->release();
|
||
if (m_fx) {
|
||
m_fx->m_columnFx = 0;
|
||
m_fx->release();
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TZeraryColumnFx::doCompute(TTile &tile, double frame,
|
||
const TRenderSettings &info) {
|
||
if (m_zeraryFxColumn) {
|
||
TRasterFx *fx = dynamic_cast<TRasterFx *>(m_fx);
|
||
if (fx) fx->compute(tile, frame, info);
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
bool TZeraryColumnFx::doGetBBox(double frame, TRectD &bBox,
|
||
const TRenderSettings &info) {
|
||
if (m_zeraryFxColumn) {
|
||
TRasterFx *fx = dynamic_cast<TRasterFx *>(m_fx);
|
||
if (fx) return fx->doGetBBox(frame, bBox, info);
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
const TPersistDeclaration *TZeraryColumnFx::getDeclaration() const {
|
||
return &zeraryColumnFxInfo;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::string TZeraryColumnFx::getPluginId() const { return "Toonz_"; }
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TFxTimeRegion TZeraryColumnFx::getTimeRegion() const {
|
||
return TFxTimeRegion(0, (std::numeric_limits<double>::max)());
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TZeraryColumnFx::setColumn(TXshZeraryFxColumn *column) {
|
||
m_zeraryFxColumn = column;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::wstring TZeraryColumnFx::getColumnName() const {
|
||
return getZeraryFx()->getName();
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::wstring TZeraryColumnFx::getColumnId() const {
|
||
return getZeraryFx()->getFxId();
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TZeraryColumnFx::setZeraryFx(TFx *fx) {
|
||
TZeraryFx *zfx = static_cast<TZeraryFx *>(fx);
|
||
|
||
if (fx) {
|
||
assert(dynamic_cast<TZeraryFx *>(fx));
|
||
|
||
fx->addRef();
|
||
fx->setNewIdentifier(); // When adopting zerary fxs, ensure that they
|
||
// have a new numeric identifier
|
||
zfx->m_columnFx = this;
|
||
}
|
||
|
||
if (m_fx) {
|
||
m_fx->m_columnFx = 0;
|
||
m_fx->release();
|
||
}
|
||
|
||
m_fx = zfx;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::string TZeraryColumnFx::getAlias(double frame,
|
||
const TRenderSettings &info) const {
|
||
return "TZeraryColumnFx[" + m_fx->getAlias(frame, info) + "]";
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TZeraryColumnFx::loadData(TIStream &is) {
|
||
if (m_fx) m_fx->release();
|
||
|
||
m_fx = 0;
|
||
TPersist *p = 0;
|
||
is >> p;
|
||
|
||
m_fx = dynamic_cast<TZeraryFx *>(p);
|
||
if (m_fx) {
|
||
m_fx->addRef();
|
||
m_fx->m_columnFx = this;
|
||
m_fx->setNewIdentifier();
|
||
}
|
||
|
||
TFx::loadData(is);
|
||
setNewIdentifier(); // Same as with TColumnFx
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TZeraryColumnFx::saveData(TOStream &os) {
|
||
assert(m_fx);
|
||
os << m_fx;
|
||
TFx::saveData(os);
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
int TZeraryColumnFx::getColumnIndex() const {
|
||
return m_zeraryFxColumn ? m_zeraryFxColumn->getIndex() : -1;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TXshColumn *TZeraryColumnFx::getXshColumn() const { return m_zeraryFxColumn; }
|
||
|
||
//****************************************************************************************
|
||
// TXSheetFx implementation
|
||
//****************************************************************************************
|
||
|
||
const TPersistDeclaration *TXsheetFx::getDeclaration() const {
|
||
return &infoTXsheetFx;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
TXsheetFx::TXsheetFx() : m_fxDag(0) { setName(L"Xsheet"); }
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TXsheetFx::doCompute(TTile &tile, double frame, const TRenderSettings &) {}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
bool TXsheetFx::doGetBBox(double frame, TRectD &bBox,
|
||
const TRenderSettings &info) {
|
||
return false;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::string TXsheetFx::getPluginId() const { return "Toonz_"; }
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::string TXsheetFx::getAlias(double frame,
|
||
const TRenderSettings &info) const {
|
||
std::string alias = getFxType();
|
||
alias += "[";
|
||
|
||
// Add each terminal fx's alias
|
||
TFxSet *terminalFxs = m_fxDag->getTerminalFxs();
|
||
int i, fxsCount = terminalFxs->getFxCount();
|
||
for (i = 0; i < fxsCount; ++i) {
|
||
alias +=
|
||
static_cast<TRasterFx *>(terminalFxs->getFx(i))->getAlias(frame, info) +
|
||
",";
|
||
}
|
||
|
||
return alias + "]";
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TXsheetFx::setFxDag(FxDag *fxDag) { m_fxDag = fxDag; }
|
||
|
||
//****************************************************************************************
|
||
// TOutputFx implementation
|
||
//****************************************************************************************
|
||
|
||
TOutputFx::TOutputFx() {
|
||
addInputPort("source", m_input);
|
||
setName(L"Output");
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
const TPersistDeclaration *TOutputFx::getDeclaration() const {
|
||
return &infoTOutputFx;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
void TOutputFx::doCompute(TTile &tile, double frame, const TRenderSettings &) {}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
bool TOutputFx::doGetBBox(double frame, TRectD &bBox,
|
||
const TRenderSettings &info) {
|
||
return false;
|
||
}
|
||
|
||
//-------------------------------------------------------------------
|
||
|
||
std::string TOutputFx::getPluginId() const { return "Toonz_"; }
|