////////////////////////////////
// Gaussian Blur Functions

MR4TH_SYMBOL F32
math_gaussian(F32 sigma, F32 x){
  // 1/(sqrt(2*pi)*sigma) * e^(-x*x/(2*sigma*sigma))
  
  F32 sqrt_2pi = sqrt_F32(tau_F32);
  F32 inv_sqrt_2pi_sigma = 1.f/(sqrt_2pi*sigma);
  F32 sigma_p2 = sigma*sigma;
  
  F32 exponent = -x*x/(2*sigma_p2);
  F32 power = pow_F32(e_F32, exponent);
  
  F32 result = inv_sqrt_2pi_sigma*power;
  return(result);
}

MR4TH_SYMBOL F32*
math_gaussian_kernel(Arena *arena, F32 sigma, U32 extra_reach, U64 *count_out){
  Assert(sigma > 0.f);
  
  // allocate
  U32 reach = (U32)ceil_F32(sigma) + extra_reach;
  U64 count = reach*2 + 1;
  F32 *vals = push_array(arena, F32, count);
  
  // calculate guassian samples & sum
  F32 sum = 0;
  {
    F32 sqrt_2pi = sqrt_F32(tau_F32);
    F32 inv_sqrt_2pi_sigma = 1.f/(sqrt_2pi*sigma);
    F32 sigma_p2 = sigma*sigma;
    
    F32 mid = (F32)reach;
    F32 *val_ptr = vals;
    for (U64 i = 0; i < count; i += 1, val_ptr += 1){
      F32 x = (F32)i - mid;
      F32 exponent = -x*x/(2*sigma_p2);
      F32 power = pow_F32(e_F32, exponent);
      F32 g = inv_sqrt_2pi_sigma*power;
      
      sum += g;
      *val_ptr = g;
    }
  }
  
  // normalize kernel
  {
    F32 *val_ptr = vals;
    for (U64 i = 0; i < count; i += 1, val_ptr += 1){
      *val_ptr = *val_ptr/sum;
    }
  }
  
  // return result
  *count_out = count;
  return(vals);
}
