+ f32 u = 1.0f-t;
+
+ v3_muls( p0, u*u, p );
+ v3_muladds( p, p1, 2.0f*u*t, p );
+ v3_muladds( p, p2, t*t, p );
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Section 5.f Volumes
+ * -----------------------------------------------------------------------------
+ */
+
+static float vg_sphere_volume( float radius ){
+ float r3 = radius*radius*radius;
+ return (4.0f/3.0f) * VG_PIf * r3;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Section 6.a PSRNG and some distributions
+ * -----------------------------------------------------------------------------
+ */
+
+/* An implementation of the MT19937 Algorithm for the Mersenne Twister
+ * by Evan Sultanik. Based upon the pseudocode in: M. Matsumoto and
+ * T. Nishimura, "Mersenne Twister: A 623-dimensionally
+ * equidistributed uniform pseudorandom number generator," ACM
+ * Transactions on Modeling and Computer Simulation Vol. 8, No. 1,
+ * January pp.3-30 1998.
+ *
+ * http://www.sultanik.com/Mersenne_twister
+ * https://github.com/ESultanik/mtwister/blob/master/mtwister.c
+ */
+
+#define MT_UPPER_MASK 0x80000000
+#define MT_LOWER_MASK 0x7fffffff
+#define MT_TEMPERING_MASK_B 0x9d2c5680
+#define MT_TEMPERING_MASK_C 0xefc60000
+
+#define MT_STATE_VECTOR_LENGTH 624
+
+/* changes to STATE_VECTOR_LENGTH also require changes to this */
+#define MT_STATE_VECTOR_M 397
+
+typedef struct vg_rand vg_rand;
+struct vg_rand {
+ u32 mt[MT_STATE_VECTOR_LENGTH];
+ i32 index;
+};
+
+static void vg_rand_seed( vg_rand *rand, unsigned long seed ) {
+ /* set initial seeds to mt[STATE_VECTOR_LENGTH] using the generator
+ * from Line 25 of Table 1 in: Donald Knuth, "The Art of Computer
+ * Programming," Vol. 2 (2nd Ed.) pp.102.
+ */
+ rand->mt[0] = seed & 0xffffffff;
+ for( rand->index=1; rand->index<MT_STATE_VECTOR_LENGTH; rand->index++){
+ rand->mt[rand->index] = (6069 * rand->mt[rand->index-1]) & 0xffffffff;
+ }
+}
+
+/*
+ * Generates a pseudo-randomly generated long.
+ */
+static u32 vg_randu32( vg_rand *rand ) {
+ u32 y;
+ /* mag[x] = x * 0x9908b0df for x = 0,1 */
+ static u32 mag[2] = {0x0, 0x9908b0df};
+ if( rand->index >= MT_STATE_VECTOR_LENGTH || rand->index < 0 ){
+ /* generate STATE_VECTOR_LENGTH words at a time */
+ int kk;
+ if( rand->index >= MT_STATE_VECTOR_LENGTH+1 || rand->index < 0 ){
+ vg_rand_seed( rand, 4357 );
+ }
+ for( kk=0; kk<MT_STATE_VECTOR_LENGTH-MT_STATE_VECTOR_M; kk++ ){
+ y = (rand->mt[kk] & MT_UPPER_MASK) |
+ (rand->mt[kk+1] & MT_LOWER_MASK);
+ rand->mt[kk] = rand->mt[kk+MT_STATE_VECTOR_M] ^ (y>>1) ^ mag[y & 0x1];
+ }
+ for( ; kk<MT_STATE_VECTOR_LENGTH-1; kk++ ){
+ y = (rand->mt[kk] & MT_UPPER_MASK) |
+ (rand->mt[kk+1] & MT_LOWER_MASK);
+ rand->mt[kk] =
+ rand->mt[ kk+(MT_STATE_VECTOR_M-MT_STATE_VECTOR_LENGTH)] ^
+ (y >> 1) ^ mag[y & 0x1];
+ }
+ y = (rand->mt[MT_STATE_VECTOR_LENGTH-1] & MT_UPPER_MASK) |
+ (rand->mt[0] & MT_LOWER_MASK);
+ rand->mt[MT_STATE_VECTOR_LENGTH-1] =
+ rand->mt[MT_STATE_VECTOR_M-1] ^ (y >> 1) ^ mag[y & 0x1];
+ rand->index = 0;
+ }
+ y = rand->mt[rand->index++];
+ y ^= (y >> 11);
+ y ^= (y << 7) & MT_TEMPERING_MASK_B;
+ y ^= (y << 15) & MT_TEMPERING_MASK_C;
+ y ^= (y >> 18);
+ return y;
+}
+
+/*
+ * Generates a pseudo-randomly generated f64 in the range [0..1].
+ */
+static inline f64 vg_randf64( vg_rand *rand ){
+ return (f64)vg_randu32(rand)/(f64)0xffffffff;
+}
+
+static inline f64 vg_randf64_range( vg_rand *rand, f64 min, f64 max ){
+ return vg_lerp( min, max, (f64)vg_randf64(rand) );
+}
+
+static inline void vg_rand_dir( vg_rand *rand, v3f dir ){
+ dir[0] = vg_randf64(rand);
+ dir[1] = vg_randf64(rand);
+ dir[2] = vg_randf64(rand);
+
+ /* warning: *could* be 0 length.
+ * very unlikely.. 1 in (2^32)^3. but its mathematically wrong. */