source: trunk/src/core/random.cc @ 519

Last change on this file since 519 was 509, checked in by epyon, 9 years ago
  • random distributions
  • resource - rename/remove support
  • debug gizmo support
  • minor resource_manager upgrades
  • several minor changes
File size: 7.5 KB
Line 
1// Copyright (C) 2012-2014 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7#include "nv/core/random.hh"
8#include "nv/core/time.hh"
9#include "nv/stl/utility/common.hh"
10
11using namespace nv;
12
13static const uint32 mt_upper_mask = 0x80000000UL;
14static const uint32 mt_lower_mask = 0x7FFFFFFFUL;
15static const uint32 mt_full_mask  = 0xFFFFFFFFUL;
16static const uint32 mt_matrix_a   = 0x9908B0DFUL;
17
18#define NV_MT_MIXBITS(u, v) ( ( (u) & mt_upper_mask) | ( (v) & mt_lower_mask) )
19#define NV_MT_TWIST(u, v)  ( (NV_MT_MIXBITS(u, v) >> 1) ^ ( (v) & 1UL ? mt_matrix_a : 0UL) )
20
21nv::random& random::get()
22{
23        static random default_rng;
24        return default_rng;
25}
26
27void random_mersenne::mt_init( uint32 seed )
28{
29        m_state[0] = static_cast<uint32>( seed & mt_full_mask );
30        for ( uint32 i = 1; i < mersenne_n; i++ )
31        {
32                m_state[i]  = ( 1812433253UL * ( m_state[i - 1] ^ ( m_state[i - 1] >> 30 ) ) + i );
33                m_state[i] &= mt_full_mask;
34        }
35
36        m_remaining = 0;
37        m_next      = nullptr;
38        m_seeded    = 1;
39}
40
41
42void random_mersenne::mt_update()
43{
44        uint32 *p = m_state;
45
46        for ( int count = ( mersenne_n - mersenne_m + 1 ); --count; p++ )
47                *p = p[mersenne_m] ^ NV_MT_TWIST( p[0], p[1] );
48
49        for ( int count = mersenne_m; --count; p++ )
50                *p = p[mersenne_m - mersenne_n] ^ NV_MT_TWIST( p[0], p[1] );
51
52        *p = p[mersenne_m - mersenne_n] ^ NV_MT_TWIST( p[0], m_state[0] );
53
54        m_remaining = mersenne_n;
55        m_next      = m_state;
56}
57
58
59uint32 random_mersenne::mt_uint32()
60{
61        uint32 r;
62
63        if ( !m_remaining ) mt_update();
64
65        r = *m_next++;
66        m_remaining--;
67
68        r ^= ( r >> 11 );
69        r ^= ( r << 7 ) & 0x9D2C5680UL;
70        r ^= ( r << 15 ) & 0xEFC60000UL;
71        r ^= ( r >> 18 );
72
73        r &= mt_full_mask;
74
75        return r;
76}
77
78random_mersenne::random_mersenne( random_mersenne::seed_type seed /*= 0 */ )
79        : m_next( nullptr ), m_remaining( 0 ), m_seeded( 0 )
80{
81        mt_init( seed );
82}
83
84random_mersenne::seed_type random_mersenne::set_seed( random_mersenne::seed_type seed /*= 0 */ )
85{
86        mt_init( seed );
87        return seed;
88}
89
90random_mersenne::result_type random_mersenne::rand()
91{
92        return mt_uint32();
93}
94
95random_base::seed_type random_base::randomized_seed()
96{
97        // TODO: this seems off, as it might often seed the same, use general time
98        // instead
99        return narrow_cast< seed_type >( get_ticks() );
100}
101
102nv::vec2 nv::random_base::precise_unit_vec2()
103{
104        f32 angle = frand( math::pi<f32>() * 2.f );
105        return vec2( cos( angle ), sin( angle ) );
106}
107
108nv::vec3 nv::random_base::precise_unit_vec3()
109{
110        f32 cos_theta = frange( -1.0f, 1.0f );
111        f32 sin_theta = sqrt( 1.0f - cos_theta * cos_theta );
112        f32 phi       = frand( 2 * math::pi<f32>() );
113        return vec3(
114                sin_theta * sin(phi),
115                sin_theta * cos(phi),
116                cos_theta
117                );
118}
119
120nv::vec2 nv::random_base::fast_disk_point()
121{
122        f32 r1 = frand();
123        f32 r2 = frand();
124        if ( r1 > r2 ) swap( r1, r2 );
125        f32 rf = 2* math::pi<f32>()*(r1/r2);
126        return vec2( r2*cos( rf ), r2*sin( rf ) );
127}
128
129nv::vec2 nv::random_base::precise_disk_point()
130{
131        f32 r = sqrt( frand() );
132        f32 rangle = frand( math::pi<f32>() );
133        return vec2( r*cos( rangle ), r*sin( rangle ) );
134}
135
136nv::vec3 nv::random_base::fast_sphere_point()
137{
138        f32 rad     = frand();
139        f32 pi      = math::pi<f32>();
140        f32 phi     = asin( frange( -1.0f, 1.0f ) ) + pi*.5f;
141        f32 theta   = frange( 0.0f, 2 * math::pi<f32>() );
142        f32 sin_phi = sin( phi );
143        return vec3(
144                rad * cos(theta) * sin_phi,
145                rad * sin(theta) * sin_phi,
146                rad * cos(phi)
147        );
148}
149
150nv::vec3 nv::random_base::precise_sphere_point()
151{
152        f32 radius = pow( frand(), 1.f/3.f );
153        f32 cos_theta = frange( -1.0f, 1.0f );
154        f32 sin_theta = sqrt( 1.0f - cos_theta * cos_theta );
155        f32 phi       = frange( 0.0f, 2 * math::pi<f32>() );
156        return vec3(
157                radius * sin_theta * sin(phi),
158                radius * sin_theta * cos(phi),
159                radius * cos_theta
160                );
161}
162
163nv::vec2 nv::random_base::precise_ellipse_point( const vec2& radii )
164{
165        vec2 p = range( -radii, radii );
166        vec2 inv_radii  = 1.f / radii;
167        vec2 inv_radii2 = inv_radii * inv_radii;
168        for ( uint32 i = 0; i < 12; ++i )
169        {
170                if ( p.x * p.x * inv_radii2.x + p.y * p.y * inv_radii2.y <= 1.f )
171                {
172                        return p;
173                }
174        }
175        return fast_disk_point() * radii;
176}
177
178nv::vec3 nv::random_base::precise_ellipsoid_point( const vec3& radii )
179{
180        vec3 p = range( -radii, radii );
181        vec3 inv_radii  = 1.f / radii;
182        vec3 inv_radii2 = inv_radii * inv_radii;
183        for ( uint32 i = 0; i < 12; ++i )
184        {
185                if ( p.x * p.x * inv_radii2.x + p.y * p.y * inv_radii2.y + p.z * p.z * inv_radii2.z <= 1.f )
186                {
187                        return p;
188                }
189        }
190        return fast_sphere_point() * radii;
191}
192
193nv::vec2 nv::random_base::fast_hollow_disk_point( f32 iradius, f32 oradius )
194{
195        f32 idist2 = iradius * iradius;
196        f32 odist2 = oradius * oradius;
197        f32 rdist  = sqrt( frange( idist2, odist2 ) );
198        return rdist * precise_unit_vec2();
199}
200
201nv::vec2 nv::random_base::precise_hollow_disk_point( f32 iradius, f32 oradius )
202{
203        return fast_hollow_disk_point( iradius, oradius );
204}
205
206nv::vec3 nv::random_base::fast_hollow_sphere_point( f32 iradius, f32 oradius )
207{
208        f32 idist3 = iradius * iradius * iradius;
209        f32 odist3 = oradius * oradius * oradius;
210        f32 rdist  = pow( frange( idist3, odist3 ), 1.f/3.f );
211        return rdist * precise_unit_vec3();
212}
213
214nv::vec3 nv::random_base::precise_hollow_sphere_point( f32 iradius, f32 oradius )
215{
216        return fast_hollow_sphere_point( iradius, oradius );
217}
218
219
220nv::vec2 nv::random_base::fast_hollow_ellipse_point( const vec2& iradii, const vec2& oradii )
221{
222        vec2 iradii2 = iradii * iradii;
223        vec2 opoint     = ellipse_edge( oradii );
224        vec2 opoint2    = opoint * opoint;
225        vec2 odir       = math::normalize( opoint );
226        f32 odist2    = opoint2.x + opoint2.y;
227
228        f32 low    = iradii2.y * opoint2.x + iradii2.x * opoint2.y;
229        f32 idist2 = ((iradii2.x * iradii2.y) / low ) * odist2;
230
231        f32 rdist     = sqrt( frange( idist2, odist2 ) );
232        return odir * rdist;   
233}
234
235nv::vec2 nv::random_base::precise_hollow_ellipse_point( const vec2& iradii, const vec2& oradii )
236{
237        return fast_hollow_ellipse_point( iradii, oradii );
238}
239
240nv::vec3 nv::random_base::fast_hollow_ellipsoid_point( const vec3& iradii, const vec3& oradii )
241{
242        vec3 iradii2 = iradii * iradii;
243        vec3 opoint     = ellipsoid_edge( oradii );
244        vec3 opoint2    = opoint * opoint;
245        vec3 odir       = math::normalize( opoint );
246        f32 odist2    = opoint2.x + opoint2.y + opoint2.z;
247
248        f32 low    =
249                iradii2.y * iradii2.z * opoint2.x +
250                iradii2.x * iradii2.z * opoint2.y +
251                iradii2.x * iradii2.y * opoint2.z;
252        f32 idist2 = ((iradii2.x * iradii2.y * iradii2.z) / low ) * odist2;
253
254        f32 odist3 = odist2 * sqrt( odist2 );
255        f32 idist3 = idist2 * sqrt( idist2 );
256
257        f32 rdist     = pow( frange( idist3, odist3 ), 1.f/3.f );
258        return odir * rdist;   
259}
260
261nv::vec3 nv::random_base::precise_hollow_ellipsoid_point( const vec3& iradii, const vec3& oradii )
262{
263        return fast_hollow_ellipsoid_point( iradii, oradii );
264}
265
266nv::random_xor128::random_xor128( seed_type seed /*= randomized_seed() */ )
267{
268        set_seed( seed );
269}
270
271nv::random_base::seed_type nv::random_xor128::set_seed( seed_type seed /*= 0 */ )
272{
273        if ( seed == 0 ) seed = randomized_seed();
274        uint32 s = uint32( 4294967296 - seed );
275        m_state[0] = 123456789 * s;
276        m_state[1] = 362436069 * s;
277        m_state[2] = 521288629 * s;
278        m_state[3] = 88675123 * s;
279        return seed;
280}
281
282nv::random_base::result_type nv::random_xor128::rand()
283{
284        uint32 t = m_state[0];
285        t ^= t << 11;
286        t ^= t >> 8;
287        m_state[0] = m_state[1]; m_state[1] = m_state[2]; m_state[2] = m_state[3];
288        m_state[3] ^= m_state[3] >> 19;
289        m_state[3] ^= t;
290        return m_state[3];
291}
Note: See TracBrowser for help on using the repository browser.