73#if defined(WITH_FFTW3)
80 const int2 frequency_size =
int2(spatial_size.x / 2 + 1, spatial_size.y);
82 float *kernel_spatial_domain = fftwf_alloc_real(spatial_size.x * spatial_size.y);
83 frequencies_ =
reinterpret_cast<std::complex<float> *
>(
84 fftwf_alloc_complex(frequency_size.x * frequency_size.y));
87 fftwf_plan forward_plan = fftwf_plan_dft_r2c_2d(spatial_size.y,
89 kernel_spatial_domain,
90 reinterpret_cast<fftwf_complex *
>(frequencies_),
98 double &sum = sum_by_thread.local();
99 for (const int64_t y : sub_y_range) {
100 for (const int64_t x : IndexRange(spatial_size.x)) {
104 const int half_kernel_size = kernel_size / 2;
105 int64_t output_x = mod_i(x - half_kernel_size, spatial_size.x);
106 int64_t output_y = mod_i(y - half_kernel_size, spatial_size.y);
108 const bool is_inside_kernel = x < kernel_size && y < kernel_size;
109 if (is_inside_kernel) {
110 const float kernel_value = compute_fog_glow_kernel_value(x, y, kernel_size);
111 kernel_spatial_domain[output_x + output_y * spatial_size.x] = kernel_value;
115 kernel_spatial_domain[output_x + output_y * spatial_size.x] = 0.0f;
121 fftwf_execute_dft_r2c(
122 forward_plan, kernel_spatial_domain,
reinterpret_cast<fftwf_complex *
>(frequencies_));
123 fftwf_destroy_plan(forward_plan);
124 fftwf_free(kernel_spatial_domain);
130 normalization_factor_ =
float(std::accumulate(sum_by_thread.begin(), sum_by_thread.end(), 0.0));