Skip to content

Commit

Permalink
Add missing fractal shaders
Browse files Browse the repository at this point in the history
  • Loading branch information
SkwalExe committed Nov 27, 2024
1 parent 2bf3147 commit dcaa230
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 33 deletions.
15 changes: 5 additions & 10 deletions src/commands/frac.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use futures::executor;

use super::Command;
use crate::{
fractals::{get_frac_index_by_name, FRACTALS},
Expand Down Expand Up @@ -43,14 +41,11 @@ pub(crate) fn execute_frac(state: &mut AppState, args: Vec<&str>) -> Result<(),
state.log_info_title(frac_obj.name, frac_obj.details);
} else {
state.request_redraw();
state.render_settings.frac_index = frac_i;
state.log_success(format!("Successfully selected fractal: <acc {frac_name}>."));
if let Err(err) = executor::block_on(state.render_settings.update_fractal_shader(None)) {
state.render_settings.use_gpu = false;
return Err(format!(
"Disabling GPU mode because fractal shader could not be loaded: {err}"
));
};
state.render_settings.select_fractal(frac_i)?;
state.log_success(format!(
"Successfully selected fractal: <acc {}>.",
state.render_settings.get_frac_obj().name
));
}
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ pub(crate) fn execute_gpu(state: &mut AppState, _args: Vec<&str>) -> Result<(),
}
Err(err) => state.log_error(format!("GPU mode could not be initialized: {err}")),
};
state.request_redraw();
}
state.request_redraw();
Ok(())
}
pub(crate) const GPU: Command = Command {
Expand Down
40 changes: 20 additions & 20 deletions src/components/canvas.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Contains the `Canvas` widget.
use futures::executor;
use ratatui::{
buffer::Buffer,
crossterm::event::{KeyCode, MouseButton, MouseEvent, MouseEventKind},
Expand Down Expand Up @@ -81,6 +80,7 @@ impl<'a> Canvas<'a> {
state.render_settings.prec,
&state.render_settings.cell_size * state.move_dist,
));
state.request_redraw();
}
// When L is pressed move the position of the canvas
// to the right by n times the cell size.
Expand All @@ -93,6 +93,7 @@ impl<'a> Canvas<'a> {
state.render_settings.prec,
&state.render_settings.cell_size * state.move_dist,
));
state.request_redraw();
}
// When J is pressed move the position of the canvas
// down by n times the cell size.
Expand All @@ -105,6 +106,7 @@ impl<'a> Canvas<'a> {
state.render_settings.prec,
&state.render_settings.cell_size * state.move_dist,
));
state.request_redraw();
}
// When K is pressed move the position of the canvas
// up by n times the cell size.
Expand All @@ -117,43 +119,47 @@ impl<'a> Canvas<'a> {
state.render_settings.prec,
&state.render_settings.cell_size * state.move_dist,
));
state.request_redraw();
}
// When S is pressed increase the cell size, which will zoom out of the canvas
KeyCode::Char('s') => state.zoom(ZoomDirection::Out),
KeyCode::Char('s') => {
state.zoom(ZoomDirection::Out);
state.request_redraw();
}
// When D is pressed decrease the cell size, which will zoom into the canvas
KeyCode::Char('d') => state.zoom(ZoomDirection::In),
KeyCode::Char('d') => {
state.zoom(ZoomDirection::In);
state.request_redraw();
}
// decrease the decimal precision
KeyCode::Char('u') => {
state.increment_decimal_prec(-10);
state.request_redraw();
}
// increase the decimal precision
KeyCode::Char('i') => {
state.increment_decimal_prec(10);
state.request_redraw();
}
// reset the position to the origin and the cell size.
KeyCode::Char('r') => {
state.render_settings.reset_cell_size();
state.render_settings.reset_pos();
state.request_redraw();
}
// Increment the selected frac index
KeyCode::Char('f') => {
state.render_settings.frac_index =
(state.render_settings.frac_index + 1) % FRACTALS.len();
if let Err(err) =
executor::block_on(state.render_settings.update_fractal_shader(None))
{
state.render_settings.use_gpu = false;
state.log_error(format!(
"Disabling GPU mode because fractal shader could not be loaded: {err}"
));
};
let frac_i = (state.render_settings.frac_index + 1) % FRACTALS.len();
if let Err(err) = state.render_settings.select_fractal(frac_i) {
state.log_error(err);
}
state.request_redraw();
}
// Increment the color palette index
KeyCode::Char('c') => {
state.render_settings.palette_index =
(state.render_settings.palette_index + 1) % colors::COLORS.len();
state.request_repaint();
return;
}
// Todo: remove duplication for + and -
// Increment color scheme offset
Expand All @@ -165,22 +171,19 @@ impl<'a> Canvas<'a> {
% state.render_settings.get_palette().colors.len() as i32;

state.request_repaint();
return;
}
// Increment color scheme offset
KeyCode::Char('+') => {
state.render_settings.color_scheme_offset =
(state.render_settings.color_scheme_offset + 1)
% state.render_settings.get_palette().colors.len() as i32;
state.request_repaint();
return;
}
// Cycle through the void fills
KeyCode::Char('v') => {
state.render_settings.void_fill_index =
(state.render_settings.void_fill_index + 1) % void_fills().len();
state.request_repaint();
return;
}
// Increment the maximum divergence
KeyCode::Char('o') => state.increment_max_iter(10),
Expand All @@ -191,9 +194,6 @@ impl<'a> Canvas<'a> {
return;
}
}

// For now, all events need to redraw the canvas.
state.request_redraw();
}
}
impl<'a> Widget for Canvas<'a> {
Expand Down
2 changes: 2 additions & 0 deletions src/frac_logic/gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ impl RenderSettings {
let cs_descriptor = match self.get_frac_obj().name.to_lowercase().as_ref() {
// TODO: implement other fractal shaders
"mandelbrot" => wgpu::include_wgsl!("shaders/mandelbrot.wgsl"),
"burningship" => wgpu::include_wgsl!("shaders/burning_ship.wgsl"),
"julia" => wgpu::include_wgsl!("shaders/julia.wgsl"),
_ => {
if let Some(sender) = sender {
sender
Expand Down
22 changes: 22 additions & 0 deletions src/frac_logic/render_settings.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Contains the `RenderSettings` struct.
use futures::executor;
use rand::{thread_rng, Rng};
use ratatui::style::Color;
use rug::{Complex, Float};
Expand Down Expand Up @@ -59,9 +60,30 @@ impl Default for RenderSettings {
}

impl RenderSettings {
/// Changes the selected fractal. Will update the GPU render pipeline if GPU mode
/// is enabled, if then an error is met, GPU mode will be disabled and an error message will be
/// returned. Note that this method will never fail, even though it can return an error
/// message.
pub(crate) fn select_fractal(&mut self, frac_i: usize) -> Result<(), String> {
self.frac_index = frac_i;
if self.use_gpu {
if let Err(err) = executor::block_on(self.update_fractal_shader(None)) {
self.use_gpu = false;
return Err(format!(
"Disabling GPU mode because fractal shader could not be loaded: {err}"
));
};
}
Ok(())
}

/// Returns the selected color palette.
pub(crate) fn get_palette(&self) -> &'static Palette {
&COLORS[self.palette_index]
}

/// Returns a color corresponding to the given iteration count, using
/// the currently selected color palette.
pub(crate) fn color_from_div(&self, diverg: &i32) -> Color {
let palette = self.get_palette();
let mut rng = thread_rng();
Expand Down
41 changes: 40 additions & 1 deletion src/frac_logic/shaders/burning_ship.wgsl
Original file line number Diff line number Diff line change
@@ -1 +1,40 @@
// TODO
struct Params {
max_iter: i32,
width_px: i32,
}


@group(0) @binding(0) var<storage, read> input_buf: array<vec2<f32>>;
@group(0) @binding(1) var<storage, read_write> output_buf: array<i32>;
@group(0) @binding(2) var<uniform> params: Params;


fn bship_iterations(real: f32, imag: f32) -> i32 {
var iter: i32 = 0i;
var z: vec2<f32> = vec2<f32>(0f, 0f);

while length(z) < 4f && iter < params.max_iter {
z = vec2<f32>(
pow(z.x, 2f) - pow(z.y, 2f) + real,
2f * abs(z.x) * abs(z.y) + imag
);
iter = iter + 1i;
}
if iter == params.max_iter {
return -1i;
}
return iter;
}

@compute
@workgroup_size(1)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let x: u32 = global_id.x;
let y: u32 = global_id.y;
let index = y * u32(params.width_px) + x;
let point: vec2<f32> = input_buf[index];
// *-1 to invert the y and x axis artificially
output_buf[index] = bship_iterations(point.x * -1f, point.y * -1f);
}


44 changes: 43 additions & 1 deletion src/frac_logic/shaders/julia.wgsl
Original file line number Diff line number Diff line change
@@ -1 +1,43 @@
// TODO
struct Params {
max_iter: i32,
width_px: i32,
}


@group(0) @binding(0) var<storage, read> input_buf: array<vec2<f32>>;
@group(0) @binding(1) var<storage, read_write> output_buf: array<i32>;
@group(0) @binding(2) var<uniform> params: Params;


fn julia_iterations(real: f32, imag: f32) -> i32 {
var iter: i32 = 0i;
var z: vec2<f32> = vec2<f32>(real, imag);

while length(z) < 4f && iter < params.max_iter {
// z = vec2<f32>(
// pow(z.x, 2f) - pow(z.y, 2f),
// 2f * z.x * z.y + imag
// );
z = vec2<f32>(
pow(z.x, 2f) - pow(z.y, 2f) - 1,
2f * z.x * z.y
);
iter = iter + 1i;
}
if iter == params.max_iter {
return -1i;
}
return iter;
}

@compute
@workgroup_size(1)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let x: u32 = global_id.x;
let y: u32 = global_id.y;
let index = y * u32(params.width_px) + x;
let point: vec2<f32> = input_buf[index];
output_buf[index] = julia_iterations(point.x, point.y);
}


0 comments on commit dcaa230

Please sign in to comment.