#include "stdfx.h" #include "ttzpimagefx.h" #include "toonz/tcolumnfx.h" #include "toonz/txshcolumn.h" #include "toonz/txshcell.h" #include "toonz/txshsimplelevel.h" #include "toonz/txshpalettelevel.h" #include "globalcontrollablefx.h" //=================================================================== class ExternalPaletteFx final : public GlobalControllableFx { FX_PLUGIN_DECLARATION(ExternalPaletteFx) TRasterFxPort m_input; TRasterFxPort m_expalette; public: ExternalPaletteFx() { addInputPort("Source", m_input); addInputPort("Palette", m_expalette); } ~ExternalPaletteFx(){}; bool doGetBBox(double frame, TRectD &bBox, const TRenderSettings &info) override { if (m_input.isConnected()) { bool ret = m_input->doGetBBox(frame, bBox, info); return ret; } else { bBox = TRectD(); return false; } } std::string getAlias(double frame, const TRenderSettings &info) const override; void doDryCompute(TRectD &rect, double frame, const TRenderSettings &info) override; void doCompute(TTile &tile, double frame, const TRenderSettings &ri) override; bool allowUserCacheOnPort(int port) override { return false; } bool canHandle(const TRenderSettings &info, double frame) override { return true; } }; //------------------------------------------------------------------- namespace { TPalette *getPalette(TXshColumn *column, int frame) { TXshCellColumn *cellColumn = dynamic_cast(column); if (!cellColumn) return 0; TXshCell cell = cellColumn->getCell(frame); // This is only relevant when Implicit Holds are enabled if (cell.isEmpty()) { int r0, r1; cellColumn->getRange(r0, r1); for (int r = std::min(r1, frame); r >= r0; r--) { cell = cellColumn->getCell(r); if (cell.isEmpty()) continue; break; } } if (cell.isEmpty()) return 0; TXshPaletteLevel *pl = cell.m_level->getPaletteLevel(); if (pl) return pl->getPalette(); TXshSimpleLevel *sl = cell.m_level->getSimpleLevel(); if (sl) return sl->getPalette(); return 0; } TPalette *getPalette(TFx *fx, double frame) { if (!fx) return 0; int branches; branches = fx->getInputPortCount(); if (branches == 1) return getPalette(fx->getInputPort(0)->getFx(), frame); if (branches > 1) return 0; if (TColumnFx *columnFx = dynamic_cast(fx)) return getPalette(columnFx->getXshColumn(), (int)frame); return 0; } } // namespace //------------------------------------------------------------------- std::string ExternalPaletteFx::getAlias(double frame, const TRenderSettings &info) const { std::string alias(TRasterFx::getAlias(frame, info)); if (m_expalette.isConnected()) { TFx *fx = m_expalette.getFx(); TPaletteP plt(getPalette(fx, frame)); if (plt && plt->isAnimated()) alias += std::to_string(frame); } return alias; } //------------------------------------------------------------------- void ExternalPaletteFx::doDryCompute(TRectD &rect, double frame, const TRenderSettings &ri) { if (!m_input.isConnected()) return; if (m_expalette.isConnected()) { TFx *fx = m_expalette.getFx(); std::string pltAlias = m_expalette->getAlias(frame, ri); TPaletteP palette(getPalette(fx, frame)); if (palette && palette->isAnimated()) pltAlias += std::to_string(frame); TRenderSettings ri2(ri); ExternalPaletteFxRenderData *data = new ExternalPaletteFxRenderData(palette, pltAlias); ri2.m_data.push_back(data); ri2.m_userCachable = false; m_input->dryCompute(rect, frame, ri2); } else m_input->dryCompute(rect, frame, ri); } //------------------------------------------------------------------- void ExternalPaletteFx::doCompute(TTile &tile, double frame, const TRenderSettings &ri) { if (!m_input.isConnected()) return; if (m_expalette.isConnected()) { TFx *fx = m_expalette.getFx(); std::string pltAlias = m_expalette->getAlias(frame, ri); TPaletteP palette(getPalette(fx, frame)); if (palette && palette->isAnimated()) pltAlias += std::to_string(frame); TRenderSettings ri2(ri); ExternalPaletteFxRenderData *data = new ExternalPaletteFxRenderData(palette, pltAlias); ri2.m_data.push_back(data); m_input->compute(tile, frame, ri2); } else m_input->compute(tile, frame, ri); } FX_PLUGIN_IDENTIFIER(ExternalPaletteFx, "externalPaletteFx");