Changeset 16

Show
Ignore:
Timestamp:
08/01/07 14:01:51 (1 year ago)
Author:
Linker
Message:

- experimental display mode class and test program;
- support for color byte-order conventions;
- Transformation class;
- fixes here and there (in Vector.d);
- integrated parts of FloatHack? into ray;
- wrote tests for new code; did some tests;
- integrated ray-box intersection code;
- set-up for tango-0.99 RC3 + DMD1.18;
- .toUtf8 property for every struct

Files:

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 
     1jake test\test.d -I.. -debug=UNITTESTS -unittest -op 
     2jake dispmode\dispmode.d -I.. -op 
     3 
     4REM jake raytrace\raytrace.d -I.. -debug=UNITTESTS -version=FLOATHACK -unittest -op 
  • trunk/examples/raytrace/raytrace.d

    r15 r16  
    33// does 2x2 anti-aliasing; the scene is composed of two spheres and one directional light. 
    44// 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. 
    76import ray.base.Math; 
    87import ray.base.Vector; 
     
    109 
    1110import ray.bv.Sphere; 
     11 
     12import tango.math.Math; // max() 
     13 
     14import tango.io.Stdout; 
     15 
     16version = SHADOWS;      // uncomment to enable shadow rays 
    1217 
    1318enum { 
     
    1823} 
    1924 
    20 invariant bool          SHADOWS = true; // set to false to disable shadow rays 
    21  
    22 Vec3                    lightDir; 
    23 Sphere[]                spheres; 
    24  
    2525struct Hit { 
    2626    float   dist; 
     
    2828} 
    2929 
    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() { 
     30static this() { 
    3631    lightDir = Vec3( -0.5f, -0.65f, 0.9f ).normalize; 
    3732    spheres ~= Sphere( Vec3( 0.0f, 0.0f, 0.0f ), 1.0f ); 
    3833    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; 
    4535} 
    4636 
     
    7565    intersectRay!( false )( ray, hit ); 
    7666 
    77     float   diffuse = hit.dist == float.infinity ? 0.0f : -( hit.normal * lightDir )
     67    float   diffuse = hit.dist == float.infinity ? 0.0f : -hit.normal * lightDir
    7868 
    7969    if ( diffuse <= 0.0f ) { 
     
    8171    } 
    8272 
    83     static if ( SHADOWS ) { 
     73    version ( SHADOWS ) { 
    8474        Ray     shadowRay = Ray( ray.origin + ( ray.dir * hit.dist ) + ( hit.normal * 0.1f ), -lightDir ); 
    8575        Hit     shadowHit = void; 
     
    9585} 
    9686 
    97 void traceRays( const int width, const int height ) { 
     87void traceRays( int width, int height ) { 
    9888    // rotated grid 
    99     invariant float[2][SS_SQR] grid = [ 
     89    const float[2][SS_SQR] grid = [ 
    10090        [ -3.0f / 3.0f, -1.0f / 3.0f ], [ +1.0f / 3.0f, -3.0f / 3.0f ], 
    10191 
    10292        [ -1.0f / 3.0f, +3.0f / 3.0f ], [ +3.0f / 3.0f, +1.0f / 3.0f ] 
    10393    ]; 
    104     invariant double  rcp = 1.0 / SS, scale = 256.0 / SS_SQR; 
    105     final double      w = width, h = height; 
    106     final Vec3[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; 
    10999 
    110100    // precompute 
     
    123113                g += traceRay( ray ); 
    124114            } 
    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 ) ); 
    131116            scan.x += 1.0f; 
    132117        } 
     118        Stdout.flush; 
    133119        scan.x = 0.0f; 
    134120        scan.y -= 1.0f; 
    135121    } 
    136     version ( Tango ) { 
    137         static assert( false ); 
    138     } 
    139     else { 
    140         std.stdio.writefln(); 
    141     } 
     122    Stdout.newline; 
    142123} 
    143124 
     125Vec3        lightDir; 
     126Sphere[]    spheres; 
     127 
    144128int main( char[][] args ) { 
    145     initialize(); 
    146129    traceRays( WIDTH, HEIGHT ); 
    147130    return 0; 
  • trunk/ray/base/Angles.d

    r15 r16  
    44 
    55    This module implements Euler angles. 
     6 
     7    Version: Aug 2007: initial release 
     8    Authors: Artyom Shalkhakov 
    69*/ 
    710module ray.base.Angles; 
    811 
    9 import ray.base.Math; 
     12import Math = ray.base.Math; 
    1013import ray.base.Vector; 
    1114import ray.base.Quat; 
    1215 
    13 invariant Angles  ang_zero = { pitch : 0.0f, yaw : 0.0f, roll : 0.0f }; 
     16const Angles  ang_zero = { pitch : 0.0f, yaw : 0.0f, roll : 0.0f }; 
    1417 
    1518/// angle indices 
     
    7174    } 
    7275 
    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 { 
    7483        return Angles( pitch * f, yaw * f, roll * f ); 
    7584    } 
    7685 
    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 { 
    7894        float   invF = 1.0f / f; 
    7995 
     
    93109    } 
    94110 
    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 { 
    96118        pitch *= f; 
    97119        yaw *= f; 
     
    99121    } 
    100122 
    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 { 
    102131        float   invF = 1.0f / f; 
    103132 
     
    145174    } 
    146175 
     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 
    147186    /// linearly interpolate from a1 to a2 
    148187    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  
    159188        if ( f <= 0.0f ) { 
    160189            *this = a1; 
     
    168197            roll = lerpAngle( a1.roll, a2.roll, f ); 
    169198        } 
     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 ) ); 
    170210    } 
    171211 
     
    207247    } 
    208248 
    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        } 
    218259    } 
    219260 
     
    222263        float   sp, cp, sy, cy, sr, cr; 
    223264 
    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 ); 
    227268 
    228269        forward.set( cp * cy, cp * sy, -sp ); 
     
    235276        float   sp, sy, cp, cy; 
    236277 
    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 ); 
    239280 
    240281        return Vec3( cp * cy, cp * sy, -sp ); 
     
    246287        float   sr, sp, sy, cr, cp, cy; 
    247288 
    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 ); 
    255296 
    256297        return dst; 
     
    262303        float   sxcy, cxcy, sxsy, cxsy; 
    263304 
    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 ); 
    267308 
    268309        sxcy = sx * cy; 
     
    276317    /// converts to string; just a convenience function 
    277318    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 ); 
    283320    } 
    284321 
     
    291328    float *ptr() { 
    292329        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        } 
    293338    } 
    294339 
  • trunk/ray/base/Color.d

    r15 r16  
    44 
    55    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 
    611*/ 
    712module ray.base.Color; 
    813 
    9 import ray.base.Math; 
    10  
    11 invariant { 
     14import Math = ray.base.Math; 
     15 
     16/// byte-order conventions (for uint conversion) 
     17enum BYTEORDER { 
     18    ARGB8, 
     19    ABGR8, 
     20    RGBA8, 
     21    BGRA8 
     22
     23 
     24const { 
    1225    Col3    col3_zero       = { r : 0.0f, g : 0.0f, b : 0.0f }; 
    1326    Col3    col3_identity   = { r : 1.0f, g : 1.0f, b : 1.0f }; 
     
    6275    } 
    6376 
    64     static Col3 opCall( uint rgb ) { 
     77    Col3 opCall( uint rgb, BYTEORDER order = BYTEORDER.RGBA8 ) { 
    6578        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     
    71104        return dst; 
    72105    } 
     
    100133    } 
    101134 
    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 { 
    103142        return Col3( r * f, g * f, b * f ); 
    104143    } 
     
    108147    } 
    109148 
    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 { 
    111157        float   invF = 1.0f / f; 
    112158 
     
    218264    } 
    219265 
     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 
    220277    /// converts to RGBA color; alpha is assumed to be 1.0f 
    221278    Col4 toCol4() { 
     
    233290 
    234291    /// packs RGB values into uint variable, alpha is assumed to be 1.0f 
    235     uint toUint(
     292    uint toUint( BYTEORDER order = BYTEORDER.RGBA8
    236293    in { 
    237294        assert( r >= 0 && r <= 1.0f ); 
     
    242299        uint    dst; 
    243300 
    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        } 
    247324        ( cast( ubyte * )&dst )[3] = 0xFF; 
    248325 
     
    252329    /// returns string, just a convenience function 
    253330    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 ); 
    259332    } 
    260333 
     
    267340    float *ptr() { 
    268341        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        } 
    269350    } 
    270351 
     
    330411    } 
    331412 
    332     static Col4 opCall( uint rgba ) { 
     413    static Col4 opCall( uint rgba, BYTEORDER order = BYTEORDER.RGBA8 ) { 
    333414        Col4    dst; 
    334415 
    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        } 
    339443 
    340444        return dst; 
     
    365469    } 
    366470 
    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 { 
    368478        return Col4( r * f, g * f, b * f, a * f ); 
    369479    } 
     
    373483    } 
    374484 
    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 { 
    376493        float   invF = 1.0f / f; 
    377494 
     
    522639    } 
    523640 
     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 
    524652    /// returns hash-code for color 
    525653    size_t toHash() { 
     
    533661 
    534662    /// packs RGBA values into uint variable 
    535     uint toUint(
     663    uint toUint( BYTEORDER order = BYTEORDER.RGBA8
    536664    in { 
    537665        assert( r >= 0.0f && r <= 1.0f ); 
     
    543671        uint    dst; 
    544672 
    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        } 
    549700 
    550701        return dst; 
     
    553704    /// returns string, just a convenience function 
    554705    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 ); 
    560707    } 
    561708 
     
    570717    } 
    571718 
     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 
    572728    float   r, g, b, a;     /// color components: red, green, blue and alpha 
    573729} 
  • trunk/ray/base/Math.d

    r15 r16  
    11/** 
    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 
    45 
    56    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    --- 
    650*/ 
    751module ray.base.Math; 
    852 
    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; 
     53private { 
     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; 
    2262} 
    2363 
     
    2767} 
    2868 
     69version ( 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 
    29100/// convert degrees to radians 
    30101type deg2rad( type )( type degrees ) { 
     
    37108} 
    38109 
    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 
     111int 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 
     116int 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) 
     121int isValid( type )( type x ) { 
     122    return !isNaN( x ) && !isInfinity( x ); 
     123
     124 
     125debug ( 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 
     155int signbit( int x ) { 
     156    return ( ( *cast( uint * )( &x ) ) >> 31 ); 
     157
     158 
     159/// ditto 
     160int signbit( float x ) { 
     161    return ( ( *cast( uint * )( &x ) ) >> 31 ); 
     162
     163 
     164debug ( 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 
     174int maskForSign( int x ) { 
     175    return ~( ( ( cast( uint )x ) >> 31 ) - 1 ); 
     176
     177 
     178/// ditto 
     179int maskForSign( float x ) { 
     180    return ~( ( ( *cast( uint * )&x ) >> 31 ) - 1 ); 
     181
     182 
     183debug ( 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 
     196float 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 { 
    45205        return x >= 0 ? x : -x; 
    46206    } 
    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 
     210float 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 
     223float floor( float x ) { 
     224    return StdcMath.floorf( x ); 
     225
     226 
     227float ceil( float x ) { 
     228    return StdcMath.ceilf( x ); 
     229
     230 
     231/// clamp to [min, max] 
     232float clamp( float x, float min, float max ) 
     233in { 
     234    assert( min < max ); 
     235
     236out ( r ) { 
     237    version ( HACKED_CLAMP ) { 
     238        assert( ( r >= min ) && ( r <= max ) ); 
     239    } 
     240
     241body { 
     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 { 
    63251        if ( x < min ) { 
    64252            return min; 
     
    67255            return max; 
    68256        } 
    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] 
     262float clampBiased( float x ) 
     263out ( r ) { 
     264    version ( HACKED_CLAMP ) { 
     265        assert( ( r >= 0.0f ) && ( r <= 1.0f ) ); 
     266    } 
     267
     268body { 
     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 { 
    74286        if ( x < 0.0f ) { 
    75287            return 0.0f; 
     
    80292        return x; 
    81293    } 
    82  
    83     /// clamp to [-1, 1] 
    84     static float clamp( float x ) { 
     294
     295 
     296/// clamp to [-1, 1] 
     297float clamp( float x ) 
     298out ( r ) { 
     299    version ( HACKED_CLAMP ) { 
     300        assert( ( r >= -1.0f ) && ( r <= 1.0f ) ); 
     301    } 
     302
     303body { 
     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&