use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::mpsc::{self, Receiver, TryRecvError};
use cgmath::{Deg, Quaternion, Rotation3, Vector3};
use crate::asset::AssetManagerRc;
use crate::audio::{AudioEngineRc, AudioFileFactory, AudioFileHandle, AudioFileTimestamp};
use crate::model::*;
use crate::scene::{GameParam, Scene, SceneFactory, SceneInput, SceneManager};
use crate::songinfo::{SongInfo, ColorScheme};
use crate::ui::{AboutWindow, PoweredByWindow, SearchWindow};
const POINTER_COLOR: Color = Color([0.4, 0.4, 0.4]);
pub struct MenuParam;
impl MenuParam {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
}
}
}
impl SceneFactory for MenuParam {
type Scene = Menu;
fn load(self, asset_mgr: AssetManagerRc, model_reg: &mut ModelRegistry, audio_engine: AudioEngineRc) -> Self::Scene {
Menu::new(self, asset_mgr, model_reg, audio_engine)
}
}
pub struct Menu {
asset_mgr: AssetManagerRc,
audio_engine: AudioEngineRc,
about_window: Rc<Window>,
search_window_rx: Receiver<()>,
search_window: Rc<Window>,
poweredby_window: Rc<Window>,
saber_l: Rc<Saber>,
saber_r: Rc<Saber>,
pointer: Rc<Pointer>,
inner: RefCell<Inner>,
}
struct Inner {
audio_file_opt: Option<AudioFileHandle>,
}
impl Menu {
fn new(_param: MenuParam, asset_mgr: AssetManagerRc, model_reg: &mut ModelRegistry, audio_engine: AudioEngineRc) -> Self {
let window_param = WindowParam::new(500, 500, move || {
AboutWindow::new().unwrap()
});
let about_window = model_reg.create(window_param);
about_window.set_visible(true);
about_window.set_scale(2.0, 2.0);
about_window.set_pos(&Vector3::new(-5.0, 3.5, 2.0));
about_window.set_rot(&Quaternion::from_angle_z(Deg(45.0)));
let (search_window_tx, search_window_rx) = mpsc::channel();
let window_param = WindowParam::new(1000, 500, move || {
let window = SearchWindow::new().unwrap();
window.on_start({
let search_window_tx = search_window_tx.clone();
move || search_window_tx.send(()).unwrap()
});
window
});
let search_window = model_reg.create(window_param);
search_window.set_visible(true);
search_window.set_scale(4.0, 2.0);
search_window.set_pos(&Vector3::new(0.0, 4.0, 2.0));
let window_param = WindowParam::new(500, 500, move || {
PoweredByWindow::new().unwrap()
});
let poweredby_window = model_reg.create(window_param);
poweredby_window.set_visible(true);
poweredby_window.set_scale(2.0, 2.0);
poweredby_window.set_pos(&Vector3::new(5.0, 3.5, 2.0));
poweredby_window.set_rot(&Quaternion::from_angle_z(Deg(-45.0)));
let floor_param = FloorParam::new(&COLOR_WHITE);
let floor = model_reg.create(floor_param);
floor.set_visible(true);
floor.set_pos(&Vector3::new(0.0, 0.0, 0.0));
let color_scheme = ColorScheme::default();
let color_l = color_scheme.get_color_l();
let color_r = color_scheme.get_color_r();
let saber_param = SaberParam::new(color_l, &SABER_HANDLE_PHONG_PARAM, color_l, &SABER_RAY_PHONG_PARAM);
let saber_l = model_reg.create(saber_param);
let saber_param = SaberParam::new(color_r, &SABER_HANDLE_PHONG_PARAM, color_r, &SABER_RAY_PHONG_PARAM);
let saber_r = model_reg.create(saber_param);
let pointer_param = PointerParam::new(&POINTER_COLOR);
let pointer = model_reg.create(pointer_param);
let inner = Inner {
audio_file_opt: None,
};
Self {
asset_mgr,
audio_engine,
about_window,
search_window_rx,
search_window,
poweredby_window,
saber_l,
saber_r,
pointer,
inner: RefCell::new(inner),
}
}
}
impl Scene for Menu {
fn update(&self, scene_mgr: &SceneManager, scene_input: &SceneInput) {
let mut inner = self.inner.borrow_mut();
let mut restart = false;
if let Some(audio_file) = &inner.audio_file_opt {
if matches!(audio_file.get_timestamp(), AudioFileTimestamp::Done) {
restart = true;
}
} else {
restart = true;
}
if restart {
let audio_file_factory = AudioFileFactory::new(Arc::clone(&self.asset_mgr), "audio/menu.mp3");
let audio_file = self.audio_engine.add(audio_file_factory);
audio_file.play();
inner.audio_file_opt = Some(audio_file);
}
scene_mgr.get_ui_subr().update(&self.saber_l, &self.saber_r, &self.pointer, [&self.about_window, &self.search_window, &self.poweredby_window].into_iter(), scene_input);
match self.search_window_rx.try_recv() {
Ok(_) => {
let song_info = SongInfo::load(Arc::clone(&self.asset_mgr), "demo").unwrap();
scene_mgr.load(GameParam::new(song_info, 1));
},
Err(e) => {
assert!(matches!(e, TryRecvError::Empty));
},
};
}
}