medfall

A super great game engine
Log | Files | Refs

linear_algebra.h (19125B)


      1 #pragma once
      2 
      3 /*
      4  * vector/matrix code
      5  */
      6 
      7 #include <math.h>
      8 
      9 #include "intrinsics.h"
     10 #include "platform_alignment.h"
     11 #include "platform_inline.h"
     12 
     13 struct m4;
     14 
     15 /*
     16  * data definitions
     17  */
     18 
     19 // AUTOVISITOR
     20 struct v2 {
     21 	float x, y;
     22 
     23 	v2() { }
     24 
     25 	explicit v2( float a ) {
     26 		x = a;
     27 		y = a;
     28 	}
     29 
     30 	explicit v2( float a, float b ) {
     31 		x = a;
     32 		y = b;
     33 	}
     34 
     35 	v2 xx() const { return v2( x, x ); }
     36 	v2 xy() const { return v2( x, y ); }
     37 	v2 yx() const { return v2( y, x ); }
     38 	v2 yy() const { return v2( y, y ); }
     39 };
     40 
     41 // AUTOVISITOR
     42 struct v2u32 {
     43 	u32 x, y;
     44 
     45 	v2u32() { }
     46 
     47 	explicit v2u32( u32 a, u32 b ) {
     48 		x = a;
     49 		y = b;
     50 	}
     51 };
     52 
     53 // AUTOVISITOR
     54 struct v2s32 {
     55 	s32 x, y;
     56 
     57 	v2s32() { }
     58 
     59 	explicit v2s32( s32 a, s32 b ) {
     60 		x = a;
     61 		y = b;
     62 	}
     63 };
     64 
     65 // AUTOVISITOR
     66 struct v3 {
     67 	float x, y, z;
     68 
     69 	v3() { }
     70 
     71 	explicit v3( float a ) {
     72 		x = a;
     73 		y = a;
     74 		z = a;
     75 	}
     76 
     77 	explicit v3( float a, float b, float c ) {
     78 		x = a;
     79 		y = b;
     80 		z = c;
     81 	}
     82 
     83 	explicit v3( v2 v, float c ) {
     84 		x = v.x;
     85 		y = v.y;
     86 		z = c;
     87 	}
     88 
     89 	explicit v3( float a, v2 v ) {
     90 		x = a;
     91 		y = v.x;
     92 		z = v.y;
     93 	}
     94 
     95 	float & operator[]( size_t idx ) {
     96 		ASSERT( idx < 3 );
     97 		if( idx == 0 ) return x;
     98 		if( idx == 1 ) return y;
     99 		return z;
    100 	}
    101 
    102 	const float & operator[]( size_t idx ) const {
    103 		ASSERT( idx < 3 );
    104 		if( idx == 0 ) return x;
    105 		if( idx == 1 ) return y;
    106 		return z;
    107 	}
    108 
    109 	v2 xy() const { return v2( x, y ); }
    110 
    111 	float * ptr() { return &x; }
    112 };
    113 
    114 // AUTOVISITOR
    115 struct v3u32 {
    116 	u32 x, y, z;
    117 
    118 	v3u32() { }
    119 
    120 	explicit v3u32( u32 a, u32 b, u32 c ) {
    121 		x = a;
    122 		y = b;
    123 		z = c;
    124 	}
    125 };
    126 
    127 // AUTOVISITOR
    128 struct m3 {
    129 	v3 col0, col1, col2;
    130 
    131 	m3() { }
    132 
    133 	explicit m3(
    134 		float e00, float e01, float e02,
    135 		float e10, float e11, float e12,
    136 		float e20, float e21, float e22
    137 	) {
    138 		col0 = v3( e00, e10, e20 );
    139 		col1 = v3( e01, e11, e21 );
    140 		col2 = v3( e02, e12, e22 );
    141 	}
    142 
    143 	explicit m3( const v3 & c0, const v3 & c1, const v3 & c2 ) {
    144 		col0 = c0;
    145 		col1 = c1;
    146 		col2 = c2;
    147 	}
    148 
    149 	explicit m3( const m4 & m );
    150 
    151 	v3 row0() const { return v3( col0.x, col1.x, col2.x ); }
    152 	v3 row1() const { return v3( col0.y, col1.y, col2.y ); }
    153 	v3 row2() const { return v3( col0.z, col1.z, col2.z ); }
    154 };
    155 
    156 struct Ray3 {
    157 	v3 origin;
    158 	v3 dir;
    159 	v3 inv_dir;
    160 
    161 	explicit Ray3( v3 o, v3 d ) {
    162 		origin = o;
    163 		dir = d;
    164 		inv_dir = v3( 1.0f / d.x, 1.0f / d.y, 1.0f / d.z );
    165 	}
    166 };
    167 
    168 // AUTOVISITOR
    169 struct ALIGNTO_SSE v4 {
    170 	float x, y, z, w;
    171 
    172 	v4() { }
    173 
    174 	explicit v4( float a ) {
    175 		x = a;
    176 		y = a;
    177 		z = a;
    178 		w = a;
    179 	}
    180 
    181 	explicit v4( float a, float b, float c, float d ) {
    182 		x = a;
    183 		y = b;
    184 		z = c;
    185 		w = d;
    186 	}
    187 
    188 	explicit v4( v3 abc, float d ) {
    189 		x = abc.x;
    190 		y = abc.y;
    191 		z = abc.z;
    192 		w = d;
    193 	}
    194 
    195 	float & operator[]( size_t idx ) {
    196 		ASSERT( idx < 4 );
    197 		if( idx == 0 ) return x;
    198 		if( idx == 1 ) return y;
    199 		if( idx == 2 ) return z;
    200 		return w;
    201 	}
    202 
    203 	const float & operator[]( size_t idx ) const {
    204 		ASSERT( idx < 4 );
    205 		if( idx == 0 ) return x;
    206 		if( idx == 1 ) return y;
    207 		if( idx == 2 ) return z;
    208 		return w;
    209 	}
    210 
    211 	v2 xy() const { return v2( x, y ); }
    212 	v3 xyz() const { return v3( x, y, z ); }
    213 
    214 	float * ptr() { return &x; }
    215 };
    216 
    217 // AUTOVISITOR
    218 struct ALIGNTO_SSE m4 {
    219 	v4 col0, col1, col2, col3;
    220 
    221 	m4() { }
    222 
    223 	explicit m4(
    224 		float e00, float e01, float e02, float e03,
    225 		float e10, float e11, float e12, float e13,
    226 		float e20, float e21, float e22, float e23,
    227 		float e30, float e31, float e32, float e33
    228 	) {
    229 		col0 = v4( e00, e10, e20, e30 );
    230 		col1 = v4( e01, e11, e21, e31 );
    231 		col2 = v4( e02, e12, e22, e32 );
    232 		col3 = v4( e03, e13, e23, e33 );
    233 	}
    234 
    235 	explicit m4( const v4 & c0, const v4 & c1, const v4 & c2, const v4 & c3 ) {
    236 		col0 = c0;
    237 		col1 = c1;
    238 		col2 = c2;
    239 		col3 = c3;
    240 	}
    241 
    242 	v4 row0() const { return v4( col0.x, col1.x, col2.x, col3.x ); }
    243 	v4 row1() const { return v4( col0.y, col1.y, col2.y, col3.y ); }
    244 	v4 row2() const { return v4( col0.z, col1.z, col2.z, col3.z ); }
    245 	v4 row3() const { return v4( col0.w, col1.w, col2.w, col3.w ); }
    246 
    247 	float * ptr() { return col0.ptr(); }
    248 };
    249 
    250 forceinline m3::m3( const m4 & m ) {
    251 	col0 = m.col0.xyz();
    252 	col1 = m.col1.xyz();
    253 	col2 = m.col2.xyz();
    254 }
    255 
    256 // AUTOVISITOR
    257 struct quat {
    258 	float x, y, z, w;
    259 
    260 	quat() { }
    261 
    262 	explicit quat( float a, float b, float c, float d ) {
    263 		x = a;
    264 		y = b;
    265 		z = c;
    266 		w = d;
    267 	}
    268 
    269 	float * ptr() { return &x; }
    270 };
    271 
    272 // TODO: v3x4, v4x4, simd matrices?
    273 
    274 /*
    275  * misc. TODO: put this stuff somewhere else
    276  */
    277 
    278 forceinline float deg_to_rad( float x ) {
    279 	return x * PI / 180.0f;
    280 }
    281 
    282 forceinline float rad_to_deg( float x ) {
    283 	return x * 180.0f / PI;
    284 }
    285 
    286 forceinline v3 deg_to_rad( const v3 & v ) {
    287 	return v3( deg_to_rad( v.x ), deg_to_rad( v.y ), deg_to_rad( v.z ) );
    288 }
    289 
    290 forceinline v3 rad_to_deg( const v3 & v ) {
    291 	return v3( rad_to_deg( v.x ), rad_to_deg( v.y ), rad_to_deg( v.z ) );
    292 }
    293 
    294 /*
    295  * v2
    296  */
    297 
    298 forceinline v2 operator+( v2 v, float x ) {
    299 	return v2( v.x + x, v.y + x );
    300 }
    301 
    302 forceinline v2 operator+( v2 lhs, v2 rhs ) {
    303 	return v2( lhs.x + rhs.x, lhs.y + rhs.y );
    304 }
    305 
    306 forceinline v2 operator-( v2 v, float x ) {
    307 	return v2( v.x - x, v.y - x );
    308 }
    309 
    310 forceinline v2 operator-( v2 lhs, v2 rhs ) {
    311 	return v2( lhs.x - rhs.x, lhs.y - rhs.y );
    312 }
    313 
    314 forceinline v2 operator*( v2 v, float scale ) {
    315 	return v2( v.x * scale, v.y * scale );
    316 }
    317 
    318 forceinline void operator*=( v2 & v, float scale ) {
    319 	v = v * scale;
    320 }
    321 
    322 forceinline v2 operator*( float scale, v2 v ) {
    323 	return v * scale;
    324 }
    325 
    326 forceinline v2 operator*( v2 lhs, v2 rhs ) {
    327 	return v2( lhs.x * rhs.x, lhs.y * rhs.y );
    328 }
    329 
    330 forceinline void operator*=( v2 & lhs, v2 rhs ) {
    331 	lhs = lhs * rhs;
    332 }
    333 
    334 forceinline v2 operator/( v2 v, float scale ) {
    335 	float inv_scale = 1.0f / scale;
    336 	return v * inv_scale;
    337 }
    338 
    339 forceinline v2 operator-( v2 v ) {
    340 	return v2( -v.x, -v.y );
    341 }
    342 
    343 forceinline float dot( v2 lhs, v2 rhs ) {
    344 	return lhs.x * rhs.x + lhs.y * rhs.y;
    345 }
    346 
    347 forceinline float length( v2 v ) {
    348 	return sqrtf( v.x * v.x + v.y * v.y );
    349 }
    350 
    351 forceinline v2 normalize( v2 v ) {
    352 	return v / length( v );
    353 }
    354 
    355 forceinline v2 floorf( v2 v ) {
    356 	return v2( floorf( v.x ), floorf( v.y ) );
    357 }
    358 
    359 /*
    360  * v2s32
    361  */
    362 
    363 forceinline v2s32 operator+( v2s32 lhs, v2s32 rhs ) {
    364 	return v2s32( lhs.x + rhs.x, lhs.y + rhs.y );
    365 }
    366 
    367 forceinline v2s32 operator-( v2s32 lhs, v2s32 rhs ) {
    368 	return v2s32( lhs.x - rhs.x, lhs.y - rhs.y );
    369 }
    370 
    371 forceinline v2s32 operator/( v2s32 v, u32 d ) {
    372 	return v2s32( v.x / d, v.y / d );
    373 }
    374 
    375 forceinline s32 dot( v2s32 lhs, v2s32 rhs ) {
    376 	return lhs.x * rhs.x + lhs.y * rhs.y;
    377 }
    378 
    379 /*
    380  * v3
    381  */
    382 
    383 forceinline v3 rcp( v3 v ) {
    384 	return v3( 1.0f / v.x, 1.0f / v.y, 1.0f / v.z );
    385 }
    386 
    387 forceinline v3 operator+( v3 lhs, v3 rhs ) {
    388 	return v3( lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z );
    389 }
    390 
    391 forceinline void operator+=( v3 & lhs, v3 rhs ) {
    392 	lhs = lhs + rhs;
    393 }
    394 
    395 forceinline v3 operator-( v3 lhs, v3 rhs ) {
    396 	return v3( lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z );
    397 }
    398 
    399 forceinline void operator-=( v3 & lhs, v3 rhs ) {
    400 	lhs = lhs - rhs;
    401 }
    402 
    403 forceinline v3 operator*( v3 v, float scale ) {
    404 	return v3( v.x * scale, v.y * scale, v.z * scale );
    405 }
    406 
    407 forceinline v3 operator*( float scale, v3 v ) {
    408 	return v * scale;
    409 }
    410 
    411 forceinline void operator*=( v3 & v, float scale ) {
    412 	v = v * scale;
    413 }
    414 
    415 forceinline v3 operator*( v3 lhs, v3 rhs ) {
    416 	return v3( lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z );
    417 }
    418 
    419 forceinline v3 operator/( v3 v, float scale ) {
    420 	float inv_scale = 1.0f / scale;
    421 	return v * inv_scale;
    422 }
    423 
    424 forceinline void operator/=( v3 & v, float scale ) {
    425 	v = v / scale;
    426 }
    427 
    428 forceinline v3 operator/( v3 lhs, v3 rhs ) {
    429 	return lhs * rcp( rhs );
    430 }
    431 
    432 forceinline v3 operator-( v3 v ) {
    433 	return v3( -v.x, -v.y, -v.z );
    434 }
    435 
    436 forceinline bool operator==( v3 lhs, v3 rhs ) {
    437 	return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z;
    438 }
    439 
    440 forceinline float dot( v3 lhs, v3 rhs ) {
    441 	return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
    442 }
    443 
    444 forceinline v3 cross( v3 lhs, v3 rhs ) {
    445 	return v3(
    446 		lhs.y * rhs.z - rhs.y * lhs.z,
    447 		rhs.x * lhs.z - lhs.x * rhs.z,
    448 		lhs.x * rhs.y - rhs.x * lhs.y
    449 	);
    450 }
    451 
    452 forceinline float length( v3 v ) {
    453 	return sqrtf( v.x * v.x + v.y * v.y + v.z * v.z );
    454 }
    455 
    456 forceinline v3 normalize( v3 v ) {
    457 	return v / length( v );
    458 }
    459 
    460 forceinline v3 expf( v3 v ) {
    461 	return v3( expf( v.x ), expf( v.y ), expf( v.z ) );
    462 }
    463 
    464 forceinline v3 powf( v3 v, v3 e ) {
    465 	return v3( powf( v.x, e.x ), powf( v.y, e.y ), powf( v.z, e.z ) );
    466 }
    467 
    468 forceinline v3 v3_forward( float pitch, float yaw ) {
    469 	pitch = deg_to_rad( pitch );
    470 	yaw = deg_to_rad( yaw );
    471 	return v3(
    472 		cosf( pitch ) * cosf( yaw ),
    473 		cosf( pitch ) * sinf( yaw ),
    474 		sinf( pitch )
    475 	);
    476 }
    477 
    478 forceinline v3 v3_forward_xy( float yaw ) {
    479 	yaw = deg_to_rad( yaw );
    480 	return v3( cosf( yaw ), sinf( yaw ), 0 );
    481 }
    482 
    483 /*
    484  * v3u32
    485  */
    486 
    487 forceinline v3u32 operator+( v3u32 lhs, v3u32 rhs ) {
    488 	return v3u32( lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z );
    489 }
    490 
    491 forceinline v3u32 operator-( v3u32 lhs, v3u32 rhs ) {
    492 	return v3u32( lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z );
    493 }
    494 
    495 forceinline v3u32 operator/( v3u32 v, u32 d ) {
    496 	return v3u32( v.x / d, v.y / d, v.z / d );
    497 }
    498 
    499 forceinline u32 dot( v3u32 lhs, v3u32 rhs ) {
    500 	return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
    501 }
    502 
    503 /*
    504  * m3
    505  */
    506 
    507 forceinline m3 m3_identity() {
    508 	return m3(
    509 		1, 0, 0,
    510 		0, 1, 0,
    511 		0, 0, 1
    512 	);
    513 }
    514 
    515 forceinline m3 m3_scale( float s ) {
    516 	return m3(
    517 		s, 0, 0,
    518 		0, s, 0,
    519 		0, 0, s
    520 	);
    521 }
    522 
    523 forceinline m3 m3_scale( float x, float y, float z ) {
    524 	return m3(
    525 		x, 0, 0,
    526 		0, y, 0,
    527 		0, 0, z
    528 	);
    529 }
    530 
    531 forceinline m3 m3_rotx( float theta ) {
    532 	float s = sinf( theta );
    533 	float c = cosf( theta );
    534 	return m3(
    535 		1, 0, 0,
    536 		0, c, -s,
    537 		0, s, c
    538 	);
    539 }
    540 
    541 forceinline m3 m3_roty( float theta ) {
    542 	float s = sinf( theta );
    543 	float c = cosf( theta );
    544 	return m3(
    545 		c, 0, s,
    546 		0, 1, 0,
    547 		-s, 0, c
    548 	);
    549 }
    550 
    551 forceinline m3 m3_rotz( float theta ) {
    552 	float s = sinf( theta );
    553 	float c = cosf( theta );
    554 	return m3(
    555 		c, -s, 0,
    556 		s, c, 0,
    557 		0, 0, 1
    558 	);
    559 }
    560 
    561 forceinline m3 operator*( const m3 & lhs, const m3 & rhs ) {
    562 	return m3(
    563 		dot( lhs.row0(), rhs.col0 ),
    564 		dot( lhs.row0(), rhs.col1 ),
    565 		dot( lhs.row0(), rhs.col2 ),
    566 
    567 		dot( lhs.row1(), rhs.col0 ),
    568 		dot( lhs.row1(), rhs.col1 ),
    569 		dot( lhs.row1(), rhs.col2 ),
    570 
    571 		dot( lhs.row2(), rhs.col0 ),
    572 		dot( lhs.row2(), rhs.col1 ),
    573 		dot( lhs.row2(), rhs.col2 )
    574 	);
    575 }
    576 
    577 forceinline v3 operator*( const m3 & m, v3 v ) {
    578 	return v3(
    579 		dot( m.row0(), v ),
    580 		dot( m.row1(), v ),
    581 		dot( m.row2(), v )
    582 	);
    583 }
    584 
    585 forceinline m3 operator-( const m3 & m ) {
    586 	return m3( -m.col0, -m.col1, -m.col2 );
    587 }
    588 
    589 /*
    590  * v4
    591  */
    592 
    593 forceinline v4 operator+( v4 lhs, v4 rhs ) {
    594 	return v4(
    595 		lhs.x + rhs.x,
    596 		lhs.y + rhs.y,
    597 		lhs.z + rhs.z,
    598 		lhs.w + rhs.w
    599 	);
    600 }
    601 
    602 forceinline v4 operator-( v4 lhs, v4 rhs ) {
    603 	return v4(
    604 		lhs.x - rhs.x,
    605 		lhs.y - rhs.y,
    606 		lhs.z - rhs.z,
    607 		lhs.w - rhs.w
    608 	);
    609 }
    610 
    611 forceinline v4 operator*( v4 v, float scale ) {
    612 	return v4(
    613 		v.x * scale,
    614 		v.y * scale,
    615 		v.z * scale,
    616 		v.w * scale
    617 	);
    618 }
    619 
    620 forceinline v4 operator*( float scale, v4 v ) {
    621 	return v * scale;
    622 }
    623 
    624 forceinline v4 operator/( v4 v, float scale ) {
    625 	float inv_scale = 1.0f / scale;
    626 	return v * inv_scale;
    627 }
    628 
    629 forceinline void operator/=( v4 & v, float scale ) {
    630 	v = v / scale;
    631 }
    632 
    633 forceinline v4 operator-( v4 v ) {
    634 	return v4( -v.x, -v.y, -v.z, -v.w );
    635 }
    636 
    637 forceinline float dot( v4 lhs, v4 rhs ) {
    638 	return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z + lhs.w * rhs.w;
    639 }
    640 
    641 forceinline float length( v4 v ) {
    642 	return sqrtf( v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w );
    643 }
    644 
    645 forceinline v4 normalize( v4 v ) {
    646 	return v / length( v );
    647 }
    648 
    649 /*
    650  * m4
    651  */
    652 
    653 forceinline m4 m4_identity() {
    654 	return m4(
    655 		1, 0, 0, 0,
    656 		0, 1, 0, 0,
    657 		0, 0, 1, 0,
    658 		0, 0, 0, 1
    659 	);
    660 }
    661 
    662 forceinline m4 m4_scale( float s ) {
    663 	return m4(
    664 		s, 0, 0, 0,
    665 		0, s, 0, 0,
    666 		0, 0, s, 0,
    667 		0, 0, 0, 1
    668 	);
    669 }
    670 
    671 forceinline m4 m4_scale( float x, float y, float z ) {
    672 	return m4(
    673 		x, 0, 0, 0,
    674 		0, y, 0, 0,
    675 		0, 0, z, 0,
    676 		0, 0, 0, 1
    677 	);
    678 }
    679 
    680 forceinline m4 m4_rotx( float theta ) {
    681 	float s = sinf( theta );
    682 	float c = cosf( theta );
    683 	return m4(
    684 		1, 0, 0, 0,
    685 		0, c, -s, 0,
    686 		0, s, c, 0,
    687 		0, 0, 0, 1
    688 	);
    689 }
    690 
    691 forceinline m4 m4_roty( float theta ) {
    692 	float s = sinf( theta );
    693 	float c = cosf( theta );
    694 	return m4(
    695 		c, 0, s, 0,
    696 		0, 1, 0, 0,
    697 		-s, 0, c, 0,
    698 		0, 0, 0, 1
    699 	);
    700 }
    701 
    702 forceinline m4 m4_rotz( float theta ) {
    703 	float s = sinf( theta );
    704 	float c = cosf( theta );
    705 	return m4(
    706 		c, -s, 0, 0,
    707 		s, c, 0, 0,
    708 		0, 0, 1, 0,
    709 		0, 0, 0, 1
    710 	);
    711 }
    712 
    713 forceinline m4 m4_rotz90() {
    714 	return m4(
    715 		0, -1, 0, 0,
    716 		1, 0, 0, 0,
    717 		0, 0, 1, 0,
    718 		0, 0, 0, 1
    719 	);
    720 }
    721 
    722 forceinline m4 m4_rotz180() {
    723 	return m4(
    724 		-1, 0, 0, 0,
    725 		0, -1, 0, 0,
    726 		0, 0, 1, 0,
    727 		0, 0, 0, 1
    728 	);
    729 }
    730 
    731 forceinline m4 m4_rotz270() {
    732 	return m4(
    733 		0, 1, 0, 0,
    734 		-1, 0, 0, 0,
    735 		0, 0, 1, 0,
    736 		0, 0, 0, 1
    737 	);
    738 }
    739 
    740 forceinline m4 m4_translation( float x, float y, float z ) {
    741 	return m4(
    742 		1, 0, 0, x,
    743 		0, 1, 0, y,
    744 		0, 0, 1, z,
    745 		0, 0, 0, 1
    746 	);
    747 }
    748 
    749 forceinline m4 m4_translation( v3 xyz ) {
    750 	return m4_translation( xyz.x, xyz.y, xyz.z );
    751 }
    752 
    753 forceinline m4 m4_ortho( float left, float right, float top, float bottom, float near_plane, float far_plane ) {
    754 	return m4(
    755 		2.0f / ( right - left ),
    756 		0.0f,
    757 		0.0f,
    758 		-( right + left ) / ( right - left ),
    759 
    760 		0.0f,
    761 		2.0f / ( top - bottom ),
    762 		0.0f,
    763 		-( top + bottom ) / ( top - bottom ),
    764 
    765 		0.0f,
    766 		0.0f,
    767 		-2.0f / ( far_plane - near_plane ),
    768 		-( far_plane + near_plane ) / ( far_plane - near_plane ),
    769 
    770 		0.0f,
    771 		0.0f,
    772 		0.0f,
    773 		1.0f
    774 	);
    775 }
    776 
    777 forceinline m4 m4_perspective( float vertical_fov_degrees, float aspect_ratio, float near_plane, float far_plane ) {
    778 	float tan_half_vertical_fov = tanf( deg_to_rad( vertical_fov_degrees ) / 2.0f );
    779 
    780 	return m4(
    781 		1.0f / ( tan_half_vertical_fov * aspect_ratio ),
    782 		0.0f,
    783 		0.0f,
    784 		0.0f,
    785 
    786 		0.0f,
    787 		1.0f / tan_half_vertical_fov,
    788 		0.0f,
    789 		0.0f,
    790 
    791 		0.0f,
    792 		0.0f,
    793 		-( far_plane + near_plane ) / ( far_plane - near_plane ),
    794 		-( 2.0f * far_plane * near_plane ) / ( far_plane - near_plane ),
    795 
    796 		0.0f,
    797 		0.0f,
    798 		-1.0f,
    799 		0.0f
    800 	);
    801 }
    802 
    803 forceinline m4 m4_perspective_inf( float vertical_fov_degrees, float aspect_ratio, float near_plane ) {
    804 	float tan_half_vertical_fov = tanf( deg_to_rad( vertical_fov_degrees ) / 2.0f );
    805 	float epsilon = 2.4e-6f;
    806 
    807 	return m4(
    808 		1.0f / ( tan_half_vertical_fov * aspect_ratio ),
    809 		0.0f,
    810 		0.0f,
    811 		0.0f,
    812 
    813 		0.0f,
    814 		1.0f / tan_half_vertical_fov,
    815 		0.0f,
    816 		0.0f,
    817 
    818 		0.0f,
    819 		0.0f,
    820 		epsilon - 1.0f,
    821 		( epsilon - 2.0f ) * near_plane,
    822 
    823 		0.0f,
    824 		0.0f,
    825 		-1.0f,
    826 		0.0f
    827 	);
    828 }
    829 
    830 forceinline m4 operator*( const m4 & lhs, const m4 & rhs ) {
    831 	return m4(
    832 		dot( lhs.row0(), rhs.col0 ),
    833 		dot( lhs.row0(), rhs.col1 ),
    834 		dot( lhs.row0(), rhs.col2 ),
    835 		dot( lhs.row0(), rhs.col3 ),
    836 
    837 		dot( lhs.row1(), rhs.col0 ),
    838 		dot( lhs.row1(), rhs.col1 ),
    839 		dot( lhs.row1(), rhs.col2 ),
    840 		dot( lhs.row1(), rhs.col3 ),
    841 
    842 		dot( lhs.row2(), rhs.col0 ),
    843 		dot( lhs.row2(), rhs.col1 ),
    844 		dot( lhs.row2(), rhs.col2 ),
    845 		dot( lhs.row2(), rhs.col3 ),
    846 
    847 		dot( lhs.row3(), rhs.col0 ),
    848 		dot( lhs.row3(), rhs.col1 ),
    849 		dot( lhs.row3(), rhs.col2 ),
    850 		dot( lhs.row3(), rhs.col3 )
    851 	);
    852 }
    853 
    854 forceinline void operator*=( m4 & lhs, const m4 & rhs ) {
    855 	lhs = lhs * rhs;
    856 }
    857 
    858 forceinline v4 operator*( const m4 & m, v4 v ) {
    859 	return v4(
    860 		dot( m.row0(), v ),
    861 		dot( m.row1(), v ),
    862 		dot( m.row2(), v ),
    863 		dot( m.row3(), v )
    864 	);
    865 }
    866 
    867 forceinline m4 operator-( const m4 & m ) {
    868 	return m4( -m.col0, -m.col1, -m.col2, -m.col3 );
    869 }
    870 
    871 forceinline m4 m4_view( const v3 & forward, const v3 & right, const v3 & up, const v3 & position ) {
    872 	m4 rotation(
    873 		right.x, right.y, right.z, 0,
    874 		up.x, up.y, up.z, 0,
    875 		-forward.x, -forward.y, -forward.z, 0,
    876 		0, 0, 0, 1
    877 	);
    878 	return rotation * m4_translation( -position );
    879 }
    880 
    881 forceinline m4 m4_lookat( const v3 & position, const v3 & target, const v3 & world_up ) {
    882 	v3 forward = normalize( target - position );
    883 	v3 right = normalize( cross( forward, world_up ) );
    884 	v3 up = normalize( cross( right, forward ) );
    885 	return m4_view( forward, right, up, position );
    886 }
    887 
    888 /*
    889  * quat
    890  */
    891 
    892 forceinline quat quat_identity() {
    893 	return quat( 0, 0, 0, 1 );
    894 }
    895 
    896 forceinline quat operator+( quat lhs, quat rhs ) {
    897 	return quat(
    898 		lhs.x + rhs.x,
    899 		lhs.y + rhs.y,
    900 		lhs.z + rhs.z,
    901 		lhs.w + rhs.w
    902 	);
    903 }
    904 
    905 forceinline quat operator-( quat lhs, quat rhs ) {
    906 	return quat(
    907 		lhs.x - rhs.x,
    908 		lhs.y - rhs.y,
    909 		lhs.z - rhs.z,
    910 		lhs.w - rhs.w
    911 	);
    912 }
    913 
    914 forceinline quat operator*( quat q, float scale ) {
    915 	return quat(
    916 		q.x * scale,
    917 		q.y * scale,
    918 		q.z * scale,
    919 		q.w * scale
    920 	);
    921 }
    922 
    923 forceinline quat operator*( float scale, quat q ) {
    924 	return q * scale;
    925 }
    926 
    927 forceinline quat operator/( quat q, float scale ) {
    928 	float inv_scale = 1.0f / scale;
    929 	return q * inv_scale;
    930 }
    931 
    932 forceinline void operator/=( quat & q, float scale ) {
    933 	q = q / scale;
    934 }
    935 
    936 forceinline quat operator-( quat q ) {
    937 	return quat( -q.x, -q.y, -q.z, -q.w );
    938 }
    939 
    940 forceinline float dot( quat lhs, quat rhs ) {
    941 	return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z + lhs.w * rhs.w;
    942 }
    943 
    944 forceinline float length( quat q ) {
    945 	return sqrtf( q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w );
    946 }
    947 
    948 forceinline quat normalize( quat q ) {
    949 	return q / length( q );
    950 }
    951 
    952 forceinline quat nlerp( quat from, float t, quat to ) {
    953 	float lt = 1.0f - t;
    954 	float rt = dot( from, to ) > 0 ? t : -t;
    955 	return normalize( from * lt + to * rt );
    956 }
    957 
    958 /*
    959  * misc. TODO: put this stuff somewhere else
    960  */
    961 
    962 forceinline u32 mean( u32 a, u32 b ) {
    963 	return a / 2 + b / 2 + ( a & b & 1 );
    964 }
    965 
    966 forceinline v3u32 mean( v3u32 mins, v3u32 maxs ) {
    967 	ASSERT( mins.x <= maxs.x );
    968 	ASSERT( mins.y <= maxs.y );
    969 	ASSERT( mins.z <= maxs.z );
    970 	return mins + ( maxs - mins ) / 2;
    971 }
    972 
    973 /*
    974  * ggformat support
    975  */
    976 
    977 #include "ggformat.h"
    978 
    979 inline void format( FormatBuffer * fb, const v2 & v, const FormatOpts & opts ) {
    980 	format( fb, "v2(" );
    981 	format( fb, v.x, opts );
    982 	format( fb, ", " );
    983 	format( fb, v.y, opts );
    984 	format( fb, ")" );
    985 }
    986 
    987 inline void format( FormatBuffer * fb, const v3 & v, const FormatOpts & opts ) {
    988 	format( fb, "v3(" );
    989 	format( fb, v.x, opts );
    990 	format( fb, ", " );
    991 	format( fb, v.y, opts );
    992 	format( fb, ", " );
    993 	format( fb, v.z, opts );
    994 	format( fb, ")" );
    995 }
    996 
    997 inline void format( FormatBuffer * fb, const v3u32 & v, const FormatOpts & opts ) {
    998 	format( fb, "v3u32(" );
    999 	format( fb, v.x, opts );
   1000 	format( fb, ", " );
   1001 	format( fb, v.y, opts );
   1002 	format( fb, ", " );
   1003 	format( fb, v.z, opts );
   1004 	format( fb, ")" );
   1005 }
   1006 
   1007 inline void format( FormatBuffer * fb, const v4 & v, const FormatOpts & opts ) {
   1008 	format( fb, "v4(" );
   1009 	format( fb, v.x, opts );
   1010 	format( fb, ", " );
   1011 	format( fb, v.y, opts );
   1012 	format( fb, ", " );
   1013 	format( fb, v.z, opts );
   1014 	format( fb, ", " );
   1015 	format( fb, v.w, opts );
   1016 	format( fb, ")" );
   1017 }
   1018 
   1019 inline void format( FormatBuffer * fb, const m3 & m, const FormatOpts & opts ) {
   1020 	format( fb, "m3(" );
   1021 	format( fb, m.row0(), opts );
   1022 	format( fb, ", " );
   1023 	format( fb, m.row1(), opts );
   1024 	format( fb, ", " );
   1025 	format( fb, m.row2(), opts );
   1026 	format( fb, ")" );
   1027 }
   1028 
   1029 inline void format( FormatBuffer * fb, const m4 & m, const FormatOpts & opts ) {
   1030 	format( fb, "m4(" );
   1031 	format( fb, m.row0(), opts );
   1032 	format( fb, ", " );
   1033 	format( fb, m.row1(), opts );
   1034 	format( fb, ", " );
   1035 	format( fb, m.row2(), opts );
   1036 	format( fb, ", " );
   1037 	format( fb, m.row3(), opts );
   1038 	format( fb, ")" );
   1039 }
   1040 
   1041 inline void format( FormatBuffer * fb, const quat & q, const FormatOpts & opts ) {
   1042 	format( fb, "quat(" );
   1043 	format( fb, q.x, opts );
   1044 	format( fb, ", " );
   1045 	format( fb, q.y, opts );
   1046 	format( fb, ", " );
   1047 	format( fb, q.z, opts );
   1048 	format( fb, ", " );
   1049 	format( fb, q.w, opts );
   1050 	format( fb, ")" );
   1051 }
   1052 
   1053 /*
   1054  * autogenerated visitor header
   1055  */
   1056 
   1057 #include "visitors/linear_algebra.h"