1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/// The documentation is taken from original C++ library by Joshua Tippetts ( http://accidentalnoise.sourceforge.net/docs.html ).
extern crate anl;
extern crate image;
use anl::*;
use anl::random_gen::PRNG;
use anl::RgbaModule;
use std::fs::*;
use std::rc::Rc;
use std::cell::RefCell;
const SIZE: u32 = 800;
const NAME: &'static str = "intro";
fn main() {
println!("Initializing '{}'", NAME);
/// This example is kind of a neat one (if a trifle useless).
/// The first thing the example does is to create a random number generator(RNG). ANL provides a number of different RNGs encapsulated in classes,
/// and based on variants of RNGs devised by George Marsaglia. It seeds the generator using the system time. After that, 7 noise fractal modules are created.
/// Many applications won't require nearly so many, and the fewer you can use the better your performance will be. After the fractals are generated,
/// they are seeded from the RNG then 7 more modules of type AutoCorrect are created.
let mut rnd = anl::random_gen::CMWC4096::new();
anl::random_gen::set_seed_time(&mut rnd);
let frac1 = Rc::new(RefCell::new(anl::ImplicitFractal::new(anl::FractalType::FBM, anl::BasisType::Gradient, anl::InterpType::Quintic)));
let frac2 = Rc::new(RefCell::new(anl::ImplicitFractal::new(anl::FractalType::FBM, anl::BasisType::Gradient, anl::InterpType::Quintic)));
let frac3 = Rc::new(RefCell::new(anl::ImplicitFractal::new(anl::FractalType::FBM, anl::BasisType::Gradient, anl::InterpType::Quintic)));
let frac4 = Rc::new(RefCell::new(anl::ImplicitFractal::new(anl::FractalType::RidgedMulti, anl::BasisType::Gradient, anl::InterpType::Quintic)));
let frac5 = Rc::new(RefCell::new(anl::ImplicitFractal::new(anl::FractalType::FBM, anl::BasisType::Gradient, anl::InterpType::Quintic)));
let frac6 = Rc::new(RefCell::new(anl::ImplicitFractal::new(anl::FractalType::FBM, anl::BasisType::Gradient, anl::InterpType::Quintic)));
let frac7 = Rc::new(RefCell::new(anl::ImplicitFractal::new(anl::FractalType::FBM, anl::BasisType::Gradient, anl::InterpType::Quintic)));
frac1.borrow_mut().set_seed(rnd.get());
frac2.borrow_mut().set_seed(rnd.get());
frac3.borrow_mut().set_seed(rnd.get());
frac4.borrow_mut().set_seed(rnd.get());
frac5.borrow_mut().set_seed(rnd.get());
frac6.borrow_mut().set_seed(rnd.get());
frac7.borrow_mut().set_seed(rnd.get());
/// AutoCorrect modules attempt to "tame" the output of a function and remap it to a different range. Some functions (mult-fractals especially)
/// are difficult to correct into an optimal range, and so AutoCorrect provides a way of doing it manually. When a function is set as the source to AutoCorrect,
/// the module will iterate some number of times, and generate that many samples from random locations in the input source. It will determine the max and min values
/// in the sample set, and from those will determine a scale/translate pair that is used to correct the output of the function into a desired range.
/// The system isn't perfect, as the random sampling might still miss the absolute max and min values of the function, but it works sufficiently well.
/// There is a bit of overhead in creating the function, during the calculate() phase when a source is initially set.
///
/// The AutoCorrect modules are set to specific ranges. The first three correct their inputs to the range (0,1). These will be used later to specify the Red,
/// Green and Blue channels of an RGBA color. The next AutoCorrect remaps its input to the range (0,360). This is used to specify a randomized rotation angle,
/// in degrees. The final three remap their inputs to the range (-1,1). These will be used to define a 3D rotation axis in RGBA color space.
///
/// Once the AutoCorrect modules are constructed, their sources are set from the fractals created earlier. Now, when the get() methods of the AutoCorrect modules
/// are called, they will first call their respective source module for a value, then apply their scale/translate pairs to "fix" the value before returning it.
let ac1 = Rc::new(RefCell::new(anl::ImplicitAutoCorrect::with_range(0.0, 1.0)));
let ac2 = Rc::new(RefCell::new(anl::ImplicitAutoCorrect::with_range(0.0, 1.0)));
let ac3 = Rc::new(RefCell::new(anl::ImplicitAutoCorrect::with_range(0.0, 1.0)));
let ac4 = Rc::new(RefCell::new(anl::ImplicitAutoCorrect::with_range(0.0, 360.0)));
let ac5 = Rc::new(RefCell::new(anl::ImplicitAutoCorrect::with_range(-1.0, 1.0)));
let ac6 = Rc::new(RefCell::new(anl::ImplicitAutoCorrect::with_range(-1.0, 1.0)));
let ac7 = Rc::new(RefCell::new(anl::ImplicitAutoCorrect::with_range(-1.0, 1.0)));
ac1.borrow_mut().set_source(Some(frac1.clone()));
ac2.borrow_mut().set_source(Some(frac2.clone()));
ac3.borrow_mut().set_source(Some(frac3.clone()));
ac4.borrow_mut().set_source(Some(frac4.clone()));
ac5.borrow_mut().set_source(Some(frac5.clone()));
ac6.borrow_mut().set_source(Some(frac6.clone()));
ac7.borrow_mut().set_source(Some(frac7.clone()));
/// The next function created is an RGBA function, CompositeChannels. This function accepts up to 4 inputs from Implicit modules, one each for the channels
/// of Red, Green, Blue and Alpha. (Or Hue, Saturation, Value and Alpha, if the function is operating in HSV space, settable via the mode parameter in the constructor.)
/// This function represents how input parameters to functions work. If a function takes an Implicit input, the input may be over-ridden to a constant double-
/// precision value, or it may be set to the output of another Implicit function.
///
/// In this case, the output of the function would have been a constant value (magenta). Any combination of constants and functional inputs may be used. In our case,
/// we are using functions for the Red, Green and Blue channels, and a constant value of 1.0 for Alpha.
let compose1 = Rc::new(RefCell::new(anl::RgbaComposeChannels::with_mode(anl::CompositeChannelsMode::Rgb)));
compose1.borrow_mut().set_red_or_hue_module(ac1.clone());
compose1.borrow_mut().set_green_or_saturation_module(ac2.clone());
compose1.borrow_mut().set_blue_or_value_module(ac3.clone());
compose1.borrow_mut().set_alpha_value(1.0);
/// snuk182 - ATTENTION. The RotateColor here does not work as intended and is not used in this example. Should be a bug in a Rust version.
///
/// Now, next we create an RGBA module of type RotateColor. This function takes an RGBA input, and 4 Implicit inputs.
/// The Implicit inputs represent the (ax,ay,az,angle) components of an axis/angle rotation. The quantity being rotated is the RGBA color, in colorspace.
/// Each color channel is first re-mapped to (-1,1), then a matrix is contructed from the axis/angle rotation. The components are transformed by this matrix,
/// then re-normalized to (0,1) and output. For the inputs, we set our ComposeChannels function as the RGBA input, and our remaining 4 fractal modules
/// for the (ax,ay,az,angle) inputs. Again, as before, it is just as easy to use double-precision constants for these inputs, and it is also as easy to specify
/// an RGBA constant for the RGBA input, rather than the compose function.
let rot = Rc::new(RefCell::new(anl::RgbaRotateColor::with_axises_angles(0.0, 0.0, 0.0, 0.0)));
rot.borrow_mut().set_degree_module(ac4.clone());
rot.borrow_mut().set_ax_module(ac5.clone());
rot.borrow_mut().set_ay_module(ac6.clone());
rot.borrow_mut().set_az_module(ac7.clone());
rot.borrow_mut().set_normalize_axis(true);
rot.borrow_mut().set_source_module(compose1.clone());
println!("Writing '{}'", NAME);
let mut imgbuf = image::ImageBuffer::new(SIZE, SIZE);
for x in 0..SIZE {
for y in 0..SIZE {
let rgba = compose1.borrow_mut().get_2d(x as f64 / SIZE as f64, y as f64 / SIZE as f64);
imgbuf.put_pixel(x, y, image::Rgba([
(rgba.r() * ::std::u8::MAX as f32) as u8,
(rgba.g() * ::std::u8::MAX as f32) as u8,
(rgba.b() * ::std::u8::MAX as f32) as u8,
(rgba.a() * ::std::u8::MAX as f32) as u8]));
}
}
let ref mut fout = File::create(format!("./target/{}.png", NAME)).unwrap();
let _ = image::ImageRgba8(imgbuf).save(fout, image::PNG);
/// To recap, we compose an RGBA from 3 channels of fractal noise, then rotate the color around an axis represented by 3 more channels of fractal noise,
/// rotating by an angle specified by a final channel of fractal noise. The results are pretty, but also pretty useless. However, it does demonstrate the basic idea
/// of the library.
println!("\nPlease visit the 'target' folder for the results");
}