perlin 0.1.0pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }