1 /*------------------------------------
2  Iwa_DirectionalBlurFx
3  ボケ足の伸ばし方を選択でき、参照画像を追加した DirectionalBlur
4 //------------------------------------*/
5 
6 #include "iwa_directionalblurfx.h"
7 
8 #include "tparamuiconcept.h"
9 
10 enum FILTER_TYPE { Linear = 0, Gaussian, Flat };
11 
12 /*------------------------------------------------------------
13  参照画像の輝度を0〜1に正規化してホストメモリに読み込む
14 ------------------------------------------------------------*/
15 
16 template <typename RASTER, typename PIXEL>
setReferenceRaster(const RASTER srcRas,float * dstMem,TDimensionI dim)17 void Iwa_DirectionalBlurFx::setReferenceRaster(const RASTER srcRas,
18                                                float *dstMem, TDimensionI dim) {
19   float *dst_p = dstMem;
20 
21   for (int j = 0; j < dim.ly; j++) {
22     PIXEL *pix = srcRas->pixels(j);
23     for (int i = 0; i < dim.lx; i++, pix++, dst_p++) {
24       (*dst_p) = ((float)pix->r * 0.3f + (float)pix->g * 0.59f +
25                   (float)pix->b * 0.11f) /
26                  (float)PIXEL::maxChannelValue;
27     }
28   }
29 }
30 
31 /*------------------------------------------------------------
32  ソース画像を0〜1に正規化してホストメモリに読み込む
33 ------------------------------------------------------------*/
34 
35 template <typename RASTER, typename PIXEL>
setSourceRaster(const RASTER srcRas,float4 * dstMem,TDimensionI dim)36 void Iwa_DirectionalBlurFx::setSourceRaster(const RASTER srcRas, float4 *dstMem,
37                                             TDimensionI dim) {
38   float4 *chann_p = dstMem;
39 
40   for (int j = 0; j < dim.ly; j++) {
41     PIXEL *pix = srcRas->pixels(j);
42     for (int i = 0; i < dim.lx; i++, pix++, chann_p++) {
43       (*chann_p).x = (float)pix->r / (float)PIXEL::maxChannelValue;
44       (*chann_p).y = (float)pix->g / (float)PIXEL::maxChannelValue;
45       (*chann_p).z = (float)pix->b / (float)PIXEL::maxChannelValue;
46       (*chann_p).w = (float)pix->m / (float)PIXEL::maxChannelValue;
47     }
48   }
49 }
50 
51 /*------------------------------------------------------------
52  出力結果をChannel値に変換してタイルに格納
53 ------------------------------------------------------------*/
54 template <typename RASTER, typename PIXEL>
setOutputRaster(float4 * srcMem,const RASTER dstRas,TDimensionI dim,int2 margin)55 void Iwa_DirectionalBlurFx::setOutputRaster(float4 *srcMem, const RASTER dstRas,
56                                             TDimensionI dim, int2 margin) {
57   int out_j = 0;
58   for (int j = margin.y; j < dstRas->getLy() + margin.y; j++, out_j++) {
59     PIXEL *pix     = dstRas->pixels(out_j);
60     float4 *chan_p = srcMem;
61     chan_p += j * dim.lx + margin.x;
62     for (int i = 0; i < dstRas->getLx(); i++, pix++, chan_p++) {
63       float val;
64       val    = (*chan_p).x * (float)PIXEL::maxChannelValue + 0.5f;
65       pix->r = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
66                                              ? (float)PIXEL::maxChannelValue
67                                              : val);
68       val    = (*chan_p).y * (float)PIXEL::maxChannelValue + 0.5f;
69       pix->g = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
70                                              ? (float)PIXEL::maxChannelValue
71                                              : val);
72       val    = (*chan_p).z * (float)PIXEL::maxChannelValue + 0.5f;
73       pix->b = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
74                                              ? (float)PIXEL::maxChannelValue
75                                              : val);
76       val    = (*chan_p).w * (float)PIXEL::maxChannelValue + 0.5f;
77       pix->m = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
78                                              ? (float)PIXEL::maxChannelValue
79                                              : val);
80     }
81   }
82 }
83 
84 //------------------------------------
85 
Iwa_DirectionalBlurFx()86 Iwa_DirectionalBlurFx::Iwa_DirectionalBlurFx()
87     : m_angle(0.0)
88     , m_intensity(10.0)
89     , m_bidirectional(false)
90     , m_filterType(new TIntEnumParam(Linear, "Linear")) {
91   m_intensity->setMeasureName("fxLength");
92   m_angle->setMeasureName("angle");
93 
94   bindParam(this, "angle", m_angle);
95   bindParam(this, "intensity", m_intensity);
96   bindParam(this, "bidirectional", m_bidirectional);
97   bindParam(this, "filterType", m_filterType);
98 
99   addInputPort("Source", m_input);
100   addInputPort("Reference", m_reference);
101   m_intensity->setValueRange(0, (std::numeric_limits<double>::max)());
102 
103   m_filterType->addItem(Gaussian, "Gaussian");
104   m_filterType->addItem(Flat, "Flat");
105 }
106 
107 //------------------------------------
108 
doCompute(TTile & tile,double frame,const TRenderSettings & settings)109 void Iwa_DirectionalBlurFx::doCompute(TTile &tile, double frame,
110                                       const TRenderSettings &settings) {
111   /*- 接続していない場合は処理しない -*/
112   if (!m_input.isConnected()) {
113     tile.getRaster()->clear();
114     return;
115   }
116 
117   TPointD blurVector;
118   double angle       = m_angle->getValue(frame) * M_PI_180;
119   double intensity   = m_intensity->getValue(frame);
120   bool bidirectional = m_bidirectional->getValue();
121 
122   blurVector.x = intensity * cos(angle);
123   blurVector.y = intensity * sin(angle);
124 
125   double shrink = (settings.m_shrinkX + settings.m_shrinkY) / 2.0;
126 
127   /*- 平行移動成分を消したアフィン変換をかけ、ボケベクトルを変形 -*/
128   TAffine aff = settings.m_affine;
129   aff.a13 = aff.a23 = 0;
130   TPointD blur      = (1.0 / shrink) * (aff * blurVector);
131 
132   /*- ボケの実際の長さを求める -*/
133   double blurValue = norm(blur);
134   /*- ボケの実際の長さがほぼ0なら入力画像をそのまま return -*/
135   if (areAlmostEqual(blurValue, 0, 1e-3)) {
136     m_input->compute(tile, frame, settings);
137     return;
138   }
139 
140   /*-  表示の範囲を得る -*/
141   TRectD bBox =
142       TRectD(tile.m_pos /*- Render画像上(Pixel単位)の位置  -*/
143              ,
144              TDimensionD(/*- Render画像上(Pixel単位)のサイズ  -*/
145                          tile.getRaster()->getLx(), tile.getRaster()->getLy()));
146   /*- 上下左右のマージンを得る -*/
147   double minX, maxX, minY, maxY;
148   if (blur.x > 0.0) /*- X成分が正の場合 -*/
149   {
150     maxX = blur.x;
151     minX = (bidirectional) ? -blur.x : 0.0;
152   } else /*- X成分が負の場合 -*/
153   {
154     maxX = (bidirectional) ? -blur.x : 0.0;
155     minX = blur.x;
156   }
157   if (blur.y > 0.0) /*- Y成分が正の場合 -*/
158   {
159     maxY = blur.y;
160     minY = (bidirectional) ? -blur.y : 0.0;
161   } else /*-  Y成分が負の場合 -*/
162   {
163     maxY = (bidirectional) ? -blur.y : 0.0;
164     minY = blur.y;
165   }
166   int marginLeft   = (int)ceil(std::abs(minX));
167   int marginRight  = (int)ceil(std::abs(maxX));
168   int marginTop    = (int)ceil(std::abs(maxY));
169   int marginBottom = (int)ceil(std::abs(minY));
170 
171   /*- マージンは、フィルタの上下左右を反転した寸法になる -*/
172   TRectD enlargedBBox(bBox.x0 - (double)marginRight,
173                       bBox.y0 - (double)marginTop, bBox.x1 + (double)marginLeft,
174                       bBox.y1 + (double)marginBottom);
175 
176   std::cout << "Margin Left:" << marginLeft << " Right:" << marginRight
177             << " Bottom:" << marginBottom << " Top:" << marginTop << std::endl;
178 
179   TDimensionI enlargedDimIn(/*- Pixel単位に四捨五入 -*/
180                             (int)(enlargedBBox.getLx() + 0.5),
181                             (int)(enlargedBBox.getLy() + 0.5));
182 
183   TTile enlarge_tile;
184   m_input->allocateAndCompute(enlarge_tile, enlargedBBox.getP00(),
185                               enlargedDimIn, tile.getRaster(), frame, settings);
186 
187   /*- 参照画像が有ったら、メモリに取り込む -*/
188   float *reference_host = 0;
189   TRasterGR8P reference_host_ras;
190   if (m_reference.isConnected()) {
191     TTile reference_tile;
192     m_reference->allocateAndCompute(reference_tile, enlargedBBox.getP00(),
193                                     enlargedDimIn, tile.getRaster(), frame,
194                                     settings);
195     /*- ホストのメモリ確保 -*/
196     reference_host_ras =
197         TRasterGR8P(sizeof(float) * enlargedDimIn.lx, enlargedDimIn.ly);
198     reference_host_ras->lock();
199     reference_host = (float *)reference_host_ras->getRawData();
200     /*- 参照画像の輝度を0〜1に正規化してホストメモリに読み込む -*/
201     TRaster32P ras32 = (TRaster32P)reference_tile.getRaster();
202     TRaster64P ras64 = (TRaster64P)reference_tile.getRaster();
203     if (ras32)
204       setReferenceRaster<TRaster32P, TPixel32>(ras32, reference_host,
205                                                enlargedDimIn);
206     else if (ras64)
207       setReferenceRaster<TRaster64P, TPixel64>(ras64, reference_host,
208                                                enlargedDimIn);
209   }
210 
211   //-------------------------------------------------------
212   /*- 計算範囲 -*/
213   TDimensionI dimOut(tile.getRaster()->getLx(), tile.getRaster()->getLy());
214   TDimensionI filterDim(marginLeft + marginRight + 1,
215                         marginTop + marginBottom + 1);
216 
217   doCompute_CPU(tile, frame, settings, blur, bidirectional, marginLeft,
218                 marginRight, marginTop, marginBottom, enlargedDimIn,
219                 enlarge_tile, dimOut, filterDim, reference_host);
220 
221   /*-  参照画像が刺さっている場合、メモリを解放する -*/
222   if (reference_host) {
223     reference_host_ras->unlock();
224     reference_host = 0;
225   }
226 }
227 
228 //------------------------------------
229 
doCompute_CPU(TTile & tile,double frame,const TRenderSettings & settings,TPointD & blur,bool bidirectional,int marginLeft,int marginRight,int marginTop,int marginBottom,TDimensionI & enlargedDimIn,TTile & enlarge_tile,TDimensionI & dimOut,TDimensionI & filterDim,float * reference_host)230 void Iwa_DirectionalBlurFx::doCompute_CPU(
231     TTile &tile, double frame, const TRenderSettings &settings, TPointD &blur,
232     bool bidirectional, int marginLeft, int marginRight, int marginTop,
233     int marginBottom, TDimensionI &enlargedDimIn, TTile &enlarge_tile,
234     TDimensionI &dimOut, TDimensionI &filterDim, float *reference_host) {
235   /*- メモリ確保 -*/
236   TRasterGR8P in_ras(sizeof(float4) * enlargedDimIn.lx, enlargedDimIn.ly);
237   in_ras->lock();
238   float4 *in = (float4 *)in_ras->getRawData();
239 
240   TRasterGR8P out_ras(sizeof(float4) * enlargedDimIn.lx, enlargedDimIn.ly);
241   out_ras->lock();
242   float4 *out = (float4 *)out_ras->getRawData();
243 
244   TRasterGR8P filter_ras(sizeof(float) * filterDim.lx, filterDim.ly);
245   filter_ras->lock();
246   float *filter = (float *)filter_ras->getRawData();
247 
248   /*- ソース画像を0〜1に正規化してホストメモリに読み込む -*/
249   TRaster32P ras32 = (TRaster32P)enlarge_tile.getRaster();
250   TRaster64P ras64 = (TRaster64P)enlarge_tile.getRaster();
251   if (ras32)
252     setSourceRaster<TRaster32P, TPixel32>(ras32, in, enlargedDimIn);
253   else if (ras64)
254     setSourceRaster<TRaster64P, TPixel64>(ras64, in, enlargedDimIn);
255 
256   /*- フィルタ作る -*/
257   makeDirectionalBlurFilter_CPU(filter, blur, bidirectional, marginLeft,
258                                 marginRight, marginTop, marginBottom,
259                                 filterDim);
260 
261   if (reference_host) /*- 参照画像がある場合 -*/
262   {
263     float4 *out_p = out + marginTop * enlargedDimIn.lx;
264     float *ref_p  = reference_host + marginTop * enlargedDimIn.lx;
265     /*- フィルタリング -*/
266     for (int y = marginTop; y < dimOut.ly + marginTop; y++) {
267       out_p += marginRight;
268       ref_p += marginRight;
269       for (int x = marginRight; x < dimOut.lx + marginRight;
270            x++, out_p++, ref_p++) {
271         /*- 参照画像が黒ならソースをそのまま返す -*/
272         if ((*ref_p) == 0.0f) {
273           (*out_p) = in[y * enlargedDimIn.lx + x];
274           continue;
275         }
276 
277         /*- 値を積算する入れ物を用意 -*/
278         float4 value = {0.0f, 0.0f, 0.0f, 0.0f};
279 
280         float *filter_p = filter;
281 
282         if ((*ref_p) == 1.0f) {
283           /*- フィルタのサイズでループ
284              ただし、フィルタはサンプル点の画像を収集するように
285                   用いるため、上下左右反転してサンプルする -*/
286           for (int fily = -marginBottom; fily < filterDim.ly - marginBottom;
287                fily++) {
288             /*- サンプル座標 と インデックス の このスキャンラインのうしろ -*/
289             int2 samplePos  = {x + marginLeft, y - fily};
290             int sampleIndex = samplePos.y * enlargedDimIn.lx + samplePos.x;
291 
292             for (int filx = -marginLeft; filx < filterDim.lx - marginLeft;
293                  filx++, filter_p++, sampleIndex--) {
294               /*- フィルター値が0またはサンプルピクセルが透明ならcontinue -*/
295               if ((*filter_p) == 0.0f || in[sampleIndex].w == 0.0f) continue;
296               /*- サンプル点の値にフィルタ値を掛けて積算する -*/
297               value.x += in[sampleIndex].x * (*filter_p);
298               value.y += in[sampleIndex].y * (*filter_p);
299               value.z += in[sampleIndex].z * (*filter_p);
300               value.w += in[sampleIndex].w * (*filter_p);
301             }
302           }
303         } else {
304           for (int fily = -marginBottom; fily < filterDim.ly - marginBottom;
305                fily++) {
306             for (int filx = -marginLeft; filx < filterDim.lx - marginLeft;
307                  filx++, filter_p++) {
308               /*- フィルター値が0ならcontinue -*/
309               if ((*filter_p) == 0.0f) continue;
310               /*- サンプル座標 -*/
311               int2 samplePos = {tround((float)x - (float)filx * (*ref_p)),
312                                 tround((float)y - (float)fily * (*ref_p))};
313               int sampleIndex = samplePos.y * enlargedDimIn.lx + samplePos.x;
314 
315               /*- サンプルピクセルが透明ならcontinue -*/
316               if (in[sampleIndex].w == 0.0f) continue;
317 
318               /*- サンプル点の値にフィルタ値を掛けて積算する -*/
319               value.x += in[sampleIndex].x * (*filter_p);
320               value.y += in[sampleIndex].y * (*filter_p);
321               value.z += in[sampleIndex].z * (*filter_p);
322               value.w += in[sampleIndex].w * (*filter_p);
323             }
324           }
325         }
326 
327         /*- 値を格納 -*/
328         (*out_p) = value;
329       }
330       out_p += marginLeft;
331       ref_p += marginLeft;
332     }
333 
334   } else /*- 参照画像が無い場合 -*/
335   {
336     float4 *out_p = out + marginTop * enlargedDimIn.lx;
337     /*- フィルタリング -*/
338     for (int y = marginTop; y < dimOut.ly + marginTop; y++) {
339       out_p += marginRight;
340       for (int x = marginRight; x < dimOut.lx + marginRight; x++, out_p++) {
341         /*- 値を積算する入れ物を用意 -*/
342         float4 value = {0.0f, 0.0f, 0.0f, 0.0f};
343         /*- フィルタのサイズでループ
344            ただし、フィルタはサンプル点の画像を収集するように
345                 用いるため、上下左右反転してサンプルする -*/
346         int filterIndex = 0;
347         for (int fily = -marginBottom; fily < filterDim.ly - marginBottom;
348              fily++) {
349           /*- サンプル座標 と インデックス の このスキャンラインのうしろ -*/
350           int2 samplePos  = {x + marginLeft, y - fily};
351           int sampleIndex = samplePos.y * enlargedDimIn.lx + samplePos.x;
352 
353           for (int filx = -marginLeft; filx < filterDim.lx - marginLeft;
354                filx++, filterIndex++, sampleIndex--) {
355             /*- フィルター値が0またはサンプルピクセルが透明ならcontinue -*/
356             if (filter[filterIndex] == 0.0f || in[sampleIndex].w == 0.0f)
357               continue;
358             /*- サンプル点の値にフィルタ値を掛けて積算する -*/
359             value.x += in[sampleIndex].x * filter[filterIndex];
360             value.y += in[sampleIndex].y * filter[filterIndex];
361             value.z += in[sampleIndex].z * filter[filterIndex];
362             value.w += in[sampleIndex].w * filter[filterIndex];
363           }
364         }
365 
366         /*- 値を格納 -*/
367         (*out_p) = value;
368       }
369       out_p += marginLeft;
370     }
371   }
372 
373   in_ras->unlock();
374   filter_ras->unlock();
375 
376   /*- ラスタのクリア -*/
377   tile.getRaster()->clear();
378   TRaster32P outRas32 = (TRaster32P)tile.getRaster();
379   TRaster64P outRas64 = (TRaster64P)tile.getRaster();
380   int2 margin         = {marginRight, marginTop};
381   if (outRas32)
382     setOutputRaster<TRaster32P, TPixel32>(out, outRas32, enlargedDimIn, margin);
383   else if (outRas64)
384     setOutputRaster<TRaster64P, TPixel64>(out, outRas64, enlargedDimIn, margin);
385 
386   out_ras->unlock();
387 }
388 
389 //------------------------------------
390 
makeDirectionalBlurFilter_CPU(float * filter,TPointD & blur,bool bidirectional,int marginLeft,int marginRight,int marginTop,int marginBottom,TDimensionI & filterDim)391 void Iwa_DirectionalBlurFx::makeDirectionalBlurFilter_CPU(
392     float *filter, TPointD &blur, bool bidirectional, int marginLeft,
393     int marginRight, int marginTop, int marginBottom, TDimensionI &filterDim) {
394   /*- 必要なら、ガウスフィルタを前計算 -*/
395   FILTER_TYPE filterType = (FILTER_TYPE)m_filterType->getValue();
396   std::vector<float> gaussian;
397   if (filterType == Gaussian) {
398     gaussian.reserve(101);
399     for (int g = 0; g < 101; g++) {
400       float x = (float)g / 100.0f;
401       // sigma == 0.25
402       gaussian.push_back(exp(-x * x / 0.125f));
403     }
404   }
405 
406   /*- フィルタを作る -*/
407   TPointD p0 =
408       (bidirectional) ? TPointD(-blur.x, -blur.y) : TPointD(0.0f, 0.0f);
409   TPointD p1       = blur;
410   float2 vec_p0_p1 = {static_cast<float>(p1.x - p0.x),
411                       static_cast<float>(p1.y - p0.y)};
412 
413   float *fil_p        = filter;
414   float intensity_sum = 0.0f;
415 
416   for (int fy = -marginBottom; fy <= marginTop; fy++) {
417     for (int fx = -marginLeft; fx <= marginRight; fx++, fil_p++) {
418       /*- 現在の座標とブラー直線の距離を求める -*/
419       /*- P0->サンプル点とP0->P1の内積を求める -*/
420       float2 vec_p0_sample = {static_cast<float>(fx - p0.x),
421                               static_cast<float>(fy - p0.y)};
422       float dot = vec_p0_sample.x * vec_p0_p1.x + vec_p0_sample.y * vec_p0_p1.y;
423       /*- 軌跡ベクトルの長さの2乗を計算する -*/
424       float length2 = vec_p0_p1.x * vec_p0_p1.x + vec_p0_p1.y * vec_p0_p1.y;
425 
426       /*- 距離の2乗を求める -*/
427       float dist2;
428       float framePosRatio;
429       /*- P0より手前にある場合 -*/
430       if (dot <= 0.0f) {
431         dist2 = vec_p0_sample.x * vec_p0_sample.x +
432                 vec_p0_sample.y * vec_p0_sample.y;
433         framePosRatio = 0.0f;
434       } else {
435         /*- P0〜P1間にある場合 -*/
436         if (dot < length2) {
437           float p0_sample_dist2 = vec_p0_sample.x * vec_p0_sample.x +
438                                   vec_p0_sample.y * vec_p0_sample.y;
439           dist2         = p0_sample_dist2 - dot * dot / length2;
440           framePosRatio = dot / length2;
441         }
442         /*- P1より先にある場合 -*/
443         else {
444           float2 vec_p1_sample = {static_cast<float>(fx - p1.x),
445                                   static_cast<float>(fy - p1.y)};
446           dist2 = vec_p1_sample.x * vec_p1_sample.x +
447                   vec_p1_sample.y * vec_p1_sample.y;
448           framePosRatio = 1.0f;
449         }
450       }
451       /*- 距離が(√2 + 1)/2より遠かったらreturn dist2との比較だから2乗している
452        * -*/
453       if (dist2 > 1.4571f) {
454         (*fil_p) = 0.0f;
455         continue;
456       }
457 
458       /*-
459          現在のピクセルのサブピクセル(16*16)が、近傍ベクトルからの距離0.5の範囲にどれだけ
460                含まれているかをカウントする -*/
461       int count = 0;
462 
463       for (int yy = 0; yy < 16; yy++) {
464         /*- サブピクセルのY座標 -*/
465         float subPosY = (float)fy + ((float)yy - 7.5f) / 16.0f;
466         for (int xx = 0; xx < 16; xx++) {
467           /*- サブピクセルのX座標 -*/
468           float subPosX = (float)fx + ((float)xx - 7.5f) / 16.0f;
469 
470           float2 vec_p0_sub = {static_cast<float>(subPosX - p0.x),
471                                static_cast<float>(subPosY - p0.y)};
472           float sub_dot =
473               vec_p0_sub.x * vec_p0_p1.x + vec_p0_sub.y * vec_p0_p1.y;
474           /*- 距離の2乗を求める -*/
475           float dist2;
476           /*- P0より手前にある場合 -*/
477           if (sub_dot <= 0.0f)
478             dist2 = vec_p0_sub.x * vec_p0_sub.x + vec_p0_sub.y * vec_p0_sub.y;
479           else {
480             /*- P0〜P1間にある場合 -*/
481             if (sub_dot < length2) {
482               float p0_sub_dist2 =
483                   vec_p0_sub.x * vec_p0_sub.x + vec_p0_sub.y * vec_p0_sub.y;
484               dist2 = p0_sub_dist2 - sub_dot * sub_dot / length2;
485             }
486             /*-  P1より先にある場合 -*/
487             else {
488               float2 vec_p1_sub = {static_cast<float>(subPosX - p1.x),
489                                    static_cast<float>(subPosY - p1.y)};
490               dist2 = vec_p1_sub.x * vec_p1_sub.x + vec_p1_sub.y * vec_p1_sub.y;
491             }
492           }
493           /*- 距離の2乗が0.25より近ければカウントをインクリメント -*/
494           if (dist2 <= 0.25f) count++;
495         }
496       }
497       /*- 保険 カウントが0の場合はフィールド値0でreturn -*/
498       if (count == 0) {
499         (*fil_p) = 0.0f;
500         continue;
501       }
502       /*- countは Max256 -*/
503       float countRatio = (float)count / 256.0f;
504 
505       /*- オフセット値を求める -*/
506       float offset =
507           (bidirectional) ? std::abs(framePosRatio * 2.0 - 1.0) : framePosRatio;
508 
509       /*- フィルタごとに分ける -*/
510       float bokeAsiVal;
511       switch (filterType) {
512       case Linear:
513         bokeAsiVal = 1.0f - offset;
514         break;
515       case Gaussian: {
516         int index   = (int)floor(offset * 100.0f);
517         float ratio = offset * 100.0f - (float)index;
518         bokeAsiVal =
519             gaussian[index] * (1.0f - ratio) + gaussian[index + 1] * ratio;
520       } break;
521       case Flat:
522         bokeAsiVal = 1.0f;
523         break;
524       default:
525         bokeAsiVal = 1.0f - offset;
526         break;
527       }
528 
529       /*- フィールド値の格納 -*/
530       (*fil_p) = bokeAsiVal * countRatio;
531       intensity_sum += (*fil_p);
532     }
533   }
534 
535   /*- 正規化 -*/
536   fil_p = filter;
537   for (int f = 0; f < filterDim.lx * filterDim.ly; f++, fil_p++) {
538     if ((*fil_p) == 0.0f) continue;
539     (*fil_p) /= intensity_sum;
540   }
541 }
542 
543 //------------------------------------
544 
doGetBBox(double frame,TRectD & bBox,const TRenderSettings & info)545 bool Iwa_DirectionalBlurFx::doGetBBox(double frame, TRectD &bBox,
546                                       const TRenderSettings &info) {
547   if (false == this->m_input.isConnected()) {
548     bBox = TRectD();
549     return false;
550   }
551 
552   bool ret = m_input->doGetBBox(frame, bBox, info);
553 
554   if (bBox == TConsts::infiniteRectD) return ret;
555 
556   TPointD blur;
557   double angle       = m_angle->getValue(frame) * M_PI_180;
558   double intensity   = m_intensity->getValue(frame);
559   bool bidirectional = m_bidirectional->getValue();
560 
561   blur.x = intensity * cos(angle);
562   blur.y = intensity * sin(angle);
563 
564   /*- 上下左右のマージンを得る -*/
565   double minX, maxX, minY, maxY;
566   if (blur.x > 0.0) /*- X成分が正の場合 -*/
567   {
568     maxX = blur.x;
569     minX = (bidirectional) ? -blur.x : 0.0;
570   } else /*- X成分が負の場合 -*/
571   {
572     maxX = (bidirectional) ? -blur.x : 0.0;
573     minX = blur.x;
574   }
575   if (blur.y > 0.0) /*- Y成分が正の場合 -*/
576   {
577     maxY = blur.y;
578     minY = (bidirectional) ? -blur.y : 0.0;
579   } else /*-  Y成分が負の場合 -*/
580   {
581     maxY = (bidirectional) ? -blur.y : 0.0;
582     minY = blur.y;
583   }
584   int marginLeft   = (int)ceil(std::abs(minX));
585   int marginRight  = (int)ceil(std::abs(maxX));
586   int marginTop    = (int)ceil(std::abs(maxY));
587   int marginBottom = (int)ceil(std::abs(minY));
588 
589   TRectD enlargedBBox(
590       bBox.x0 - (double)marginLeft, bBox.y0 - (double)marginBottom,
591       bBox.x1 + (double)marginRight, bBox.y1 + (double)marginTop);
592 
593   bBox = enlargedBBox;
594 
595   return ret;
596 }
597 
598 //------------------------------------
599 
canHandle(const TRenderSettings & info,double frame)600 bool Iwa_DirectionalBlurFx::canHandle(const TRenderSettings &info,
601                                       double frame) {
602   return isAlmostIsotropic(info.m_affine) || m_intensity->getValue(frame) == 0;
603 }
604 
605 //------------------------------------
606 
getParamUIs(TParamUIConcept * & concepts,int & length)607 void Iwa_DirectionalBlurFx::getParamUIs(TParamUIConcept *&concepts,
608                                         int &length) {
609   concepts = new TParamUIConcept[length = 1];
610 
611   concepts[0].m_type  = TParamUIConcept::POLAR;
612   concepts[0].m_label = "Angle and Intensity";
613   concepts[0].m_params.push_back(m_angle);
614   concepts[0].m_params.push_back(m_intensity);
615 }
616 
617 //------------------------------------
618 
619 FX_PLUGIN_IDENTIFIER(Iwa_DirectionalBlurFx, "iwa_DirectionalBlurFx")
620