Changeset 16
- Timestamp:
- 08/01/07 14:01:51 (1 year ago)
- Files:
-
- trunk/examples/build-all.bat (modified) (1 diff)
- trunk/examples/dispmode (added)
- trunk/examples/dispmode/dispmode.d (added)
- trunk/examples/raytrace/raytrace.d (modified) (8 diffs)
- trunk/examples/test (added)
- trunk/examples/test/test.d (added)
- trunk/ray/base/Angles.d (modified) (13 diffs)
- trunk/ray/base/Color.d (modified) (17 diffs)
- trunk/ray/base/Math.d (modified) (6 diffs)
- trunk/ray/base/Plane.d (modified) (3 diffs)
- trunk/ray/base/Pluecker.d (modified) (7 diffs)
- trunk/ray/base/Quat.d (modified) (7 diffs)
- trunk/ray/base/Ray.d (modified) (3 diffs)
- trunk/ray/base/Transformation.d (added)
- trunk/ray/base/Vector.d (modified) (37 diffs)
- trunk/ray/bv/Bounds.d (modified) (4 diffs)
- trunk/ray/bv/Frustum.d (modified) (30 diffs)
- trunk/ray/bv/Sphere.d (modified) (2 diffs)
- trunk/ray/ds/HashIndex.d (modified) (2 diffs)
- trunk/ray/video (added)
- trunk/ray/video/DisplayMode.d (added)
- trunk/ray/video/internal (added)
- trunk/ray/video/internal/DisplayModeWin.d (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/examples/build-all.bat
r15 r16 1 dmd raytrace\raytrace.d ..\ray\base\Math.d ..\ray\base\Vector.d ..\ray\base\Ray.d ..\ray\bv\Sphere.d -op -I.. -unittest 1 jake test\test.d -I.. -debug=UNITTESTS -unittest -op 2 jake dispmode\dispmode.d -I.. -op 3 4 REM jake raytrace\raytrace.d -I.. -debug=UNITTESTS -version=FLOATHACK -unittest -op trunk/examples/raytrace/raytrace.d
r15 r16 3 3 // does 2x2 anti-aliasing; the scene is composed of two spheres and one directional light. 4 4 // PGM file is output to stdout. 5 // BUGS: strange pattern on lit spheres. How to fix this? 6 // TODO: implement tango support (or make it stdlib-agnostic) 5 // BUGS: strange pattern on lit spheres. How to fix this? I guess I'm wrong somewhere. 7 6 import ray.base.Math; 8 7 import ray.base.Vector; … … 10 9 11 10 import ray.bv.Sphere; 11 12 import tango.math.Math; // max() 13 14 import tango.io.Stdout; 15 16 version = SHADOWS; // uncomment to enable shadow rays 12 17 13 18 enum { … … 18 23 } 19 24 20 invariant bool SHADOWS = true; // set to false to disable shadow rays21 22 Vec3 lightDir;23 Sphere[] spheres;24 25 25 struct Hit { 26 26 float dist; … … 28 28 } 29 29 30 // TODO: use function from standard library 31 T max( T )( T a, T b ) { 32 return a > b ? a : b; 33 } 34 35 void initialize() { 30 static this() { 36 31 lightDir = Vec3( -0.5f, -0.65f, 0.9f ).normalize; 37 32 spheres ~= Sphere( Vec3( 0.0f, 0.0f, 0.0f ), 1.0f ); 38 33 spheres ~= Sphere( Vec3( 0.65f, 0.25f, -1.5f ), 0.25f ); 39 version ( Tango ) { 40 static assert( false ); 41 } 42 else { 43 std.stdio.writefln( "P2\n%d %d\n256", WIDTH, HEIGHT ); 44 } 34 Stdout.format( "P2\n{0} {1}\n256", WIDTH, HEIGHT ).newline; 45 35 } 46 36 … … 75 65 intersectRay!( false )( ray, hit ); 76 66 77 float diffuse = hit.dist == float.infinity ? 0.0f : - ( hit.normal * lightDir );67 float diffuse = hit.dist == float.infinity ? 0.0f : -hit.normal * lightDir; 78 68 79 69 if ( diffuse <= 0.0f ) { … … 81 71 } 82 72 83 static if( SHADOWS ) {73 version ( SHADOWS ) { 84 74 Ray shadowRay = Ray( ray.origin + ( ray.dir * hit.dist ) + ( hit.normal * 0.1f ), -lightDir ); 85 75 Hit shadowHit = void; … … 95 85 } 96 86 97 void traceRays( const int width, constint height ) {87 void traceRays( int width, int height ) { 98 88 // rotated grid 99 invariant float[2][SS_SQR] grid = [89 const float[2][SS_SQR] grid = [ 100 90 [ -3.0f / 3.0f, -1.0f / 3.0f ], [ +1.0f / 3.0f, -3.0f / 3.0f ], 101 91 102 92 [ -1.0f / 3.0f, +3.0f / 3.0f ], [ +3.0f / 3.0f, +1.0f / 3.0f ] 103 93 ]; 104 invariant double rcp = 1.0 / SS, scale = 256.0 / SS_SQR;105 final doublew = width, h = height;106 finalVec3[SS_SQR] rgss;107 Ray ray = Ray( Vec3( 0.0f, 0.0f, -4.5f ) );108 Vec3 scan = void;94 const double rcp = 1.0 / SS, scale = 256.0 / SS_SQR; 95 double w = width, h = height; 96 Vec3[SS_SQR] rgss; 97 Ray ray = Ray( Vec3( 0.0f, 0.0f, -4.5f ) ); 98 Vec3 scan = void; 109 99 110 100 // precompute … … 123 113 g += traceRay( ray ); 124 114 } 125 version ( Tango ) { 126 static assert( false ); 127 } 128 else { 129 std.stdio.writef( "%d ", cast( int )( g * scale ) ); 130 } 115 Stdout.format( "{} ", cast( int )( g * scale ) ); 131 116 scan.x += 1.0f; 132 117 } 118 Stdout.flush; 133 119 scan.x = 0.0f; 134 120 scan.y -= 1.0f; 135 121 } 136 version ( Tango ) { 137 static assert( false ); 138 } 139 else { 140 std.stdio.writefln(); 141 } 122 Stdout.newline; 142 123 } 143 124 125 Vec3 lightDir; 126 Sphere[] spheres; 127 144 128 int main( char[][] args ) { 145 initialize();146 129 traceRays( WIDTH, HEIGHT ); 147 130 return 0; trunk/ray/base/Angles.d
r15 r16 4 4 5 5 This module implements Euler angles. 6 7 Version: Aug 2007: initial release 8 Authors: Artyom Shalkhakov 6 9 */ 7 10 module ray.base.Angles; 8 11 9 import ray.base.Math;12 import Math = ray.base.Math; 10 13 import ray.base.Vector; 11 14 import ray.base.Quat; 12 15 13 invariant Angles ang_zero = { pitch : 0.0f, yaw : 0.0f, roll : 0.0f };16 const Angles ang_zero = { pitch : 0.0f, yaw : 0.0f, roll : 0.0f }; 14 17 15 18 /// angle indices … … 71 74 } 72 75 73 Angles opMul( float f ) { 76 Angles opMul( float f ) 77 in { 78 debug ( FLOAT_PARANOID ) { 79 assert( Math.isValid( f ) ); 80 } 81 } 82 body { 74 83 return Angles( pitch * f, yaw * f, roll * f ); 75 84 } 76 85 77 Angles opDiv( float f ) { 86 Angles opDiv( float f ) 87 in { 88 debug ( FLOAT_PARANOID ) { 89 assert( Math.isValid( f ) ); 90 assert( Math.abs( f - 0.0f ) > 1e-14 ); 91 } 92 } 93 body { 78 94 float invF = 1.0f / f; 79 95 … … 93 109 } 94 110 95 void opMulAssign( float f ) { 111 void opMulAssign( float f ) 112 in { 113 debug ( FLOAT_PARANOID ) { 114 assert( Math.isValid( f ) ); 115 } 116 } 117 body { 96 118 pitch *= f; 97 119 yaw *= f; … … 99 121 } 100 122 101 void opDivAssign( float f ) { 123 void opDivAssign( float f ) 124 in { 125 debug ( FLOAT_PARANOID ) { 126 assert( Math.isValid( f ) ); 127 assert( Math.abs( f - 0.0f ) > 1e-14 ); 128 } 129 } 130 body { 102 131 float invF = 1.0f / f; 103 132 … … 145 174 } 146 175 176 static private float lerpAngle( float from, float to, float f ) { 177 if ( to - from > 180.0f ) { 178 return ( from + ( ( to - 360.0f ) - from ) * f ); 179 } 180 if ( to - from < -180.0f ) { 181 return ( from + ( ( to + 360.0f ) - from ) * f ); 182 } 183 return ( from + ( to - from ) * f ); 184 } 185 147 186 /// linearly interpolate from a1 to a2 148 187 void lerpSelf( ref Angles a1, ref Angles a2, float f ) { 149 static float lerpAngle( float from, float to, float f ) {150 if ( to - from > 180.0f ) {151 return ( from + ( ( to - 360.0f ) - from ) * f );152 }153 if ( to - from < -180.0f ) {154 return ( from + ( ( to + 360.0f ) - from ) * f );155 }156 return ( from + ( to - from ) * f );157 }158 159 188 if ( f <= 0.0f ) { 160 189 *this = a1; … … 168 197 roll = lerpAngle( a1.roll, a2.roll, f ); 169 198 } 199 } 200 201 /// returns angles linearly interpolated from this to a2 202 Angles lerp( ref Angles a2, float f ) { 203 if ( f <= 0.0f ) { 204 return *this; 205 } 206 else if ( f >= 1.0f ) { 207 return a2; 208 } 209 return Angles( lerpAngle( pitch, a2.pitch, f ), lerpAngle( yaw, a2.yaw, f ), lerpAngle( roll, a2.roll, f ) ); 170 210 } 171 211 … … 207 247 } 208 248 209 unittest { 210 Angles t; 211 212 t.set( 1080.0f, 0.0f, -240.0f ); 213 t.normalize360(); 214 215 assert( Math.abs( t.pitch - 0.0f ) < 0.01f ); 216 assert( Math.abs( t.yaw - 0.0f ) < 0.01f ); 217 assert( Math.abs( t.roll - 120.0f ) < 0.01f ); 249 debug ( UNITTESTS ) { 250 unittest { 251 Angles t = Angles( 1080.0f, 0.0f, -240.0f ); 252 253 t.normalize360(); 254 255 assert( Math.abs( t.pitch - 0.0f ) < 0.01f ); 256 assert( Math.abs( t.yaw - 0.0f ) < 0.01f ); 257 assert( Math.abs( t.roll - 120.0f ) < 0.01f ); 258 } 218 259 } 219 260 … … 222 263 float sp, cp, sy, cy, sr, cr; 223 264 224 Math.sinCos( deg2rad( pitch ), sp, cp );225 Math.sinCos( deg2rad( yaw ), sy, cy );226 Math.sinCos( deg2rad( roll ), sr, cr );265 Math.sinCos( Math.deg2rad( pitch ), sp, cp ); 266 Math.sinCos( Math.deg2rad( yaw ), sy, cy ); 267 Math.sinCos( Math.deg2rad( roll ), sr, cr ); 227 268 228 269 forward.set( cp * cy, cp * sy, -sp ); … … 235 276 float sp, sy, cp, cy; 236 277 237 Math.sinCos( deg2rad( yaw ), sy, cy );238 Math.sinCos( deg2rad( pitch ), sp, cp );278 Math.sinCos( Math.deg2rad( yaw ), sy, cy ); 279 Math.sinCos( Math.deg2rad( pitch ), sp, cp ); 239 280 240 281 return Vec3( cp * cy, cp * sy, -sp ); … … 246 287 float sr, sp, sy, cr, cp, cy; 247 288 248 Math.sinCos( deg2rad( yaw ), sy, cy );249 Math.sinCos( deg2rad( pitch ), sp, cp );250 Math.sinCos( deg2rad( roll ), sr, cr );251 252 dst.cols[0] .set( cp * cy, cp * sy, -sp );253 dst.cols[1] .set( sr * sp * cy + cr * -sy, sr * sp * sy + cr * cy, sr * cp );254 dst.cols[2] .set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp );289 Math.sinCos( Math.deg2rad( yaw ), sy, cy ); 290 Math.sinCos( Math.deg2rad( pitch ), sp, cp ); 291 Math.sinCos( Math.deg2rad( roll ), sr, cr ); 292 293 dst.cols[0] = Vec3( cp * cy, cp * sy, -sp ); 294 dst.cols[1] = Vec3( sr * sp * cy + cr * -sy, sr * sp * sy + cr * cy, sr * cp ); 295 dst.cols[2] = Vec3( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp ); 255 296 256 297 return dst; … … 262 303 float sxcy, cxcy, sxsy, cxsy; 263 304 264 Math.sinCos( deg2rad( yaw ) * 0.5f, sz, cz );265 Math.sinCos( deg2rad( pitch ) * 0.5f, sy, cy );266 Math.sinCos( deg2rad( roll ) * 0.5f, sx, cx );305 Math.sinCos( Math.deg2rad( yaw ) * 0.5f, sz, cz ); 306 Math.sinCos( Math.deg2rad( pitch ) * 0.5f, sy, cy ); 307 Math.sinCos( Math.deg2rad( roll ) * 0.5f, sx, cx ); 267 308 268 309 sxcy = sx * cy; … … 276 317 /// converts to string; just a convenience function 277 318 char[] toUtf8() { 278 return Math.floatArrayToUtf8( ptr[0..length] ); 279 } 280 281 version ( Phobos ) { 282 alias toString toUtf8; 319 return Math.toUtf8( "( p:{0:E} y:{1:E} r:{2:E} )", pitch, yaw, roll ); 283 320 } 284 321 … … 291 328 float *ptr() { 292 329 return ( &pitch ); 330 } 331 332 debug ( FLOAT_PARANOID ) { 333 invariant() { 334 assert( Math.isValid( pitch ) ); 335 assert( Math.isValid( yaw ) ); 336 assert( Math.isValid( roll ) ); 337 } 293 338 } 294 339 trunk/ray/base/Color.d
r15 r16 4 4 5 5 Structures to represent colors. 6 7 FIXME: byte-order selection should be done in compile-time. 8 9 Version: Aug 2007: initial release 10 Authors: Artyom Shalkhakov 6 11 */ 7 12 module ray.base.Color; 8 13 9 import ray.base.Math; 10 11 invariant { 14 import Math = ray.base.Math; 15 16 /// byte-order conventions (for uint conversion) 17 enum BYTEORDER { 18 ARGB8, 19 ABGR8, 20 RGBA8, 21 BGRA8 22 } 23 24 const { 12 25 Col3 col3_zero = { r : 0.0f, g : 0.0f, b : 0.0f }; 13 26 Col3 col3_identity = { r : 1.0f, g : 1.0f, b : 1.0f }; … … 62 75 } 63 76 64 static Col3 opCall( uint rgb) {77 Col3 opCall( uint rgb, BYTEORDER order = BYTEORDER.RGBA8 ) { 65 78 Col3 dst; 66 67 dst.r = ( cast( ubyte * )&rgb )[0] * ( 1.0f / 255.0f ); 68 dst.g = ( cast( ubyte * )&rgb )[1] * ( 1.0f / 255.0f ); 69 dst.b = ( cast( ubyte * )&rgb )[2] * ( 1.0f / 255.0f ); 70 79 80 // unpack according to byte-order 81 switch ( order ) { 82 case BYTEORDER.ARGB8: 83 dst.r = ( cast( ubyte * )&rgb )[1] * ( 1.0f / 255.0f ); 84 dst.g = ( cast( ubyte * )&rgb )[2] * ( 1.0f / 255.0f ); 85 dst.b = ( cast( ubyte * )&rgb )[3] * ( 1.0f / 255.0f ); 86 break; 87 case BYTEORDER.ABGR8: 88 dst.b = ( cast( ubyte * )&rgb )[1] * ( 1.0f / 255.0f ); 89 dst.g = ( cast( ubyte * )&rgb )[2] * ( 1.0f / 255.0f ); 90 dst.r = ( cast( ubyte * )&rgb )[3] * ( 1.0f / 255.0f ); 91 break; 92 case BYTEORDER.RGBA8: 93 dst.r = ( cast( ubyte * )&rgb )[0] * ( 1.0f / 255.0f ); 94 dst.g = ( cast( ubyte * )&rgb )[1] * ( 1.0f / 255.0f ); 95 dst.b = ( cast( ubyte * )&rgb )[2] * ( 1.0f / 255.0f ); 96 break; 97 case BYTEORDER.BGRA8: 98 dst.b = ( cast( ubyte * )&rgb )[0] * ( 1.0f / 255.0f ); 99 dst.g = ( cast( ubyte * )&rgb )[1] * ( 1.0f / 255.0f ); 100 dst.r = ( cast( ubyte * )&rgb )[2] * ( 1.0f / 255.0f ); 101 break; 102 } 103 71 104 return dst; 72 105 } … … 100 133 } 101 134 102 Col3 opMul( float f ) { 135 Col3 opMul( float f ) 136 in { 137 debug ( FLOAT_PARANOID ) { 138 assert( Math.isValid( f ) ); 139 } 140 } 141 body { 103 142 return Col3( r * f, g * f, b * f ); 104 143 } … … 108 147 } 109 148 110 Col3 opDiv( float f ) { 149 Col3 opDiv( float f ) 150 in { 151 debug ( FLOAT_PARANOID ) { 152 assert( Math.isValid( f ) ); 153 assert( Math.abs( f - 0.0f ) > 1e-14 ); 154 } 155 } 156 body { 111 157 float invF = 1.0f / f; 112 158 … … 218 264 } 219 265 266 /// returns color linearly interpolated from this to c2 by fraction f 267 Col3 lerp( ref Col3 c2, float f ) { 268 if ( f <= 0.0f ) { 269 return *this; 270 } 271 else if ( f >= 1.0f ) { 272 return c2; 273 } 274 return ( *this ) + f * ( c2 - ( *this ) ); 275 } 276 220 277 /// converts to RGBA color; alpha is assumed to be 1.0f 221 278 Col4 toCol4() { … … 233 290 234 291 /// packs RGB values into uint variable, alpha is assumed to be 1.0f 235 uint toUint( )292 uint toUint( BYTEORDER order = BYTEORDER.RGBA8 ) 236 293 in { 237 294 assert( r >= 0 && r <= 1.0f ); … … 242 299 uint dst; 243 300 244 ( cast( ubyte * )&dst )[0] = cast( ubyte )Math.ftoiFast( r * 255.0f ); 245 ( cast( ubyte * )&dst )[1] = cast( ubyte )Math.ftoiFast( g * 255.0f ); 246 ( cast( ubyte * )&dst )[2] = cast( ubyte )Math.ftoiFast( b * 255.0f ); 301 // pack according to byte-order 302 switch ( order ) { 303 case BYTEORDER.ARGB8: 304 ( cast( ubyte * )&dst )[1] = cast( ubyte )Math.ftoiFast( r * 255.0f ); 305 ( cast( ubyte * )&dst )[2] = cast( ubyte )Math.ftoiFast( g * 255.0f ); 306 ( cast( ubyte * )&dst )[3] = cast( ubyte )Math.ftoiFast( b * 255.0f ); 307 break; 308 case BYTEORDER.ABGR8: 309 ( cast( ubyte * )&dst )[1] = cast( ubyte )Math.ftoiFast( b * 255.0f ); 310 ( cast( ubyte * )&dst )[2] = cast( ubyte )Math.ftoiFast( g * 255.0f ); 311 ( cast( ubyte * )&dst )[3] = cast( ubyte )Math.ftoiFast( r * 255.0f ); 312 break; 313 case BYTEORDER.RGBA8: 314 ( cast( ubyte * )&dst )[0] = cast( ubyte )Math.ftoiFast( r * 255.0f ); 315 ( cast( ubyte * )&dst )[1] = cast( ubyte )Math.ftoiFast( g * 255.0f ); 316 ( cast( ubyte * )&dst )[2] = cast( ubyte )Math.ftoiFast( b * 255.0f ); 317 break; 318 case BYTEORDER.BGRA8: 319 ( cast( ubyte * )&dst )[0] = cast( ubyte )Math.ftoiFast( b * 255.0f ); 320 ( cast( ubyte * )&dst )[1] = cast( ubyte )Math.ftoiFast( g * 255.0f ); 321 ( cast( ubyte * )&dst )[2] = cast( ubyte )Math.ftoiFast( r * 255.0f ); 322 break; 323 } 247 324 ( cast( ubyte * )&dst )[3] = 0xFF; 248 325 … … 252 329 /// returns string, just a convenience function 253 330 char[] toUtf8() { 254 return Math.floatArrayToUtf8( ptr[0..length] ); 255 } 256 257 version ( Phobos ) { 258 alias toUtf8 toString; 331 return Math.toUtf8( "( r:{0:E} g:{1:E} b:{2:E} )", r, g, b ); 259 332 } 260 333 … … 267 340 float *ptr() { 268 341 return &r; 342 } 343 344 debug ( FLOAT_PARANOID ) { 345 invariant() { 346 assert( Math.isValid( r ) ); 347 assert( Math.isValid( g ) ); 348 assert( Math.isValid( b ) ); 349 } 269 350 } 270 351 … … 330 411 } 331 412 332 static Col4 opCall( uint rgba ) {413 static Col4 opCall( uint rgba, BYTEORDER order = BYTEORDER.RGBA8 ) { 333 414 Col4 dst; 334 415 335 dst.r = ( cast( ubyte * )&rgba )[0] * ( 1.0f / 255.0f ); 336 dst.g = ( cast( ubyte * )&rgba )[1] * ( 1.0f / 255.0f ); 337 dst.b = ( cast( ubyte * )&rgba )[2] * ( 1.0f / 255.0f ); 338 dst.a = ( cast( ubyte * )&rgba )[3] * ( 1.0f / 255.0f ); 416 // unpack according to byte-order 417 switch ( order ) { 418 case BYTEORDER.ARGB8: 419 dst.a = ( cast( ubyte * )&rgba )[0] * ( 1.0f / 255.0f ); 420 dst.r = ( cast( ubyte * )&rgba )[1] * ( 1.0f / 255.0f ); 421 dst.g = ( cast( ubyte * )&rgba )[2] * ( 1.0f / 255.0f ); 422 dst.b = ( cast( ubyte * )&rgba )[3] * ( 1.0f / 255.0f ); 423 break; 424 case BYTEORDER.ABGR8: 425 dst.a = ( cast( ubyte * )&rgba )[0] * ( 1.0f / 255.0f ); 426 dst.b = ( cast( ubyte * )&rgba )[1] * ( 1.0f / 255.0f ); 427 dst.g = ( cast( ubyte * )&rgba )[2] * ( 1.0f / 255.0f ); 428 dst.r = ( cast( ubyte * )&rgba )[3] * ( 1.0f / 255.0f ); 429 break; 430 case BYTEORDER.RGBA8: 431 dst.r = ( cast( ubyte * )&rgba )[0] * ( 1.0f / 255.0f ); 432 dst.g = ( cast( ubyte * )&rgba )[1] * ( 1.0f / 255.0f ); 433 dst.b = ( cast( ubyte * )&rgba )[2] * ( 1.0f / 255.0f ); 434 dst.a = ( cast( ubyte * )&rgba )[3] * ( 1.0f / 255.0f ); 435 break; 436 case BYTEORDER.BGRA8: 437 dst.b = ( cast( ubyte * )&rgba )[0] * ( 1.0f / 255.0f ); 438 dst.g = ( cast( ubyte * )&rgba )[1] * ( 1.0f / 255.0f ); 439 dst.r = ( cast( ubyte * )&rgba )[2] * ( 1.0f / 255.0f ); 440 dst.a = ( cast( ubyte * )&rgba )[3] * ( 1.0f / 255.0f ); 441 break; 442 } 339 443 340 444 return dst; … … 365 469 } 366 470 367 Col4 opMul( float f ) { 471 Col4 opMul( float f ) 472 in { 473 debug ( FLOAT_PARANOID ) { 474 assert( Math.isValid( f ) ); 475 } 476 } 477 body { 368 478 return Col4( r * f, g * f, b * f, a * f ); 369 479 } … … 373 483 } 374 484 375 Col4 opDiv( float f ) { 485 Col4 opDiv( float f ) 486 in { 487 debug ( FLOAT_PARANOID ) { 488 assert( Math.isValid( f ) ); 489 assert( Math.abs( f - 0.0f ) > 1e-14 ); 490 } 491 } 492 body { 376 493 float invF = 1.0f / f; 377 494 … … 522 639 } 523 640 641 /// returns color linearly interpolated from this to c2 by fraction f 642 Col4 lerp( ref Col4 c2, float f ) { 643 if ( f <= 0.0f ) { 644 return *this; 645 } 646 else if ( f >= 1.0f ) { 647 return c2; 648 } 649 return ( *this ) + f * ( c2 - ( *this ) ); 650 } 651 524 652 /// returns hash-code for color 525 653 size_t toHash() { … … 533 661 534 662 /// packs RGBA values into uint variable 535 uint toUint( )663 uint toUint( BYTEORDER order = BYTEORDER.RGBA8 ) 536 664 in { 537 665 assert( r >= 0.0f && r <= 1.0f ); … … 543 671 uint dst; 544 672 545 ( cast( ubyte * )&dst )[0] = cast( ubyte )Math.ftoiFast( r * 255.0f ); 546 ( cast( ubyte * )&dst )[1] = cast( ubyte )Math.ftoiFast( g * 255.0f ); 547 ( cast( ubyte * )&dst )[2] = cast( ubyte )Math.ftoiFast( b * 255.0f ); 548 ( cast( ubyte * )&dst )[3] = cast( ubyte )Math.ftoiFast( a * 255.0f ); 673 // pack according to byte-order 674 switch ( order ) { 675 case BYTEORDER.ARGB8: 676 ( cast( ubyte * )&dst )[0] = cast( ubyte )Math.ftoiFast( a * 255.0f ); 677 ( cast( ubyte * )&dst )[1] = cast( ubyte )Math.ftoiFast( r * 255.0f ); 678 ( cast( ubyte * )&dst )[2] = cast( ubyte )Math.ftoiFast( g * 255.0f ); 679 ( cast( ubyte * )&dst )[3] = cast( ubyte )Math.ftoiFast( b * 255.0f ); 680 break; 681 case BYTEORDER.ABGR8: 682 ( cast( ubyte * )&dst )[0] = cast( ubyte )Math.ftoiFast( a * 255.0f ); 683 ( cast( ubyte * )&dst )[1] = cast( ubyte )Math.ftoiFast( b * 255.0f ); 684 ( cast( ubyte * )&dst )[2] = cast( ubyte )Math.ftoiFast( g * 255.0f ); 685 ( cast( ubyte * )&dst )[3] = cast( ubyte )Math.ftoiFast( r * 255.0f ); 686 break; 687 case BYTEORDER.RGBA8: 688 ( cast( ubyte * )&dst )[0] = cast( ubyte )Math.ftoiFast( r * 255.0f ); 689 ( cast( ubyte * )&dst )[1] = cast( ubyte )Math.ftoiFast( g * 255.0f ); 690 ( cast( ubyte * )&dst )[2] = cast( ubyte )Math.ftoiFast( b * 255.0f ); 691 ( cast( ubyte * )&dst )[3] = cast( ubyte )Math.ftoiFast( a * 255.0f ); 692 break; 693 case BYTEORDER.BGRA8: 694 ( cast( ubyte * )&dst )[0] = cast( ubyte )Math.ftoiFast( b * 255.0f ); 695 ( cast( ubyte * )&dst )[1] = cast( ubyte )Math.ftoiFast( g * 255.0f ); 696 ( cast( ubyte * )&dst )[2] = cast( ubyte )Math.ftoiFast( r * 255.0f ); 697 ( cast( ubyte * )&dst )[3] = cast( ubyte )Math.ftoiFast( a * 255.0f ); 698 break; 699 } 549 700 550 701 return dst; … … 553 704 /// returns string, just a convenience function 554 705 char[] toUtf8() { 555 return Math.floatArrayToUtf8( ptr[0..length] ); 556 } 557 558 version ( Phobos ) { 559 alias toUtf8 toString; 706 return Math.toUtf8( "( r:{0:E} g:{1:E} b:{2:E} a:{3:E} )", r, g, b, a ); 560 707 } 561 708 … … 570 717 } 571 718 719 debug ( FLOAT_PARANOID ) { 720 invariant() { 721 assert( Math.isValid( r ) ); 722 assert( Math.isValid( g ) ); 723 assert( Math.isValid( b ) ); 724 assert( Math.isValid( a ) ); 725 } 726 } 727 572 728 float r, g, b, a; /// color components: red, green, blue and alpha 573 729 } trunk/ray/base/Math.d
r15 r16 1 1 /** 2 Copyright: Copyright (c) 2007, Artyom Shalkhakov. All rights reserved. 3 License: BSD 2 Copyright: Copyright (c) 2002-2006 Chris Lomont 3 Copyright: Copyright (c) 2007 Artyom Shalkhakov 4 License: BSD-style 4 5 5 6 This module contains replacements for some library functions. 7 Some functions were taken from FloatHack library by Chris 8 Lomont (www.lomont.org), which has the following license agreement: 9 --- 10 FloatHack.cpp -- implementation of Chris Lomont's fast and alternative floating point routines 11 version 0.5, October, 2005 12 www.lomont.org 13 14 Copyright (C) 2002-2006 Chris Lomont 15 16 This software is provided 'as-is', without any express or implied 17 warranty. In no event will the author be held liable for any damages 18 arising from the use of this software. 19 20 Permission is granted to anyone to use this software for any purpose, 21 excluding commercial applications, and to alter it and redistribute it 22 freely, subject to the following restrictions: 23 24 1. The origin of this software must not be misrepresented; you must not 25 claim that you wrote the original software. If you use this software 26 in a product, an acknowledgment in the product documentation would be 27 appreciated but is not required. 28 2. Altered source versions must be plainly marked as such, and must not be 29 misrepresented as being the original software. 30 3. This notice may not be removed or altered from any source distribution. 31 32 If you want to use this for commercial applications please contact me. 33 34 Chris Lomont, you can contact me from www.lomont.org 35 --- 36 37 It is highly recommended that an import aliasing is applied 38 to this module to avoid namespace pollution. 39 40 Version: Aug 2007: initial release 41 Authors: Chris Lomont, Artyom Shalkhakov 42 43 Version and debug identifiers: 44 --- 45 version = HACKED_MATH; // enable FloatHack math routines: sqrt, 1/sqrt, abs 46 version = HACKED_CLAMP; // enable FloatHack clamping routines 47 version = HACKED_CONVERSION; // enable FloatHack int-to-float/float-to-int conversion 48 debug = UNITTESTS; // run unit tests 49 --- 6 50 */ 7 51 module ray.base.Math; 8 52 9 version ( Tango ) { 10 private import StdcMath = tango.stdc.math; // math functions 11 private import tango.text.convert.Sprint; // string formatting functions 12 13 // important constants 14 public import tango.math.Math : E, LOG2T, LOG2E, LOG2, LOG10E, LN2, LN10, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI, SQRT2, SQRT1_2; 15 } 16 else { 17 private import StdcMath = std.c.math; // math functions 18 private import std.utf, std.format; // string formatting functions 19 20 // important constants 21 public import std.math : E, LOG2T, LOG2E, LOG2, LOG10E, LN2, LN10, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI, SQRT2, SQRT1_2; 53 private { 54 import StdcMath = tango.stdc.math; // math functions 55 import tango.text.convert.Layout; // string formatting functions 56 debug ( UNITTESTS ) { 57 import tango.io.Stdout; 58 import tango.math.Random; 59 } 60 import tango.math.IEEE; 61 import tango.math.Math : E, LOG2T, LOG2E, LOG2, LOG10E, LN2, LN10, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI, SQRT2, SQRT1_2; 22 62 } 23 63 … … 27 67 } 28 68 69 version ( HACKED_MATH ) { 70 private { 71 union IntFloat { 72 float f; 73 int i; 74 } 75 76 enum { 77 LOOKUP_BITS = 8, 78 EXP_POS = 23, 79 EXP_BIAS = 127, 80 LOOKUP_POS = ( EXP_POS - LOOKUP_BITS ), 81 SEED_POS = ( EXP_POS - 8 ), 82 SQRT_TABLE_SIZE = ( 2 << LOOKUP_BITS ), 83 LOOKUP_MASK = ( SQRT_TABLE_SIZE - 1 ) 84 } 85 uint[SQRT_TABLE_SIZE] sqrtValues; 86 } 87 88 static this() { 89 IntFloat fi, fo; 90 91 for ( int i = 0; i < SQRT_TABLE_SIZE; i++ ) { 92 fi.i = ( ( EXP_BIAS - 1 ) << EXP_POS ) | ( i << LOOKUP_POS ); 93 fo.f = cast( float )( 1.0 / StdcMath.sqrtf( fi.f ) ); 94 sqrtValues[i] = ( cast( uint )( ( ( fo.i + ( 1 << ( SEED_POS - 2 ) ) ) >> SEED_POS ) & 0xFF ) ) << SEED_POS; 95 } 96 sqrtValues[SQRT_TABLE_SIZE / 2] = ( cast( uint )0xFF ) << SEED_POS; 97 } 98 } 99 29 100 /// convert degrees to radians 30 101 type deg2rad( type )( type degrees ) { … … 37 108 } 38 109 39 /** 40 Some math functions are encapsulated to faciliate optimization. 41 */ 42 struct Math { 43 /// absolute value of x 44 static int abs( int x ) { 110 /// returns true if any of arguments is NaN 111 int isNaN( float x ) { 112 return ( *( cast( uint * )( &x ) ) & 0x7f800000 ) == 0x7f800000; 113 } 114 115 /// returns true if any of arguments is either float.infinity or -float.infinity 116 int isInfinity( float x ) { 117 return ( *( cast( uint * )( &x ) ) & 0x7fffffff ) == 0x7f800000; 118 } 119 120 /// returns true if x is valid (not a NaN, and not infinity) 121 int isValid( type )( type x ) { 122 return !isNaN( x ) && !isInfinity( x ); 123 } 124 125 debug ( UNITTESTS ) { 126 unittest { 127 assert( isValid( 0.0f ) ); 128 } 129 130 unittest { 131 float a, b; 132 133 Stdout( "...testing exceptional functions:" ).newline; 134 Stdout( "all expressions should return true" ).newline; 135 136 Stdout.format( "every float is initialized to NaN: {}", isNaN( a ) ).newline; 137 a = -1.0f; 138 Stdout.format( "-1 is a number: {}", isValid( a ) ).newline; 139 b = StdcMath.sqrtf( a ); 140 Stdout.format( "sqrt( -1 ) is a NaN: {}", isNaN( b ) ).newline; 141 142 a = makeFloat( 0, 0, 0 ); // make 0 this way to prevent optimizer from removing 143 b = 1.0f / a; 144 Stdout.format( "1/0 is infinity: {}", isInfinity( b ) ).newline; 145 146 // create denormalized value: 147 a = makeFloat( 0, 1, 0 ); // smallest normalized number 148 Stdout.format( "normalized: {}", !isSubnormal( a ) ).newline; 149 a = a * 0.5f; // now denormalized 150 Stdout.format( "denormalized: {}", isSubnormal( a ) ).newline; 151 } 152 } 153 154 /// returns the sign-bit of x 155 int signbit( int x ) { 156 return ( ( *cast( uint * )( &x ) ) >> 31 ); 157 } 158 159 /// ditto 160 int signbit( float x ) { 161 return ( ( *cast( uint * )( &x ) ) >> 31 ); 162 } 163 164 debug ( UNITTESTS ) { 165 unittest { 166 assert( signbit( 1 ) == 0 ); 167 assert( signbit( -1 ) == 1 ); 168 assert( signbit( 0.5f ) == 0 ); 169 assert( signbit( -2.0f ) == 1 ); 170 } 171 } 172 173 /// returns 0x00000000 if x >= 0 and returns 0xFFFFFFFF if x < 0 174 int maskForSign( int x ) { 175 return ~( ( ( cast( uint )x ) >> 31 ) - 1 ); 176 } 177 178 /// ditto 179 int maskForSign( float x ) { 180 return ~( ( ( *cast( uint * )&x ) >> 31 ) - 1 ); 181 } 182 183 debug ( UNITTESTS ) { 184 unittest { 185 assert( maskForSign( 0 ) == 0 ); 186 assert( maskForSign( 1 ) == 0 ); 187 assert( maskForSign( -1 ) == 0xFFFFFFFF ); 188 assert( maskForSign( 0.0f ) == 0 ); 189 assert( maskForSign( -0.0f ) == 0xFFFFFFFF ); 190 assert( maskForSign( 1.0f ) == 0 ); 191 assert( maskForSign( -1.0f ) == 0xFFFFFFFF ); 192 } 193 } 194 195 /// absolute value of x 196 float abs( float x ) { 197 version ( HACKED_MATH ) { 198 int i = *cast( int * )( &x ); 199 200 i &= 0x7FFFFFFF; // strip sign bit 201 202 return ( *cast( float * )( &i ) ); 203 } 204 else { 45 205 return x >= 0 ? x : -x; 46 206 } 47 48 /// ditto 49 static float abs( float x ) { 50 return x >= 0 ? x : -x; 51 } 52 53 static float floor( float x ) { 54 return StdcMath.floorf( x ); 55 } 56 57 static float ceil( float x ) { 58 return StdcMath.ceilf( x ); 59 } 60 61 /// clamp to [min, max] 62 static float clamp( float x, float min, float max ) { 207 } 208 209 /// negate x 210 float negate( float x ) { 211 version ( HACKED_MATH ) { 212 int i = *cast( int * )( &x ); 213 214 i ^= 0x80000000; // flip sign bit 215 216 return ( *cast( float * )( &i ) ); 217 } 218 else { 219 return -x; 220 } 221 } 222 223 float floor( float x ) { 224 return StdcMath.floorf( x ); 225 } 226 227 float ceil( float x ) { 228 return StdcMath.ceilf( x ); 229 } 230 231 /// clamp to [min, max] 232 float clamp( float x, float min, float max ) 233 in { 234 assert( min < max ); 235 } 236 out ( r ) { 237 version ( HACKED_CLAMP ) { 238 assert( ( r >= min ) && ( r <= max ) ); 239 } 240 } 241 body { 242 version ( HACKED_CLAMP ) { 243 x -= min; 244 x /= ( max - min ); 245 x = clampBiased( x ); 246 x *= ( max - min ); 247 x += min; 248 return x; 249 } 250 else { 63 251 if ( x < min ) { 64 252 return min; … … 67 255 return max; 68 256 } 69 return x; 70 } 71 72 /// clamp to [0, 1] 73 static float clampBiased( float x ) { 257 return x; 258 } 259 } 260 261 /// clamp x to [0, 1] 262 float clampBiased( float x ) 263 out ( r ) { 264 version ( HACKED_CLAMP ) { 265 assert( ( r >= 0.0f ) && ( r <= 1.0f ) ); 266 } 267 } 268 body { 269 version ( HACKED_CLAMP ) { 270 int s = void; 271 IntFloat v = void; 272 273 v.f = x; 274 s = maskForSign( v.i ); // all 1's if signbit is 1 275 v.i &= ~s; // 0 if was negative 276 277 // clamp to 1 278 v.f = 1.0f - v.f; 279 s = maskForSign( v.i ); // all 1's if signbit is 1 280 v.i &= ~s; // 0 if was negative 281 v.f = 1.0f - v.f; 282 283 return v.f; 284 } 285 else { 74 286 if ( x < 0.0f ) { 75 287 return 0.0f; … … 80 292 return x; 81 293 } 82 83 /// clamp to [-1, 1] 84 static float clamp( float x ) { 294 } 295 296 /// clamp to [-1, 1] 297 float clamp( float x ) 298 out ( r ) { 299 version ( HACKED_CLAMP ) { 300 assert( ( r >= -1.0f ) && ( r <= 1.0f ) ); 301 } 302 } 303 body { 304 version ( HACKED_CLAMP ) { 305 x += 1.0f; 306 x *= 0.5f; 307 x = clampBiased( x ); 308 x *= 2.0f; 309 x -= 1.0f; 310 return x; 311 &
