code cleanup: give rng functions BLI prefix.
[blender.git] / source / blender / blenlib / intern / rand.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/blenlib/intern/rand.c
29  *  \ingroup bli
30  */
31
32
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "PIL_time.h"
39
40 #include "BLI_threads.h"
41 #include "BLI_rand.h"
42
43 #ifdef _MSC_VER
44 typedef unsigned __int64 r_uint64;
45
46 #define MULTIPLIER  0x5DEECE66Di64
47 #define MASK        0x0000FFFFFFFFFFFFi64
48 #else
49 typedef unsigned long long r_uint64;
50
51 #define MULTIPLIER  0x5DEECE66Dll
52 #define MASK        0x0000FFFFFFFFFFFFll
53 #endif
54
55 #define ADDEND      0xB
56
57 #define LOWSEED     0x330E
58
59 extern unsigned char hash[];    // noise.c
60
61 /***/
62
63 struct RNG {
64         r_uint64 X;
65 };
66
67 RNG *BLI_rng_new(unsigned int seed)
68 {
69         RNG *rng = MEM_mallocN(sizeof(*rng), "rng");
70
71         BLI_rng_seed(rng, seed);
72
73         return rng;
74 }
75
76 void BLI_rng_free(RNG *rng)
77 {
78         MEM_freeN(rng);
79 }
80
81 void BLI_rng_seed(RNG *rng, unsigned int seed)
82 {
83         rng->X = (((r_uint64) seed) << 16) | LOWSEED;
84 }
85
86 void BLI_rng_srandom(RNG *rng, unsigned int seed)
87 {
88         BLI_rng_seed(rng, seed + hash[seed & 255]);
89         seed = BLI_rng_get_int(rng);
90         BLI_rng_seed(rng, seed + hash[seed & 255]);
91         seed = BLI_rng_get_int(rng);
92         BLI_rng_seed(rng, seed + hash[seed & 255]);
93 }
94
95 int BLI_rng_get_int(RNG *rng)
96 {
97         rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK;
98         return (int) (rng->X >> 17);
99 }
100
101 double BLI_rng_get_double(RNG *rng)
102 {
103         return (double) BLI_rng_get_int(rng) / 0x80000000;
104 }
105
106 float BLI_rng_get_float(RNG *rng)
107 {
108         return (float) BLI_rng_get_int(rng) / 0x80000000;
109 }
110
111 void BLI_rng_shuffle_array(RNG *rng, void *data, int elemSize, int numElems)
112 {
113         int i = numElems;
114         void *temp;
115
116         if (numElems <= 0) {
117                 return;
118         }
119
120         temp = malloc(elemSize);
121
122         /* XXX Shouldn't it rather be "while (i--) {" ?
123          *     Else we have no guaranty first (0) element has a chance to be shuffled... --mont29 */
124         while (--i) {
125                 int j = BLI_rng_get_int(rng) % numElems;
126                 if (i != j) {
127                         void *iElem = (unsigned char *)data + i * elemSize;
128                         void *jElem = (unsigned char *)data + j * elemSize;
129                         memcpy(temp, iElem, elemSize);
130                         memcpy(iElem, jElem, elemSize);
131                         memcpy(jElem, temp, elemSize);
132                 }
133         }
134
135         free(temp);
136 }
137
138 void BLI_rng_skip(RNG *rng, int n)
139 {
140         int i;
141
142         for (i = 0; i < n; i++)
143                 BLI_rng_get_int(rng);
144 }
145
146 /***/
147
148 static RNG theBLI_rng = {0};
149
150 /* note, this one creates periodical patterns */
151 void BLI_srand(unsigned int seed)
152 {
153         BLI_rng_seed(&theBLI_rng, seed);
154 }
155
156 /* using hash table to create better seed */
157 void BLI_srandom(unsigned int seed)
158 {
159         BLI_rng_srandom(&theBLI_rng, seed);
160 }
161
162 int BLI_rand(void)
163 {
164         return BLI_rng_get_int(&theBLI_rng);
165 }
166
167 double BLI_drand(void)
168 {
169         return BLI_rng_get_double(&theBLI_rng);
170 }
171
172 float BLI_frand(void)
173 {
174         return BLI_rng_get_float(&theBLI_rng);
175 }
176
177 void BLI_fillrand(void *addr, int len)
178 {
179         RNG rng;
180         unsigned char *p = addr;
181
182         BLI_rng_seed(&rng, (unsigned int) (PIL_check_seconds_timer() * 0x7FFFFFFF));
183         while (len--) *p++ = BLI_rng_get_int(&rng) & 0xFF;
184 }
185
186 void BLI_array_randomize(void *data, int elemSize, int numElems, unsigned int seed)
187 {
188         RNG rng;
189
190         BLI_rng_seed(&rng, seed);
191         BLI_rng_shuffle_array(&rng, data, elemSize, numElems);
192 }
193
194 /* ********* for threaded random ************** */
195
196 static RNG rng_tab[BLENDER_MAX_THREADS];
197
198 void BLI_thread_srandom(int thread, unsigned int seed)
199 {
200         if (thread >= BLENDER_MAX_THREADS)
201                 thread = 0;
202         
203         BLI_rng_seed(&rng_tab[thread], seed + hash[seed & 255]);
204         seed = BLI_rng_get_int(&rng_tab[thread]);
205         BLI_rng_seed(&rng_tab[thread], seed + hash[seed & 255]);
206         seed = BLI_rng_get_int(&rng_tab[thread]);
207         BLI_rng_seed(&rng_tab[thread], seed + hash[seed & 255]);
208 }
209
210 int BLI_thread_rand(int thread)
211 {
212         return BLI_rng_get_int(&rng_tab[thread]);
213 }
214
215 float BLI_thread_frand(int thread)
216 {
217         return BLI_rng_get_float(&rng_tab[thread]);
218 }
219