perlin 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,4 +1,13 @@
1
- 0.1.0
1
+ 0.2.0
2
+ -----
3
+
4
+ * Optimised C code to avoid use of slow Ruby ivars (up to 50% time reduction!).
5
+ * Added Perlin::Generator#simplex?
6
+ * Added checks for valid values given for Perlin::Generator#octave= and Perlin::Generator#seed= (both must >= 1).
7
+ * Added visualization example/tool using Gosu (which is usable in Ruby 1.8 and 1.9, unlike the old FXRuby/OpenGL example).
8
+ * FIXED: artifacts introduced into Simplex noise as seed value increases.
9
+
10
+ 0.1.1
2
11
  -----
3
12
 
4
13
  * Converted to gem (previously was just a .c file).
@@ -0,0 +1,101 @@
1
+ require 'rubygems'
2
+ require 'texplay'
3
+ require 'fidgit'
4
+ require 'perlin'
5
+
6
+ include Gosu
7
+
8
+ class Visualizer < Chingu::Window
9
+ def initialize
10
+ super 800, 600, false, 0.1
11
+ self.caption = "Perlin Visualizer"
12
+ enable_undocumented_retrofication
13
+ push_game_state Visualize
14
+ end
15
+ end
16
+
17
+ class Visualize < Fidgit::GuiState
18
+ SLIDER_WIDTH = 180
19
+ IMAGE_WIDTH = 74
20
+ IMAGE_SCALE = 8
21
+
22
+ def initialize
23
+ super
24
+
25
+ @image = TexPlay.create_image $window, IMAGE_WIDTH, IMAGE_WIDTH, :color => :red
26
+ @noise = Perlin::Generator.new 1, 0, 1
27
+
28
+ horizontal do
29
+ image_frame @image, :factor => IMAGE_SCALE
30
+
31
+ vertical do
32
+ vertical do
33
+ @seed_label = label ""
34
+ @seed_slider = slider :range => 1..10000, :width => SLIDER_WIDTH, :tip => "Perlin::Generator#seed" do |_, value|
35
+ @seed_label.text = "Seed = #{value}"
36
+ @noise.seed = value
37
+ update_image
38
+ end
39
+ end
40
+
41
+ vertical do
42
+ @persistence_label = label ""
43
+ @persistence_slider = slider :range => 0.0..1.0, :width => SLIDER_WIDTH, :tip => "Perlin::Generator#persistence" do |_, value|
44
+ @persistence_label.text = "Persist = #{"%.2f" % value}"
45
+ @noise.persistence = value
46
+ update_image
47
+ end
48
+ end
49
+
50
+ vertical do
51
+ @octave_label = label ""
52
+ @octave_slider = slider :range => 1..10, :width => SLIDER_WIDTH, :tip => "Perlin::Generator#octave" do |_, value|
53
+ @octave_label.text = "Octave = #{value}"
54
+ @noise.octave = value
55
+ update_image
56
+ end
57
+ end
58
+
59
+ vertical :padding_top => 32 do
60
+ @classic_button = toggle_button "Classic noise?" do |_, value|
61
+ @noise.classic = value
62
+ update_image
63
+ end
64
+ end
65
+
66
+ vertical :padding_top => 64 do
67
+ @step_label = label ""
68
+ @step_slider = slider :range => 0.01..1.0, :width => SLIDER_WIDTH, value: 0.1, :tip => "Step between points (pixels) in chunk" do |_, value|
69
+ @step_label.text = "Step = #{"%.2f" % value}"
70
+ @width_label.text = "Width = #{"%.2f" % (value * IMAGE_WIDTH)}"
71
+ update_image
72
+ end
73
+
74
+ @width_label = label "", :tip => "Width of visualized area in window"
75
+ end
76
+
77
+ # Initial values, so we get the correct details.
78
+ @seed_slider.value = 0
79
+ @persistence_slider.value = 0
80
+ @octave_slider.value = 0
81
+ @step_slider.value = 0.1
82
+ end
83
+ end
84
+
85
+ update_image
86
+ end
87
+
88
+ def update_image
89
+ step = @step_slider.value
90
+ width = @image.width
91
+
92
+ @noise.chunk 0, 0, width, width, step do |n, x, y|
93
+ intensity = (n + 1) * 0.5
94
+ @image.set_pixel x.fdiv(step).round, y.fdiv(step).round, :color => [intensity, intensity, intensity], :sync_mode => :no_sync
95
+ end
96
+
97
+ @image.force_sync [0, 0, width, width]
98
+ end
99
+ end
100
+
101
+ Visualizer.new.show
@@ -1,6 +1,17 @@
1
- require 'perlin'
1
+ # WARNING:
2
+ # This code WILL NOT work with Ruby 1.9, since FXRuby/OpenGL are not compatible with the newer Ruby version.
3
+ # Since gem/bundler can't be persuaded to only require gems based on Ruby version, you'll have to manage the gems
4
+ # yourself.
5
+ #
6
+ # Requiring 'fox16' actually uses the 'fxruby' gem, which is no longer supported.
7
+ #
8
+ # Requiring 'opengl' actually uses the 'ruby-opengl' gem, not the 'opengl' gem (they are only compatible with Ruby 1.8
9
+ # and Ruby 1.9, respectively).
10
+
2
11
  require 'rubygems'
12
+ require 'perlin'
3
13
  require 'fox16'
14
+ require 'opengl'
4
15
 
5
16
  # Base framework borrowed from: http://www.fxruby.org/examples/gltest.rb
6
17
 
@@ -2,24 +2,7 @@
2
2
 
3
3
  long seed = 0; // Speeds up lookup of this value when it is accessed a LOT. PROBABLY NOT THREAD SAFE!
4
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)
5
+ float perlin_smooth_noise_2d(const int x, const int y)
23
6
  {
24
7
  const float corners = (
25
8
  perlin_noise_2d(x - 1, y - 1) +
@@ -74,14 +57,7 @@ float perlin_octaves_2d(const float x, const float y, const float p, const float
74
57
 
75
58
  // 3D ------------------------------------------------------------------
76
59
 
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)
60
+ float perlin_smooth_noise_3d(const int x, const int y, const int z)
85
61
  {
86
62
  const float corners = (
87
63
  perlin_noise_3d(x - 1, y - 1, z + 1) +
@@ -9,15 +9,32 @@
9
9
 
10
10
  extern long seed;
11
11
 
12
- static inline float perlin_interpolate(const float a, const float b, const float x);
12
+ inline float perlin_interpolate(const float a, const float b, const float x)
13
+ {
14
+ const float ft = x * M_PI;
15
+ const float f = (1 - cos(ft)) * 0.5;
16
+ return a * (1 - f) + b * f;
17
+ }
13
18
 
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);
19
+ inline float perlin_noise_2d(const int x, const int y)
20
+ {
21
+ long n = x + y * 57;
22
+ n = (n << 13) ^ n;
23
+ return (1.0 - ((n * (n * n * 15731*seed + 789221*seed) + 1376312589*seed) & 0x7fffffff) / 1073741824.0);
24
+ }
25
+
26
+ inline float perlin_noise_3d(const int x, const int y, const int z)
27
+ {
28
+ long n = x + y + z * 57;
29
+ n = (n << 13) ^ n;
30
+ return (1.0 - ((n * (n * n * 15731*seed + 789221*seed) + 1376312589*seed) & 0x7fffffff) / 1073741824.0);
31
+ }
32
+
33
+ float perlin_smooth_noise_2d(const int x, const int y);
16
34
  float perlin_interpolated_noise_2d(const float x, const float y);
17
35
  float perlin_octaves_2d(const float x, const float y, const float p, const float n);
18
36
 
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);
37
+ float perlin_smooth_noise_3d(const int x, const int y, const int z);
21
38
  float perlin_interpolated_noise_3d(const float x, const float y, const float z);
22
39
  float perlin_octaves_3d(const float x, const float y, const float z, const float p, const float n);
23
40
 
@@ -1,23 +1,106 @@
1
1
  #include "generator.h"
2
2
 
3
+ void Init_Perlin_Generator(VALUE module)
4
+ {
5
+ VALUE rb_cPerlinGenerator = rb_define_class_under(module, "Generator", rb_cObject);
6
+ rb_define_alloc_func(rb_cPerlinGenerator, Perlin_Generator_allocate);
7
+
8
+ rb_define_method(rb_cPerlinGenerator, "initialize", Perlin_Generator_init, -1);
9
+
10
+ rb_define_method(rb_cPerlinGenerator, "seed", Perlin_Generator_get_seed, 0);
11
+ rb_define_method(rb_cPerlinGenerator, "persistence", Perlin_Generator_get_persistence, 0);
12
+ rb_define_method(rb_cPerlinGenerator, "octave", Perlin_Generator_get_octave, 0);
13
+ rb_define_method(rb_cPerlinGenerator, "classic?", Perlin_Generator_get_classic, 0);
14
+
15
+ rb_define_method(rb_cPerlinGenerator, "seed=", Perlin_Generator_set_seed, 1);
16
+ rb_define_method(rb_cPerlinGenerator, "persistence=", Perlin_Generator_set_persistence, 1);
17
+ rb_define_method(rb_cPerlinGenerator, "octave=", Perlin_Generator_set_octave, 1);
18
+ rb_define_method(rb_cPerlinGenerator, "classic=", Perlin_Generator_set_classic, 1);
19
+
20
+ rb_define_method(rb_cPerlinGenerator, "[]", Perlin_Generator_run, -1);
21
+ rb_define_method(rb_cPerlinGenerator, "run2d", Perlin_Generator_run2d, 2);
22
+ rb_define_method(rb_cPerlinGenerator, "run3d", Perlin_Generator_run3d, 3);
23
+
24
+ rb_define_method(rb_cPerlinGenerator, "chunk", Perlin_Generator_chunk, -1);
25
+ rb_define_method(rb_cPerlinGenerator, "chunk2d", Perlin_Generator_chunk2d, 5);
26
+ rb_define_method(rb_cPerlinGenerator, "chunk3d", Perlin_Generator_chunk3d, 7);
27
+ }
28
+
29
+ // Memory management.
30
+
31
+ VALUE Perlin_Generator_allocate(VALUE klass)
32
+ {
33
+ PerlinGenerator* generator = ALLOC(PerlinGenerator);
34
+ memset(generator, 0, sizeof(PerlinGenerator));
35
+
36
+ return Data_Wrap_Struct(klass, 0, Perlin_Generator_free, generator);
37
+ }
38
+
39
+ void Perlin_Generator_free(PerlinGenerator* generator)
40
+ {
41
+ xfree(generator);
42
+ }
43
+
44
+ // Getters and setters.
45
+
3
46
  VALUE Perlin_Generator_set_seed(const VALUE self, const VALUE seed)
4
47
  {
5
- rb_iv_set(self, "@seed", rb_funcall(seed, rb_intern("to_i"), 0));
48
+ GENERATOR();
49
+
50
+ long _seed = NUM2LONG(seed);
51
+ if(_seed < 1) rb_raise(rb_eArgError, "seed must be >= 1");
52
+ generator->seed = _seed;
53
+
54
+ return seed;
55
+ }
56
+
57
+ VALUE Perlin_Generator_get_seed(const VALUE self)
58
+ {
59
+ GENERATOR();
60
+ return LONG2NUM(generator->seed);
6
61
  }
7
62
 
8
63
  VALUE Perlin_Generator_set_persistence(const VALUE self, const VALUE persistence)
9
64
  {
10
- rb_iv_set(self, "@persistence", rb_funcall(persistence, rb_intern("to_f"), 0));
65
+ GENERATOR();
66
+ generator->persistence = NUM2DBL(persistence);
67
+ return persistence;
68
+ }
69
+
70
+ VALUE Perlin_Generator_get_persistence(const VALUE self)
71
+ {
72
+ GENERATOR();
73
+ return rb_float_new(generator->persistence);
11
74
  }
12
75
 
13
76
  VALUE Perlin_Generator_set_octave(const VALUE self, const VALUE octave)
14
77
  {
15
- rb_iv_set(self, "@octave", rb_funcall(octave, rb_intern("to_i"), 0));
78
+ GENERATOR();
79
+
80
+ long _octave = NUM2LONG(octave);
81
+ if(_octave < 1) rb_raise(rb_eArgError, "octave must be >= 1");
82
+ generator->octave = _octave;
83
+
84
+ return octave;
85
+ }
86
+
87
+ VALUE Perlin_Generator_get_octave(const VALUE self)
88
+ {
89
+ GENERATOR();
90
+ return LONG2NUM(generator->octave);
16
91
  }
17
92
 
18
93
  VALUE Perlin_Generator_set_classic(const VALUE self, const VALUE classic)
19
94
  {
20
- rb_iv_set(self, "@classic", classic);
95
+ GENERATOR();
96
+ generator->is_classic = RTEST(classic);
97
+ return classic;
98
+ }
99
+
100
+ VALUE Perlin_Generator_get_classic(const VALUE self)
101
+ {
102
+ GENERATOR();
103
+ return (generator->is_classic ? Qtrue : Qfalse);
21
104
  }
22
105
 
23
106
  // x, y
@@ -30,16 +113,9 @@ VALUE Perlin_Generator_run(const int argc, const VALUE *argv, const VALUE self)
30
113
 
31
114
  switch(argc)
32
115
  {
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);
116
+ case 2: return Perlin_Generator_run2d(self, x, y);
117
+ case 3: return Perlin_Generator_run3d(self, x, y, z);
118
+ default: rb_raise(rb_eArgError, "%d parameters not supported (2D and 3D are)", argc);
43
119
  }
44
120
  }
45
121
 
@@ -48,19 +124,17 @@ Takes points (x, y) and returns a height (n)
48
124
  */
49
125
  VALUE Perlin_Generator_run2d(const VALUE self, const VALUE x, const VALUE y)
50
126
  {
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");
127
+ GENERATOR();
54
128
 
55
- seed = NUM2LONG(rb_iv_get(self, "@seed")); // Store in global, for speed.
56
-
57
- if(RTEST(classic))
129
+ if(generator->is_classic)
58
130
  {
59
- return rb_float_new(perlin_octaves_2d(NUM2DBL(x), NUM2DBL(y), p, n));
131
+ seed = generator->seed; // Store in global, for speed.
132
+ return rb_float_new(perlin_octaves_2d(NUM2DBL(x), NUM2DBL(y), generator->persistence, generator->octave));
60
133
  }
61
134
  else
62
135
  {
63
- return rb_float_new(octave_noise_3d(n, p, 1.0, NUM2DBL(x), NUM2DBL(y), seed * SEED_OFFSET));
136
+ return rb_float_new(octave_noise_3d(generator->octave, generator->persistence, 1.0, NUM2DBL(x), NUM2DBL(y),
137
+ generator->seed));
64
138
  }
65
139
  }
66
140
 
@@ -69,19 +143,17 @@ Takes points (x, y, z) and returns a height (n)
69
143
  */
70
144
  VALUE Perlin_Generator_run3d(const VALUE self, const VALUE x, const VALUE y, const VALUE z)
71
145
  {
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.
146
+ GENERATOR();
77
147
 
78
- if(RTEST(classic))
148
+ if(generator->is_classic)
79
149
  {
80
- return rb_float_new(perlin_octaves_3d(NUM2DBL(x), NUM2DBL(y), NUM2DBL(z), p, n));
150
+ seed = generator->seed; // Store in global, for speed.
151
+ return rb_float_new(perlin_octaves_3d(NUM2DBL(x), NUM2DBL(y), NUM2DBL(z), generator->persistence, generator->octave));
81
152
  }
82
153
  else
83
154
  {
84
- return rb_float_new(octave_noise_4d(n, p, 1.0, NUM2DBL(x), NUM2DBL(y), NUM2DBL(z), seed * SEED_OFFSET));
155
+ return rb_float_new(octave_noise_4d(generator->octave, generator->persistence, 1.0, NUM2DBL(x), NUM2DBL(y), NUM2DBL(z),
156
+ generator->seed));
85
157
  }
86
158
 
87
159
  }
@@ -96,16 +168,9 @@ VALUE Perlin_Generator_chunk(const int argc, const VALUE *argv, const VALUE self
96
168
 
97
169
  switch(argc)
98
170
  {
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);
171
+ case 5: return Perlin_Generator_chunk2d(self, a, b, c, d, e);
172
+ case 7: return Perlin_Generator_chunk3d(self, a, b, c, d, e, f, g);
173
+ default: rb_raise(rb_eArgError, "%d parameters not supported (5 for 2D and 7 for 3D are)", argc);
109
174
  }
110
175
  }
111
176
 
@@ -114,9 +179,7 @@ Returns a chunk of coordinates starting from x, y and of size steps_x, steps_y w
114
179
  */
115
180
  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
181
  {
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"));
182
+ GENERATOR();
120
183
 
121
184
  VALUE arr, row;
122
185
  int i, j;
@@ -131,7 +194,7 @@ VALUE Perlin_Generator_chunk2d(const VALUE self, const VALUE x, const VALUE y, c
131
194
  rb_raise(rb_eArgError, "steps must be >= 1");
132
195
  }
133
196
 
134
- seed = NUM2LONG(rb_iv_get(self, "@seed")); // Store in global, for speed.
197
+ if(generator->is_classic) seed = generator->seed; // Store in global, for speed.
135
198
 
136
199
  if(rb_block_given_p())
137
200
  {
@@ -142,14 +205,14 @@ VALUE Perlin_Generator_chunk2d(const VALUE self, const VALUE x, const VALUE y, c
142
205
  _y = y_min;
143
206
  for (j = 0; j < _steps_y; j++)
144
207
  {
145
- if(is_classic)
208
+ if(generator->is_classic)
146
209
  {
147
- rb_yield_values(3, rb_float_new(perlin_octaves_2d(_x, _y, p, n)),
210
+ rb_yield_values(3, rb_float_new(perlin_octaves_2d(_x, _y, generator->persistence, generator->octave)),
148
211
  rb_float_new(_x), rb_float_new(_y));
149
212
  }
150
213
  else
151
214
  {
152
- rb_yield_values(3, rb_float_new(octave_noise_3d(n, p, 1.0, _x, _y, seed * SEED_OFFSET)),
215
+ rb_yield_values(3, rb_float_new(octave_noise_3d(generator->octave, generator->persistence, 1.0, _x, _y, generator->seed)),
153
216
  rb_float_new(_x), rb_float_new(_y));
154
217
  }
155
218
 
@@ -171,13 +234,13 @@ VALUE Perlin_Generator_chunk2d(const VALUE self, const VALUE x, const VALUE y, c
171
234
  _y = y_min;
172
235
  for (j = 0; j < _steps_y; j++)
173
236
  {
174
- if(is_classic)
237
+ if(generator->is_classic)
175
238
  {
176
- rb_ary_push(row, rb_float_new(perlin_octaves_2d(_x, _y, p, n)));
239
+ rb_ary_push(row, rb_float_new(perlin_octaves_2d(_x, _y, generator->persistence, generator->octave)));
177
240
  }
178
241
  else
179
242
  {
180
- rb_ary_push(row, rb_float_new(octave_noise_3d(n, p, 1.0, _x, _y, seed * SEED_OFFSET)));
243
+ rb_ary_push(row, rb_float_new(octave_noise_3d(generator->octave, generator->persistence, 1.0, _x, _y, generator->seed)));
181
244
  }
182
245
 
183
246
  _y += _interval;
@@ -194,9 +257,7 @@ Returns a chunk of coordinates starting from x, y, z and of size steps_x, steps_
194
257
  */
195
258
  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
259
  {
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"));
260
+ GENERATOR();
200
261
 
201
262
  VALUE arr, row, column;
202
263
  int i, j, k;
@@ -211,7 +272,7 @@ VALUE Perlin_Generator_chunk3d(const VALUE self, const VALUE x, const VALUE y, c
211
272
  rb_raise(rb_eArgError, "steps must be >= 1");
212
273
  }
213
274
 
214
- seed = NUM2LONG(rb_iv_get(self, "@seed")); // Store in global, for speed.
275
+ if(generator->is_classic) seed = generator->seed; // Store in global, for speed.
215
276
 
216
277
  if(rb_block_given_p())
217
278
  {
@@ -224,14 +285,15 @@ VALUE Perlin_Generator_chunk3d(const VALUE self, const VALUE x, const VALUE y, c
224
285
  _z = z_min;
225
286
  for (k = 0; k < _steps_z; k++)
226
287
  {
227
- if(is_classic)
288
+ if(generator->is_classic)
228
289
  {
229
- rb_yield_values(4, rb_float_new(perlin_octaves_3d(_x, _y, _z, p, n)),
290
+ rb_yield_values(4, rb_float_new(perlin_octaves_3d(_x, _y, _z, generator->persistence, generator->octave)),
230
291
  rb_float_new(_x), rb_float_new(_y), rb_float_new(_z));
231
292
  }
232
293
  else
233
294
  {
234
- rb_yield_values(4, rb_float_new(octave_noise_4d(n, p, 1.0, _x, _y, _z, seed * SEED_OFFSET)),
295
+ rb_yield_values(4,
296
+ rb_float_new(octave_noise_4d(generator->octave, generator->persistence, 1.0, _x, _y, _z, generator->seed)),
235
297
  rb_float_new(_x), rb_float_new(_y), rb_float_new(_z));
236
298
  }
237
299
 
@@ -257,13 +319,14 @@ VALUE Perlin_Generator_chunk3d(const VALUE self, const VALUE x, const VALUE y, c
257
319
  _z = z_min;
258
320
  for (k = 0; k < _steps_z; k++)
259
321
  {
260
- if(is_classic)
322
+ if(generator->is_classic)
261
323
  {
262
- rb_ary_push(column, rb_float_new(perlin_octaves_3d(_x, _y, _z, p, n)));
324
+ rb_ary_push(column, rb_float_new(perlin_octaves_3d(_x, _y, _z, generator->persistence, generator->octave)));
263
325
  }
264
326
  else
265
327
  {
266
- rb_ary_push(column, rb_float_new(octave_noise_4d(n, p, 1.0, _x, _y, _z, seed * SEED_OFFSET)));
328
+ rb_ary_push(column, rb_float_new(octave_noise_4d(generator->octave, generator->persistence, 1.0,
329
+ _x, _y, _z, generator->seed)));
267
330
  }
268
331
 
269
332
  _z += _interval;
@@ -281,12 +344,24 @@ VALUE Perlin_Generator_chunk3d(const VALUE self, const VALUE x, const VALUE y, c
281
344
  /*
282
345
  The main initialize function which receives the inputs persistence and octave.
283
346
  */
284
- VALUE Perlin_Generator_init(VALUE self, VALUE seed, VALUE persistence, VALUE octave, VALUE classic)
347
+ VALUE Perlin_Generator_init(const int argc, const VALUE *argv, const VALUE self)
285
348
  {
349
+ VALUE seed, persistence, octave, options;
350
+
351
+ rb_scan_args(argc, argv, "31", &seed, &persistence, &octave, &options);
352
+ if(NIL_P(options))
353
+ {
354
+ options = rb_hash_new();
355
+ }
356
+ else
357
+ {
358
+ Check_Type(options, T_HASH);
359
+ }
360
+
286
361
  Perlin_Generator_set_seed(self, seed);
287
362
  Perlin_Generator_set_persistence(self, persistence);
288
363
  Perlin_Generator_set_octave(self, octave);
289
- Perlin_Generator_set_classic(self, classic);
364
+ Perlin_Generator_set_classic(self, rb_hash_aref(options, ID2SYM(rb_intern("classic"))));
290
365
 
291
366
  return self;
292
367
  }
@@ -7,21 +7,28 @@
7
7
 
8
8
  #include <ruby.h>
9
9
 
10
+ #include <stdbool.h>
11
+
10
12
  #include "classic.h"
11
13
  #include "simplex.h"
12
14
 
13
15
  extern long seed;
14
16
 
15
- // Arbitrary number used to add an extra "seed" dimension for Simplex noise.
16
- // Seed 2D noise by offsetting the 3rd dimension.
17
- // Seed 3D noise by seeding with the 4th dimension.
18
- #define SEED_OFFSET -12354.1123f
17
+ void Init_Perlin_Generator();
18
+
19
+ // Getters.
20
+ VALUE Perlin_Generator_get_seed(const VALUE self);
21
+ VALUE Perlin_Generator_get_persistence(const VALUE self);
22
+ VALUE Perlin_Generator_get_octave(const VALUE self);
23
+ VALUE Perlin_Generator_get_classic(const VALUE self);
19
24
 
25
+ // Setters.
20
26
  VALUE Perlin_Generator_set_seed(const VALUE self, const VALUE seed);
21
27
  VALUE Perlin_Generator_set_persistence(const VALUE self, const VALUE persistence);
22
28
  VALUE Perlin_Generator_set_octave(const VALUE self, const VALUE octave);
23
29
  VALUE Perlin_Generator_set_classic(const VALUE self, const VALUE classic);
24
30
 
31
+ // Actually getting noise.
25
32
  VALUE Perlin_Generator_run(const int argc, const VALUE *argv, const VALUE self);
26
33
  VALUE Perlin_Generator_run2d(const VALUE self, const VALUE x, const VALUE y);
27
34
  VALUE Perlin_Generator_run3d(const VALUE self, const VALUE x, const VALUE y, const VALUE z);
@@ -30,6 +37,23 @@ VALUE Perlin_Generator_chunk(const int argc, const VALUE *argv, const VALUE self
30
37
  VALUE Perlin_Generator_chunk2d(const VALUE self, const VALUE x, const VALUE y, const VALUE steps_x, const VALUE steps_y, VALUE interval);
31
38
  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);
32
39
 
33
- VALUE Perlin_Generator_init(const VALUE self, const VALUE seed, const VALUE persistence, const VALUE octave, const VALUE classic);
40
+ VALUE Perlin_Generator_init(const int argc, const VALUE *argv, const VALUE self);
41
+
42
+ // Data management stuff.
43
+
44
+ typedef struct _PerlinGenerator
45
+ {
46
+ bool is_classic; // True if Classic, false if Simplex.
47
+ long seed; // >= 1
48
+ long octave; // >= 1
49
+ double persistence;
50
+ } PerlinGenerator;
51
+
52
+ #define GENERATOR() \
53
+ PerlinGenerator* generator; \
54
+ Data_Get_Struct(self, PerlinGenerator, generator);
55
+
56
+ VALUE Perlin_Generator_allocate(VALUE klass);
57
+ void Perlin_Generator_free(PerlinGenerator* generator);
34
58
 
35
59
  #endif // GENERATOR_H
@@ -7,21 +7,6 @@ located at http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
7
7
 
8
8
  void Init_perlin() {
9
9
  VALUE jm_Module = rb_define_module("Perlin");
10
- VALUE rb_cPerlin = rb_define_class_under(jm_Module, "Generator", rb_cObject);
11
-
12
- rb_define_method(rb_cPerlin, "initialize_", Perlin_Generator_init, 4);
13
-
14
- rb_define_method(rb_cPerlin, "seed=", Perlin_Generator_set_seed, 1);
15
- rb_define_method(rb_cPerlin, "persistence=", Perlin_Generator_set_persistence, 1);
16
- rb_define_method(rb_cPerlin, "octave=", Perlin_Generator_set_octave, 1);
17
- rb_define_method(rb_cPerlin, "classic=", Perlin_Generator_set_classic, 1);
18
-
19
- rb_define_method(rb_cPerlin, "[]", Perlin_Generator_run, -1);
20
- rb_define_method(rb_cPerlin, "run2d", Perlin_Generator_run2d, 2);
21
- rb_define_method(rb_cPerlin, "run3d", Perlin_Generator_run3d, 3);
22
-
23
- rb_define_method(rb_cPerlin, "chunk", Perlin_Generator_chunk, -1);
24
- rb_define_method(rb_cPerlin, "chunk2d", Perlin_Generator_chunk2d, 5);
25
- rb_define_method(rb_cPerlin, "chunk3d", Perlin_Generator_chunk3d, 7);
10
+ Init_Perlin_Generator(jm_Module);
26
11
  }
27
12
 
@@ -2,34 +2,37 @@ module Perlin
2
2
  # Perlin noise generator.
3
3
  #
4
4
  # @!attribute [rw] seed
5
+ # Seed value for the noise pattern (>= 0)
5
6
  # @return [Integer]
6
7
  #
7
- # @!attribute [r] persistence
8
+ # @!attribute [rw] persistence
9
+ # Amount of persistence of noise through each octave
8
10
  # @return [Float]
9
11
  #
10
- # @!attribute [r] octave
12
+ # @!attribute [rw] octave
13
+ # Number of octaves (or iterations) of noise to generate (>= 1)
11
14
  # @return [Integer]
12
15
  class Generator
13
- attr_reader :seed, :octave, :persistence
14
- def classic?; @classic; end
16
+ # @!method classic?
17
+ # @return [Boolean] True for Classic noise, false for Simplex noise.
15
18
 
16
- # @!method initialize(seed, persistence, octave)
19
+ # @!method classic=(value)
20
+ # @param value [Boolean] True for Classic noise, false for Simplex noise.
21
+ # @return [Boolean]
22
+
23
+ # @return [Boolean] True for Simplex noise, false for Classic noise.
24
+ def simplex?; !classic? end
25
+
26
+ # @!method initialize(seed, persistence, octave, options={})
17
27
  # Create a noise generator.
18
28
  #
19
29
  # Using the same seed will always produce the same pattern. Animate a perlin 'texture' by altering the seed based on time.
20
30
  #
21
- # @param seed [Integer] Seed value to create a different pattern.
22
- # @param persistence [Float] Used to generate different frequencies/amplitudes of output.
23
- # @param octave [Integer] Number of iterations to run (higher number of octaves takes more time)
31
+ # @param seed [Integer] Seed value to create a different pattern (must be >= 0).
32
+ # @param persistence [Float] Used to generate different frequencies/amplitudes of output .
33
+ # @param octave [Integer] Number of iterations to run (higher number of octaves takes more time) (must be >= 1)
24
34
  # @option options :classic [Boolean] (false) Whether to use the slower Classic algorithm, rather than default (and much faster) Simplex.
25
- def initialize(seed, persistence, octave, options = {})
26
- options = {
27
- :classic => false,
28
- }.merge! options
29
35
 
30
- initialize_(seed, persistence, octave, options[:classic])
31
- end
32
- protected :initialize_ # Underlying C implementation.
33
36
 
34
37
  # @overload chunk(x, y, steps_x, steps_y, interval)
35
38
  # Calculates a rectangular section of height (n) values and returns them as a 2D array.
@@ -1,5 +1,5 @@
1
1
  # Perlin noise generation.
2
2
  module Perlin
3
3
  # Current version of the gem.
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -4,7 +4,7 @@ require File.expand_path("../../helper.rb", __FILE__)
4
4
  describe Perlin::Generator do
5
5
  before :each do
6
6
  @classic = Perlin::Generator.new 123, 1.5, 2, :classic => true
7
- @simplex = Perlin::Generator.new 0, 1.5, 2
7
+ @simplex = Perlin::Generator.new 1, 1.5, 2
8
8
  @accuracy = 0.00001
9
9
  end
10
10
 
@@ -50,12 +50,16 @@ describe Perlin::Generator do
50
50
  @classic.seed.should eq 12
51
51
  @classic.seed.should be_kind_of Integer
52
52
  end
53
+
54
+ it "should fail unless >= 1" do
55
+ lambda { @classic.seed = 0 }.should raise_error ArgumentError, "seed must be >= 1"
56
+ end
53
57
  end
54
58
 
55
59
  describe "persistence=" do
56
60
  it "should set persistence correctly" do
57
- @classic.persistence = 12
58
- @classic.persistence.should eq 12
61
+ @classic.persistence = 12.1513
62
+ @classic.persistence.should eq 12.1513
59
63
  @classic.persistence.should be_kind_of Float
60
64
  end
61
65
  end
@@ -66,6 +70,10 @@ describe Perlin::Generator do
66
70
  @classic.octave.should eq 12
67
71
  @classic.octave.should be_kind_of Integer
68
72
  end
73
+
74
+ it "should fail unless >= 1" do
75
+ lambda { @classic.octave = 0 }.should raise_error ArgumentError, "octave must be >= 1"
76
+ end
69
77
  end
70
78
 
71
79
  describe "classic=" do
@@ -97,7 +105,7 @@ describe Perlin::Generator do
97
105
  describe "SIMPLEX" do
98
106
  describe "[](x, y)" do
99
107
  it "should return the appropriate value" do
100
- @simplex[0, 1].should be_within(@accuracy).of 0.7600996515471077
108
+ @simplex[0, 1].should be_within(@accuracy).of -0.7169484162988542
101
109
  end
102
110
 
103
111
  it "should return different values based on seed" do
@@ -109,7 +117,7 @@ describe Perlin::Generator do
109
117
 
110
118
  describe "[](x, y, z)" do
111
119
  it "should return the appropriate value" do
112
- @simplex[0, 1, 2].should be_within(@accuracy).of -0.4994023090387083
120
+ @simplex[0, 1, 2].should be_within(@accuracy).of 0.3528568374548613
113
121
  end
114
122
  end
115
123
  end
@@ -141,7 +149,7 @@ describe Perlin::Generator do
141
149
  describe "SIMPLEX" do
142
150
  it "should return the appropriate values" do
143
151
  chunk = @simplex.chunk 1, 2, 3, 4, 1
144
- chunk.should eq [[0.0, 0.19517135798668975, 0.19616149193873283, -5.932618130464163e-07], [0.10886869609093779, 0.10787834101090553, -5.932618130464163e-07, -0.19616171787047829], [-0.0431512326002121, 0.0, 0.260888409614563, 0.45605969740428703]]
152
+ chunk.should eq [[0.3256153247344187, -0.044141564834959, -1.9775393411691766e-07, -0.30403976440429686], [0.0, 1.9775393411691766e-07, 0.0, -0.21674697868461495], [1.9775393411691766e-07, -0.23931307266021215, -0.7600996287015893, -5.93261818394248e-07]]
145
153
  end
146
154
 
147
155
  it "should give the same results, regardless of x/y offset" do
@@ -159,7 +167,7 @@ describe Perlin::Generator do
159
167
  @simplex.chunk 1, 2, 3, 4, 1 do |h, x, y|
160
168
  arr << [h, x, y]
161
169
  end
162
- arr.should eq [[0.0, 1.0, 2.0], [0.19517135798668975, 1.0, 3.0], [0.19616149193873283, 1.0, 4.0], [-5.932618130464163e-07, 1.0, 5.0], [0.10886869609093779, 2.0, 2.0], [0.10787834101090553, 2.0, 3.0], [-5.932618130464163e-07, 2.0, 4.0], [-0.19616171787047829, 2.0, 5.0], [-0.0431512326002121, 3.0, 2.0], [0.0, 3.0, 3.0], [0.260888409614563, 3.0, 4.0], [0.45605969740428703, 3.0, 5.0]]
170
+ arr.should eq [[0.3256153247344187, 1.0, 2.0], [-0.044141564834959, 1.0, 3.0], [-1.9775393411691766e-07, 1.0, 4.0], [-0.30403976440429686, 1.0, 5.0], [0.0, 2.0, 2.0], [1.9775393411691766e-07, 2.0, 3.0], [0.0, 2.0, 4.0], [-0.21674697868461495, 2.0, 5.0], [1.9775393411691766e-07, 3.0, 2.0], [-0.23931307266021215, 3.0, 3.0], [-0.7600996287015893, 3.0, 4.0], [-5.93261818394248e-07, 3.0, 5.0]]
163
171
  end
164
172
  end
165
173
 
@@ -201,7 +209,7 @@ describe Perlin::Generator do
201
209
  describe "SIMPLEX" do
202
210
  it "should return the appropriate values" do
203
211
  chunk = @simplex.chunk 6, 5, 4, 3, 2, 1, 1
204
- chunk.should eq [[[-0.0506731136544405], [0.13219586780905937]], [[0.32796947870374366], [0.5241572306428496]], [[-0.10557871005195935], [-0.10961889028549195]]]
212
+ chunk.should eq [[[-0.13219586780905937], [-0.10557871005195935]], [[0.057937057229464836], [0.14160177316516637]], [[0.4784122159704566], [0.23034484239760417]]]
205
213
  end
206
214
 
207
215
  it "should work with a block" do
@@ -209,7 +217,7 @@ describe Perlin::Generator do
209
217
  @simplex.chunk 6, 5, 4, 3, 2, 1, 1 do |h, x, y, z|
210
218
  arr << [h, x, y, z]
211
219
  end
212
- arr.should eq [[-0.0506731136544405, 6.0, 5.0, 4.0], [0.13219586780905937, 6.0, 6.0, 4.0], [0.32796947870374366, 7.0, 5.0, 4.0], [0.5241572306428496, 7.0, 6.0, 4.0], [-0.10557871005195935, 8.0, 5.0, 4.0], [-0.10961889028549195, 8.0, 6.0, 4.0]]
220
+ arr.should eq [[-0.13219586780905937, 6.0, 5.0, 4.0], [-0.10557871005195935, 6.0, 6.0, 4.0], [0.057937057229464836, 7.0, 5.0, 4.0], [0.14160177316516637, 7.0, 6.0, 4.0], [0.4784122159704566, 8.0, 5.0, 4.0], [0.23034484239760417, 8.0, 6.0, 4.0]]
213
221
  end
214
222
  end
215
223
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perlin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-07-16 00:00:00.000000000 Z
14
+ date: 2012-12-03 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: RedCloth
@@ -109,6 +109,54 @@ dependencies:
109
109
  - - ~>
110
110
  - !ruby/object:Gem::Version
111
111
  version: 2.1.0
112
+ - !ruby/object:Gem::Dependency
113
+ name: texplay
114
+ requirement: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ~>
118
+ - !ruby/object:Gem::Version
119
+ version: 0.4.3
120
+ type: :development
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ~>
126
+ - !ruby/object:Gem::Version
127
+ version: 0.4.3
128
+ - !ruby/object:Gem::Dependency
129
+ name: gosu
130
+ requirement: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ~>
134
+ - !ruby/object:Gem::Version
135
+ version: 0.7.45
136
+ type: :development
137
+ prerelease: false
138
+ version_requirements: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ~>
142
+ - !ruby/object:Gem::Version
143
+ version: 0.7.45
144
+ - !ruby/object:Gem::Dependency
145
+ name: fidgit
146
+ requirement: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ~>
150
+ - !ruby/object:Gem::Version
151
+ version: 0.2.4
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ none: false
156
+ requirements:
157
+ - - ~>
158
+ - !ruby/object:Gem::Version
159
+ version: 0.2.4
112
160
  description: ! 'Perlin Noise C extension
113
161
 
114
162
 
@@ -119,6 +167,7 @@ description: ! 'Perlin Noise C extension
119
167
 
120
168
  '
121
169
  email:
170
+ - bil.bagpuss@gmail.com
122
171
  - mojobojo@gmail.com
123
172
  executables: []
124
173
  extensions:
@@ -143,13 +192,14 @@ files:
143
192
  - ext/perlin/extconf.rb
144
193
  - examples/chunk_in_2d.rb
145
194
  - examples/chunk_in_3d.rb
195
+ - examples/gosu.rb
146
196
  - examples/index_in_2d.rb
147
197
  - examples/index_in_3d.rb
148
198
  - examples/ogl/README.md
149
199
  - examples/ogl/run.rb
150
200
  - spec/helper.rb
151
201
  - spec/perlin/generator_spec.rb
152
- homepage: https://github.com/boj/ruby-perlin
202
+ homepage: https://github.com/spooner/ruby-perlin
153
203
  licenses:
154
204
  - MIT
155
205
  post_install_message: