Initial Notan setup

This commit is contained in:
Rolf Martin Glomsrud 2023-11-28 11:23:28 +01:00
parent a4946f0117
commit cd3cef1691
7 changed files with 2566 additions and 630 deletions

2629
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -6,8 +6,10 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
macroquad = "0.3.25"
anyhow = "1.0.75"
async-trait = "0.1.64"
notan = "0.11.0"
tokio = {version = "1.34.0", features = ["full"] }
tokio-test = "*"
[profile.release]

View file

@ -1,28 +1,10 @@
use macroquad::audio::PlaySoundParams;
use macroquad::audio::Sound;
use macroquad::audio::play_sound;
use macroquad::audio::play_sound_once;
use macroquad::color;
use macroquad::color_u8;
use macroquad::rand;
use crate::soundGenerator;
#[derive(Debug, Clone, Copy)]
pub struct Bar {
pub position:usize,
pub color:color::Color,
pub position: usize,
}
impl Bar{
pub fn new(position:usize, hsl_color:f32) -> Self{
Bar{
position,
color: color::hsl_to_rgb((hsl_color as f32) , 1.0, 0.5),
}
impl Bar {
pub fn new(position: usize, hsl_color: f32) -> Self {
Bar { position }
}
}

View file

@ -1,191 +1,91 @@
use async_trait::async_trait;
use macroquad::audio::{play_sound_once, Sound, play_sound, PlaySoundParams};
use macroquad::color::{BROWN, WHITE};
use macroquad::{hash, time};
use macroquad::prelude::{clear_background, Vec2, BLACK};
use macroquad::rand::ChooseRandom;
use macroquad::shapes::draw_rectangle;
use macroquad::text::draw_text;
use macroquad::time::{get_frame_time, get_fps};
use macroquad::ui::root_ui;
use macroquad::window::{next_frame, screen_height, screen_width};
use crate::BarPlugin::Bar;
use crate::soundGenerator;
use async_trait::async_trait;
#[derive(Clone, Debug)]
pub struct GuiVec{
pub struct GuiVec {
pub list: Vec<Bar>,
initialSize:usize,
pub lastTime:f64,
pub reads:i32,
pub writes:i32,
pub comps:i32,
isPaused:bool,
delay:f32,
pub done:bool,
renderSkip:i32,
skipped:i32,
lastTouched:Vec<usize>,
lastPlayed:f64,
sounds:Vec<Sound>
initialSize: usize,
pub lastTime: f64,
pub reads: i32,
pub writes: i32,
pub comps: i32,
isPaused: bool,
delay: f32,
pub done: bool,
renderSkip: i32,
skipped: i32,
lastTouched: Vec<usize>,
lastPlayed: f64,
}
#[async_trait]
pub trait SortingList{
async fn new(length:usize, delay:f32) -> Self;
pub trait SortingList {
async fn new(length: usize, delay: f32) -> Self;
fn len(&self) -> usize;
async fn swap(&mut self, index1:usize, index2:usize) -> bool;
async fn swap(&mut self, index1: usize, index2: usize) -> bool;
async fn draw(&mut self);
fn randomize(&mut self);
fn elements(&mut self) -> std::slice::Iter<'_, Bar>;
fn get(&mut self, i:usize)-> &Bar;
fn get(&mut self, i: usize) -> &Bar;
fn lessThan(&mut self, a:usize, b:usize) -> bool;
fn lessThan(&mut self, a: usize, b: usize) -> bool;
fn lessThanEqual(&mut self, a:usize, b:usize) -> bool;
fn lessThanEqual(&mut self, a: usize, b: usize) -> bool;
fn isSorted(&mut self) -> bool;
async fn set(&mut self, i:usize, elem:Bar) -> bool;
async fn set(&mut self, i: usize, elem: Bar) -> bool;
async fn show(&mut self);
fn getListClone(&self) -> Vec<Bar>;
}
#[async_trait]
impl SortingList for GuiVec{
async fn new(length:usize, delay:f32) -> Self {
let colorStep = 360./length as f32;
let mut list:Vec<Bar> = vec!();
let freqStep = 50. + ((2000.-50.)/length as f32);
impl SortingList for GuiVec {
async fn new(length: usize, delay: f32) -> Self {
let colorStep = 360. / length as f32;
let mut list: Vec<Bar> = vec![];
let freqStep = 50. + ((2000. - 50.) / length as f32);
for i in 1..length+1 {
for i in 1..length + 1 {
let frequency = i as f32 * freqStep;
list.push(Bar::new(i, (colorStep*i as f32)/360.));
list.push(Bar::new(i, (colorStep * i as f32) / 360.));
}
//Generate sounds
let mut sounds = Vec::with_capacity(1000);
for i in (50..2051).step_by(2){
sounds.push(soundGenerator::generateTone(i as f32, 0.1).await);
}
GuiVec{
list,
initialSize:length as usize,
lastTime: 0.0 ,
reads:0,
writes:0,
comps:0,
isPaused:false,
delay,
done:false,
renderSkip:1,
skipped:0,
lastTouched:Vec::with_capacity(2),
lastPlayed:0.,
sounds,
GuiVec {
list,
initialSize: length as usize,
lastTime: 0.0,
reads: 0,
writes: 0,
comps: 0,
isPaused: false,
delay,
done: false,
renderSkip: 1,
skipped: 0,
lastTouched: Vec::with_capacity(2),
lastPlayed: 0.,
}
}
async fn draw(&mut self){
let mut frames = 0.0;
let mut delayText = self.delay.to_string();
let mut renderSkipText = self.renderSkip.to_string();
async fn draw(&mut self) {}
loop {
if self.skipped >= self.renderSkip{
clear_background(WHITE);
for (count,bar) in self.list.iter().enumerate(){
let mut color = bar.color;
if self.lastTouched.contains(&count){
color = BLACK;
}
draw_rectangle(screen_width() * ((count as f32)/(self.initialSize as f32)),screen_height() - (screen_height()/((self.len()) as f32))*bar.position as f32 , screen_width()/((self.len()) as f32), (screen_height()/((self.len()) as f32))*bar.position as f32, color);
}
root_ui().window(hash!(),Vec2::new(screen_width()*0.01, 5.), Vec2::new(800.0, 50.), |ui|{
ui.input_text(hash!(), "Delay (ms)", &mut delayText);
ui.input_text(hash!(), "StepsPrFrame (How many steps of the algorithm pr frame)", &mut renderSkipText);
draw_text(&format!("FPS: {}", get_fps()), screen_width()*0.01 + 40., 80.0, 20.0, BLACK);
draw_text(&format!("Array reads: {}", self.reads), screen_width()*0.01 + 40., 110.0, 20.0, BLACK);
draw_text(&format!("Array writes: {}", self.writes), screen_width()*0.01 + 40., 140.0, 20.0, BLACK);
draw_text(&format!("Comparisons: {}", self.comps), screen_width()*0.01 + 40., 170.0, 20.0, BLACK);
});
if root_ui().button(Vec2::new(screen_width()*0.01, 60.), "Exit"){
self.done = true;
break;
}
if root_ui().button(Vec2::new(screen_width()*0.01, 90.), "Pause"){
self.isPaused = !self.isPaused;
}
self.renderSkip = match renderSkipText.parse::<i32>(){
Ok(a) => a,
Err(_) => 1
};
self.delay = match (delayText.parse::<f32>(), self.isPaused){
(_, true) => f32::MAX,
(Ok(a), false) => a,
(Err(_), _)=> {f32::MAX}
};
next_frame().await;
self.skipped = 0;
}else{
self.skipped += 1;
}
if frames >= self.delay && !self.done{
break;
}
frames += get_frame_time()* 1000.;
}
}
fn len(&self) -> usize{
fn len(&self) -> usize {
self.list.len()
}
async fn swap(&mut self, index1:usize, index2:usize) -> bool{
async fn swap(&mut self, index1: usize, index2: usize) -> bool {
self.writes += 2;
self.reads += 2;
self.list.swap(index1, index2);
if time::get_time() + 0.1 >= self.lastPlayed{
play_sound(self.sounds[ (self.list[index1].position * 1000 / self.list.len()) ], PlaySoundParams{
looped:false,
volume:0.5
});
self.lastPlayed = time::get_time()+0.1;
}
self.lastTouched.clear();
self.lastTouched.push(index1);
self.lastTouched.push(index2);
@ -193,145 +93,123 @@ impl SortingList for GuiVec{
self.done
}
fn randomize(&mut self){
self.list.shuffle();
}
fn randomize(&mut self) {}
fn elements(&mut self) -> std::slice::Iter<'_, Bar> {
self.list.iter()
}
fn get(&mut self, i:usize)-> &Bar{
fn get(&mut self, i: usize) -> &Bar {
self.reads += 1;
self.lastTouched.clear();
self.lastTouched.push(i);
self.list.get(i).unwrap()
}
fn lessThan(&mut self, a:usize, b:usize) -> bool{
fn lessThan(&mut self, a: usize, b: usize) -> bool {
self.comps += 1;
return self.get(a).position < self.get(b).position
return self.get(a).position < self.get(b).position;
}
fn lessThanEqual(&mut self, a:usize, b:usize) -> bool{
fn lessThanEqual(&mut self, a: usize, b: usize) -> bool {
self.comps += 1;
return self.get(a).position <= b
return self.get(a).position <= b;
}
fn isSorted(&mut self) -> bool{
fn isSorted(&mut self) -> bool {
self.reads += self.len() as i32;
let mut prev = 0;
for bar in self.list.iter() {
if bar.position < prev{
if bar.position < prev {
return false;
}else{
} else {
prev = bar.position;
}
}
true
}
async fn set(&mut self, i:usize, elem:Bar) -> bool{
async fn set(&mut self, i: usize, elem: Bar) -> bool {
self.writes += 1;
self.reads += 1;
self.list[i] = elem;
self.draw().await;
if time::get_time() + 0.1 >= self.lastPlayed{
play_sound(self.sounds[ (self.list[i].position * 1000 / self.list.len()) ], PlaySoundParams{
looped:false,
volume:1.
});
self.lastPlayed = time::get_time()+0.1;
}
self.lastTouched.clear();
self.lastTouched.push(i);
self.done
}
async fn show(&mut self){
loop{
if !self.done{
async fn show(&mut self) {
loop {
if !self.done {
self.draw().await
}else{
break
} else {
break;
}
}
}
fn getListClone(&self) -> Vec<Bar>{
fn getListClone(&self) -> Vec<Bar> {
self.list.clone()
}
}
pub struct NonGuiVec{
pub struct NonGuiVec {
pub list: Vec<Bar>,
}
#[async_trait]
impl SortingList for NonGuiVec{
async fn new(length:usize, delay:f32) -> Self{
impl SortingList for NonGuiVec {
async fn new(length: usize, delay: f32) -> Self {
let mut list = Vec::new();
for i in 0..(length as usize){
for i in 0..(length as usize) {
list.push(Bar::new(i, i as f32))
}
NonGuiVec { list: list }
}
}
fn len(&self) -> usize{
fn len(&self) -> usize {
self.list.len()
}
async fn swap(&mut self, index1:usize, index2:usize) -> bool{
async fn swap(&mut self, index1: usize, index2: usize) -> bool {
self.list.swap(index1, index2);
false
}
async fn draw(&mut self){
async fn draw(&mut self) {
self.swap(0, 0).await;
}
fn randomize(&mut self){
self.list.shuffle();
}
fn randomize(&mut self) {}
fn elements(&mut self) -> std::slice::Iter<'_, Bar> {
self.list.iter()
}
fn get(&mut self, i:usize)-> &Bar{
fn get(&mut self, i: usize) -> &Bar {
self.list.get(i).unwrap()
}
fn lessThan(&mut self, a:usize, b:usize) -> bool{
return self.get(a).position < self.get(b).position
fn lessThan(&mut self, a: usize, b: usize) -> bool {
return self.get(a).position < self.get(b).position;
}
fn lessThanEqual(&mut self, a:usize, b:usize) -> bool{
return self.get(a).position <= b
fn lessThanEqual(&mut self, a: usize, b: usize) -> bool {
return self.get(a).position <= b;
}
fn isSorted(&mut self) -> bool{
fn isSorted(&mut self) -> bool {
let mut prev = 0;
for bar in self.list.iter() {
if bar.position < prev{
if bar.position < prev {
return false;
}else{
} else {
prev = bar.position;
}
}
true
}
async fn set(&mut self, i:usize, elem:Bar) -> bool{
async fn set(&mut self, i: usize, elem: Bar) -> bool {
self.list[i] = elem;
self.draw().await;
false
}
async fn show(&mut self){
}
fn getListClone(&self) -> Vec<Bar>{
async fn show(&mut self) {}
fn getListClone(&self) -> Vec<Bar> {
self.list.clone()
}
}

View file

@ -1,63 +1,24 @@
use macroquad::hash;
use macroquad::{ui::root_ui, window::screen_width, prelude::Vec2};
enum Status{
enum Status {
Open,
Closed
Closed,
}
pub struct ButtonDropDown{
selected:String,
elements:Vec<String>,
status:Status
pub struct ButtonDropDown {
selected: String,
elements: Vec<String>,
status: Status,
}
impl ButtonDropDown{
pub fn new(elements:&Vec<String>) -> Self{
ButtonDropDown{
selected:elements.get(0).unwrap().clone(),
elements:elements.clone(),
status:Status::Closed
impl ButtonDropDown {
pub fn new(elements: &Vec<String>) -> Self {
ButtonDropDown {
selected: elements.get(0).unwrap().clone(),
elements: elements.clone(),
status: Status::Closed,
}
}
pub fn render(&mut self) -> String{
let mut algo = "";
let location = Vec2::new((screen_width() / 2.) - 150., 200.);
match self.status{
Status::Open => {
let size = Vec2::new(300., (self.elements.len() as f32*25.0) + 20.0);
root_ui().window(hash!(), location, size, |ui|{
let mut position = Vec2::new(10.0, 10.);
for i in self.elements.iter(){
let label = format!("{}{}", i[0..1].to_string().to_uppercase(), i[1..i.len()].to_string());
if ui.button(position, label.as_str()){
self.selected = i.clone();
self.status = Status::Closed;
}
position.y += 25.0;
}
});
}
Status::Closed => {
root_ui().window(hash!(), location, Vec2::new(300., 50.), |ui|{
let uppercasedSelected = format!("{}{}", self.selected[0..1].to_string().to_uppercase(), self.selected[1..self.selected.len()].to_string());
ui.label(Vec2::new(10.0, 0.0), format!("Curent chosen algorithm: {}", uppercasedSelected).as_str());
if ui.button(Vec2::new(10.0, 20.0), "Open Menu!"){
self.status = Status::Open;
}
if ui.button(Vec2::new(200.0, 20.0), "RUN!"){
algo = self.selected.as_str();
}
});
},
}
algo.to_string()
pub fn render(&mut self) -> String {
"LOL".to_string()
}
}

View file

@ -1,67 +1,40 @@
mod BarPlugin;
mod GuiHookVec;
mod algorithm;
mod dropdown;
mod soundGenerator;
use std::f32::consts::PI;
use std::fs::File;
use std::path::Path;
use dropdown::ButtonDropDown;
use macroquad::prelude::*;
use macroquad::hash;
use macroquad::ui::root_ui;
#[macroquad::main("BeepSort")]
async fn main() {
let mut length = 1_usize;
let mut lengthString = "100".to_owned();
let mut delayText = "1".to_owned();
let mut algorithm = algorithm::Algorithm::new();
let mut buttonDropDown = ButtonDropDown::new(&algorithm.getAlgorithms());
loop{
clear_background(WHITE);
length = match lengthString.parse::<usize>(){
Ok(a) => a,
Err(_)=> {100}
};
let mut centerX = screen_width()/2.0;
draw_text("Sorting! Made by Polsevev", centerX-170.0, screen_height()*0.1, 100.0, BLACK);
draw_text(&get_fps().to_string(), centerX + 300., 30.0, 20.0, BLACK);
root_ui().window(hash!(), Vec2::new(centerX - 150.0, 150.), Vec2::new(300., 45.), |ui|{
ui.input_text(hash!(), "Delay (ms)", &mut delayText);
ui.input_text(hash!(), "Length Of Array!", &mut lengthString);
});
let mut algo = buttonDropDown.render();
if algo != ""{
algorithm::Algorithm::run(length, 1.0, algo.to_string()).await;
}
next_frame().await
}
use anyhow::Result;
use notan::draw::*;
use notan::prelude::*;
use tokio::runtime::Runtime;
use tokio::time::{sleep, Duration};
#[notan_main]
fn main() -> Result<(), String> {
notan::init().draw(draw).add_config(DrawConfig).build()
}
fn draw(gfx: &mut Graphics) {
let _ = run(gfx);
}
fn run(gfx: &mut Graphics) -> Result<()> {
let mut rt = Runtime::new()?;
rt.block_on(async {
let mut draw = gfx.create_draw();
draw.clear(Color::BLACK);
draw.triangle((400.0, 100.0), (100.0, 500.0), (700.0, 500.0));
gfx.render(&draw);
println!("Before sleep");
sleep(Duration::from_millis(10000)).await;
println!("After sleep");
draw.clear(Color::BLACK);
draw.rect((400., 100.), (100., 100.));
gfx.render(&draw);
});
Ok(())
}

View file

@ -1,99 +0,0 @@
use std::{f32::consts::PI};
use macroquad::{audio::{Sound, load_sound_from_bytes, play_sound_once}, window::{next_frame, screen_width, screen_height, clear_background}, text::draw_text, prelude::{BLACK, WHITE}};
const CHUNK_ID:&str = "RIFF";
const CHUNK_SIZE:&str = "----";
const FORMAT:&str = "WAVE";
//FMT sub-chunk
const SUBCHUNK_1_ID:&str = "fmt ";
const SUBCHUNK_1_SIZE:i32 = 16;
const AUDIO_FORMAT:i16 = 1;
const NUM_CHANNELS:i16 = 1;
const SAMPLE_RATE:i32 = 44100;
const BYTE_RATE:i32 = SAMPLE_RATE * NUM_CHANNELS as i32 * (SUBCHUNK_1_SIZE / 8);
const BLOACK_ALIGN:i16 = NUM_CHANNELS * (SUBCHUNK_1_SIZE / 8) as i16;
const BITS_PR_SAMPLE:i16 = 16;
//Data sub-chunk
const SUBCHUNK_2_ID:&str = "data";
const SUBCHUNK_2_SIZE:&str = "----";
const MAX_AMPLITUDE:usize = 32760;
pub async fn generateTone(frequency: f32, duration:f32) -> Sound{
// const CHUNK_ID:&str = "RIFF";
// const CHUNK_SIZE:&str = "----";
// const FORMAT:&str = "WAVE";
// //FMT sub-chunk
// const SUBCHUNK_1_ID:&str = "fmt ";
// const SUBCHUNK_1_SIZE:u32 = 16;
// const AUDIO_FORMAT:u16 = 1;
// const NUM_CHANNELS:u16 = 1;
// const SAMPLE_RATE:u32 = 44100;
// const BYTE_RATE:u32 = SAMPLE_RATE * NUM_CHANNELS as u32 * (SUBCHUNK_1_SIZE / 8);
// const BLOACK_ALIGN:u16 = NUM_CHANNELS * (SUBCHUNK_1_SIZE / 8) as u16;
// const BITS_PR_SAMPLE:u16 = 16;
// //Data sub-chunk
// const SUBCHUNK_2_ID:&str = "data";
// const SUBCHUNK_2_SIZE:&str = "----";
// const MAX_AMPLITUDE:usize = 32760;
let mut soundFileBytes = [
CHUNK_ID.as_bytes(),
CHUNK_SIZE.as_bytes(),
FORMAT.as_bytes(),
SUBCHUNK_1_ID.as_bytes(),
&SUBCHUNK_1_SIZE.to_le_bytes(),
&AUDIO_FORMAT.to_le_bytes(),
&NUM_CHANNELS.to_le_bytes(),
&SAMPLE_RATE.to_le_bytes(),
&BYTE_RATE.to_le_bytes(),
&BLOACK_ALIGN.to_le_bytes(),
&BITS_PR_SAMPLE.to_le_bytes(),
SUBCHUNK_2_ID.as_bytes(),
SUBCHUNK_2_SIZE.as_bytes()
].concat();
let startAudio = soundFileBytes.len();
let lim = ((SAMPLE_RATE as f32 * duration) as usize);
for i in 0..((SAMPLE_RATE as f32 * duration) as usize){
let amplitude = 500. * f32::sin((i as f32 - 300.) / 1200.);
let value = f32::sin((2. * PI * (i as f32) * (frequency as f32)) / SAMPLE_RATE as f32);
let channel = (amplitude * if i+100 > lim {0.} else {value});
soundFileBytes.append(&mut (channel as i16).to_le_bytes().to_vec());
}
let endAudio = soundFileBytes.len() as u32;
for (i, elem) in (endAudio-startAudio as u32).to_le_bytes().into_iter().enumerate(){
soundFileBytes[(startAudio-4)+i] = elem;
}
for (i, elem) in (36+endAudio-startAudio as u32).to_be_bytes().into_iter().enumerate(){
soundFileBytes[4+i] = elem;
}
load_sound_from_bytes(&soundFileBytes).await.expect("Failed to load")
}