-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a demo showcasing a procedurally generated flame
- Loading branch information
Showing
8 changed files
with
441 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
runner = "probe-run --chip RP2040" | ||
|
||
rustflags = [ | ||
"-C", "linker=flip-link", | ||
"-C", "link-arg=--nmagic", | ||
"-C", "link-arg=-Tlink.x", | ||
"-C", "link-arg=-Tdefmt.x", | ||
|
||
# Code-size optimizations. | ||
# trap unreachable can save a lot of space, but requires nightly compiler. | ||
# uncomment the next line if you wish to enable it | ||
# "-Z", "trap-unreachable=no", | ||
"-C", "inline-threshold=5", | ||
"-C", "no-vectorize-loops", | ||
] | ||
|
||
[build] | ||
target = "thumbv6m-none-eabi" | ||
|
||
[env] | ||
DEFMT_LOG = "debug" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
[package] | ||
edition = "2021" | ||
name = "dashy" | ||
version = "0.1.0" | ||
|
||
[dependencies] | ||
cortex-m = "0.7" | ||
cortex-m-rt = "0.7" | ||
embedded-hal = { version = "0.2.5", features = ["unproven"] } | ||
embedded-time = "0.12" | ||
|
||
defmt = "0.3" | ||
defmt-rtt = "0.3" | ||
panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
|
||
rp-pico = "0.6.0" | ||
|
||
embedded-graphics = "0.7.1" | ||
hub75-pio = { path = "../../" } | ||
|
||
nalgebra = { version = "0.31.4", default-features = false, features= ["libm"] } | ||
libm = "0.2.6" | ||
|
||
# cargo build/run | ||
[profile.dev] | ||
codegen-units = 1 | ||
debug = 2 | ||
debug-assertions = true | ||
incremental = false | ||
opt-level = 3 | ||
overflow-checks = true | ||
|
||
# cargo build/run --release | ||
[profile.release] | ||
codegen-units = 1 | ||
debug = 2 | ||
debug-assertions = false | ||
incremental = false | ||
lto = 'fat' | ||
opt-level = 3 | ||
overflow-checks = false | ||
|
||
# do not optimize proc-macro crates = faster builds from scratch | ||
[profile.dev.build-override] | ||
codegen-units = 8 | ||
debug = false | ||
debug-assertions = false | ||
opt-level = 0 | ||
overflow-checks = false | ||
|
||
[profile.release.build-override] | ||
codegen-units = 8 | ||
debug = false | ||
debug-assertions = false | ||
opt-level = 0 | ||
overflow-checks = false | ||
|
||
# cargo test | ||
[profile.test] | ||
codegen-units = 1 | ||
debug = 2 | ||
debug-assertions = true | ||
incremental = false | ||
opt-level = 3 | ||
overflow-checks = true | ||
|
||
# cargo test --release | ||
[profile.bench] | ||
codegen-units = 1 | ||
debug = 2 | ||
debug-assertions = false | ||
incremental = false | ||
lto = 'fat' | ||
opt-level = 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
[default.probe] | ||
protocol = "Swd" | ||
speed = 20000 | ||
# If you only have one probe cargo embed will pick automatically | ||
# Otherwise: add your probe's VID/PID/serial to filter | ||
|
||
## rust-dap | ||
# usb_vid = "6666" | ||
# usb_pid = "4444" | ||
# serial = "test" | ||
|
||
|
||
[default.flashing] | ||
enabled = true | ||
|
||
[default.reset] | ||
enabled = true | ||
halt_afterwards = false | ||
|
||
[default.general] | ||
chip = "RP2040" | ||
log_level = "WARN" | ||
# RP2040 does not support connect_under_reset | ||
connect_under_reset = false | ||
|
||
[default.rtt] | ||
enabled = true | ||
up_mode = "NoBlockSkip" | ||
channels = [ | ||
{ up = 0, down = 0, name = "name", up_mode = "NoBlockSkip", format = "Defmt" }, | ||
] | ||
timeout = 3000 | ||
show_timestamps = true | ||
log_enabled = false | ||
log_path = "./logs" | ||
|
||
[default.gdb] | ||
enabled = false | ||
gdb_connection_string = "127.0.0.1:2345" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
//! This build script copies the `memory.x` file from the crate root into | ||
//! a directory where the linker can always find it at build time. | ||
//! For many projects this is optional, as the linker always searches the | ||
//! project root directory -- wherever `Cargo.toml` is. However, if you | ||
//! are using a workspace or have a more complicated build setup, this | ||
//! build script becomes required. Additionally, by requesting that | ||
//! Cargo re-run the build script whenever `memory.x` is changed, | ||
//! updating `memory.x` ensures a rebuild of the application with the | ||
//! new memory settings. | ||
use std::env; | ||
use std::fs::File; | ||
use std::io::Write; | ||
use std::path::PathBuf; | ||
|
||
fn main() { | ||
// Put `memory.x` in our output directory and ensure it's | ||
// on the linker search path. | ||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
File::create(out.join("memory.x")) | ||
.unwrap() | ||
.write_all(include_bytes!("memory.x")) | ||
.unwrap(); | ||
println!("cargo:rustc-link-search={}", out.display()); | ||
|
||
// By default, Cargo will re-run a build script whenever | ||
// any file in the project changes. By specifying `memory.x` | ||
// here, we ensure the build script is only re-run when | ||
// `memory.x` is changed. | ||
println!("cargo:rerun-if-changed=memory.x"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Compatible CMSIS-DAP debug probes | ||
|
||
## Raspberry Pi Pico | ||
|
||
You can use a second Pico as your debugger. | ||
|
||
- Download this file: https://github.com/majbthrd/DapperMime/releases/download/20210225/raspberry_pi_pico-DapperMime.uf2 | ||
- Boot the Pico in bootloader mode by holding the bootset button while plugging it in | ||
- Open the drive RPI-RP2 when prompted | ||
- Copy raspberry_pi_pico-DapperMime.uf2 from Downloads into RPI-RP2 | ||
- Connect the debug pins of your CMSIS-DAP Pico to the target one | ||
- Connect GP2 on the Probe to SWCLK on the Target | ||
- Connect GP3 on the Probe to SWDIO on the Target | ||
- Connect a ground line from the CMSIS-DAP Probe to the Target too | ||
|
||
## WeAct MiniF4 | ||
https://therealprof.github.io/blog/usb-c-pill-part1/ | ||
|
||
## HS-Probe | ||
https://github.com/probe-rs/hs-probe | ||
|
||
## ST-LINK v2 clone | ||
It's getting harder to source these with stm32f103's as time goes on, so you might be better off choosing a stm32f103 dev board | ||
|
||
Firmware: https://github.com/devanlai/dap42 | ||
|
||
## LPC-Link2 | ||
https://www.nxp.com/design/microcontrollers-developer-resources/lpc-link2:OM13054 | ||
|
||
## MCU-Link | ||
https://www.nxp.com/part/MCU-LINK#/ | ||
|
||
## DAPLink | ||
You can use DAPLink firmware with any of it's supported chips (LPC4322, LPC11U35, K20, K22, KL26). You'll need to use the 'develop' branch to use GCC to build it. You'll need to find a chip with the correct | ||
|
||
Firmware source: https://github.com/ARMmbed/DAPLink/tree/develop |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
MEMORY { | ||
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 | ||
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 | ||
RAM : ORIGIN = 0x20000000, LENGTH = 256K | ||
} | ||
|
||
EXTERN(BOOT2_FIRMWARE) | ||
|
||
SECTIONS { | ||
/* ### Boot loader */ | ||
.boot2 ORIGIN(BOOT2) : | ||
{ | ||
KEEP(*(.boot2)); | ||
} > BOOT2 | ||
} INSERT BEFORE .text; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
use libm::{floorf, modff}; | ||
use nalgebra::{clamp, SMatrix, Vector2, Vector3}; | ||
|
||
type FlameCanvas = SMatrix<Vector3<u8>, 32, 32>; | ||
|
||
fn fractf(x: f32) -> f32 { | ||
return modff(x).0; | ||
} | ||
|
||
fn hash(x: Vector2<f32>) -> Vector2<f32> { | ||
let k: Vector2<f32> = Vector2::new(0.3183099, 0.3678794); | ||
let x = x.component_mul(&k) + k.yx(); | ||
2.0 * (16.0 * k * fractf(x.x * x.y * (x.x + x.y))).map(fractf) - Vector2::from_element(1.0) | ||
} | ||
|
||
fn noised(p: Vector2<f32>) -> Vector3<f32> { | ||
let i = p.map(floorf); | ||
let f = p.map(fractf); | ||
|
||
let u1 = f * 6.0 - Vector2::from_element(15.0); | ||
let u2 = f.component_mul(&u1) + Vector2::from_element(10.0); | ||
let u = f | ||
.component_mul(&f) | ||
.component_mul(&f) | ||
.component_mul(&f) | ||
.component_mul(&u2); | ||
|
||
let du1 = f - Vector2::from_element(2.0); | ||
let du2 = f.component_mul(&du1) + Vector2::from_element(1.0); | ||
let du = 30.0 * f.component_mul(&f).component_mul(&du2); | ||
|
||
let ga = hash(i + Vector2::new(0.0, 0.0)); | ||
let gb = hash(i + Vector2::new(1.0, 0.0)); | ||
let gc = hash(i + Vector2::new(0.0, 1.0)); | ||
let gd = hash(i + Vector2::new(1.0, 1.0)); | ||
|
||
let fa = f - Vector2::new(0.0, 0.0); | ||
let fb = f - Vector2::new(1.0, 0.0); | ||
let fc = f - Vector2::new(0.0, 1.0); | ||
let fd = f - Vector2::new(1.0, 1.0); | ||
|
||
let va = ga.dot(&fa); | ||
let vb = ga.dot(&fb); | ||
let vc = ga.dot(&fc); | ||
let vd = ga.dot(&fd); | ||
|
||
let r1 = va + u.x * (vb - va) + u.y * (vc - va) + u.x * u.y * (va - vb - vc + vd); | ||
let r22 = u.yx() * (va - vb - vc + vd) + Vector2::new(vb, vc) - Vector2::from_element(va); | ||
let r2 = ga | ||
+ u.x * (gb - ga) | ||
+ u.y * (gc - ga) | ||
+ u.x * u.y * (ga - gb - gc + gd) | ||
+ du.component_mul(&r22); | ||
|
||
Vector3::new(r1, r2.x, r2.y) | ||
} | ||
|
||
fn stepf(x: f32, l: f32) -> f32 { | ||
if x < l { | ||
1.0 | ||
} else { | ||
0.0 | ||
} | ||
} | ||
|
||
fn sdf_circle(p: Vector2<f32>, r: f32) -> f32 { | ||
p.norm() - r | ||
} | ||
|
||
fn shader(t: usize, x: f32, y: f32, _color: Vector3<u8>) -> Vector3<f32> { | ||
let uv = Vector2::new(x as f32, y as f32) / 31f32; | ||
let octaves = 7f32; | ||
let noise_amount = noised(octaves * uv + Vector2::new(0.0, t as f32)).x; | ||
let y_gradient = clamp(0.7 - uv.y, 0.0, 1.0) * 0.6; | ||
let sdf_noise = Vector2::new(0.1, 2.5 * y_gradient) * noise_amount; | ||
|
||
let p1 = uv - Vector2::new(0.6, 0.7) + sdf_noise; | ||
let p2 = uv - Vector2::new(0.6, 0.775) + sdf_noise; | ||
let p3 = uv - Vector2::new(0.6, 0.80) + sdf_noise; | ||
|
||
let amount_outer = stepf(sdf_circle(p1, 0.25), 0.0); | ||
let amount_inner = stepf(sdf_circle(p2, 0.175), 0.0); | ||
let amount_center = stepf(sdf_circle(p3, 0.075), 0.0); | ||
|
||
let couter: Vector3<f32> = Vector3::new(214.0, 10.0, 3.0); | ||
let cinner: Vector3<f32> = Vector3::new(214.0, 63.0, 2.0); | ||
let center: Vector3<f32> = Vector3::new(255.0, 204.0, 23.0); | ||
|
||
if amount_center > 0.0 { | ||
center | ||
} else if amount_inner > 0.0 { | ||
cinner | ||
} else if amount_outer > 0.0 { | ||
couter | ||
} else { | ||
Vector3::from_element(0f32) | ||
} | ||
} | ||
|
||
fn into_color_vec(color: Vector3<f32>) -> Vector3<u8> { | ||
color.map(|v| u8::try_from(floorf(v) as u32).unwrap_or(0)) | ||
} | ||
|
||
pub fn tick(t: usize) -> FlameCanvas { | ||
let canvas = FlameCanvas::from_element(Vector3::repeat(0)); | ||
canvas | ||
.map_with_location(|x, y, c| shader(t, x as f32, y as f32, c)) | ||
.map(into_color_vec) | ||
} |
Oops, something went wrong.