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_linear_light final : public TBlendForeBackRasterFx {
8 FX_PLUGIN_DECLARATION(ino_blend_linear_light)
9 TRasterFxPort m_up;
10 TRasterFxPort m_down;
11 TDoubleParamP m_opacity;
12 TBoolParamP m_clipping_mask;
13
14 public:
ino_blend_linear_light()15 ino_blend_linear_light()
16 : m_opacity(1.0 * ino::param_range()), m_clipping_mask(true) {
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_linear_light()23 ~ino_blend_linear_light() {}
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 ¶m) {}
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_linear_light, "inoLinearLightFx");
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_linear_light::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_linear_light::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::linear_light(
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_linear_light::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