134 lines
4.2 KiB
Rust
134 lines
4.2 KiB
Rust
use bevy::prelude::*;
|
|
use bevy::render::texture::{Extent3d, TextureDimension, TextureFormat};
|
|
use mandelbrot::{Bounds, Mandelbrot, TEXTURE_HEIGHT, TEXTURE_WIDTH};
|
|
use std::time::Instant;
|
|
|
|
fn main() {
|
|
// Mandelbrot::escape_time_image();
|
|
App::build()
|
|
.add_plugins(DefaultPlugins)
|
|
.add_startup_system(startup.system())
|
|
.insert_resource(TextureOptions::default())
|
|
.add_system(mandelbrot_render_system.system())
|
|
.add_system(transform_mandelbrot_system.system())
|
|
.run();
|
|
}
|
|
|
|
struct TextureOptions {
|
|
zoom: f64,
|
|
horizontal: f64,
|
|
vertical: f64,
|
|
step: f64,
|
|
iteration_limit: u32,
|
|
}
|
|
|
|
impl Default for TextureOptions {
|
|
fn default() -> Self {
|
|
Self {
|
|
zoom: 1.0,
|
|
horizontal: 0.0,
|
|
vertical: 0.0,
|
|
step: 0.01,
|
|
iteration_limit: 64,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn transform_mandelbrot_system(input: Res<Input<KeyCode>>, mut scale: ResMut<TextureOptions>) {
|
|
// Zoom: E to Zoom In, Q to Zoom Out
|
|
// Horizontal Movement: D to move right, A to move left
|
|
// Vertical Movement: W to move up, S to move Down
|
|
// R to increase the steps taken by zoom, horizontal movement, and vertical movement
|
|
// T to increase the Iteration Limit, G to decrease the iteration limit
|
|
let zoom = input.pressed(KeyCode::Q) as i8 - input.pressed(KeyCode::E) as i8;
|
|
let horizontal = input.pressed(KeyCode::D) as i8 - input.pressed(KeyCode::A) as i8;
|
|
let vertical = input.pressed(KeyCode::W) as i8 - input.pressed(KeyCode::S) as i8;
|
|
let step_change = input.pressed(KeyCode::R) as i8 - input.pressed(KeyCode::F) as i8;
|
|
let limit_change = input.just_pressed(KeyCode::T) as i8 - input.just_pressed(KeyCode::G) as i8;
|
|
|
|
scale.step += (scale.step / 10.0) * step_change as f64;
|
|
scale.vertical += scale.step * vertical as f64;
|
|
scale.horizontal += scale.step * horizontal as f64;
|
|
scale.zoom += scale.step * zoom as f64;
|
|
|
|
if limit_change == 1 {
|
|
scale.iteration_limit *= 2;
|
|
|
|
if scale.iteration_limit > 512 {
|
|
scale.iteration_limit = 512;
|
|
}
|
|
} else if limit_change == -1 {
|
|
scale.iteration_limit /= 2;
|
|
|
|
if scale.iteration_limit < 32 {
|
|
scale.iteration_limit = 32;
|
|
}
|
|
}
|
|
|
|
if scale.zoom < 0.0 {
|
|
// We can't go below 0
|
|
scale.zoom -= scale.step * zoom as f64;
|
|
|
|
// slow down our step function
|
|
scale.step /= 10.0;
|
|
}
|
|
}
|
|
|
|
fn mandelbrot_render_system(
|
|
materials: Res<Assets<ColorMaterial>>,
|
|
mut textures: ResMut<Assets<Texture>>,
|
|
scale: Res<TextureOptions>,
|
|
mut query: Query<(&mut Mandelbrot, &Handle<ColorMaterial>)>,
|
|
) {
|
|
for (mut fractal, handle) in query.iter_mut() {
|
|
if let Some(material) = materials.get(handle) {
|
|
if let Some(texture_handle) = &material.texture {
|
|
if let Some(texture) = textures.get_mut(texture_handle) {
|
|
let z = scale.zoom;
|
|
let h = scale.horizontal;
|
|
let v = scale.vertical;
|
|
let limit = scale.iteration_limit;
|
|
|
|
let x = ((-2.5 * z) + h, (1.0 * z) + h);
|
|
let y = ((-1.0 * z) - v, (1.0 * z) - v);
|
|
let bounds = Bounds::new(x, y);
|
|
|
|
let start = Instant::now();
|
|
|
|
texture
|
|
.data
|
|
.copy_from_slice(fractal.scaled_image(bounds, limit));
|
|
|
|
let _diff = Instant::now() - start;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn startup(
|
|
mut commands: Commands,
|
|
mut textures: ResMut<Assets<Texture>>,
|
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
) {
|
|
let mut fractal = Mandelbrot::default();
|
|
|
|
let texture_size = Extent3d::new(TEXTURE_WIDTH as u32, TEXTURE_HEIGHT as u32, 1);
|
|
let texture_data = fractal.image().to_vec();
|
|
|
|
let texture_handle = textures.add(Texture::new(
|
|
texture_size,
|
|
TextureDimension::D2,
|
|
texture_data,
|
|
TextureFormat::Rgba8UnormSrgb,
|
|
));
|
|
|
|
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
|
|
commands
|
|
.spawn_bundle(SpriteBundle {
|
|
material: materials.add(texture_handle.into()),
|
|
..Default::default()
|
|
})
|
|
.insert(fractal);
|
|
}
|