perlin 0.1.0pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,160 @@
1
+ #include "classic.h"
2
+
3
+ long seed = 0; // Speeds up lookup of this value when it is accessed a LOT. PROBABLY NOT THREAD SAFE!
4
+
5
+ static inline float perlin_interpolate(const float a, const float b, const float x)
6
+ {
7
+ const float ft = x * M_PI;
8
+ const float f = (1 - cos(ft)) * 0.5;
9
+ return a * (1 - f) + b * f;
10
+ }
11
+
12
+
13
+ // 2D ------------------------------------------------------------------
14
+
15
+ static inline float perlin_noise_2d(const int x, const int y)
16
+ {
17
+ long n = x + y * 57;
18
+ n = (n << 13) ^ n;
19
+ return (1.0 - ((n * (n * n * 15731*seed + 789221*seed) + 1376312589*seed) & 0x7fffffff) / 1073741824.0);
20
+ }
21
+
22
+ static float perlin_smooth_noise_2d(const int x, const int y)
23
+ {
24
+ const float corners = (
25
+ perlin_noise_2d(x - 1, y - 1) +
26
+ perlin_noise_2d(x + 1, y - 1) +
27
+ perlin_noise_2d(x - 1, y + 1) +
28
+ perlin_noise_2d(x + 1, y + 1)
29
+ ) / 4;
30
+ const float sides = (
31
+ perlin_noise_2d(x - 1, y) +
32
+ perlin_noise_2d(x + 1, y) +
33
+ perlin_noise_2d(x, y - 1) +
34
+ perlin_noise_2d(x, y + 1)
35
+ ) / 4;
36
+ const float center = perlin_noise_2d(x, y) / 4;
37
+ return corners + sides + center;
38
+ }
39
+
40
+ float perlin_interpolated_noise_2d(const float x, const float y)
41
+ {
42
+ const int integer_X = (int)x;
43
+ const float fractional_X = x - integer_X;
44
+
45
+ const int integer_Y = (int)y;
46
+ const float fractional_Y = y - integer_Y;
47
+
48
+ const float v1 = perlin_smooth_noise_2d(integer_X, integer_Y);
49
+ const float v2 = perlin_smooth_noise_2d(integer_X + 1, integer_Y);
50
+ const float v3 = perlin_smooth_noise_2d(integer_X, integer_Y + 1);
51
+ const float v4 = perlin_smooth_noise_2d(integer_X + 1, integer_Y + 1);
52
+
53
+ const float i1 = perlin_interpolate(v1, v2, fractional_X);
54
+ const float i2 = perlin_interpolate(v3, v4, fractional_X);
55
+
56
+ return perlin_interpolate(i1, i2, fractional_Y);
57
+ }
58
+
59
+ float perlin_octaves_2d(const float x, const float y, const float p, const float n)
60
+ {
61
+ float total = 0.;
62
+ float frequency = 1., amplitude = 1.;
63
+ int i;
64
+
65
+ for (i = 0; i < n; ++i)
66
+ {
67
+ total += perlin_interpolated_noise_2d(x * frequency, y * frequency) * amplitude;
68
+ frequency *= 2;
69
+ amplitude *= p;
70
+ }
71
+
72
+ return total;
73
+ }
74
+
75
+ // 3D ------------------------------------------------------------------
76
+
77
+ static inline float perlin_noise_3d(const int x, const int y, const int z)
78
+ {
79
+ long n = x + y + z * 57;
80
+ n = (n << 13) ^ n;
81
+ return (1.0 - ((n * (n * n * 15731*seed + 789221*seed) + 1376312589*seed) & 0x7fffffff) / 1073741824.0);
82
+ }
83
+
84
+ static float perlin_smooth_noise_3d(const int x, const int y, const int z)
85
+ {
86
+ const float corners = (
87
+ perlin_noise_3d(x - 1, y - 1, z + 1) +
88
+ perlin_noise_3d(x + 1, y - 1, z + 1) +
89
+ perlin_noise_3d(x - 1, y + 1, z + 1) +
90
+ perlin_noise_3d(x + 1, y + 1, z + 1) +
91
+ perlin_noise_3d(x - 1, y - 1, z - 1) +
92
+ perlin_noise_3d(x + 1, y - 1, z - 1) +
93
+ perlin_noise_3d(x - 1, y + 1, z - 1) +
94
+ perlin_noise_3d(x + 1, y + 1, z - 1)
95
+ ) / 16;
96
+ const float sides = (
97
+ perlin_noise_3d(x - 1, y, z + 1) +
98
+ perlin_noise_3d(x + 1, y, z + 1) +
99
+ perlin_noise_3d(x, y - 1, z + 1) +
100
+ perlin_noise_3d(x, y + 1, z + 1) +
101
+ perlin_noise_3d(x - 1, y, z - 1) +
102
+ perlin_noise_3d(x + 1, y, z - 1) +
103
+ perlin_noise_3d(x, y - 1, z - 1) +
104
+ perlin_noise_3d(x, y + 1, z - 1) +
105
+ perlin_noise_3d(x - 1, y - 1, z) +
106
+ perlin_noise_3d(x + 1, y - 1, z) +
107
+ perlin_noise_3d(x + 1, y + 1, z) +
108
+ perlin_noise_3d(x - 1, y + 1, z)
109
+ ) / 8;
110
+ const float center = perlin_noise_2d(x, y) / 12;
111
+ return corners + sides + center;
112
+ }
113
+
114
+ float perlin_interpolated_noise_3d(const float x, const float y, const float z)
115
+ {
116
+ const int integer_X = (int)x;
117
+ const float fractional_X = x - integer_X;
118
+
119
+ const int integer_Y = (int)y;
120
+ const float fractional_Y = y - integer_Y;
121
+
122
+ const int integer_Z = (int)z;
123
+ const float fractional_Z = z - integer_Z;
124
+
125
+ const float a = perlin_smooth_noise_3d(integer_X, integer_Y, integer_Z);
126
+ const float b = perlin_smooth_noise_3d(integer_X + 1, integer_Y, integer_Z);
127
+ const float c = perlin_smooth_noise_3d(integer_X, integer_Y + 1, integer_Z);
128
+ const float d = perlin_smooth_noise_3d(integer_X, integer_Y, integer_Z + 1);
129
+ const float e = perlin_smooth_noise_3d(integer_X + 1, integer_Y + 1, integer_Z);
130
+ const float f = perlin_smooth_noise_3d(integer_X, integer_Y + 1, integer_Z + 1);
131
+ const float g = perlin_smooth_noise_3d(integer_X + 1, integer_Y, integer_Z + 1);
132
+ const float h = perlin_smooth_noise_3d(integer_X + 1, integer_Y + 1, integer_Z + 1);
133
+
134
+ const float i1 = perlin_interpolate(a, b, fractional_X);
135
+ const float i2 = perlin_interpolate(c, d, fractional_X);
136
+ const float i3 = perlin_interpolate(e, f, fractional_X);
137
+ const float i4 = perlin_interpolate(g, h, fractional_X);
138
+
139
+ const float y1 = perlin_interpolate(i1, i2, fractional_Y);
140
+ const float y2 = perlin_interpolate(i3, i4, fractional_Y);
141
+
142
+ return perlin_interpolate(y1, y2, fractional_Z);
143
+ }
144
+
145
+ float perlin_octaves_3d(const float x, const float y, const float z, const float p, const float n)
146
+ {
147
+ float total = 0.;
148
+ float frequency = 1., amplitude = 1.;
149
+ int i;
150
+
151
+ for (i = 0; i < n; ++i)
152
+ {
153
+ total += perlin_interpolated_noise_3d(x * frequency, y * frequency, z * frequency) * amplitude;
154
+ frequency *= 2;
155
+ amplitude *= p;
156
+ }
157
+
158
+ return total;
159
+ }
160
+
@@ -0,0 +1,24 @@
1
+ /*
2
+ * "Classic" Perlin noise generation.
3
+ */
4
+
5
+ #ifndef CLASSIC_H
6
+ #define CLASSIC_H
7
+
8
+ #include <math.h>
9
+
10
+ extern long seed;
11
+
12
+ static inline float perlin_interpolate(const float a, const float b, const float x);
13
+
14
+ static inline float perlin_noise_2d(const int x, const int y);
15
+ static float perlin_smooth_noise_2d(const int x, const int y);
16
+ float perlin_interpolated_noise_2d(const float x, const float y);
17
+ float perlin_octaves_2d(const float x, const float y, const float p, const float n);
18
+
19
+ static inline float perlin_noise_3d(const int x, const int y, const int z);
20
+ static float perlin_smooth_noise_3d(const int x, const int y, const int z);
21
+ float perlin_interpolated_noise_3d(const float x, const float y, const float z);
22
+ float perlin_octaves_3d(const float x, const float y, const float z, const float p, const float n);
23
+
24
+ #endif // CLASSIC_H
@@ -0,0 +1,15 @@
1
+ require 'mkmf'
2
+
3
+ RUBY_VERSION =~ /(\d+.\d+)/
4
+ extension_name = "perlin/#{$1}/perlin"
5
+
6
+ dir_config(extension_name)
7
+
8
+ # 1.9 compatibility
9
+ $CFLAGS += ' -DRUBY_19' if RUBY_VERSION =~ /^1.9/
10
+
11
+ # let's use c99
12
+ #$CFLAGS += " -std=c99"
13
+ $CFLAGS += " -std=gnu99"
14
+
15
+ create_makefile(extension_name)
@@ -0,0 +1,292 @@
1
+ #include "generator.h"
2
+
3
+ VALUE Perlin_Generator_set_seed(const VALUE self, const VALUE seed)
4
+ {
5
+ rb_iv_set(self, "@seed", rb_funcall(seed, rb_intern("to_i"), 0));
6
+ }
7
+
8
+ VALUE Perlin_Generator_set_persistence(const VALUE self, const VALUE persistence)
9
+ {
10
+ rb_iv_set(self, "@persistence", rb_funcall(persistence, rb_intern("to_f"), 0));
11
+ }
12
+
13
+ VALUE Perlin_Generator_set_octave(const VALUE self, const VALUE octave)
14
+ {
15
+ rb_iv_set(self, "@octave", rb_funcall(octave, rb_intern("to_i"), 0));
16
+ }
17
+
18
+ VALUE Perlin_Generator_set_classic(const VALUE self, const VALUE classic)
19
+ {
20
+ rb_iv_set(self, "@classic", classic);
21
+ }
22
+
23
+ // x, y
24
+ // x, y, z
25
+ VALUE Perlin_Generator_run(const int argc, const VALUE *argv, const VALUE self)
26
+ {
27
+ VALUE x, y, z;
28
+
29
+ rb_scan_args(argc, argv, "21", &x, &y, &z);
30
+
31
+ switch(argc)
32
+ {
33
+ case 2:
34
+ Perlin_Generator_run2d(self, x, y);
35
+ break;
36
+
37
+ case 3:
38
+ Perlin_Generator_run3d(self, x, y, z);
39
+ break;
40
+
41
+ default:
42
+ rb_raise(rb_eArgError, "%d parameters not supported (2D and 3D are)", argc);
43
+ }
44
+ }
45
+
46
+ /*
47
+ Takes points (x, y) and returns a height (n)
48
+ */
49
+ VALUE Perlin_Generator_run2d(const VALUE self, const VALUE x, const VALUE y)
50
+ {
51
+ const float p = RFLOAT_VALUE(rb_iv_get(self, "@persistence"));
52
+ const int n = NUM2INT(rb_iv_get(self, "@octave"));
53
+ const VALUE classic = rb_iv_get(self, "@classic");
54
+
55
+ seed = NUM2LONG(rb_iv_get(self, "@seed")); // Store in global, for speed.
56
+
57
+ if(RTEST(classic))
58
+ {
59
+ return rb_float_new(perlin_octaves_2d(NUM2DBL(x), NUM2DBL(y), p, n));
60
+ }
61
+ else
62
+ {
63
+ return rb_float_new(octave_noise_3d(n, p, 1.0, NUM2DBL(x), NUM2DBL(y), seed * SEED_OFFSET));
64
+ }
65
+ }
66
+
67
+ /*
68
+ Takes points (x, y, z) and returns a height (n)
69
+ */
70
+ VALUE Perlin_Generator_run3d(const VALUE self, const VALUE x, const VALUE y, const VALUE z)
71
+ {
72
+ const float p = RFLOAT_VALUE(rb_iv_get(self, "@persistence"));
73
+ const int n = NUM2INT(rb_iv_get(self, "@octave"));
74
+ const VALUE classic = rb_iv_get(self, "@classic");
75
+
76
+ seed = NUM2LONG(rb_iv_get(self, "@seed")); // Store in global, for speed.
77
+
78
+ if(RTEST(classic))
79
+ {
80
+ return rb_float_new(perlin_octaves_3d(NUM2DBL(x), NUM2DBL(y), NUM2DBL(z), p, n));
81
+ }
82
+ else
83
+ {
84
+ return rb_float_new(octave_noise_4d(n, p, 1.0, NUM2DBL(x), NUM2DBL(y), NUM2DBL(z), seed * SEED_OFFSET));
85
+ }
86
+
87
+ }
88
+
89
+ // x, y steps_x, steps_y, interval
90
+ // x, y, z, steps_x, steps_y, steps_z, interval
91
+ VALUE Perlin_Generator_chunk(const int argc, const VALUE *argv, const VALUE self)
92
+ {
93
+ VALUE a, b, c, d, e, f, g;
94
+
95
+ rb_scan_args(argc, argv, "52", &a, &b, &c, &d, &e, &f, &g);
96
+
97
+ switch(argc)
98
+ {
99
+ case 5:
100
+ Perlin_Generator_chunk2d(self, a, b, c, d, e);
101
+ break;
102
+
103
+ case 7:
104
+ Perlin_Generator_chunk3d(self, a, b, c, d, e, f, g);
105
+ break;
106
+
107
+ default:
108
+ rb_raise(rb_eArgError, "%d parameters not supported (5 for 2D and 7 for 3D are)", argc);
109
+ }
110
+ }
111
+
112
+ /*
113
+ Returns a chunk of coordinates starting from x, y and of size steps_x, steps_y with interval.
114
+ */
115
+ VALUE Perlin_Generator_chunk2d(const VALUE self, const VALUE x, const VALUE y, const VALUE steps_x, const VALUE steps_y, const VALUE interval)
116
+ {
117
+ const float p = RFLOAT_VALUE(rb_iv_get(self, "@persistence"));
118
+ const int n = NUM2INT(rb_iv_get(self, "@octave"));
119
+ const int is_classic = RTEST(rb_iv_get(self, "@classic"));
120
+
121
+ VALUE arr, row;
122
+ int i, j;
123
+
124
+ const float x_min = NUM2DBL(x), y_min = NUM2DBL(y);
125
+ float _x, _y;
126
+ const int _steps_x = NUM2INT(steps_x), _steps_y = NUM2INT(steps_y);
127
+ const float _interval = NUM2DBL(interval);
128
+
129
+ if(_steps_x < 1 || _steps_y < 1)
130
+ {
131
+ rb_raise(rb_eArgError, "steps must be >= 1");
132
+ }
133
+
134
+ seed = NUM2LONG(rb_iv_get(self, "@seed")); // Store in global, for speed.
135
+
136
+ if(rb_block_given_p())
137
+ {
138
+ // Iterate through x, then y [0, 0], [1, 0], [2, 0]...
139
+ _x = x_min;
140
+ for (i = 0; i < _steps_x; i++)
141
+ {
142
+ _y = y_min;
143
+ for (j = 0; j < _steps_y; j++)
144
+ {
145
+ if(is_classic)
146
+ {
147
+ rb_yield_values(3, rb_float_new(perlin_octaves_2d(_x, _y, p, n)),
148
+ rb_float_new(_x), rb_float_new(_y));
149
+ }
150
+ else
151
+ {
152
+ rb_yield_values(3, rb_float_new(octave_noise_3d(n, p, 1.0, _x, _y, seed * SEED_OFFSET)),
153
+ rb_float_new(_x), rb_float_new(_y));
154
+ }
155
+
156
+ _y += _interval;
157
+ }
158
+ _x += _interval;
159
+ }
160
+
161
+ return Qnil;
162
+ }
163
+ else
164
+ {
165
+ // 2D array can be indexed with arr[x][y]
166
+ arr = rb_ary_new();
167
+ _x = x_min;
168
+ for (i = 0; i < _steps_x; i++)
169
+ {
170
+ row = rb_ary_new();
171
+ _y = y_min;
172
+ for (j = 0; j < _steps_y; j++)
173
+ {
174
+ if(is_classic)
175
+ {
176
+ rb_ary_push(row, rb_float_new(perlin_octaves_2d(_x, _y, p, n)));
177
+ }
178
+ else
179
+ {
180
+ rb_ary_push(row, rb_float_new(octave_noise_3d(n, p, 1.0, _x, _y, seed * SEED_OFFSET)));
181
+ }
182
+
183
+ _y += _interval;
184
+ }
185
+ rb_ary_push(arr, row);
186
+ _x += _interval;
187
+ }
188
+ return arr;
189
+ }
190
+ }
191
+
192
+ /*
193
+ Returns a chunk of coordinates starting from x, y, z and of size steps_x, steps_y, size_z with interval.
194
+ */
195
+ VALUE Perlin_Generator_chunk3d(const VALUE self, const VALUE x, const VALUE y, const VALUE z, const VALUE steps_x, const VALUE steps_y, const VALUE steps_z, const VALUE interval)
196
+ {
197
+ const float p = RFLOAT_VALUE(rb_iv_get(self, "@persistence"));
198
+ const int n = NUM2INT(rb_iv_get(self, "@octave"));
199
+ const int is_classic = RTEST(rb_iv_get(self, "@classic"));
200
+
201
+ VALUE arr, row, column;
202
+ int i, j, k;
203
+
204
+ const float x_min = NUM2DBL(x), y_min = NUM2DBL(y), z_min = NUM2DBL(z);
205
+ float _x, _y, _z;
206
+ const int _steps_x = NUM2INT(steps_x), _steps_y = NUM2INT(steps_y), _steps_z = NUM2INT(steps_z);
207
+ const float _interval = NUM2DBL(interval);
208
+
209
+ if(_steps_x < 1 || _steps_y < 1 || _steps_z < 1)
210
+ {
211
+ rb_raise(rb_eArgError, "steps must be >= 1");
212
+ }
213
+
214
+ seed = NUM2LONG(rb_iv_get(self, "@seed")); // Store in global, for speed.
215
+
216
+ if(rb_block_given_p())
217
+ {
218
+ _x = x_min;
219
+ for (i = 0; i < _steps_x; i++)
220
+ {
221
+ _y = y_min;
222
+ for (j = 0; j < _steps_y; j++)
223
+ {
224
+ _z = z_min;
225
+ for (k = 0; k < _steps_z; k++)
226
+ {
227
+ if(is_classic)
228
+ {
229
+ rb_yield_values(4, rb_float_new(perlin_octaves_3d(_x, _y, _z, p, n)),
230
+ rb_float_new(_x), rb_float_new(_y), rb_float_new(_z));
231
+ }
232
+ else
233
+ {
234
+ rb_yield_values(4, rb_float_new(octave_noise_4d(n, p, 1.0, _x, _y, _z, seed * SEED_OFFSET)),
235
+ rb_float_new(_x), rb_float_new(_y), rb_float_new(_z));
236
+ }
237
+
238
+ _z += _interval;
239
+ }
240
+ _y += _interval;
241
+ }
242
+ _x += _interval;
243
+ }
244
+ return Qnil;
245
+ }
246
+ else
247
+ {
248
+ arr = rb_ary_new();
249
+ _x = x_min;
250
+ for (i = 0; i < _steps_x; i++)
251
+ {
252
+ row = rb_ary_new();
253
+ _y = y_min;
254
+ for (j = 0; j < _steps_y; j++)
255
+ {
256
+ column = rb_ary_new();
257
+ _z = z_min;
258
+ for (k = 0; k < _steps_z; k++)
259
+ {
260
+ if(is_classic)
261
+ {
262
+ rb_ary_push(column, rb_float_new(perlin_octaves_3d(_x, _y, _z, p, n)));
263
+ }
264
+ else
265
+ {
266
+ rb_ary_push(column, rb_float_new(octave_noise_4d(n, p, 1.0, _x, _y, _z, seed * SEED_OFFSET)));
267
+ }
268
+
269
+ _z += _interval;
270
+ }
271
+ rb_ary_push(row, column);
272
+ _y += _interval;
273
+ }
274
+ rb_ary_push(arr, row);
275
+ _x += _interval;
276
+ }
277
+ return arr;
278
+ }
279
+ }
280
+
281
+ /*
282
+ The main initialize function which receives the inputs persistence and octave.
283
+ */
284
+ VALUE Perlin_Generator_init(VALUE self, VALUE seed, VALUE persistence, VALUE octave, VALUE classic)
285
+ {
286
+ Perlin_Generator_set_seed(self, seed);
287
+ Perlin_Generator_set_persistence(self, persistence);
288
+ Perlin_Generator_set_octave(self, octave);
289
+ Perlin_Generator_set_classic(self, classic);
290
+
291
+ return self;
292
+ }