// Copyright 2019 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <rkcommon/math/vec.ih>

///////////////////////////////////////////////////////////////////////////////
// TEA - Random numbers based on Tiny Encryption Algorithm ////////////////////
///////////////////////////////////////////////////////////////////////////////

inline void tea8(unsigned int &_v0, unsigned int &_v1)
{
  unsigned int v0  = _v0;  // Operate on registers to avoid slowdown!
  unsigned int v1  = _v1;
  unsigned int sum = 0;

  for (uniform int i = 0; i < 8; i++) {  // just 8 instead of 32 rounds
    sum += 0x9e3779b9;
    v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + sum) ^ ((v1 >> 5) + 0xc8013ea4);
    v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + sum) ^ ((v0 >> 5) + 0x7e95761e);
  }

  _v0 = v0;
  _v1 = v1;
}

struct RandomTEA
{
  unsigned int v0, v1;
};

inline void RandomTEA__Constructor(varying RandomTEA *uniform this,
                                   const unsigned int idx,
                                   const unsigned int seed)
{
  this->v0 = idx;
  this->v1 = seed;
}

inline varying vec2f RandomTEA__getFloats(varying RandomTEA *uniform this)
{
  tea8(this->v0, this->v1);
  const float tofloat = 2.3283064365386962890625e-10f;  // 1/2^32
  return make_vec2f(this->v0 * tofloat, this->v1 * tofloat);
}

inline vec3f cartesian(const float phi,
                       const float sinTheta,
                       const float cosTheta)
{
  float sinPhi, cosPhi;
  sincos(phi, &sinPhi, &cosPhi);
  return make_vec3f(cosPhi * sinTheta, sinPhi * sinTheta, cosTheta);
}

inline vec3f uniformSampleSphere(const float radius, const vec2f s)
{
  const float phi      = two_pi * s.x;
  const float cosTheta = radius * (1.f - 2.f * s.y);
  const float sinTheta = 2.f * radius * sqrt(s.y * (1.f - s.y));
  return cartesian(phi, sinTheta, cosTheta);
}
