Compare commits
17 commits
7b39c8e6dc
...
b6eb5720c9
Author | SHA1 | Date | |
---|---|---|---|
b6eb5720c9 | |||
2190440b3f | |||
95aaed66e7 | |||
d994f316a7 | |||
ff3a6ee5fc | |||
f8ed6d2ce1 | |||
ba055093be | |||
3315342aa5 | |||
c56b0b6227 | |||
a0d82499c0 | |||
825bcfa5a1 | |||
e34287df9e | |||
5d39e227b6 | |||
5c2607b574 | |||
14c98f484b | |||
1dec7aad56 | |||
0194f60ca3 |
17 changed files with 350 additions and 121 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,3 @@
|
||||||
/target
|
/target
|
||||||
*.lock
|
*.lock
|
||||||
bmp/out.bmp
|
bmp/out.*
|
||||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -9,4 +9,16 @@ package.repository = "https://codeberg.org/p6nj/bent"
|
||||||
package.keywords = ["databending", "data-bending", "bending", "bend", "art"]
|
package.keywords = ["databending", "data-bending", "bending", "bend", "art"]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
fundsp = "0.18.2"
|
||||||
|
image = "0.25.1"
|
||||||
|
anyhow = "1.0.86"
|
||||||
|
bingus = { version = "0.1.0", path = "bingus" }
|
||||||
|
num-traits = "0.2.19"
|
||||||
dasp_sample = "0.11.0"
|
dasp_sample = "0.11.0"
|
||||||
|
rayon = "1.10.0"
|
||||||
|
dirs = "5.0.1"
|
||||||
|
rfd = "0.14.1"
|
||||||
|
derive-new = "0.6.0"
|
||||||
|
infer = "0.16.0"
|
||||||
|
indicatif = { version = "0.17.8", features = ["rayon"] }
|
||||||
|
getset = "0.1.2"
|
||||||
|
|
24
LICENSE
Normal file
24
LICENSE
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
|
@ -11,7 +11,14 @@ keywords.workspace = true
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.86"
|
image = { workspace = true }
|
||||||
bmp = "0.5.0"
|
fundsp = { workspace = true }
|
||||||
dasp_sample = "0.11.0"
|
anyhow = { workspace = true }
|
||||||
fundsp = { version = "0.18.1", default-features = false, features = ["std"] }
|
bingus = { workspace = true }
|
||||||
|
dasp_sample = { workspace = true }
|
||||||
|
rayon = { workspace = true }
|
||||||
|
dirs = { workspace = true }
|
||||||
|
rfd = { workspace = true }
|
||||||
|
derive-new = { workspace = true }
|
||||||
|
infer = { workspace = true }
|
||||||
|
indicatif = { workspace = true }
|
||||||
|
|
|
@ -1,75 +1,131 @@
|
||||||
use std::fs::File;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use bmp::{open, Pixel};
|
use bingus::rawdata::RawData;
|
||||||
use dasp_sample::{FromSample, Sample, ToSample, U24};
|
use dasp_sample::{Sample, U24};
|
||||||
|
use derive_new::new;
|
||||||
|
use dirs::{download_dir, home_dir, picture_dir};
|
||||||
|
use fundsp::math::uparc;
|
||||||
|
use image::{ImageFormat, ImageReader, RgbImage};
|
||||||
|
use indicatif::{ParallelProgressIterator, ProgressStyle};
|
||||||
|
use rayon::{iter::ParallelIterator, slice::ParallelSlice};
|
||||||
|
use rfd::FileDialog;
|
||||||
|
|
||||||
|
struct Files {
|
||||||
|
input: PathBuf,
|
||||||
|
output: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(new)]
|
||||||
|
struct DataPath {
|
||||||
|
files: Files,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Files {
|
||||||
|
fn try_new(input: PathBuf, output: PathBuf) -> Result<Self> {
|
||||||
|
Ok(Files {
|
||||||
|
input: Self::verify_image_file(input, "input")?,
|
||||||
|
output: Self::verify_image_file(output, "output")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn verify_image_file(path: PathBuf, label: &'static str) -> Result<PathBuf> {
|
||||||
|
ImageFormat::from_path(&path).with_context(|| {
|
||||||
|
format!("your {label} image must have a supported extension from this list:")
|
||||||
|
+ &ImageFormat::all()
|
||||||
|
.map(|format| {
|
||||||
|
format!(
|
||||||
|
"\n\t{:?} ({})",
|
||||||
|
format,
|
||||||
|
format
|
||||||
|
.extensions_str()
|
||||||
|
.iter()
|
||||||
|
.fold(String::new(), |acc, x| acc + &format!(".{x}, "))
|
||||||
|
.strip_suffix(", ")
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.reduce(|acc, x| acc + &x)
|
||||||
|
.unwrap()
|
||||||
|
})?;
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
fn prompt() -> Result<Self> {
|
||||||
|
Files::try_new(
|
||||||
|
FileDialog::new()
|
||||||
|
.set_title("Input image")
|
||||||
|
.set_directory(working_dir())
|
||||||
|
.add_filter(
|
||||||
|
"images",
|
||||||
|
&ImageFormat::all()
|
||||||
|
.map(ImageFormat::extensions_str)
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<&'static &'static str>>(),
|
||||||
|
)
|
||||||
|
.pick_file()
|
||||||
|
.context("no input image selected")?,
|
||||||
|
FileDialog::new()
|
||||||
|
.set_title("Output image")
|
||||||
|
.set_directory(working_dir())
|
||||||
|
.save_file()
|
||||||
|
.context("no output filename provided")?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let mut bmp = open("bmp/bigsample.bmp")?;
|
let dp = DataPath::new(Files::prompt()?);
|
||||||
for y in 0..bmp.get_height() {
|
let img = RawData::<RgbImage>::new(
|
||||||
for x in 0..bmp.get_width() {
|
ImageReader::open(dp.files.input)?
|
||||||
if x > 100 && x < 300 {
|
.decode()
|
||||||
bmp.set_pixel(
|
.context("can't use this picture")?
|
||||||
x,
|
.into_rgb8(),
|
||||||
y,
|
);
|
||||||
sample_to_rgb(rgb_to_sample::<f64>(bmp.get_pixel(x, y))),
|
let processed = RawData::<RgbImage>::new(
|
||||||
);
|
RgbImage::from_raw(
|
||||||
}
|
img.width(),
|
||||||
}
|
img.height(),
|
||||||
}
|
img.par_chunks_exact(3)
|
||||||
bmp.to_writer(&mut File::create("bmp/out.bmp")?)?;
|
.progress_count((img.width() * img.height()).into())
|
||||||
|
.with_style(ProgressStyle::with_template(
|
||||||
|
"[{eta}] {bar:40.green/red} {pos}/{len} pixels",
|
||||||
|
)?)
|
||||||
|
.map(|px: &[u8]| (px[2] as i32) | ((px[1] as i32) << 8) | ((px[0] as i32) << 16))
|
||||||
|
.map(U24::new_unchecked)
|
||||||
|
.map(|x| uparc(x.to_sample()))
|
||||||
|
.flat_map(|sample: f32| {
|
||||||
|
let rgb: U24 = sample.to_sample();
|
||||||
|
let rgo = ((rgb) >> 8.into()) << 8.into();
|
||||||
|
let roo = ((rgo) >> 16.into()) << 16.into();
|
||||||
|
[
|
||||||
|
((roo) >> 16.into()).inner() as u8,
|
||||||
|
((rgo - roo) >> 8.into()).inner() as u8,
|
||||||
|
(rgb - rgo).inner() as u8,
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
processed.save(dp.files.output)?;
|
||||||
|
|
||||||
|
// let bytes: Vec<u8> = (1u8..7).into_iter().collect();
|
||||||
|
// assert_eq!(
|
||||||
|
// bytes,
|
||||||
|
// bytes
|
||||||
|
// .chunks_exact(3)
|
||||||
|
// .map(|px: &[u8]| f64::from_ne_bytes(array::from_fn(|i| px[i % px.len()])))
|
||||||
|
// .flat_map(|px: f64| -> [u8; 3] {
|
||||||
|
// let px = px.to_ne_bytes();
|
||||||
|
// array::from_fn(move |i| px[i])
|
||||||
|
// })
|
||||||
|
// .collect::<Vec<u8>>()
|
||||||
|
// );
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rgb_to_sample<T: Sample + FromSample<U24>>(pix: Pixel) -> T {
|
fn working_dir() -> PathBuf {
|
||||||
(((U24::from(pix.r)) << 16.into()) | (U24::from(pix.g) << 8.into()) | U24::from(pix.b))
|
picture_dir()
|
||||||
.to_sample()
|
.or(download_dir())
|
||||||
}
|
.or(home_dir())
|
||||||
|
.unwrap_or("/".into())
|
||||||
fn sample_to_rgb<T: Sample + ToSample<U24>>(sample: T) -> Pixel {
|
|
||||||
let rgb: U24 = sample.to_sample();
|
|
||||||
let rgo = ((rgb) >> 8.into()) << 8.into();
|
|
||||||
let roo = ((rgo) >> 16.into()) << 16.into();
|
|
||||||
Pixel::new(
|
|
||||||
((roo) >> 16.into()).inner() as u8,
|
|
||||||
((rgo - roo) >> 8.into()).inner() as u8,
|
|
||||||
(rgb - rgo).inner() as u8,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use bmp::Pixel;
|
|
||||||
use dasp_sample::{Sample, I24, I48, U24, U48};
|
|
||||||
|
|
||||||
use super::{rgb_to_sample, sample_to_rgb};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sample_convert_consistency() {
|
|
||||||
let original = U24::from(42);
|
|
||||||
assert_eq!(original.clone(), original.to_sample::<f64>().to_sample())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn rgb2s2rgb_type_consistency() {
|
|
||||||
let pix = Pixel::new(45, 18, 143);
|
|
||||||
assert_eq!(
|
|
||||||
sample_to_rgb(rgb_to_sample::<f32>(pix)),
|
|
||||||
sample_to_rgb(rgb_to_sample::<f64>(pix))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
sample_to_rgb(rgb_to_sample::<I24>(pix)),
|
|
||||||
sample_to_rgb(rgb_to_sample::<I48>(pix))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
sample_to_rgb(rgb_to_sample::<U24>(pix)),
|
|
||||||
sample_to_rgb(rgb_to_sample::<U48>(pix))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn rgb2s2rgb() {
|
|
||||||
let pix = Pixel::new(45, 18, 143);
|
|
||||||
assert_eq!(pix, (sample_to_rgb(rgb_to_sample::<f64>(pix))));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,4 +10,11 @@ keywords.workspace = true
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
wasm-bindgen = "0.2"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
|
24
bent/LICENSE
Normal file
24
bent/LICENSE
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
12
bent/assets/bent.svg
Normal file
12
bent/assets/bent.svg
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
path {
|
||||||
|
stroke: blue;
|
||||||
|
stroke-width: .2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<path
|
||||||
|
d="M 0 0 L 100 100 M 100 0 L 0 100 M 1 0 L 99 100 M 0 1 L 100 99 M 2 0 L 98 100 M 0 2 L 100 98 M 3 0 L 97 100 M 0 3 L 100 97 M 4 0 L 96 100 M 0 4 L 100 96 M 5 0 L 95 100 M 0 5 L 100 95 M 6 0 L 94 100 M 0 6 L 100 94 M 7 0 L 93 100 M 0 7 L 100 93 M 8 0 L 92 100 M 0 8 L 100 92 M 9 0 L 91 100 M 0 9 L 100 91 M 10 0 L 90 100 M 0 10 L 100 90 M 11 0 L 89 100 M 0 11 L 100 89 M 12 0 L 88 100 M 0 12 L 100 88 M 13 0 L 87 100 M 0 13 L 100 87 M 14 0 L 86 100 M 0 14 L 100 86 M 15 0 L 85 100 M 0 15 L 100 85 M 16 0 L 84 100 M 0 16 L 100 84 M 17 0 L 83 100 M 0 17 L 100 83 M 18 0 L 82 100 M 0 18 L 100 82 M 19 0 L 81 100 M 0 19 L 100 81 M 20 0 L 80 100 M 0 20 L 100 80 M 21 0 L 79 100 M 0 21 L 100 79 M 22 0 L 78 100 M 0 22 L 100 78 M 23 0 L 77 100 M 0 23 L 100 77 M 24 0 L 76 100 M 0 24 L 100 76 M 25 0 L 75 100 M 0 25 L 100 75 M 26 0 L 74 100 M 0 26 L 100 74 M 27 0 L 73 100 M 0 27 L 100 73 M 28 0 L 72 100 M 0 28 L 100 72 M 29 0 L 71 100 M 0 29 L 100 71 M 30 0 L 70 100 M 0 30 L 100 70 M 31 0 L 69 100 M 0 31 L 100 69 M 32 0 L 68 100 M 0 32 L 100 68 M 33 0 L 67 100 M 0 33 L 100 67 M 34 0 L 66 100 M 0 34 L 100 66 M 35 0 L 65 100 M 0 35 L 100 65 M 36 0 L 64 100 M 0 36 L 100 64 M 37 0 L 63 100 M 0 37 L 100 63 M 38 0 L 62 100 M 0 38 L 100 62 M 39 0 L 61 100 M 0 39 L 100 61 M 40 0 L 60 100 M 0 40 L 100 60 M 41 0 L 59 100 M 0 41 L 100 59 M 42 0 L 58 100 M 0 42 L 100 58 M 43 0 L 57 100 M 0 43 L 100 57 M 44 0 L 56 100 M 0 44 L 100 56 M 45 0 L 55 100 M 0 45 L 100 55 M 46 0 L 54 100 M 0 46 L 100 54 M 47 0 L 53 100 M 0 47 L 100 53 M 48 0 L 52 100 M 0 48 L 100 52 M 49 0 L 51 100 M 0 49 L 100 51 M 50 0 L 50 100 M 0 50 L 100 50 M 51 0 L 49 100 M 0 51 L 100 49 M 52 0 L 48 100 M 0 52 L 100 48 M 53 0 L 47 100 M 0 53 L 100 47 M 54 0 L 46 100 M 0 54 L 100 46 M 55 0 L 45 100 M 0 55 L 100 45 M 56 0 L 44 100 M 0 56 L 100 44 M 57 0 L 43 100 M 0 57 L 100 43 M 58 0 L 42 100 M 0 58 L 100 42 M 59 0 L 41 100 M 0 59 L 100 41 M 60 0 L 40 100 M 0 60 L 100 40 M 61 0 L 39 100 M 0 61 L 100 39 M 62 0 L 38 100 M 0 62 L 100 38 M 63 0 L 37 100 M 0 63 L 100 37 M 64 0 L 36 100 M 0 64 L 100 36 M 65 0 L 35 100 M 0 65 L 100 35 M 66 0 L 34 100 M 0 66 L 100 34 M 67 0 L 33 100 M 0 67 L 100 33 M 68 0 L 32 100 M 0 68 L 100 32 M 69 0 L 31 100 M 0 69 L 100 31 M 70 0 L 30 100 M 0 70 L 100 30 M 71 0 L 29 100 M 0 71 L 100 29 M 72 0 L 28 100 M 0 72 L 100 28 M 73 0 L 27 100 M 0 73 L 100 27 M 74 0 L 26 100 M 0 74 L 100 26 M 75 0 L 25 100 M 0 75 L 100 25 M 76 0 L 24 100 M 0 76 L 100 24 M 77 0 L 23 100 M 0 77 L 100 23 M 78 0 L 22 100 M 0 78 L 100 22 M 79 0 L 21 100 M 0 79 L 100 21 M 80 0 L 20 100 M 0 80 L 100 20 M 81 0 L 19 100 M 0 81 L 100 19 M 82 0 L 18 100 M 0 82 L 100 18 M 83 0 L 17 100 M 0 83 L 100 17 M 84 0 L 16 100 M 0 84 L 100 16 M 85 0 L 15 100 M 0 85 L 100 15 M 86 0 L 14 100 M 0 86 L 100 14 M 87 0 L 13 100 M 0 87 L 100 13 M 88 0 L 12 100 M 0 88 L 100 12 M 89 0 L 11 100 M 0 89 L 100 11 M 90 0 L 10 100 M 0 90 L 100 10 M 91 0 L 9 100 M 0 91 L 100 9 M 92 0 L 8 100 M 0 92 L 100 8 M 93 0 L 7 100 M 0 93 L 100 7 M 94 0 L 6 100 M 0 94 L 100 6 M 95 0 L 5 100 M 0 95 L 100 5 M 96 0 L 4 100 M 0 96 L 100 4 M 97 0 L 3 100 M 0 97 L 100 3 M 98 0 L 2 100 M 0 98 L 100 2 M 99 0 L 1 100 M 0 99 L 100 1"
|
||||||
|
mask="url(#Mask)" />
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
15
bent/assets/path-generator.py
Normal file
15
bent/assets/path-generator.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
p = lambda x: print(x, end=" ")
|
||||||
|
|
||||||
|
|
||||||
|
def line(coords: tuple[tuple[int]]):
|
||||||
|
p(f"M {coords[0][0]} {coords[0][1]} L {coords[1][0]} {coords[1][1]}")
|
||||||
|
|
||||||
|
|
||||||
|
n = 100
|
||||||
|
line(((0, 0), (n, n)))
|
||||||
|
line(((n, 0), (0, n)))
|
||||||
|
for i in range(1, n):
|
||||||
|
line(((i, 0), (n - i, n)))
|
||||||
|
line(((0, i), (n, n - i)))
|
||||||
|
|
||||||
|
print()
|
36
bent/index.html
Normal file
36
bent/index.html
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en-US">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>BENT</title>
|
||||||
|
<link rel="shortcut icon" href="assets/bent.svg" type="image/svg">
|
||||||
|
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import init, { greet } from "./pkg/bent.js";
|
||||||
|
init().then(() => {
|
||||||
|
document.getElementById("greet-button").onclick = () => {
|
||||||
|
const name = document.getElementById("name").value;
|
||||||
|
greet(name);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>BENT</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<form onsubmit="return false;">
|
||||||
|
<p>
|
||||||
|
<label>Enter your name:</label>
|
||||||
|
<input type="text" id="name" />
|
||||||
|
</p>
|
||||||
|
<button id="greet-button">Greet</button>
|
||||||
|
<button type="reset">Reset</button>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
7
bent/src/js.rs
Normal file
7
bent/src/js.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
#[wasm_bindgen(js_namespace = console)]
|
||||||
|
pub fn log(a: &str);
|
||||||
|
}
|
10
bent/src/lib.rs
Normal file
10
bent/src/lib.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
#[macro_use]
|
||||||
|
pub mod macros;
|
||||||
|
pub mod js;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn greet(name: &str) {
|
||||||
|
println!("Hello, {name}!");
|
||||||
|
}
|
27
bent/src/macros.rs
Normal file
27
bent/src/macros.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
macro_rules! println {
|
||||||
|
($($t:tt)*) => (crate::js::log(&format_args!($($t)*).to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! dbg {
|
||||||
|
// NOTE: We cannot use `concat!` to make a static string as a format argument
|
||||||
|
// of `eprintln!` because `file!` could contain a `{` or
|
||||||
|
// `$val` expression could be a block (`{ .. }`), in which case the `eprintln!`
|
||||||
|
// will be malformed.
|
||||||
|
() => {
|
||||||
|
println!("[{}:{}:{}]", file!(), line!(), column!())
|
||||||
|
};
|
||||||
|
($val:expr $(,)?) => {
|
||||||
|
// Use of `match` here is intentional because it affects the lifetimes
|
||||||
|
// of temporaries - https://stackoverflow.com/a/48732525/1063961
|
||||||
|
match $val {
|
||||||
|
tmp => {
|
||||||
|
println!("[{}:{}:{}] {} = {:#?}",
|
||||||
|
file!(), line!(), column!(), stringify!($val), &tmp);
|
||||||
|
tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($($val:expr),+ $(,)?) => {
|
||||||
|
($(dbg!($val)),+,)
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
fn main() {
|
|
||||||
println!("Hello, world!");
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "bingus"
|
name = "bingus"
|
||||||
version = "0.1.0"
|
version = "0.1.2"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
description.workspace = true
|
description.workspace = true
|
||||||
|
@ -10,4 +10,4 @@ keywords.workspace = true
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dasp_sample = { workspace = true }
|
derive-new = { workspace = true }
|
||||||
|
|
|
@ -1,43 +1,2 @@
|
||||||
use dasp_sample::{FromSample, Sample, U24, U48};
|
#![forbid(unused_crate_dependencies)]
|
||||||
|
pub mod rawdata;
|
||||||
pub trait IntoSample<F>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
fn _prepare(self) -> F;
|
|
||||||
fn into_sample<S: Sample + FromSample<F>>(self) -> S {
|
|
||||||
Sample::from_sample(self._prepare())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSample<u8> for u8 {
|
|
||||||
fn _prepare(self) -> u8 {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSample<u16> for [u8; 2] {
|
|
||||||
fn _prepare(self) -> u16 {
|
|
||||||
((self[0]._prepare() as u16) << 8) | self[1] as u16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSample<U24> for [u8; 3] {
|
|
||||||
fn _prepare(self) -> U24 {
|
|
||||||
(U24::from([self[0], self[1]]._prepare()) << 8.into()) | U24::from(self[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSample<u32> for [u8; 4] {
|
|
||||||
fn _prepare(self) -> u32 {
|
|
||||||
(([self[0], self[1], self[2]]._prepare().inner() as u32) << 8) | self[3] as u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSample<U48> for [u8; 6] {
|
|
||||||
fn _prepare(self) -> U48 {
|
|
||||||
((U48::from([self[0], self[1], self[2], self[3]]._prepare()) << 16u8.into())
|
|
||||||
| (U48::from(self[4]) << 8u8.into()))
|
|
||||||
| U48::from(self[5])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
36
bingus/src/rawdata.rs
Normal file
36
bingus/src/rawdata.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use derive_new::new;
|
||||||
|
|
||||||
|
pub type Bytes = [u8];
|
||||||
|
|
||||||
|
#[derive(new)]
|
||||||
|
pub struct RawData<D: Deref<Target = Bytes>>(D);
|
||||||
|
|
||||||
|
impl<D> From<RawData<D>> for Vec<u8>
|
||||||
|
where
|
||||||
|
D: Deref<Target = Bytes>,
|
||||||
|
{
|
||||||
|
fn from(value: RawData<D>) -> Self {
|
||||||
|
value.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> Clone for RawData<D>
|
||||||
|
where
|
||||||
|
D: Clone + Deref<Target = Bytes>,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.deref().clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> Deref for RawData<D>
|
||||||
|
where
|
||||||
|
D: Deref<Target = Bytes>,
|
||||||
|
{
|
||||||
|
type Target = D;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue