1 //------------------------------------------------------------
2 #include "tfxparam.h"
3 #include "stdfx.h"
4 
5 #include "ino_common.h"
6 /* tnzbase --> Source Files --> tfx --> binaryFx.cppを参照 */
7 class ino_blend_darker_color final : public TBlendForeBackRasterFx {
8   FX_PLUGIN_DECLARATION(ino_blend_darker_color)
9   TRasterFxPort m_up;
10   TRasterFxPort m_down;
11   TDoubleParamP m_opacity;
12   TBoolParamP m_clipping_mask;
13 
14 public:
ino_blend_darker_color()15   ino_blend_darker_color()
16       : m_opacity(1.0 * ino::param_range()), m_clipping_mask(false) {
17     addInputPort("Fore", this->m_up);
18     addInputPort("Back", this->m_down);
19     bindParam(this, "opacity", this->m_opacity);
20     bindParam(this, "clipping_mask", this->m_clipping_mask);
21     this->m_opacity->setValueRange(0, 1.0 * ino::param_range());
22   }
~ino_blend_darker_color()23   ~ino_blend_darker_color() {}
canHandle(const TRenderSettings & rs,double frame)24   bool canHandle(const TRenderSettings &rs, double frame) override {
25     return true;
26   }
doGetBBox(double frame,TRectD & bBox,const TRenderSettings & rs)27   bool doGetBBox(double frame, TRectD &bBox,
28                  const TRenderSettings &rs) override {
29     TRectD up_bx;
30     const bool up_sw =
31         (m_up.isConnected() ? m_up->doGetBBox(frame, up_bx, rs) : false);
32     TRectD dn_bx;
33     const bool dn_sw =
34         (m_down.isConnected() ? m_down->doGetBBox(frame, dn_bx, rs) : false);
35     if (up_sw && dn_sw) {
36       bBox = up_bx + dn_bx;
37       return !bBox.isEmpty();
38     } else if (up_sw) {
39       bBox = up_bx;
40       return true;
41     } else if (dn_sw) {
42       bBox = dn_bx;
43       return true;
44     } else {
45       bBox = TRectD();
46       return false;
47     }
48   }
49   // TRect getInvalidRect(const TRect &max) {return max;}
50   // void doSetParam(const std::string &name, const TParamP &param) {}
getMemoryRequirement(const TRectD & rect,double frame,const TRenderSettings & rs)51   int getMemoryRequirement(const TRectD &rect, double frame,
52                            const TRenderSettings &rs) override {
53     return TRasterFx::memorySize(rect, rs.m_bpp);
54   }
55 
doDryCompute(TRectD & rect,double frame,const TRenderSettings & rs)56   void doDryCompute(TRectD &rect, double frame,
57                     const TRenderSettings &rs) override {
58     this->dryComputeUpAndDown(rect, frame, rs, false);
59   }
60   void doCompute(TTile &tile, double frame, const TRenderSettings &rs) override;
61   void computeUpAndDown(TTile &tile, double frame, const TRenderSettings &rs,
62                         TRasterP &dn_ras, TRasterP &up_ras,
63                         bool upComputesWholeTile = false);
64   void dryComputeUpAndDown(TRectD &rect, double frame,
65                            const TRenderSettings &rs,
66                            bool upComputesWholeTile = false
67                            /*
68            upComputesWholeTile は Screen, Min, Blendでtrueにして使用している。
69            */
70                            );
71 };
72 FX_PLUGIN_IDENTIFIER(ino_blend_darker_color, "inoDarkerColorFx");
73 //------------------------------------------------------------
74 namespace {
75 /* より大きな四角エリアにPixel整数値で密着する */
makeRectCoherent(TRectD & rect,const TPointD & pos)76 void makeRectCoherent(TRectD &rect, const TPointD &pos) {
77   rect -= pos;
78   rect.x0 = tfloor(rect.x0); /* ((x)<(int)(x)? (int)(x)-1: (int)(x))*/
79   rect.y0 = tfloor(rect.y0);
80   rect.x1 = tceil(rect.x1); /* ((int)(x)<(x)? (int)(x)+1: (int)(x))*/
81   rect.y1 = tceil(rect.y1);
82   rect += pos;
83 }
84 }
computeUpAndDown(TTile & tile,double frame,const TRenderSettings & rs,TRasterP & dn_ras,TRasterP & up_ras,bool upComputesWholeTile)85 void ino_blend_darker_color::computeUpAndDown(TTile &tile, double frame,
86                                               const TRenderSettings &rs,
87                                               TRasterP &dn_ras,
88                                               TRasterP &up_ras,
89                                               bool upComputesWholeTile) {
90   /* ------ サポートしていないPixelタイプはエラーを投げる --- */
91   if (!((TRaster32P)tile.getRaster()) && !((TRaster64P)tile.getRaster())) {
92     throw TRopException("unsupported input pixel type");
93   }
94   /*
95 m_down,m_upは繋がっている方があればそれを表示する
96 両方とも接続していれば合成処理する
97 表示スイッチを切ってあるならm_upを表示する
98 fxをreplaceすると、
99   m_source   --> m_up  (=port0)
100   m_refernce --> m_down(=port1)
101 となる
102 */
103   const bool up_is = (this->m_up.isConnected() &&
104                       this->m_up.getFx()->getTimeRegion().contains(frame));
105   const bool down_is = (this->m_down.isConnected() &&
106                         this->m_down.getFx()->getTimeRegion().contains(frame));
107   /* ------ 両方とも切断の時処理しない ---------------------- */
108   if (!up_is && !down_is) {
109     tile.getRaster()->clear();
110     return;
111   }
112   /* ------ up接続かつdown切断の時 -------------------------- */
113   if (up_is && !down_is) {
114     this->m_up->compute(tile, frame, rs);
115     return;
116   }
117   /* ------ down接続時 downのみ描画して... ------------------ */
118   if (down_is) {
119     this->m_down->compute(tile, frame, rs);
120   }
121   /* ------ up切断時 ---------------------------------------- */
122   if (!up_is) {
123     return;
124   }
125 
126   /* upと重なる部分を描画する */
127 
128   /* ------ tileの範囲 -------------------------------------- */
129   const TDimension tsz(tile.getRaster()->getSize()); /* 整数 */
130   const TRectD tileRect(tile.m_pos, TDimensionD(tsz.lx, tsz.ly));
131   TRectD upBBox;
132   if (upComputesWholeTile) {
133     upBBox = tileRect;
134   }      /* tile全体を得る */
135   else { /* 厳密なエリア... */
136     this->m_up->getBBox(frame, upBBox, rs);
137     upBBox *= tileRect; /* upとtileの交差エリア */
138 
139     /* より大きな四角エリアにPixel整数値で密着する */
140     makeRectCoherent(upBBox, tile.m_pos);  // double-->int grid
141   }
142 
143   TDimensionI upSize(                        /* TRectDをTDimensionIに変換 */
144                      tround(upBBox.getLx())  // getLx() = "x1>=x0?x1-x0:0"
145                      ,
146                      tround(upBBox.getLy())  // getLy() = "y1>=y0?y1-y0:0"
147                      );
148   if ((upSize.lx <= 0) || (upSize.ly <= 0)) {
149     return;
150   }
151 
152   /* ------ upのメモリ確保と描画 ---------------------------- */
153   TTile upTile;
154   this->m_up->allocateAndCompute(upTile, upBBox.getP00(), upSize,
155                                  tile.getRaster() /* 32/64bitsの判定に使う */
156                                  ,
157                                  frame, rs);
158   /* ------ upとdownのTRasterを得る ------------------------- */
159   TRectI dnRect(upTile.getRaster()->getSize());  // TDimensionI(-)
160 
161   dnRect += convert(upTile.m_pos - tile.m_pos); /* uptile->tile原点 */
162   /*
163   ここで問題はdoubleの位置を、四捨五入して整数値にしていること
164   移動してから四捨五入ではないの???
165   dnRectの元位置が整数位置なので、問題ないか...
166   */
167 
168   dn_ras = upComputesWholeTile ? tile.getRaster()
169                                : tile.getRaster()->extract(dnRect);
170   up_ras = upTile.getRaster();
171   assert(dn_ras->getSize() == up_ras->getSize());
172 }
dryComputeUpAndDown(TRectD & rect,double frame,const TRenderSettings & rs,bool upComputesWholeTile)173 void ino_blend_darker_color::dryComputeUpAndDown(TRectD &rect, double frame,
174                                                  const TRenderSettings &rs,
175                                                  bool upComputesWholeTile) {
176   const bool up_is = (this->m_up.isConnected() &&
177                       this->m_up.getFx()->getTimeRegion().contains(frame));
178   const bool down_is = (this->m_down.isConnected() &&
179                         this->m_down.getFx()->getTimeRegion().contains(frame));
180   /* ------ 両方とも切断の時処理しない ---------------------- */
181   if (!up_is && !down_is) {
182     return;
183   }
184   /* ------ up接続かつdown切断の時 -------------------------- */
185   if (up_is && !down_is) {
186     this->m_up->dryCompute(rect, frame, rs);
187     return;
188   }
189   /* ------ down接続時 -------------------------------------- */
190   if (down_is) {
191     this->m_down->dryCompute(rect, frame, rs);
192   }
193   /* ------ up切断時 ---------------------------------------- */
194   if (!up_is) {
195     return;
196   }
197 
198   /* ------ tileのgeometryを計算する ------------------------ */
199   TRectD upBBox;
200 
201   if (upComputesWholeTile) {
202     upBBox = rect;
203   } else {
204     this->m_up->getBBox(frame, upBBox, rs);
205     upBBox *= rect;
206     makeRectCoherent(upBBox, rect.getP00());
207   }
208   if ((upBBox.getLx() > 0.5) && (upBBox.getLy() > 0.5)) {
209     this->m_up->dryCompute(upBBox, frame, rs);
210   }
211 }
212 //------------------------------------------------------------
213 #include <sstream> /* std::ostringstream */
214 #include "igs_color_blend.h"
215 namespace {
216 template <class T, class Q>
tmpl_(TRasterPT<T> dn_ras_out,const TRasterPT<T> & up_ras,const double up_opacity,const bool clipping_mask_sw)217 void tmpl_(TRasterPT<T> dn_ras_out, const TRasterPT<T> &up_ras,
218            const double up_opacity, const bool clipping_mask_sw) {
219   double maxi = static_cast<double>(T::maxChannelValue);  // 255or65535
220 
221   assert(dn_ras_out->getSize() == up_ras->getSize());
222 
223   for (int yy = 0; yy < dn_ras_out->getLy(); ++yy) {
224     T *out_pix             = dn_ras_out->pixels(yy);
225     const T *const out_end = out_pix + dn_ras_out->getLx();
226     const T *up_pix        = up_ras->pixels(yy);
227     for (; out_pix < out_end; ++out_pix, ++up_pix) {
228       double upr = static_cast<double>(up_pix->r) / maxi;
229       double upg = static_cast<double>(up_pix->g) / maxi;
230       double upb = static_cast<double>(up_pix->b) / maxi;
231       double upa = static_cast<double>(up_pix->m) / maxi;
232       double dnr = static_cast<double>(out_pix->r) / maxi;
233       double dng = static_cast<double>(out_pix->g) / maxi;
234       double dnb = static_cast<double>(out_pix->b) / maxi;
235       double dna = static_cast<double>(out_pix->m) / maxi;
236       igs::color::darker_color(
237           dnr, dng, dnb, dna, upr, upg, upb, upa,
238           clipping_mask_sw ? up_opacity * dna : up_opacity);
239       out_pix->r = static_cast<Q>(dnr * (maxi + 0.999999));
240       out_pix->g = static_cast<Q>(dng * (maxi + 0.999999));
241       out_pix->b = static_cast<Q>(dnb * (maxi + 0.999999));
242       out_pix->m = static_cast<Q>(dna * (maxi + 0.999999));
243     }
244   }
245 }
fx_(TRasterP & dn_ras_out,const TRasterP & up_ras,const TPoint & pos,const double up_opacity,const bool clipping_mask_sw)246 void fx_(TRasterP &dn_ras_out, const TRasterP &up_ras, const TPoint &pos,
247          const double up_opacity, const bool clipping_mask_sw) {
248   /* 交差したエリアを処理するようにする、いるのか??? */
249   TRect outRect(dn_ras_out->getBounds());
250   TRect upRect(up_ras->getBounds() + pos);
251   TRect intersection = outRect * upRect;
252   if (intersection.isEmpty()) return;
253 
254   TRasterP cRout = dn_ras_out->extract(intersection);
255   TRect rr       = intersection - pos;
256   TRasterP cRup  = up_ras->extract(rr);
257 
258   TRaster32P rout32 = cRout, rup32 = cRup;
259   TRaster64P rout64 = cRout, rup64 = cRup;
260 
261   if (rout32 && rup32) {
262     tmpl_<TPixel32, UCHAR>(rout32, rup32, up_opacity, clipping_mask_sw);
263   } else if (rout64 && rup64) {
264     tmpl_<TPixel64, USHORT>(rout64, rup64, up_opacity, clipping_mask_sw);
265   } else {
266     throw TRopException("unsupported pixel type");
267   }
268 }
269 }
doCompute(TTile & tile,double frame,const TRenderSettings & rs)270 void ino_blend_darker_color::doCompute(TTile &tile, double frame,
271                                        const TRenderSettings &rs) {
272   /* ------ 画像生成 ---------------------------------------- */
273   TRasterP dn_ras, up_ras;
274   this->computeUpAndDown(tile, frame, rs, dn_ras, up_ras);
275   if (!dn_ras || !up_ras) {
276     return;
277   }
278   /* ------ 動作パラメータを得る ---------------------------- */
279   const double up_opacity =
280       this->m_opacity->getValue(frame) / ino::param_range();
281   /* ------ (app_begin)log記憶 ------------------------------ */
282   const bool log_sw = ino::log_enable_sw();
283 
284   if (log_sw) {
285     std::ostringstream os;
286     os << "params"
287        << "  up_opacity " << up_opacity << "   dn_tile w " << dn_ras->getLx()
288        << "  wrap " << dn_ras->getWrap() << "  h " << dn_ras->getLy()
289        << "  pixbits " << ino::pixel_bits(dn_ras) << "   up_tile w "
290        << up_ras->getLx() << "  wrap " << up_ras->getWrap() << "  h "
291        << up_ras->getLy() << "  pixbits " << ino::pixel_bits(up_ras)
292        << "   frame " << frame;
293   }
294   /* ------ fx処理 ------------------------------------------ */
295   try {
296     if (dn_ras) {
297       dn_ras->lock();
298     }
299     if (up_ras) {
300       up_ras->lock();
301     }
302     fx_(dn_ras, up_ras, TPoint(), up_opacity,
303         this->m_clipping_mask->getValue());
304     if (up_ras) {
305       up_ras->unlock();
306     }
307     if (dn_ras) {
308       dn_ras->unlock();
309     }
310   }
311   /* ------ error処理 --------------------------------------- */
312   catch (std::exception &e) {
313     if (up_ras) {
314       up_ras->unlock();
315     }
316     if (dn_ras) {
317       dn_ras->unlock();
318     }
319     if (log_sw) {
320       std::string str("exception <");
321       str += e.what();
322       str += '>';
323     }
324     throw;
325   } catch (...) {
326     if (up_ras) {
327       up_ras->unlock();
328     }
329     if (dn_ras) {
330       dn_ras->unlock();
331     }
332     if (log_sw) {
333       std::string str("other exception");
334     }
335     throw;
336   }
337 }
338