|
8 | 8 | // option. This file may not be copied, modified, or distributed
|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 |
| -// Perlin noise benchmark from https://gist.github.com/1170424 |
| 11 | +// Multi-language Perlin noise benchmark. |
| 12 | +// See https://github.com/nsf/pnoise for timings and alternative implementations. |
12 | 13 |
|
13 |
| -use std::f64; |
14 |
| -use std::rand::Rng; |
15 |
| -use std::rand; |
| 14 | +use std::f32::consts::PI; |
| 15 | +use std::rand::{Rng, StdRng}; |
16 | 16 |
|
17 | 17 | struct Vec2 {
|
18 | 18 | x: f32,
|
19 | 19 | y: f32,
|
20 | 20 | }
|
21 | 21 |
|
22 |
| -#[inline(always)] |
23 | 22 | fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v }
|
24 | 23 |
|
25 |
| -#[inline(always)] |
26 | 24 | fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) }
|
27 | 25 |
|
28 |
| -fn random_gradient<R:Rng>(r: &mut R) -> Vec2 { |
29 |
| - let v = 2.0 * f64::consts::PI * r.gen(); |
30 |
| - Vec2 { |
31 |
| - x: v.cos() as f32, |
32 |
| - y: v.sin() as f32, |
33 |
| - } |
| 26 | +fn random_gradient<R: Rng>(r: &mut R) -> Vec2 { |
| 27 | + let v = PI * 2.0 * r.gen(); |
| 28 | + Vec2 { x: v.cos(), y: v.sin() } |
34 | 29 | }
|
35 | 30 |
|
36 | 31 | fn gradient(orig: Vec2, grad: Vec2, p: Vec2) -> f32 {
|
37 |
| - let sp = Vec2 {x: p.x - orig.x, y: p.y - orig.y}; |
38 |
| - grad.x * sp.x + grad.y * sp.y |
| 32 | + (p.x - orig.x) * grad.x + (p.y - orig.y) * grad.y |
39 | 33 | }
|
40 | 34 |
|
41 | 35 | struct Noise2DContext {
|
42 | 36 | rgradients: [Vec2, ..256],
|
43 |
| - permutations: [int, ..256], |
| 37 | + permutations: [i32, ..256], |
44 | 38 | }
|
45 | 39 |
|
46 | 40 | impl Noise2DContext {
|
47 |
| - pub fn new() -> Noise2DContext { |
48 |
| - let mut r = rand::rng(); |
49 |
| - let mut rgradients = [ Vec2 { x: 0.0, y: 0.0 }, ..256 ]; |
50 |
| - for i in range(0, 256) { |
51 |
| - rgradients[i] = random_gradient(&mut r); |
52 |
| - } |
53 |
| - let mut permutations = [ 0, ..256 ]; |
54 |
| - for i in range(0, 256) { |
55 |
| - permutations[i] = i; |
| 41 | + fn new() -> Noise2DContext { |
| 42 | + let mut rng = StdRng::new(); |
| 43 | + |
| 44 | + let mut rgradients = [Vec2 { x: 0.0, y: 0.0 }, ..256]; |
| 45 | + for x in rgradients.mut_iter() { |
| 46 | + *x = random_gradient(&mut rng); |
56 | 47 | }
|
57 |
| - r.shuffle_mut(permutations); |
58 | 48 |
|
59 |
| - Noise2DContext { |
60 |
| - rgradients: rgradients, |
61 |
| - permutations: permutations, |
| 49 | + let mut permutations = [0i32, ..256]; |
| 50 | + for (i, x) in permutations.mut_iter().enumerate() { |
| 51 | + *x = i as i32; |
62 | 52 | }
|
| 53 | + rng.shuffle_mut(permutations); |
| 54 | + |
| 55 | + Noise2DContext { rgradients: rgradients, permutations: permutations } |
63 | 56 | }
|
64 | 57 |
|
65 |
| - #[inline(always)] |
66 |
| - pub fn get_gradient(&self, x: int, y: int) -> Vec2 { |
| 58 | + fn get_gradient(&self, x: i32, y: i32) -> Vec2 { |
67 | 59 | let idx = self.permutations[x & 255] + self.permutations[y & 255];
|
68 | 60 | self.rgradients[idx & 255]
|
69 | 61 | }
|
70 | 62 |
|
71 |
| - #[inline] |
72 |
| - pub fn get_gradients(&self, |
73 |
| - gradients: &mut [Vec2, ..4], |
74 |
| - origins: &mut [Vec2, ..4], |
75 |
| - x: f32, |
76 |
| - y: f32) { |
| 63 | + fn get_gradients(&self, x: f32, y: f32) -> ([Vec2, ..4], [Vec2, ..4]) { |
77 | 64 | let x0f = x.floor();
|
78 | 65 | let y0f = y.floor();
|
79 |
| - let x0 = x0f as int; |
80 |
| - let y0 = y0f as int; |
| 66 | + let x1f = x0f + 1.0; |
| 67 | + let y1f = y0f + 1.0; |
| 68 | + |
| 69 | + let x0 = x0f as i32; |
| 70 | + let y0 = y0f as i32; |
81 | 71 | let x1 = x0 + 1;
|
82 | 72 | let y1 = y0 + 1;
|
83 | 73 |
|
84 |
| - gradients[0] = self.get_gradient(x0, y0); |
85 |
| - gradients[1] = self.get_gradient(x1, y0); |
86 |
| - gradients[2] = self.get_gradient(x0, y1); |
87 |
| - gradients[3] = self.get_gradient(x1, y1); |
88 |
| - |
89 |
| - origins[0] = Vec2 {x: x0f + 0.0, y: y0f + 0.0}; |
90 |
| - origins[1] = Vec2 {x: x0f + 1.0, y: y0f + 0.0}; |
91 |
| - origins[2] = Vec2 {x: x0f + 0.0, y: y0f + 1.0}; |
92 |
| - origins[3] = Vec2 {x: x0f + 1.0, y: y0f + 1.0}; |
| 74 | + ([self.get_gradient(x0, y0), self.get_gradient(x1, y0), |
| 75 | + self.get_gradient(x0, y1), self.get_gradient(x1, y1)], |
| 76 | + [Vec2 { x: x0f, y: y0f }, Vec2 { x: x1f, y: y0f }, |
| 77 | + Vec2 { x: x0f, y: y1f }, Vec2 { x: x1f, y: y1f }]) |
93 | 78 | }
|
94 | 79 |
|
95 |
| - #[inline] |
96 |
| - pub fn get(&self, x: f32, y: f32) -> f32 { |
| 80 | + fn get(&self, x: f32, y: f32) -> f32 { |
97 | 81 | let p = Vec2 {x: x, y: y};
|
98 |
| - let mut gradients = [ Vec2 { x: 0.0, y: 0.0 }, ..4 ]; |
99 |
| - let mut origins = [ Vec2 { x: 0.0, y: 0.0 }, ..4 ]; |
100 |
| - self.get_gradients(&mut gradients, &mut origins, x, y); |
| 82 | + let (gradients, origins) = self.get_gradients(x, y); |
| 83 | + |
101 | 84 | let v0 = gradient(origins[0], gradients[0], p);
|
102 | 85 | let v1 = gradient(origins[1], gradients[1], p);
|
103 | 86 | let v2 = gradient(origins[2], gradients[2], p);
|
104 | 87 | let v3 = gradient(origins[3], gradients[3], p);
|
| 88 | + |
105 | 89 | let fx = smooth(x - origins[0].x);
|
106 | 90 | let vx0 = lerp(v0, v1, fx);
|
107 | 91 | let vx1 = lerp(v2, v3, fx);
|
108 | 92 | let fy = smooth(y - origins[0].y);
|
| 93 | + |
109 | 94 | lerp(vx0, vx1, fy)
|
110 | 95 | }
|
111 | 96 | }
|
112 | 97 |
|
113 | 98 | fn main() {
|
114 |
| - let symbols = [" ", "░", "▒", "▓", "█", "█"]; |
| 99 | + let symbols = [' ', '░', '▒', '▓', '█', '█']; |
115 | 100 | let mut pixels = [0f32, ..256*256];
|
116 |
| - let n2d = ~Noise2DContext::new(); |
117 |
| - for _ in range(0, 100u) { |
| 101 | + let n2d = Noise2DContext::new(); |
| 102 | + |
| 103 | + for _ in range(0, 100) { |
118 | 104 | for y in range(0, 256) {
|
119 | 105 | for x in range(0, 256) {
|
120 |
| - let v = n2d.get( |
121 |
| - x as f32 * 0.1f32, |
122 |
| - y as f32 * 0.1f32 |
123 |
| - ) * 0.5f32 + 0.5f32; |
124 |
| - pixels[y*256+x] = v; |
125 |
| - }; |
126 |
| - }; |
127 |
| - }; |
| 106 | + let v = n2d.get(x as f32 * 0.1, y as f32 * 0.1); |
| 107 | + pixels[y*256+x] = v * 0.5 + 0.5; |
| 108 | + } |
| 109 | + } |
| 110 | + } |
128 | 111 |
|
129 | 112 | for y in range(0, 256) {
|
130 | 113 | for x in range(0, 256) {
|
131 |
| - print!("{}", symbols[(pixels[y*256+x] / 0.2f32) as int]); |
| 114 | + let idx = (pixels[y*256+x] / 0.2) as uint; |
| 115 | + print!("{:c}", symbols[idx]); |
132 | 116 | }
|
133 |
| - println!(""); |
| 117 | + print!("\n"); |
134 | 118 | }
|
135 | 119 | }
|
0 commit comments