1 #include <sstream> /* std::ostringstream */
2 #include "tfxparam.h"
3 #include "stdfx.h"
4 
5 #include "ino_common.h"
6 namespace {
7 const double smoothing_edge_ = 1.0;
8 }
9 //------------------------------------------------------------
10 class ino_maxmin final : public TStandardRasterFx {
11   FX_PLUGIN_DECLARATION(ino_maxmin)
12   TRasterFxPort m_input;
13   TRasterFxPort m_refer;
14 
15   TIntEnumParamP m_max_min_select;
16   TDoubleParamP m_radius;
17   TDoubleParamP m_polygon_number;
18   TDoubleParamP m_degree;
19   TBoolParamP m_alpha_rendering;
20 
21   TIntEnumParamP m_ref_mode;
22 
23 public:
ino_maxmin()24   ino_maxmin()
25       : m_max_min_select(new TIntEnumParam(0, "Max"))
26       , m_radius(1.0)
27       /*	1mmにしたければ 1.0 * 640. / 12. / 25.4 とする
28             0.35    = mm = ユーザ指定の初期値
29             640/12  = 53.33333 = toonz独自の係数 =tunit.cpp参照
30             25.4    = mm/inch
31     */
32       , m_polygon_number(2.0)
33       , m_degree(0.0)
34       , m_alpha_rendering(true)
35 
36       , m_ref_mode(new TIntEnumParam()) {
37     this->m_radius->setMeasureName("fxLength");
38 
39     addInputPort("Source", this->m_input);
40     addInputPort("Reference", this->m_refer);
41 
42     bindParam(this, "max_min_select", this->m_max_min_select);
43     bindParam(this, "radius", this->m_radius);
44     bindParam(this, "polygon_number", this->m_polygon_number);
45     bindParam(this, "degree", this->m_degree);
46     bindParam(this, "alpha_rendering", this->m_alpha_rendering);
47 
48     bindParam(this, "reference", this->m_ref_mode);
49 
50     this->m_max_min_select->addItem(1, "Min");
51     this->m_radius->setValueRange(0.0, 100.0);
52     this->m_polygon_number->setValueRange(2.0, 16.0);
53     this->m_degree->setValueRange(0.0, std::numeric_limits<double>::max());
54 
55     this->m_ref_mode->addItem(0, "Red");
56     this->m_ref_mode->addItem(1, "Green");
57     this->m_ref_mode->addItem(2, "Blue");
58     this->m_ref_mode->addItem(3, "Alpha");
59     this->m_ref_mode->addItem(4, "Luminance");
60     this->m_ref_mode->addItem(-1, "Nothing");
61     this->m_ref_mode->setDefaultValue(0);
62     this->m_ref_mode->setValue(0);
63   }
doGetBBox(double frame,TRectD & bBox,const TRenderSettings & info)64   bool doGetBBox(double frame, TRectD &bBox,
65                  const TRenderSettings &info) override {
66     if (this->m_input.isConnected()) {
67       const bool ret = this->m_input->doGetBBox(frame, bBox, info);
68       const double margin =
69           ceil(ino::pixel_per_mm() *
70                (this->m_radius->getValue(frame) + smoothing_edge_));
71       if (0.0 < margin) {
72         bBox = bBox.enlarge(margin);
73       }
74       return ret;
75     } else {
76       bBox = TRectD();
77       return false;
78     }
79   }
canHandle(const TRenderSettings & info,double frame)80   bool canHandle(const TRenderSettings &info, double frame) override {
81     return true;
82   }
getMemoryRequirement(const TRectD & rect,double frame,const TRenderSettings & info)83   int getMemoryRequirement(const TRectD &rect, double frame,
84                            const TRenderSettings &info) override {
85     const double radius = (this->m_radius->getValue(frame) + smoothing_edge_) *
86                           ino::pixel_per_mm() *
87                           sqrt(fabs(info.m_affine.det())) /
88                           ((info.m_shrinkX + info.m_shrinkY) / 2.0);
89     return TRasterFx::memorySize(rect.enlarge(ceil(radius) + 0.5), info.m_bpp);
90   }
91   void doCompute(TTile &tile, double frame,
92                  const TRenderSettings &rend_sets) override;
93 };
94 FX_PLUGIN_IDENTIFIER(ino_maxmin, "inoMaxMinFx");
95 //------------------------------------------------------------
96 #include "igs_maxmin.h"
97 namespace {
fx_(const TRasterP in_ras,const int margin,TRasterP out_ras,const TRasterP refer_ras,const int refer_mode,const int min_sw,const double radius,const double smoothing_edge,const int npolygon,const double degree,const bool alp_rend_sw,const int nthread)98 void fx_(const TRasterP in_ras  // with margin
99          ,
100          const int margin, TRasterP out_ras  // no margin
101 
102          ,
103          const TRasterP refer_ras, const int refer_mode
104 
105          ,
106          const int min_sw, const double radius, const double smoothing_edge,
107          const int npolygon, const double degree, const bool alp_rend_sw
108 
109          ,
110          const int nthread) {
111   TRasterGR8P out_gr8(in_ras->getLy(),
112                       in_ras->getLx() * ino::channels() *
113                           ((TRaster64P)in_ras ? sizeof(unsigned short)
114                                               : sizeof(unsigned char)));
115   out_gr8->lock();
116 
117   igs::maxmin::convert(
118       in_ras->getRawData()  // BGRA
119       ,
120       out_gr8->getRawData()
121 
122           ,
123       in_ras->getLy(), in_ras->getLx(), ino::channels(), ino::bits(in_ras)
124 
125                                                              ,
126       (((refer_ras != nullptr) && (0 <= refer_mode)) ? refer_ras->getRawData()
127                                                      : nullptr)  // BGRA
128       ,
129       (((refer_ras != nullptr) && (0 <= refer_mode)) ? ino::bits(refer_ras) : 0)
130 
131           ,
132       refer_mode, radius, smoothing_edge  // smooth_outer_range
133       ,
134       npolygon, degree + 180.0
135 
136       ,
137       min_sw, alp_rend_sw, false
138 
139       ,
140       nthread);
141 
142   ino::arr_to_ras(out_gr8->getRawData(), ino::channels(), out_ras, margin);
143   out_gr8->unlock();
144 }
145 }
146 //------------------------------------------------------------
doCompute(TTile & tile,double frame,const TRenderSettings & rend_sets)147 void ino_maxmin::doCompute(TTile &tile, double frame,
148                            const TRenderSettings &rend_sets) {
149   /* ------ 接続していなければ処理しない -------------------- */
150   if (!this->m_input.isConnected()) {
151     tile.getRaster()->clear(); /* 塗りつぶしクリア */
152     return;
153   }
154 
155   /* ------ サポートしていないPixelタイプはエラーを投げる --- */
156   if (!((TRaster32P)tile.getRaster()) && !((TRaster64P)tile.getRaster())) {
157     throw TRopException("unsupported input pixel type");
158   }
159 
160   /* ------ Pixel単位で動作パラメータを得る ----------------- */
161   const double mm2scale_shrink_pixel =
162       ino::pixel_per_mm() * sqrt(fabs(rend_sets.m_affine.det())) /
163       ((rend_sets.m_shrinkX + rend_sets.m_shrinkY) / 2.0);
164 
165   /* 動作パラメータを得る */
166   const int min_sw    = this->m_max_min_select->getValue();  // 0,1
167   const double radius = this->m_radius->getValue(frame) * mm2scale_shrink_pixel;
168   const int npolygon  = this->m_polygon_number->getValue(frame);
169   const double degree = this->m_degree->getValue(frame);
170   const bool alp_rend_sw = this->m_alpha_rendering->getValue();
171 
172   const int refer_mode = this->m_ref_mode->getValue();
173 
174   /* 	tcomposer(RenderManager)でRenderingするときはthreadは1つ、
175           toonz(Desktop)でPreview,Outputするなら-1を指定
176           -1は自動でthread数を決めCPUを最大に使い高速化 */
177   const int nthread = -1;
178 
179   /* ------ 参照マージン含めた画像生成 ---------------------- */
180   /* Rendering画像のBBox値 --> Pixel単位のdouble値 */
181   /*	typedef TRectT<double> TRectD;
182           inline TRectT<double>::TRectT(
183                   const TPointT<double> &bottomLeft
184                   , const TDimensionT<double> &d
185           )	: x0(bottomLeft.x)
186                   , y0(bottomLeft.y)
187                   , x1(bottomLeft.x+d.lx)
188                   , y1(bottomLeft.y+d.ly)
189           {}
190   */
191   TRectD enlarge_rect =
192       TRectD(tile.m_pos /* TPointD */
193              ,
194              TDimensionD(/* int --> doubleにしてセット */
195                          tile.getRaster()->getLx(), tile.getRaster()->getLy()));
196   /* BBoxの拡大 Pixel単位 */
197   const int enlarge_pixel = (int)(ceil(radius + smoothing_edge_) + 0.5);
198   enlarge_rect            = enlarge_rect.enlarge(enlarge_pixel);
199 
200   /*	void TRasterFx::allocateAndCompute(
201                   TTile &tile,
202                   const TPointD &pos, const TDimension &size,
203                   const TRasterP &templateRas, double frame,
204                   const TRenderSettings &info
205           ) {
206                   if (templateRas) {
207           tile.getRaster() = templateRas->create(size.lx, size.ly);
208                   } else {
209           tile.getRaster() = TRaster32P(size.lx, size.ly);
210                   }
211           tile.m_pos = pos;
212                   compute(tile, frame, info);
213           }
214   */
215   TTile enlarge_tile;
216   this->m_input->allocateAndCompute(
217       enlarge_tile, enlarge_rect.getP00(),
218       TDimensionI(/* Pixel単位のdouble -> intにしてセット */
219                   (int)(enlarge_rect.getLx() + 0.5),
220                   (int)(enlarge_rect.getLy() + 0.5)),
221       tile.getRaster(), frame, rend_sets);
222 
223   /*------ 参照画像生成 --------------------------------------*/
224   TTile refer_tile;
225   bool refer_sw = false;
226   if (this->m_refer.isConnected()) {
227     refer_sw = true;
228     this->m_refer->allocateAndCompute(
229         refer_tile, enlarge_tile.m_pos,
230         TDimensionI(/* Pixel単位 */
231                     enlarge_tile.getRaster()->getLx(),
232                     enlarge_tile.getRaster()->getLy()),
233         enlarge_tile.getRaster(), frame, rend_sets);
234   }
235   /* ------ 保存すべき画像メモリを塗りつぶしクリア ---------- */
236   tile.getRaster()->clear(); /* 塗りつぶしクリア */
237 
238   /* ------ (app_begin)log記憶 ------------------------------ */
239   const bool log_sw = ino::log_enable_sw();
240 
241   if (log_sw) {
242     std::ostringstream os;
243     os << "params"
244        << "  min_sw " << min_sw << "  radius " << radius << "  npolygon "
245        << npolygon << "  degree " << degree << "  alp_rend_sw " << alp_rend_sw
246        << "  smoothing_edge " << smoothing_edge_ << "  nthread " << nthread
247        << "  refer_mode " << refer_mode << "   tile w "
248        << tile.getRaster()->getLx() << "  h " << tile.getRaster()->getLy()
249        << "  pixbits " << ino::pixel_bits(tile.getRaster()) << "   frame "
250        << frame << "   rand_sets affine_det " << rend_sets.m_affine.det()
251        << "  shrink x " << rend_sets.m_shrinkX << "  y " << rend_sets.m_shrinkY;
252     if (refer_sw) {
253       os << "  refer_tile.m_pos " << refer_tile.m_pos << "  refer_tile_getLx "
254          << refer_tile.getRaster()->getLx() << "  y "
255          << refer_tile.getRaster()->getLy();
256     }
257   }
258   /* ------ fx処理 ------------------------------------------ */
259   try {
260     tile.getRaster()->lock();
261     enlarge_tile.getRaster()->lock();
262     if (refer_tile.getRaster() != nullptr) {
263       refer_tile.getRaster()->lock();
264     }
265     fx_(enlarge_tile.getRaster()  // in with margin
266         ,
267         enlarge_pixel  // margin
268         ,
269         tile.getRaster()  // out with no margin
270 
271         ,
272         refer_tile.getRaster(), refer_mode
273 
274         ,
275         min_sw, radius, smoothing_edge_, npolygon, degree, alp_rend_sw
276 
277         ,
278         nthread);
279     if (refer_tile.getRaster() != nullptr) {
280       refer_tile.getRaster()->unlock();
281     }
282     enlarge_tile.getRaster()->unlock();
283     tile.getRaster()->unlock();
284   }
285   /* ------ error処理 --------------------------------------- */
286   catch (std::bad_alloc &e) {
287     if (refer_tile.getRaster() != nullptr) {
288       refer_tile.getRaster()->unlock();
289     }
290     enlarge_tile.getRaster()->unlock();
291     tile.getRaster()->unlock();
292     if (log_sw) {
293       std::string str("std::bad_alloc <");
294       str += e.what();
295       str += '>';
296     }
297     throw;
298   } catch (std::exception &e) {
299     if (refer_tile.getRaster() != nullptr) {
300       refer_tile.getRaster()->unlock();
301     }
302     enlarge_tile.getRaster()->unlock();
303     tile.getRaster()->unlock();
304     if (log_sw) {
305       std::string str("exception <");
306       str += e.what();
307       str += '>';
308     }
309     throw;
310   } catch (...) {
311     if (refer_tile.getRaster() != nullptr) {
312       refer_tile.getRaster()->unlock();
313     }
314     enlarge_tile.getRaster()->unlock();
315     tile.getRaster()->unlock();
316     if (log_sw) {
317       std::string str("other exception");
318     }
319     throw;
320   }
321 }
322