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 |
|
---|
11 | using namespace nv;
|
---|
12 |
|
---|
13 | static const uint32 mt_upper_mask = 0x80000000UL;
|
---|
14 | static const uint32 mt_lower_mask = 0x7FFFFFFFUL;
|
---|
15 | static const uint32 mt_full_mask = 0xFFFFFFFFUL;
|
---|
16 | static 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 |
|
---|
21 | nv::random& random::get()
|
---|
22 | {
|
---|
23 | static random default_rng;
|
---|
24 | return default_rng;
|
---|
25 | }
|
---|
26 |
|
---|
27 | void 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 |
|
---|
42 | void 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 |
|
---|
59 | uint32 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 |
|
---|
78 | random_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 |
|
---|
84 | random_mersenne::seed_type random_mersenne::set_seed( random_mersenne::seed_type seed /*= 0 */ )
|
---|
85 | {
|
---|
86 | mt_init( seed );
|
---|
87 | return seed;
|
---|
88 | }
|
---|
89 |
|
---|
90 | random_mersenne::result_type random_mersenne::rand()
|
---|
91 | {
|
---|
92 | return mt_uint32();
|
---|
93 | }
|
---|
94 |
|
---|
95 | random_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 |
|
---|
102 | nv::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 |
|
---|
108 | nv::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 |
|
---|
120 | nv::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 |
|
---|
129 | nv::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 |
|
---|
136 | nv::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 |
|
---|
150 | nv::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 |
|
---|
163 | nv::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 |
|
---|
178 | nv::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 |
|
---|
193 | nv::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 |
|
---|
201 | nv::vec2 nv::random_base::precise_hollow_disk_point( f32 iradius, f32 oradius )
|
---|
202 | {
|
---|
203 | return fast_hollow_disk_point( iradius, oradius );
|
---|
204 | }
|
---|
205 |
|
---|
206 | nv::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 |
|
---|
214 | nv::vec3 nv::random_base::precise_hollow_sphere_point( f32 iradius, f32 oradius )
|
---|
215 | {
|
---|
216 | return fast_hollow_sphere_point( iradius, oradius );
|
---|
217 | }
|
---|
218 |
|
---|
219 |
|
---|
220 | nv::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 |
|
---|
235 | nv::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 |
|
---|
240 | nv::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 |
|
---|
261 | nv::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 |
|
---|
266 | nv::random_xor128::random_xor128( seed_type seed /*= randomized_seed() */ )
|
---|
267 | {
|
---|
268 | set_seed( seed );
|
---|
269 | }
|
---|
270 |
|
---|
271 | nv::random_base::seed_type nv::random_xor128::set_seed( seed_type seed /*= 0 */ )
|
---|
272 | {
|
---|
273 | uint32 s = uint32( 4294967296 - seed );
|
---|
274 | m_state[0] = 123456789 * s;
|
---|
275 | m_state[1] = 362436069 * s;
|
---|
276 | m_state[2] = 521288629 * s;
|
---|
277 | m_state[3] = 88675123 * s;
|
---|
278 | return seed;
|
---|
279 | }
|
---|
280 |
|
---|
281 | nv::random_base::result_type nv::random_xor128::rand()
|
---|
282 | {
|
---|
283 | uint32 t = m_state[0];
|
---|
284 | t ^= t << 11;
|
---|
285 | t ^= t >> 8;
|
---|
286 | m_state[0] = m_state[1]; m_state[1] = m_state[2]; m_state[2] = m_state[3];
|
---|
287 | m_state[3] ^= m_state[3] >> 19;
|
---|
288 | m_state[3] ^= t;
|
---|
289 | return m_state[3];
|
---|
290 | }
|
---|