Factored out crates for web version
This commit is contained in:
24
Cargo.lock
generated
24
Cargo.lock
generated
@@ -1980,19 +1980,37 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mandelia"
|
name = "mandelia_native"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"eframe",
|
||||||
|
"egui",
|
||||||
|
"mandelia_ui",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mandelia_renderer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
"eframe",
|
|
||||||
"egui",
|
|
||||||
"image",
|
"image",
|
||||||
"nalgebra",
|
"nalgebra",
|
||||||
"num",
|
"num",
|
||||||
"rayon",
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mandelia_ui"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"eframe",
|
||||||
|
"egui",
|
||||||
|
"image",
|
||||||
|
"mandelia_renderer",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matrixmultiply"
|
name = "matrixmultiply"
|
||||||
version = "0.3.10"
|
version = "0.3.10"
|
||||||
|
|||||||
21
Cargo.toml
21
Cargo.toml
@@ -1,14 +1,7 @@
|
|||||||
[package]
|
[workspace]
|
||||||
name = "mandelia"
|
resolver = "3"
|
||||||
version = "0.1.0"
|
members = [
|
||||||
edition = "2024"
|
"mandelia_renderer",
|
||||||
|
"mandelia_native",
|
||||||
[dependencies]
|
"mandelia_ui"
|
||||||
image = { version = "0.25.6", features = ["png"] }
|
]
|
||||||
rayon = "1.10.0"
|
|
||||||
num = "0.4.3"
|
|
||||||
nalgebra = "0.33.2"
|
|
||||||
anyhow = "1.0.98"
|
|
||||||
clap = { version = "4.5.40", features = ["derive"] }
|
|
||||||
egui = "0.31"
|
|
||||||
eframe = { version = "0.31", features = ["wayland", "glow"] }
|
|
||||||
|
|||||||
10
mandelia_native/Cargo.toml
Normal file
10
mandelia_native/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "mandelia_native"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
mandelia_ui = { path = "../mandelia_ui" }
|
||||||
|
eframe = { version = "0.31", features = ["wayland", "glow"] }
|
||||||
|
egui = "0.31"
|
||||||
|
|
||||||
17
mandelia_native/src/main.rs
Normal file
17
mandelia_native/src/main.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
fn main() -> eframe::Result {
|
||||||
|
// mandelia::main()
|
||||||
|
|
||||||
|
let options = eframe::NativeOptions {
|
||||||
|
..eframe::NativeOptions::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
eframe::run_native(
|
||||||
|
"Mandelia",
|
||||||
|
options,
|
||||||
|
Box::new(|cc| {
|
||||||
|
Ok(Box::new(mandelia_ui::App::new(cc)))
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is backend-independent
|
||||||
12
mandelia_renderer/Cargo.toml
Normal file
12
mandelia_renderer/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "mandelia_renderer"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
image = { version = "0.25.6", features = ["png"] }
|
||||||
|
rayon = "1.10.0"
|
||||||
|
num = "0.4.3"
|
||||||
|
nalgebra = "0.33.2"
|
||||||
|
anyhow = "1.0.98"
|
||||||
|
clap = { version = "4.5.40", features = ["derive"] }
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
//#![feature(portable_simd)]
|
//#![feature(portable_simd)]
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use image::{ImageBuffer, Rgb};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use clap::{Arg, Parser};
|
|
||||||
use image::{GrayImage, ImageBuffer, Luma, Rgb};
|
|
||||||
use image::buffer::ConvertBuffer;
|
|
||||||
use rayon::iter::ParallelIterator;
|
|
||||||
|
|
||||||
pub mod transform;
|
pub mod transform;
|
||||||
|
|
||||||
@@ -60,7 +58,6 @@ impl Config {
|
|||||||
const ESCAPE: Float = 2.;
|
const ESCAPE: Float = 2.;
|
||||||
const ESCAPE2: Float = ESCAPE * ESCAPE;
|
const ESCAPE2: Float = ESCAPE * ESCAPE;
|
||||||
|
|
||||||
let mut base = base;
|
|
||||||
let result =
|
let result =
|
||||||
std::iter::successors(Some(base), |i| Some(*i * *i + delta))
|
std::iter::successors(Some(base), |i| Some(*i * *i + delta))
|
||||||
.take(self.maxiter)
|
.take(self.maxiter)
|
||||||
@@ -114,7 +114,6 @@ pub fn transform_to_coords(mat: &MTransform) -> super::Transform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_transforms<'a>(transforms: impl Iterator<Item=impl AsRef<str>>) ->anyhow::Result<super::Transform> {
|
pub fn parse_transforms<'a>(transforms: impl Iterator<Item=impl AsRef<str>>) ->anyhow::Result<super::Transform> {
|
||||||
use super::Point;
|
|
||||||
let mat = transforms
|
let mat = transforms
|
||||||
.map(|s| parse_step(s.as_ref())
|
.map(|s| parse_step(s.as_ref())
|
||||||
.ok_or_else(|| anyhow::anyhow!("Invalid step: {:?}", s.as_ref())))
|
.ok_or_else(|| anyhow::anyhow!("Invalid step: {:?}", s.as_ref())))
|
||||||
11
mandelia_ui/Cargo.toml
Normal file
11
mandelia_ui/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "mandelia_ui"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
mandelia_renderer = {path = "../mandelia_renderer"}
|
||||||
|
anyhow = "1.0.98"
|
||||||
|
egui = "0.31"
|
||||||
|
eframe = { version = "0.31" }
|
||||||
|
image = "0.25.6"
|
||||||
@@ -1,44 +1,26 @@
|
|||||||
// extern crate mandelia;
|
use eframe::{CreationContext, Frame};
|
||||||
use eframe::{CreationContext, Frame, Result};
|
|
||||||
use egui::Context;
|
use egui::Context;
|
||||||
use egui::load::SizedTexture;
|
|
||||||
use image::EncodableLayout;
|
use image::EncodableLayout;
|
||||||
use mandelia::Float;
|
use mandelia_renderer::Float;
|
||||||
fn main() -> eframe::Result {
|
|
||||||
// mandelia::main()
|
|
||||||
|
|
||||||
let options = eframe::NativeOptions {
|
|
||||||
..eframe::NativeOptions::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
eframe::run_native(
|
|
||||||
"Mandelia",
|
|
||||||
options,
|
|
||||||
Box::new(|cc| {
|
|
||||||
Ok(Box::new(App::new(cc)))
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is backend-independent
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
tx_mat: nalgebra::Matrix5<mandelia::Float>,
|
tx_mat: mandelia_renderer::transform::MTransform,
|
||||||
transform: mandelia::Transform,
|
transform: mandelia_renderer::Transform,
|
||||||
texture: egui::TextureHandle,
|
texture: egui::TextureHandle,
|
||||||
last_render: RenderData,
|
last_render: RenderData,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug, Default)]
|
#[derive(Copy, Clone, PartialEq, Debug, Default)]
|
||||||
struct RenderData {
|
struct RenderData {
|
||||||
transform: mandelia::Transform,
|
transform: mandelia_renderer::Transform,
|
||||||
render_size: [usize; 2],
|
render_size: [usize; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
fn new(cc: &CreationContext) -> Self {
|
pub fn new(cc: &CreationContext) -> Self {
|
||||||
let mut result = Self {
|
let mut result = Self {
|
||||||
transform: Default::default(),
|
transform: Default::default(),
|
||||||
tx_mat: nalgebra::Matrix5::identity(),
|
tx_mat: mandelia_renderer::transform::MTransform::identity(),
|
||||||
texture: cc.egui_ctx.load_texture("rendering", egui::ColorImage::example(), egui::TextureOptions::LINEAR),
|
texture: cc.egui_ctx.load_texture("rendering", egui::ColorImage::example(), egui::TextureOptions::LINEAR),
|
||||||
last_render: Default::default(),
|
last_render: Default::default(),
|
||||||
};
|
};
|
||||||
@@ -47,12 +29,12 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_transform(&mut self) {
|
pub fn reset_transform(&mut self) {
|
||||||
self.tx_mat = nalgebra::Matrix5::identity();
|
self.tx_mat = mandelia_renderer::transform::MTransform::identity();
|
||||||
self.update_transform();
|
self.update_transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_transform(&mut self) {
|
fn update_transform(&mut self) {
|
||||||
use mandelia::Point;
|
use mandelia_renderer::Point;
|
||||||
let mat = &self.tx_mat;
|
let mat = &self.tx_mat;
|
||||||
let bx = Point::new(mat[(0,0)], mat[(0,1)]);
|
let bx = Point::new(mat[(0,0)], mat[(0,1)]);
|
||||||
let by = Point::new(mat[(1,0)], mat[(1,1)]);
|
let by = Point::new(mat[(1,0)], mat[(1,1)]);
|
||||||
@@ -69,12 +51,12 @@ impl App {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_transform(&mut self, xf: mandelia::transform::Type) {
|
fn add_transform(&mut self, xf: mandelia_renderer::transform::Type) {
|
||||||
self.tx_mat = mandelia::transform::MTransform::from(xf) * self.tx_mat;
|
self.tx_mat = mandelia_renderer::transform::MTransform::from(xf) * self.tx_mat;
|
||||||
self.update_transform();
|
self.update_transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_adjuster(&mut self, ui: &mut egui::Ui, label: &str, key_dec: egui::Key, key_inc: egui::Key, mut action: impl Fn(Float) -> mandelia::transform::Type) {
|
fn mk_adjuster(&mut self, ui: &mut egui::Ui, label: &str, key_dec: egui::Key, key_inc: egui::Key, action: impl Fn(Float) -> mandelia_renderer::transform::Type) {
|
||||||
let (dn, up) = ui.ctx().input(|is| (is.key_pressed(key_dec), is.key_pressed(key_inc)));
|
let (dn, up) = ui.ctx().input(|is| (is.key_pressed(key_dec), is.key_pressed(key_inc)));
|
||||||
if ui.button(format!("- ({})", key_dec.symbol_or_name())).clicked() || dn {
|
if ui.button(format!("- ({})", key_dec.symbol_or_name())).clicked() || dn {
|
||||||
self.add_transform(action(-1.));
|
self.add_transform(action(-1.));
|
||||||
@@ -94,7 +76,7 @@ impl App {
|
|||||||
};
|
};
|
||||||
if self.last_render != new_rdata {
|
if self.last_render != new_rdata {
|
||||||
self.last_render = new_rdata;
|
self.last_render = new_rdata;
|
||||||
let config = mandelia::Config {
|
let config = mandelia_renderer::Config {
|
||||||
transform: self.transform,
|
transform: self.transform,
|
||||||
width: size[0] as u32,
|
width: size[0] as u32,
|
||||||
height: size[1] as u32,
|
height: size[1] as u32,
|
||||||
@@ -111,26 +93,26 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// transform functions
|
// transform functions
|
||||||
fn mk_translation(axis: u8) -> impl Fn(Float) -> mandelia::transform::Type {
|
fn mk_translation(axis: u8) -> impl Fn(Float) -> mandelia_renderer::transform::Type {
|
||||||
move |amt| mandelia::transform::Type::Translation(axis, amt / 100.)
|
move |amt| mandelia_renderer::transform::Type::Translation(axis, amt / 100.)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_rotation(a0: u8, a1: u8) -> impl Fn(Float) -> mandelia::transform::Type {
|
fn mk_rotation(a0: u8, a1: u8) -> impl Fn(Float) -> mandelia_renderer::transform::Type {
|
||||||
move |amt| mandelia::transform::Type::Rotation(a0, a1, amt)
|
move |amt| mandelia_renderer::transform::Type::Rotation(a0, a1, amt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_scale(scale: Float) -> mandelia::transform::Type {
|
fn mk_scale(scale: Float) -> mandelia_renderer::transform::Type {
|
||||||
mandelia::transform::Type::Scale(1. + scale / 4.)
|
mandelia_renderer::transform::Type::Scale(1. + scale / 4.)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum JumpMode {
|
pub enum JumpMode {
|
||||||
Mandelbrot,
|
Mandelbrot,
|
||||||
Julia,
|
Julia,
|
||||||
Origin,
|
Origin,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for App {
|
impl eframe::App for App {
|
||||||
fn update(&mut self, ctx: &Context, frame: &mut Frame) {
|
fn update(&mut self, ctx: &Context, _frame: &mut Frame) {
|
||||||
if let Some(jump_mode) = ctx.input(|is| {
|
if let Some(jump_mode) = ctx.input(|is| {
|
||||||
if is.key_pressed(egui::Key::Num0) {
|
if is.key_pressed(egui::Key::Num0) {
|
||||||
Some(JumpMode::Origin)
|
Some(JumpMode::Origin)
|
||||||
@@ -142,7 +124,7 @@ impl eframe::App for App {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
use mandelia::transform::Type;
|
use mandelia_renderer::transform::Type;
|
||||||
match jump_mode {
|
match jump_mode {
|
||||||
JumpMode::Mandelbrot => {
|
JumpMode::Mandelbrot => {
|
||||||
self.reset_transform();
|
self.reset_transform();
|
||||||
@@ -160,7 +142,6 @@ impl eframe::App for App {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
egui::SidePanel::left("nav").show(ctx, |ui| {
|
egui::SidePanel::left("nav").show(ctx, |ui| {
|
||||||
use mandelia::transform::Type;
|
|
||||||
use egui::Key;
|
use egui::Key;
|
||||||
egui::Grid::new("nav_grid")
|
egui::Grid::new("nav_grid")
|
||||||
.num_columns(3)
|
.num_columns(3)
|
||||||
@@ -169,9 +150,9 @@ impl eframe::App for App {
|
|||||||
self.mk_adjuster(ui, "base y", Key::S, Key::W, mk_translation(1));
|
self.mk_adjuster(ui, "base y", Key::S, Key::W, mk_translation(1));
|
||||||
self.mk_adjuster(ui, "delta x", Key::J, Key::L, mk_translation(2));
|
self.mk_adjuster(ui, "delta x", Key::J, Key::L, mk_translation(2));
|
||||||
self.mk_adjuster(ui, "delta y", Key::K, Key::I, mk_translation(3));
|
self.mk_adjuster(ui, "delta y", Key::K, Key::I, mk_translation(3));
|
||||||
|
|
||||||
self.mk_adjuster(ui, "scale", Key::OpenBracket, Key::CloseBracket, mk_scale);
|
self.mk_adjuster(ui, "scale", Key::OpenBracket, Key::CloseBracket, mk_scale);
|
||||||
|
|
||||||
self.mk_adjuster(ui, "xy", Key::Q, Key::E, mk_rotation(0, 1));
|
self.mk_adjuster(ui, "xy", Key::Q, Key::E, mk_rotation(0, 1));
|
||||||
self.mk_adjuster(ui, "XY", Key::U, Key::O, mk_rotation(2, 3));
|
self.mk_adjuster(ui, "XY", Key::U, Key::O, mk_rotation(2, 3));
|
||||||
self.mk_adjuster(ui, "xX", Key::F, Key::G, mk_rotation(0, 2));
|
self.mk_adjuster(ui, "xX", Key::F, Key::G, mk_rotation(0, 2));
|
||||||
@@ -185,7 +166,7 @@ impl eframe::App for App {
|
|||||||
let size = base_size * ui.pixels_per_point();
|
let size = base_size * ui.pixels_per_point();
|
||||||
let size = [size.x as usize, size.y as usize];
|
let size = [size.x as usize, size.y as usize];
|
||||||
self.update_texture(size);
|
self.update_texture(size);
|
||||||
ui.add(egui::Image::from_texture(SizedTexture::new(&self.texture, base_size)));
|
ui.add(egui::Image::from_texture(egui::load::SizedTexture::new(&self.texture, base_size)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user