////////////////////////////////
// PRNG Functions

#include "pcg/pcg_basic.c"

MR4TH_SYMBOL PRNG
prng_from_seed(PRNG_Seed *seed){
  PRNG prng = {0};
  
  U64 st0  = *(U64*)(seed->v + 0);
  U64 seq0 = *(U64*)(seed->v + 8);
  U64 st1  = *(U64*)(seed->v + 16);
  U64 seq1 = *(U64*)(seed->v + 24);
  
  if ((seq0|1) == (seq1|1)){
    seq1 = ~seq1;
  }
  
  pcg32_srandom_r(&prng.gen[0], st0, seq0);
  pcg32_srandom_r(&prng.gen[1], st1, seq1);
  
  return(prng);
}

MR4TH_SYMBOL U32
prng_u32(PRNG *prng){
  U32 result = pcg32_random_r(&prng->gen[0]);
  return(result);
}

MR4TH_SYMBOL U64
prng_u64(PRNG *prng){
  U32 hi = pcg32_random_r(&prng->gen[0]);
  U32 lo = pcg32_random_r(&prng->gen[1]);
  U32 result = (((U64)hi) << 32) | lo;
  return(result);
}

MR4TH_SYMBOL U32
prng_u32_bounded(PRNG *prng, U32 bound){
  U32 threshold = (-bound)%bound;
  U32 r = pcg32_random_r(&prng->gen[0]);
  for (;r < threshold;){
    r = pcg32_random_r(&prng->gen[0]);
  }
  U32 result = r%bound;
  return(result);
}

MR4TH_SYMBOL F32
prng_f32_unit(PRNG *prng){
  U32 x = prng_u32(prng);
  U32 x_masked = (x & 0x1FFFFF); // 21-bit mask
  F32 result = (F32)x_masked/2097151.f;
  return(result);
}

MR4TH_SYMBOL F32
prng_f32_biunit(PRNG *prng){
  U32 x = prng_u32(prng);
  U32 x_masked = (x & 0x3FFFFF); // 22-bit mask
  F32 result = ((F32)x_masked/2097151.f) - 1.f;
  return(result);
}

MR4TH_SYMBOL F32
prng_f32_range(PRNG *prng, F32 min, F32 max){
  F32 s = prng_f32_unit(prng);
  F32 r = sc_lerp(min, s, max);
  return(r);
}

MR4TH_SYMBOL B32
prng_b32_pcoin(PRNG *prng, F32 p){
  F32 x = prng_f32_unit(prng);
  B32 result = (x <= p);
  return(result);
}
