#define VG_PIf 3.14159265358979323846264338327950288f
#define VG_TAUf 6.28318530717958647692528676655900576f
+
/*
* -----------------------------------------------------------------------------
* Section 0. Misc Operations
return deg * VG_PIf / 180.0f;
}
+/* angle to reach b from a */
+static f32 vg_angle_diff( f32 a, f32 b ){
+ f32 d = fmod(b,VG_TAUf)-fmodf(a,VG_TAUf);
+ if( fabsf(d) > VG_PIf )
+ d = -vg_signf(d) * (VG_TAUf - fabsf(d));
+
+ return d;
+}
+
+/*
+ * quantize float to bit count
+ */
+static u32 vg_quantf( f32 a, u32 bits, f32 min, f32 max ){
+ u32 mask = (0x1 << bits) - 1;
+ return vg_clampf((a - min) * ((f32)mask/(max-min)), 0.0f, mask );
+}
+
+/*
+ * un-quantize discreet to float
+ */
+static f32 vg_dequantf( u32 q, u32 bits, f32 min, f32 max ){
+ u32 mask = (0x1 << bits) - 1;
+ return min + (f32)q * ((max-min) / (f32)mask);
+}
+
+/* https://iquilezles.org/articles/functions/
+ *
+ * Use k to control the stretching of the function. Its maximum, which is 1,
+ * happens at exactly x = 1/k.
+ */
+static f32 vg_exp_impulse( f32 x, f32 k ){
+ f32 h = k*x;
+ return h*expf(1.0f-h);
+}
+
/*
* -----------------------------------------------------------------------------
* Section 2.a 2D Vectors
v3_cross( n, tx, ty );
}
+/*
+ * Compute yaw and pitch based of a normalized vector representing forward
+ * forward: -z
+ * result -> (YAW,PITCH,0.0)
+ */
+static void v3_angles( v3f v, v3f out_angles ){
+ float yaw = atan2f( v[0], -v[2] ),
+ pitch = atan2f(
+ -v[1],
+ sqrtf(
+ v[0]*v[0] + v[2]*v[2]
+ )
+ );
+
+ out_angles[0] = yaw;
+ out_angles[1] = pitch;
+ out_angles[2] = 0.0f;
+}
+
+/*
+ * Compute the forward vector from (YAW,PITCH,ROLL)
+ * forward: -z
+ */
+static void v3_angles_vector( v3f angles, v3f out_v ){
+ out_v[0] = sinf( angles[0] ) * cosf( angles[1] );
+ out_v[1] = -sinf( angles[1] );
+ out_v[2] = -cosf( angles[0] ) * cosf( angles[1] );
+}
/*
* -----------------------------------------------------------------------------
v3_add( v1, v2, d );
}
+static f32 q_dist( v4f q0, v4f q1 ){
+ return acosf( 2.0f * v4_dot(q0,q1) -1.0f );
+}
+
/*
* -----------------------------------------------------------------------------
* Section 4.a 2x2 matrices
a[1][1] = c;
}
+static inline void m2x2_mulv( m2x2f m, v2f v, v2f d )
+{
+ v2f res;
+
+ res[0] = m[0][0]*v[0] + m[1][0]*v[1];
+ res[1] = m[0][1]*v[0] + m[1][1]*v[1];
+
+ v2_copy( res, d );
+}
+
/*
* -----------------------------------------------------------------------------
* Section 4.b 3x3 matrices
m3x3_q( rot, q );
}
-static void m4x3_expand_aabb_point( m4x3f m, boxf box, v3f point )
-{
+static void m4x3_expand_aabb_point( m4x3f m, boxf box, v3f point ){
v3f v;
m4x3_mulv( m, point, v );
v3_maxv( box[1], v, box[1] );
}
-static void m4x3_transform_aabb( m4x3f m, boxf box )
-{
+static void m4x3_expand_aabb_aabb( m4x3f m, boxf boxa, boxf boxb ){
v3f a; v3f b;
-
- v3_copy( box[0], a );
- v3_copy( box[1], b );
- v3_fill( box[0], INFINITY );
- v3_fill( box[1], -INFINITY );
-
- m4x3_expand_aabb_point( m, box, (v3f){ a[0], a[1], a[2] } );
- m4x3_expand_aabb_point( m, box, (v3f){ a[0], b[1], a[2] } );
- m4x3_expand_aabb_point( m, box, (v3f){ b[0], b[1], a[2] } );
- m4x3_expand_aabb_point( m, box, (v3f){ b[0], a[1], a[2] } );
-
- m4x3_expand_aabb_point( m, box, (v3f){ a[0], a[1], b[2] } );
- m4x3_expand_aabb_point( m, box, (v3f){ a[0], b[1], b[2] } );
- m4x3_expand_aabb_point( m, box, (v3f){ b[0], b[1], b[2] } );
- m4x3_expand_aabb_point( m, box, (v3f){ b[0], a[1], b[2] } );
+ v3_copy( boxb[0], a );
+ v3_copy( boxb[1], b );
+ m4x3_expand_aabb_point( m, boxa, (v3f){ a[0], a[1], a[2] } );
+ m4x3_expand_aabb_point( m, boxa, (v3f){ a[0], b[1], a[2] } );
+ m4x3_expand_aabb_point( m, boxa, (v3f){ b[0], b[1], a[2] } );
+ m4x3_expand_aabb_point( m, boxa, (v3f){ b[0], a[1], a[2] } );
+ m4x3_expand_aabb_point( m, boxa, (v3f){ a[0], a[1], b[2] } );
+ m4x3_expand_aabb_point( m, boxa, (v3f){ a[0], b[1], b[2] } );
+ m4x3_expand_aabb_point( m, boxa, (v3f){ b[0], b[1], b[2] } );
+ m4x3_expand_aabb_point( m, boxa, (v3f){ b[0], a[1], b[2] } );
}
-
static inline void m4x3_lookat( m4x3f m, v3f pos, v3f target, v3f up )
{
v3f dir;
return 0;
}
-static inline void box_init_inf( boxf box )
-{
+static inline void box_init_inf( boxf box ){
v3_fill( box[0], INFINITY );
v3_fill( box[1], -INFINITY );
}
static int plane_segment( v4f plane, v3f a, v3f b, v3f co )
{
f32 d0 = v3_dot( a, plane ) - plane[3],
- d1 = v3_dot( b, plane ) - plane[3];
+ d1 = v3_dot( b, plane ) - plane[3];
if( d0*d1 < 0.0f )
{
;
}
+static f32 ray_plane( v4f plane, v3f co, v3f dir ){
+ f32 d = v3_dot( plane, dir );
+ if( fabsf(d) > 1e-6f ){
+ v3f v0;
+ v3_muls( plane, plane[3], v0 );
+ v3_sub( v0, co, v0 );
+ return v3_dot( v0, plane ) / d;
+ }
+ else return INFINITY;
+}
+
/*
* -----------------------------------------------------------------------------
* Section 5.c Closest point functions
* These closest point tests were learned from Real-Time Collision Detection by
* Christer Ericson
*/
-VG_STATIC f32 closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2,
+static f32 closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2,
f32 *s, f32 *t, v3f c1, v3f c2)
{
v3f d1,d2,r;
return v3_length2( v0 );
}
-VG_STATIC int point_inside_aabb( boxf box, v3f point )
+static int point_inside_aabb( boxf box, v3f point )
{
if((point[0]<=box[1][0]) && (point[1]<=box[1][1]) && (point[2]<=box[1][2]) &&
(point[0]>=box[0][0]) && (point[1]>=box[0][1]) && (point[2]>=box[0][2]) )
return 0;
}
-VG_STATIC void closest_point_aabb( v3f p, boxf box, v3f dest )
+static void closest_point_aabb( v3f p, boxf box, v3f dest )
{
v3_maxv( p, box[0], dest );
v3_minv( dest, box[1], dest );
}
-VG_STATIC void closest_point_obb( v3f p, boxf box,
+static void closest_point_obb( v3f p, boxf box,
m4x3f mtx, m4x3f inv_mtx, v3f dest )
{
v3f local;
m4x3_mulv( mtx, local, dest );
}
-VG_STATIC f32 closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
+static f32 closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
{
v3f v0, v1;
v3_sub( b, a, v0 );
return t;
}
-VG_STATIC void closest_on_triangle( v3f p, v3f tri[3], v3f dest )
+static void closest_on_triangle( v3f p, v3f tri[3], v3f dest )
{
v3f ab, ac, ap;
f32 d1, d2;
k_contact_type_edge
};
-VG_STATIC enum contact_type closest_on_triangle_1( v3f p, v3f tri[3], v3f dest )
+static enum contact_type closest_on_triangle_1( v3f p, v3f tri[3], v3f dest )
{
v3f ab, ac, ap;
f32 d1, d2;
/* Time of intersection with ray vs triangle */
static int ray_tri( v3f tri[3], v3f co,
- v3f dir, f32 *dist )
+ v3f dir, f32 *dist, int backfaces )
{
f32 const kEpsilon = 0.00001f;
v3_cross( dir, v1, h );
v3_cross( v0, v1, n );
- if( v3_dot( n, dir ) > 0.0f ) /* Backface culling */
+ if( (v3_dot( n, dir ) > 0.0f) && !backfaces ) /* Backface culling */
return 0;
/* Parralel */
f32 t_min = INFINITY,
t1;
- if( ray_tri( sum, co, dir, &t1 ) ){
+ if( ray_tri( sum, co, dir, &t1, 0 ) ){
t_min = vg_minf( t_min, t1 );
hit = 1;
}
/* changes to STATE_VECTOR_LENGTH also require changes to this */
#define MT_STATE_VECTOR_M 397
-struct {
+typedef struct vg_rand vg_rand;
+struct vg_rand {
u32 mt[MT_STATE_VECTOR_LENGTH];
i32 index;
-}
-static vg_rand;
+};
-static void vg_rand_seed( unsigned long seed )
-{
+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.
*/
- vg_rand.mt[0] = seed & 0xffffffff;
- for( vg_rand.index=1; vg_rand.index<MT_STATE_VECTOR_LENGTH; vg_rand.index++){
- vg_rand.mt[vg_rand.index] =
- (6069 * vg_rand.mt[vg_rand.index-1]) & 0xffffffff;
+ 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(void)
-{
+static u32 vg_randu32( vg_rand *rand ) {
u32 y;
/* mag[x] = x * 0x9908b0df for x = 0,1 */
static u32 mag[2] = {0x0, 0x9908b0df};
- if( vg_rand.index >= MT_STATE_VECTOR_LENGTH || vg_rand.index < 0 ){
+ if( rand->index >= MT_STATE_VECTOR_LENGTH || rand->index < 0 ){
/* generate STATE_VECTOR_LENGTH words at a time */
int kk;
- if( vg_rand.index >= MT_STATE_VECTOR_LENGTH+1 || vg_rand.index < 0 ){
- vg_rand_seed( 4357 );
+ 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 = (vg_rand.mt[kk] & MT_UPPER_MASK) |
- (vg_rand.mt[kk+1] & MT_LOWER_MASK);
- vg_rand.mt[kk] = vg_rand.mt[kk+MT_STATE_VECTOR_M] ^
- (y >> 1) ^ mag[y & 0x1];
+ 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 = (vg_rand.mt[kk] & MT_UPPER_MASK) |
- (vg_rand.mt[kk+1] & MT_LOWER_MASK);
- vg_rand.mt[kk] =
- vg_rand.mt[ kk+(MT_STATE_VECTOR_M-MT_STATE_VECTOR_LENGTH)] ^
+ 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 = (vg_rand.mt[MT_STATE_VECTOR_LENGTH-1] & MT_UPPER_MASK) |
- (vg_rand.mt[0] & MT_LOWER_MASK);
- vg_rand.mt[MT_STATE_VECTOR_LENGTH-1] =
- vg_rand.mt[MT_STATE_VECTOR_M-1] ^ (y >> 1) ^ mag[y & 0x1];
- vg_rand.index = 0;
+ 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 = vg_rand.mt[vg_rand.index++];
+ y = rand->mt[rand->index++];
y ^= (y >> 11);
y ^= (y << 7) & MT_TEMPERING_MASK_B;
y ^= (y << 15) & MT_TEMPERING_MASK_C;
/*
* Generates a pseudo-randomly generated f64 in the range [0..1].
*/
-static inline f64 vg_randf64(void)
-{
- return (f64)vg_randu32()/(f64)0xffffffff;
+static inline f64 vg_randf64( vg_rand *rand ){
+ return (f64)vg_randu32(rand)/(f64)0xffffffff;
}
-static inline f64 vg_randf64_range( f64 min, f64 max )
-{
- return vg_lerp( min, max, (f64)vg_randf64() );
+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( v3f dir )
-{
- dir[0] = vg_randf64();
- dir[1] = vg_randf64();
- dir[2] = vg_randf64();
+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. */
v3_muls( dir, 2.0f, dir );
v3_sub( dir, (v3f){1.0f,1.0f,1.0f}, dir );
v3_normalize( dir );
}
-static inline void vg_rand_sphere( v3f co )
-{
- vg_rand_dir(co);
- v3_muls( co, cbrtf( vg_randf64() ), co );
+static inline void vg_rand_sphere( vg_rand *rand, v3f co ){
+ vg_rand_dir(rand,co);
+ v3_muls( co, cbrtf( vg_randf64(rand) ), co );
+}
+
+static void vg_rand_disc( vg_rand *rand, v2f co ){
+ f32 a = vg_randf64(rand) * VG_TAUf;
+ co[0] = sinf(a);
+ co[1] = cosf(a);
+ v2_muls( co, sqrtf( vg_randf64(rand) ), co );
+}
+
+static void vg_rand_cone( vg_rand *rand, v3f out_dir, f32 angle ){
+ f32 r = sqrtf(vg_randf64(rand)) * angle * 0.5f,
+ a = vg_randf64(rand) * VG_TAUf;
+
+ out_dir[0] = sinf(a) * sinf(r);
+ out_dir[1] = cosf(a) * sinf(r);
+ out_dir[2] = cosf(r);
}
#endif /* VG_M_H */