378 lines
12 KiB
Rust
378 lines
12 KiB
Rust
use crate::color::color_serde;
|
|
use std::f32::consts::PI;
|
|
|
|
use iced::Size;
|
|
use iced::Vector;
|
|
use iced::mouse;
|
|
use iced::widget::canvas;
|
|
use iced::widget::canvas::{Frame, Stroke, Style};
|
|
use iced::{Color, Point, Rectangle, Renderer, Theme};
|
|
use kira::sound::static_sound::StaticSoundData;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
pub trait RotationExt {
|
|
fn rotate(&mut self, teta: f32) -> Self;
|
|
}
|
|
|
|
impl RotationExt for Vector {
|
|
fn rotate(&mut self, teta: f32) -> Vector {
|
|
Vector::new(
|
|
self.x * teta.cos() - self.y * teta.sin(),
|
|
self.x * teta.sin() + self.y * teta.cos(),
|
|
)
|
|
}
|
|
}
|
|
#[derive(Serialize, Deserialize, Clone)]
|
|
pub struct PolygonFrame {
|
|
pub teta: f32,
|
|
pub polygons: Vec<Polygon>,
|
|
}
|
|
|
|
impl PolygonFrame {
|
|
pub fn all_sound_to_play_btw(&self, before: f32, after: f32) -> Vec<&StaticSoundData> {
|
|
let mut all_sound: Vec<&StaticSoundData> = vec![];
|
|
for poly in &self.polygons {
|
|
all_sound.extend(poly.sound_to_play_btw(before, after));
|
|
}
|
|
all_sound
|
|
}
|
|
pub fn update(&mut self, path_of_project: &str) {
|
|
for poly in &mut self.polygons {
|
|
poly.update(path_of_project);
|
|
}
|
|
}
|
|
|
|
pub fn default() -> PolygonFrame {
|
|
PolygonFrame {
|
|
teta: 0.0,
|
|
polygons: vec![],
|
|
}
|
|
}
|
|
pub fn draw_in_frame(&self, frame: &mut Frame, size: Size) {
|
|
let radius = size.height / 2.0 - (size.height / 10.);
|
|
let mut vec = Vector::new(0.0, -radius);
|
|
let c = Point {
|
|
x: size.width / 2.,
|
|
y: size.height / 2.,
|
|
};
|
|
|
|
// Draw Circle
|
|
let circle = canvas::Path::circle(c, radius);
|
|
frame.stroke(
|
|
&circle,
|
|
Stroke {
|
|
width: 6.0,
|
|
style: Style::Solid(Color::from_rgba8(210, 193, 182, 0.25)),
|
|
..Stroke::default()
|
|
},
|
|
);
|
|
|
|
// Draw all polygons by there points
|
|
for poly in &self.polygons {
|
|
let l = poly.points_teta.len();
|
|
let mut line: canvas::Path;
|
|
let mut t1: f32;
|
|
let mut t2: f32;
|
|
let mut color: Color;
|
|
for i in 0..l {
|
|
t1 = poly.points_teta[i] + poly.global_teta;
|
|
t2 = poly.points_teta[(i + 1) % l] + poly.global_teta;
|
|
line = canvas::Path::line(c + vec.rotate(t1), c + vec.rotate(t2));
|
|
color = poly.color.clone();
|
|
color.a = 0.25;
|
|
frame.stroke(
|
|
&line,
|
|
Stroke {
|
|
width: 4.0,
|
|
style: Style::Solid(poly.color.clone()),
|
|
..Stroke::default()
|
|
},
|
|
);
|
|
}
|
|
}
|
|
/*
|
|
// Draw the red dot on the current position
|
|
let dot = canvas::Path::circle(frame.center() + vec.rotate(self.teta), 10.0);
|
|
frame.fill(&dot, Color::from_rgb(1.0, 0.0, 0.0));
|
|
*/
|
|
// Draw the frame
|
|
/*
|
|
frame.stroke_rectangle(
|
|
iced::Point { x: 0.0, y: 0.0 },
|
|
size,
|
|
Stroke {
|
|
width: 8.0,
|
|
style: Style::Solid(Color::from_rgb8(207, 74, 28)),
|
|
..Stroke::default()
|
|
},
|
|
);*/
|
|
}
|
|
}
|
|
|
|
impl<Message> canvas::Program<Message> for PolygonFrame {
|
|
// No internal state
|
|
type State = ();
|
|
|
|
fn draw(
|
|
&self,
|
|
_state: &(),
|
|
renderer: &Renderer,
|
|
_theme: &Theme,
|
|
bounds: Rectangle,
|
|
_cursor: mouse::Cursor,
|
|
) -> Vec<canvas::Geometry> {
|
|
let mut frame = canvas::Frame::new(renderer, bounds.size());
|
|
let radius = frame.size().width.min(frame.size().height) / 2.0 - 32.0;
|
|
let mut vec = Vector::new(0.0, -radius);
|
|
let c = frame.center();
|
|
frame.fill_rectangle(
|
|
iced::Point { x: 0., y: 0. },
|
|
frame.size(),
|
|
Color::from_rgb8(27, 60, 83),
|
|
);
|
|
// Draw Circle
|
|
let circle = canvas::Path::circle(frame.center(), radius);
|
|
frame.stroke(
|
|
&circle,
|
|
Stroke {
|
|
width: 6.0,
|
|
style: Style::Solid(Color::from_rgb8(210, 193, 182)),
|
|
..Stroke::default()
|
|
},
|
|
);
|
|
|
|
// Draw all polygons by there points
|
|
for poly in &self.polygons {
|
|
let l = poly.points_teta.len();
|
|
let mut line: canvas::Path;
|
|
let mut t1: f32;
|
|
let mut t2: f32;
|
|
for i in 0..l {
|
|
t1 = poly.points_teta[i] + poly.global_teta;
|
|
t2 = poly.points_teta[(i + 1) % l] + poly.global_teta;
|
|
line = canvas::Path::line(c + vec.rotate(t1), c + vec.rotate(t2));
|
|
frame.stroke(
|
|
&line,
|
|
Stroke {
|
|
width: 4.0,
|
|
style: Style::Solid(poly.color.clone()),
|
|
..Stroke::default()
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
// Draw the red dot on the current position
|
|
let dot = canvas::Path::circle(frame.center() + vec.rotate(self.teta), 10.0);
|
|
frame.fill(&dot, Color::from_rgb(1.0, 0.0, 0.0));
|
|
|
|
// Draw the frame
|
|
frame.stroke_rectangle(
|
|
iced::Point { x: 0.0, y: 0.0 },
|
|
frame.size(),
|
|
Stroke {
|
|
width: 16.0,
|
|
style: Style::Solid(Color::from_rgb8(207, 74, 28)),
|
|
..Stroke::default()
|
|
},
|
|
);
|
|
|
|
// Then, we produce the geometry
|
|
vec![frame.into_geometry()]
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct Polygon {
|
|
pub global_teta: f32,
|
|
pub points_teta: Vec<f32>,
|
|
#[serde(skip, default = "dummy_sound")]
|
|
pub sound: StaticSoundData,
|
|
pub sound_name: String,
|
|
pub name: String,
|
|
#[serde(with = "color_serde")]
|
|
pub color: Color,
|
|
#[serde(skip)]
|
|
pub show_color_picker: bool,
|
|
}
|
|
#[warn(dead_code)]
|
|
impl Polygon {
|
|
pub fn update(&mut self, path_of_project: &str) {
|
|
let path = format!("{0}", &self.sound_name);
|
|
dbg!(path.clone());
|
|
self.sound = if path == String::from("Default_Sound.ogg") {
|
|
StaticSoundData::from_file("assets/Default_Sound.ogg").expect("fail to load the sound")
|
|
} else {
|
|
StaticSoundData::from_file(format!("{0}/{1}", path_of_project, path))
|
|
.expect("fail to load the sound")
|
|
}
|
|
}
|
|
pub fn sound_to_play_btw(&self, before: f32, after: f32) -> Vec<&StaticSoundData> {
|
|
let mut sound_to_play: Vec<&StaticSoundData> = vec![];
|
|
if after < before {
|
|
sound_to_play = self.sound_to_play_btw(before, 2.0 * PI);
|
|
sound_to_play.extend(self.sound_to_play_btw(0.0, after));
|
|
return sound_to_play;
|
|
}
|
|
let mut p_g;
|
|
for p in self.points_teta.clone() {
|
|
p_g = (p + self.global_teta) % (2.0 * PI);
|
|
if before <= p_g && p_g <= after {
|
|
sound_to_play.push(&self.sound);
|
|
}
|
|
}
|
|
sound_to_play
|
|
}
|
|
pub fn default(sound: StaticSoundData) -> Self {
|
|
Polygon {
|
|
global_teta: 0.,
|
|
points_teta: vec![],
|
|
sound: sound,
|
|
sound_name: "Default_Sound.ogg".to_string(),
|
|
name: "".to_string(),
|
|
color: Color::BLACK,
|
|
show_color_picker: false,
|
|
}
|
|
}
|
|
|
|
pub fn n_gon(n_side: u8, sound: StaticSoundData) -> Self {
|
|
let mut v: Vec<f32> = Vec::with_capacity(n_side as usize);
|
|
for i in 0..n_side {
|
|
v.push((i as f32 * 2.0 * PI) / n_side as f32);
|
|
}
|
|
let mut p = Polygon::default(sound);
|
|
p.points_teta = v;
|
|
p
|
|
}
|
|
pub fn segment(sound: StaticSoundData) -> Self {
|
|
Polygon::n_gon(2, sound)
|
|
}
|
|
|
|
pub fn triangle(sound: StaticSoundData) -> Self {
|
|
Polygon::n_gon(3, sound)
|
|
}
|
|
|
|
pub fn square(sound: StaticSoundData) -> Self {
|
|
Polygon::n_gon(4, sound)
|
|
}
|
|
|
|
pub fn nr_6_in_30(sound: StaticSoundData) -> Self {
|
|
let mut p = Polygon::default(sound);
|
|
p.points_teta = vec![
|
|
2.0 * 5.0 * PI / 30.0,
|
|
2.0 * 6.0 * PI / 30.0,
|
|
2.0 * 12.0 * PI / 30.0,
|
|
2.0 * 18.0 * PI / 30.0,
|
|
2.0 * 24.0 * PI / 30.0,
|
|
2.0 * 25.0 * PI / 30.0,
|
|
];
|
|
p
|
|
}
|
|
pub fn nr_7_in_30(sound: StaticSoundData) -> Self {
|
|
let mut p = Polygon::default(sound);
|
|
p.points_teta = vec![
|
|
0.0,
|
|
2.0 * 6.0 * PI / 30.0,
|
|
2.0 * 7.0 * PI / 30.0,
|
|
2.0 * 13.0 * PI / 30.0,
|
|
2.0 * 17.0 * PI / 30.0,
|
|
2.0 * 23.0 * PI / 30.0,
|
|
2.0 * 24.0 * PI / 30.0,
|
|
];
|
|
p
|
|
}
|
|
pub fn nr_8_in_30(sound: StaticSoundData) -> Self {
|
|
let mut p = Polygon::default(sound);
|
|
p.points_teta = vec![
|
|
2.0 * PI / 30.0,
|
|
2.0 * 5.0 * PI / 30.0,
|
|
2.0 * 11.0 * PI / 30.0,
|
|
2.0 * 12.0 * PI / 30.0,
|
|
2.0 * 18.0 * PI / 30.0,
|
|
2.0 * 19.0 * PI / 30.0,
|
|
2.0 * 25.0 * PI / 30.0,
|
|
2.0 * 29.0 * PI / 30.0,
|
|
];
|
|
p
|
|
}
|
|
pub fn nr_9_in_30(sound: StaticSoundData) -> Self {
|
|
let mut p = Polygon::default(sound);
|
|
p.points_teta = vec![
|
|
0.0,
|
|
2.0 * PI / 30.0,
|
|
2.0 * 7.0 * PI / 30.0,
|
|
2.0 * 11.0 * PI / 30.0,
|
|
2.0 * 13.0 * PI / 30.0,
|
|
2.0 * 17.0 * PI / 30.0,
|
|
2.0 * 19.0 * PI / 30.0,
|
|
2.0 * 23.0 * PI / 30.0,
|
|
2.0 * 29.0 * PI / 30.0,
|
|
];
|
|
p
|
|
}
|
|
pub fn nr_8_in_42(sound: StaticSoundData) -> Self {
|
|
let mut p = Polygon::default(sound);
|
|
p.points_teta = vec![
|
|
2.0 * 3.0 * PI / 42.0,
|
|
2.0 * 9.0 * PI / 42.0,
|
|
2.0 * 14.0 * PI / 42.0,
|
|
2.0 * 15.0 * PI / 42.0,
|
|
2.0 * 27.0 * PI / 42.0,
|
|
2.0 * 28.0 * PI / 42.0,
|
|
2.0 * 33.0 * PI / 42.0,
|
|
2.0 * 39.0 * PI / 42.0,
|
|
];
|
|
p
|
|
}
|
|
pub fn nr_9_in_42(sound: StaticSoundData) -> Self {
|
|
let mut p = Polygon::default(sound);
|
|
p.points_teta = vec![
|
|
0.0,
|
|
2.0 * 6.0 * PI / 42.0,
|
|
2.0 * 11.0 * PI / 42.0,
|
|
2.0 * 12.0 * PI / 42.0,
|
|
2.0 * 17.0 * PI / 42.0,
|
|
2.0 * 25.0 * PI / 42.0,
|
|
2.0 * 30.0 * PI / 42.0,
|
|
2.0 * 31.0 * PI / 42.0,
|
|
2.0 * 36.0 * PI / 42.0,
|
|
];
|
|
p
|
|
}
|
|
pub fn nr_10a_in_42(sound: StaticSoundData) -> Self {
|
|
let mut p = Polygon::default(sound);
|
|
p.points_teta = vec![
|
|
2.0 * 6.0 * PI / 42.0,
|
|
2.0 * 7.0 * PI / 42.0,
|
|
2.0 * 11.0 * PI / 42.0,
|
|
2.0 * 12.0 * PI / 42.0,
|
|
2.0 * 17.0 * PI / 42.0,
|
|
2.0 * 25.0 * PI / 42.0,
|
|
2.0 * 30.0 * PI / 42.0,
|
|
2.0 * 31.0 * PI / 42.0,
|
|
2.0 * 35.0 * PI / 42.0,
|
|
2.0 * 36.0 * PI / 42.0,
|
|
];
|
|
p
|
|
}
|
|
pub fn nr_10b_in_42(sound: StaticSoundData) -> Self {
|
|
let mut p = Polygon::default(sound);
|
|
p.points_teta = vec![
|
|
0.0,
|
|
2.0 * 1.0 * PI / 42.0,
|
|
2.0 * 5.0 * PI / 42.0,
|
|
2.0 * 13.0 * PI / 42.0,
|
|
2.0 * 18.0 * PI / 42.0,
|
|
2.0 * 19.0 * PI / 42.0,
|
|
2.0 * 24.0 * PI / 42.0,
|
|
2.0 * 29.0 * PI / 42.0,
|
|
2.0 * 30.0 * PI / 42.0,
|
|
2.0 * 41.0 * PI / 42.0,
|
|
];
|
|
p
|
|
}
|
|
}
|
|
fn dummy_sound() -> StaticSoundData {
|
|
StaticSoundData::from_file("assets/Default_Sound.ogg").expect("Fail to load audio")
|
|
}
|