72#if defined(WITH_FFTW3)
78 const int2 frequency_size =
int2(spatial_size.x / 2 + 1, spatial_size.y);
80 float *kernel_spatial_domain = fftwf_alloc_real(spatial_size.x * spatial_size.y);
81 frequencies_ =
reinterpret_cast<std::complex<float> *
>(
82 fftwf_alloc_complex(frequency_size.x * frequency_size.y));
85 fftwf_plan forward_plan = fftwf_plan_dft_r2c_2d(spatial_size.y,
87 kernel_spatial_domain,
88 reinterpret_cast<fftwf_complex *
>(frequencies_),
96 double &sum = sum_by_thread.local();
97 for (const int64_t y : sub_y_range) {
98 for (const int64_t x : IndexRange(spatial_size.x)) {
102 const int half_kernel_size = kernel_size / 2;
103 int64_t output_x = mod_i(x - half_kernel_size, spatial_size.x);
104 int64_t output_y = mod_i(y - half_kernel_size, spatial_size.y);
106 const bool is_inside_kernel = x < kernel_size && y < kernel_size;
107 if (is_inside_kernel) {
108 const float kernel_value = compute_fog_glow_kernel_value(x, y, kernel_size);
109 kernel_spatial_domain[output_x + output_y * spatial_size.x] = kernel_value;
113 kernel_spatial_domain[output_x + output_y * spatial_size.x] = 0.0f;
119 fftwf_execute_dft_r2c(
120 forward_plan, kernel_spatial_domain,
reinterpret_cast<fftwf_complex *
>(frequencies_));
121 fftwf_destroy_plan(forward_plan);
122 fftwf_free(kernel_spatial_domain);
128 normalization_factor_ = float(std::accumulate(sum_by_thread.begin(), sum_by_thread.end(), 0.0));