cone & disc distributions
[vg.git] / vg_m.h
diff --git a/vg_m.h b/vg_m.h
index 833f1f01598a628a4c09df3c873c1a7cef7a3644..91071ffb163d1b38617679c938bf68a7ba5bc590 100644 (file)
--- a/vg_m.h
+++ b/vg_m.h
@@ -18,6 +18,7 @@
  *    5.c Closest points
  *    5.d Raycast & Spherecasts
  *    5.e Curves
+ *    5.f Volumes
  *  6. Statistics
  *    6.a Random numbers
  **/
@@ -31,6 +32,7 @@
 
 #define VG_PIf  3.14159265358979323846264338327950288f
 #define VG_TAUf 6.28318530717958647692528676655900576f
+
 /*
  * -----------------------------------------------------------------------------
  * Section 0.                    Misc Operations
@@ -62,6 +64,12 @@ static int vg_validf( f32 a )
    return ((vg_ftu32(a)) & 0x7F800000U) != 0x7F800000U;
 }
 
+static int v3_valid( v3f a ){
+   for( u32 i=0; i<3; i++ )
+      if( !vg_validf(a[i]) ) return 0;
+   return 1;
+}
+
 /*
  * -----------------------------------------------------------------------------
  * Section 1.                   Scalar Operations
@@ -99,6 +107,31 @@ static inline f32 vg_rad( f32 deg )
    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);
+}
+
 /*
  * -----------------------------------------------------------------------------
  * Section 2.a                   2D Vectors
@@ -392,8 +425,7 @@ static inline void v3_normalize( v3f a )
    v3_muls( a, 1.f / v3_length( a ), a );
 }
 
-static inline f32 vg_lerpf( f32 a, f32 b, f32 t )
-{
+static inline f32 vg_lerpf( f32 a, f32 b, f32 t ){
    return a + t*(b-a);
 }
 
@@ -402,6 +434,17 @@ static inline f64 vg_lerp( f64 a, f64 b, f64 t )
    return a + t*(b-a);
 }
 
+static inline void vg_slewf( f32 *a, f32 b, f32 speed ){
+   f32 d = vg_signf( b-*a ),
+       c = *a + d*speed;
+   *a = vg_minf( b*d, c*d ) * d;
+}
+
+static inline f32 vg_smoothstepf( f32 x ){
+   return x*x*(3.0f - 2.0f*x);
+}
+
+
 /* correctly lerp around circular period -pi -> pi */
 static f32 vg_alerpf( f32 a, f32 b, f32 t )
 {
@@ -480,6 +523,52 @@ static inline void v3_rotate( v3f v, f32 angle, v3f axis, v3f d )
   v3_add( v1, v2, d );
 }
 
+static void v3_tangent_basis( v3f n, v3f tx, v3f ty ){
+   /* Compute tangent basis (box2d) */
+   if( fabsf( n[0] ) >= 0.57735027f ){
+      tx[0] =  n[1];
+      tx[1] = -n[0];
+      tx[2] =  0.0f;
+   }
+   else{
+      tx[0] =  0.0f;
+      tx[1] =  n[2];
+      tx[2] = -n[1];
+   }
+
+   v3_normalize( tx );
+   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] );
+}
+
 /*
  * -----------------------------------------------------------------------------
  * Section 2.c                   4D Vectors
@@ -593,11 +682,11 @@ static inline void q_inv( v4f q, v4f d )
    d[3] =  q[3]*s;
 }
 
-static inline void q_nlerp( v4f a, v4f b, f32 t, v4f d )
-{
+static inline void q_nlerp( v4f a, v4f b, f32 t, v4f d ){
    if( v4_dot(a,b) < 0.0f ){
-      v4_muls( b, -1.0f, d );
-      v4_lerp( a, d, t, d );
+      v4f c;
+      v4_muls( b, -1.0f, c );
+      v4_lerp( a, c, t, d );
    }
    else
       v4_lerp( a, b, t, d );
@@ -638,6 +727,10 @@ static void q_mulv( v4f q, v3f v, v3f d )
    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
@@ -675,6 +768,16 @@ static inline void m2x2_create_rotation( m2x2f a, f32 theta )
    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
@@ -1159,8 +1262,7 @@ static void m4x3_decompose( m4x3f m, v3f co, v4f q, v3f s )
    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 );
 
@@ -1168,26 +1270,19 @@ static void m4x3_expand_aabb_point( m4x3f m, boxf box, v3f point )
    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;
@@ -1422,8 +1517,7 @@ static int box_within( boxf greater, boxf lesser )
    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 );
 }
@@ -1510,7 +1604,7 @@ int plane_intersect2( v4f a, v4f b, v3f p, v3f n )
 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 )
    {
@@ -1532,6 +1626,17 @@ static inline f64 plane_polarity( f64 p[4], f64 a[3] )
    ;
 }
 
+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
@@ -1542,7 +1647,7 @@ static inline f64 plane_polarity( f64 p[4], f64 a[3] )
  * 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;
@@ -1619,7 +1724,7 @@ VG_STATIC f32 closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2,
    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]) )
@@ -1628,13 +1733,13 @@ VG_STATIC int point_inside_aabb( boxf box, v3f point )
       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;
@@ -1643,7 +1748,7 @@ VG_STATIC void closest_point_obb( v3f p, boxf box,
    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 );
@@ -1655,7 +1760,7 @@ VG_STATIC f32 closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
    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;
@@ -1751,7 +1856,7 @@ enum contact_type
    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;
@@ -2124,6 +2229,17 @@ static void eval_bezier3( v3f p0, v3f p1, v3f p2, f32 t, v3f 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
@@ -2157,8 +2273,7 @@ struct {
 } 
 static vg_rand;
 
-static void vg_rand_seed( unsigned long seed ) 
-{
+static void vg_rand_seed( 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.
@@ -2173,8 +2288,7 @@ static void vg_rand_seed( unsigned long seed )
 /*
  * Generates a pseudo-randomly generated long.
  */
-static u32 vg_randu32(void) 
-{
+static u32 vg_randu32(void) {
    u32 y;
    /* mag[x] = x * 0x9908b0df for x = 0,1 */
    static u32 mag[2] = {0x0, 0x9908b0df}; 
@@ -2214,32 +2328,47 @@ static u32 vg_randu32(void)
 /*
  * Generates a pseudo-randomly generated f64 in the range [0..1].
  */
-static inline f64 vg_randf64(void)
-{
+static inline f64 vg_randf64(void){
    return (f64)vg_randu32()/(f64)0xffffffff;
 }
 
-static inline f64 vg_randf64_range( f64 min, f64 max )
-{
+static inline f64 vg_randf64_range( f64 min, f64 max ){
    return vg_lerp( min, max, (f64)vg_randf64() );
 }
 
-static inline void vg_rand_dir( v3f dir )
-{
+static inline void vg_rand_dir( v3f dir ){
    dir[0] = vg_randf64();
    dir[1] = vg_randf64();
    dir[2] = vg_randf64();
 
+   /* 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 )
-{
+static inline void vg_rand_sphere( v3f co ){
    vg_rand_dir(co);
    v3_muls( co, cbrtf( vg_randf64() ), co );
 }
 
+static void vg_rand_disc( v2f co ){
+   f32 a = vg_randf64() * VG_TAUf;
+   co[0] = sinf(a);
+   co[1] = cosf(a); 
+   v2_muls( co, sqrtf( vg_randf64() ), co );
+}
+
+static void vg_rand_cone( v3f out_dir, f32 angle ){
+   f32 r = sqrtf(vg_randf64()) * angle * 0.5f,
+       a = vg_randf64() * 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 */