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 +10 -1
- data/examples/gosu.rb +101 -0
- data/examples/ogl/run.rb +12 -1
- data/ext/perlin/classic.c +2 -26
- data/ext/perlin/classic.h +22 -5
- data/ext/perlin/generator.c +137 -62
- data/ext/perlin/generator.h +29 -5
- data/ext/perlin/perlin.c +1 -16
- data/lib/perlin/generator.rb +18 -15
- data/lib/perlin/version.rb +1 -1
- data/spec/perlin/generator_spec.rb +17 -9
- metadata +53 -3
data/CHANGELOG
CHANGED
@@ -1,4 +1,13 @@
|
|
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).
|
data/examples/gosu.rb
ADDED
@@ -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
|
data/examples/ogl/run.rb
CHANGED
@@ -1,6 +1,17 @@
|
|
1
|
-
|
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
|
|
data/ext/perlin/classic.c
CHANGED
@@ -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
|
-
|
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
|
-
|
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) +
|
data/ext/perlin/classic.h
CHANGED
@@ -9,15 +9,32 @@
|
|
9
9
|
|
10
10
|
extern long seed;
|
11
11
|
|
12
|
-
|
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
|
-
|
15
|
-
|
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
|
-
|
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
|
|
data/ext/perlin/generator.c
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
35
|
-
|
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
|
-
|
52
|
-
const int n = NUM2INT(rb_iv_get(self, "@octave"));
|
53
|
-
const VALUE classic = rb_iv_get(self, "@classic");
|
127
|
+
GENERATOR();
|
54
128
|
|
55
|
-
|
56
|
-
|
57
|
-
if(RTEST(classic))
|
129
|
+
if(generator->is_classic)
|
58
130
|
{
|
59
|
-
|
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(
|
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
|
-
|
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(
|
148
|
+
if(generator->is_classic)
|
79
149
|
{
|
80
|
-
|
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(
|
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
|
-
|
101
|
-
|
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
|
-
|
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 =
|
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,
|
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(
|
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,
|
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(
|
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
|
-
|
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 =
|
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,
|
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,
|
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,
|
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(
|
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(
|
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
|
}
|
data/ext/perlin/generator.h
CHANGED
@@ -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
|
-
|
16
|
-
|
17
|
-
//
|
18
|
-
|
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
|
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
|
data/ext/perlin/perlin.c
CHANGED
@@ -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
|
-
|
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
|
|
data/lib/perlin/generator.rb
CHANGED
@@ -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 [
|
8
|
+
# @!attribute [rw] persistence
|
9
|
+
# Amount of persistence of noise through each octave
|
8
10
|
# @return [Float]
|
9
11
|
#
|
10
|
-
# @!attribute [
|
12
|
+
# @!attribute [rw] octave
|
13
|
+
# Number of octaves (or iterations) of noise to generate (>= 1)
|
11
14
|
# @return [Integer]
|
12
15
|
class Generator
|
13
|
-
|
14
|
-
|
16
|
+
# @!method classic?
|
17
|
+
# @return [Boolean] True for Classic noise, false for Simplex noise.
|
15
18
|
|
16
|
-
# @!method
|
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.
|
data/lib/perlin/version.rb
CHANGED
@@ -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
|
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.
|
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
|
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.
|
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.
|
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.
|
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.
|
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.
|
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-
|
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/
|
202
|
+
homepage: https://github.com/spooner/ruby-perlin
|
153
203
|
licenses:
|
154
204
|
- MIT
|
155
205
|
post_install_message:
|