#include <sstream> /* std::ostringstream */
/* Not use boost at toonz-6.1 */
// #include <boost/shared_array.hpp> /* boost::shared_array<> */
#include "tfxparam.h"
#include "stdfx.h"
#include "ino_common.h"
//------------------------------------------------------------
class ino_channel_selector final : public TStandardRasterFx {
FX_PLUGIN_DECLARATION(ino_channel_selector)
TRasterFxPort m_source1;
TRasterFxPort m_source2;
TRasterFxPort m_source3;
TRasterFxPort m_source4;
TIntParamP m_red_source;
TIntParamP m_gre_source;
TIntParamP m_blu_source;
TIntParamP m_alp_source;
TIntEnumParamP m_red_channel;
TIntEnumParamP m_gre_channel;
TIntEnumParamP m_blu_channel;
TIntEnumParamP m_alp_channel;
public:
ino_channel_selector()
: m_red_source(1)
, m_gre_source(1)
, m_blu_source(1)
, m_alp_source(1)
, m_red_channel(new TIntEnumParam(0, "Red"))
, m_gre_channel(new TIntEnumParam(1, "Green"))
, m_blu_channel(new TIntEnumParam(2, "Blue"))
, m_alp_channel(new TIntEnumParam(3, "Alpha")) {
addInputPort("Source1", this->m_source1);
addInputPort("Source2", this->m_source2);
addInputPort("Source3", this->m_source3);
addInputPort("Source4", this->m_source4);
bindParam(this, "red_source", this->m_red_source);
bindParam(this, "green_source", this->m_gre_source);
bindParam(this, "blue_source", this->m_blu_source);
bindParam(this, "alpha_source", this->m_alp_source);
bindParam(this, "red_channel", this->m_red_channel);
bindParam(this, "green_channel", this->m_gre_channel);
bindParam(this, "blue_channel", this->m_blu_channel);
bindParam(this, "alpha_channel", this->m_alp_channel);
this->m_red_channel->addItem(1, "Green");
this->m_red_channel->addItem(2, "Blue");
this->m_red_channel->addItem(3, "Alpha");
this->m_gre_channel->addItem(0, "Red");
this->m_gre_channel->addItem(2, "Blue");
this->m_gre_channel->addItem(3, "Alpha");
this->m_blu_channel->addItem(0, "Red");
this->m_blu_channel->addItem(1, "Green");
this->m_blu_channel->addItem(3, "Alpha");
this->m_alp_channel->addItem(0, "Red");
this->m_alp_channel->addItem(1, "Green");
this->m_alp_channel->addItem(2, "Blue");
}
bool doGetBBox(double frame, TRectD &bBox,
const TRenderSettings &info) override {
for (int ii = 0; ii < this->getInputPortCount(); ++ii) {
std::string nm = this->getInputPortName(ii);
TRasterFxPort *tmp_port = (TRasterFxPort *)this->getInputPort(nm);
if (tmp_port->isConnected()) {
return (*tmp_port)->doGetBBox(frame, bBox, info);
}
}
bBox = TRectD();
return false;
}
bool canHandle(const TRenderSettings &info, double frame) override {
return true;
}
void doCompute(TTile &tile, double frame, const TRenderSettings &ri) override;
};
FX_PLUGIN_IDENTIFIER(ino_channel_selector, "inoChannelSelectorFx");
//--------------------------------------------------------------------
// #include "igs_channel_selector.h"
namespace {
template <typename IN_PIXEL, typename OUT_PIXEL>
void fx_template(const TRasterPT<IN_PIXEL> in_ras, const int in_sel,
const TRasterPT<OUT_PIXEL> out_ras, const int out_sel) {
for (int yy = 0; yy < out_ras->getLy(); ++yy) {
IN_PIXEL *sl_in = in_ras->pixels(yy);
OUT_PIXEL *sl_out = out_ras->pixels(yy);
for (int xx = 0; xx < out_ras->getLx(); ++xx, ++sl_in, ++sl_out) {
int val = 0;
switch (in_sel) {
case 0:
val = sl_in->r;
break;
case 1:
val = sl_in->g;
break;
case 2:
val = sl_in->b;
break;
case 3:
val = sl_in->m;
break;
}
switch (out_sel) {
case 0:
sl_out->r = val;
break;
case 1:
sl_out->g = val;
break;
case 2:
sl_out->b = val;
break;
case 3:
sl_out->m = val;
break;
}
}
}
}
void fx_(const TRasterP in_ras, const int in_sel, TRasterP out_ras,
const int out_sel) {
if ((TRaster32P)in_ras && (TRaster32P)out_ras) {
fx_template<TPixel32, TPixel32>(in_ras, in_sel, out_ras, out_sel);
} else if ((TRaster64P)in_ras && (TRaster64P)out_ras) {
fx_template<TPixel64, TPixel64>(in_ras, in_sel, out_ras, out_sel);
}
}
}
//------------------------------------------------------------
void ino_channel_selector::doCompute(TTile &tile, double frame,
const TRenderSettings &ri) {
/* ------ サポートしていないPixelタイプはエラーを投げる --- */
if (!((TRaster32P)tile.getRaster()) && !((TRaster64P)tile.getRaster())) {
throw TRopException("unsupported input pixel type");
}
/* ------ 動作パラメータを得る ---------------------------- */
const int red_source = this->m_red_source->getValue() - 1;
const int gre_source = this->m_gre_source->getValue() - 1;
const int blu_source = this->m_blu_source->getValue() - 1;
const int alp_source = this->m_alp_source->getValue() - 1;
const int red_channel = this->m_red_channel->getValue();
const int gre_channel = this->m_gre_channel->getValue();
const int blu_channel = this->m_blu_channel->getValue();
const int alp_channel = this->m_alp_channel->getValue();
/* ------ 画像位置とサイズ -------------------------------- */
/***const TRectD rect = TRectD( tile.m_pos, TDimensionD(
tile.getRaster()->getLx()
, tile.getRaster()->getLy()
));
const TPointD poin = TPointD(rect.getP00());
const TDimension dime = TDimension(
(int)(rect.getLx()+0.5)
,(int)(rect.getLy()+0.5)
);***/
/* ------ 塗りつぶしクリア -------------------------------- */
tile.getRaster()->clear();
/* ------ 入力画像を接続していなければ処理しない ---------- */
if (this->getInputPortCount() <= 0) {
return;
}
/* ------ 入力画像の参照を確保 ---------------------------- */
// TTile *source_tiles = new TTile[this->getInputPortCount()];
// int *source_sw = new int[this->getInputPortCount()];
// TRasterP *ras_a = new TRasterP[this->getInputPortCount()];
/* Not use boost at toonz-6.1 */
/******
boost::shared_array<TTile>
source_tiles(new TTile[this->getInputPortCount()]);
boost::shared_array<int>
source_sw(new int[this->getInputPortCount()]);
boost::shared_array<TRasterP>
ras_a(new TRasterP[this->getInputPortCount()]);
******/
/* Array item(TRasterFxPort) number is 4(fix) in this code */
TTile source_tiles[4];
int source_sw[4];
TRasterP ras_a[4];
int ras_s = 0;
/* ------ 画像生成 ---------------------------------------- */
for (int ii = 0; ii < this->getInputPortCount(); ++ii) {
std::string nm = this->getInputPortName(ii);
TRasterFxPort *tmp_port = (TRasterFxPort *)this->getInputPort(nm);
if (tmp_port->isConnected() && ((ii == red_source) || (ii == gre_source) ||
(ii == blu_source) || (ii == alp_source))) {
(*tmp_port)->allocateAndCompute(
source_tiles[ii]
//,poin,dime
,
tile.m_pos /* 位置 */
,
TDimension(/* サイズ */
tile.getRaster()->getLx(), tile.getRaster()->getLy()),
tile.getRaster() /* sampling */
,
frame, ri);
source_sw[ii] = 1;
ras_a[ras_s++] = source_tiles[ii].getRaster();
} else
source_sw[ii] = 0;
}
TRasterP red_ras = 0;
TRasterP gre_ras = 0;
TRasterP blu_ras = 0;
TRasterP alp_ras = 0;
if ((0 <= red_source) && (red_source < this->getInputPortCount()) &&
source_sw[red_source]) {
red_ras = source_tiles[red_source].getRaster();
}
if ((0 <= gre_source) && (gre_source < this->getInputPortCount()) &&
source_sw[gre_source]) {
gre_ras = source_tiles[gre_source].getRaster();
}
if ((0 <= blu_source) && (blu_source < this->getInputPortCount()) &&
source_sw[blu_source]) {
blu_ras = source_tiles[blu_source].getRaster();
}
if ((0 <= alp_source) && (alp_source < this->getInputPortCount()) &&
source_sw[alp_source]) {
alp_ras = source_tiles[alp_source].getRaster();
}
/* ------ (app_begin)log記憶 ------------------------------ */
const bool log_sw = ino::log_enable_sw();
if (log_sw) {
std::ostringstream os;
os << "red"
<< " s " << red_source << " c " << red_channel << " green"
<< " s " << gre_source << " c " << gre_channel << " blue"
<< " s " << blu_source << " c " << blu_channel << " alpha"
<< " s " << alp_source << " c " << alp_channel << " tile w "
<< tile.getRaster()->getLx() << " h " << tile.getRaster()->getLy()
<< " b " << ino::pixel_bits(tile.getRaster());
os << " s_count " << this->getInputPortCount();
for (int ii = 0; ii < this->getInputPortCount(); ++ii) {
if (source_sw[ii]) {
os << " tile" << ii << " w " << source_tiles[ii].getRaster()->getLx()
<< " h " << source_tiles[ii].getRaster()->getLy() << " b "
<< ino::pixel_bits(source_tiles[ii].getRaster());
}
}
os << " frame " << frame;
}
/* ------ 入力画像の参照開放 ------------------------------ */
// delete [] source_sw;
// delete [] source_tiles;
/* ------ fx処理 ------------------------------------------ */
try {
tile.getRaster()->lock();
for (int ii = 0; ii < ras_s; ++ii) {
ras_a[ii]->lock();
}
if (red_ras) {
fx_(red_ras, red_channel, tile.getRaster(), 0);
}
if (gre_ras) {
fx_(gre_ras, gre_channel, tile.getRaster(), 1);
}
if (blu_ras) {
fx_(blu_ras, blu_channel, tile.getRaster(), 2);
}
if (alp_ras) {
fx_(alp_ras, alp_channel, tile.getRaster(), 3);
}
for (int ii = ras_s - 1; 0 <= ii; --ii) {
ras_a[ii]->unlock();
}
tile.getRaster()->unlock();
}
/* ------ error処理 --------------------------------------- */
catch (std::bad_alloc &e) {
for (int ii = ras_s - 1; 0 <= ii; --ii) {
ras_a[ii]->unlock();
}
tile.getRaster()->unlock();
if (log_sw) {
std::string str("std::bad_alloc <");
str += e.what();
str += '>';
}
// delete [] ras_a;
throw;
} catch (std::exception &e) {
for (int ii = ras_s - 1; 0 <= ii; --ii) {
ras_a[ii]->unlock();
}
tile.getRaster()->unlock();
if (log_sw) {
std::string str("exception <");
str += e.what();
str += '>';
}
// delete [] ras_a;
throw;
} catch (...) {
for (int ii = ras_s - 1; 0 <= ii; --ii) {
ras_a[ii]->unlock();
}
tile.getRaster()->unlock();
if (log_sw) {
std::string str("other exception");
}
// delete [] ras_a;
throw;
}
// delete [] ras_a;
}