#[macro_use]
extern crate glium;
extern crate rusttype;
#[macro_use]
extern crate serde_derive;
extern crate serde;
pub mod ui;
pub mod math;
pub mod text;
pub mod mesh;
pub mod context;
pub mod color;
mod transform;
mod frame;
use std::rc::Rc;
use std::collections::HashSet;
use std::time;
use glium::glutin::{ElementState, Event as GliumEvent};
pub use glium::glutin::VirtualKeyCode as Key;
pub use context::{Shader, Texture};
pub use transform::Transform;
pub use math::{Vec2, Vec3};
pub struct State<Action> {
ui: ui::Ui<Action>,
context: Rc<context::Context>,
transform_system: transform::TransformSystem,
render_system: RenderSystem,
pressed: HashSet<Key>,
}
impl<Action> State<Action> {
pub fn ui(&mut self) -> &mut ui::Ui<Action> {
&mut self.ui
}
pub fn context(&self) -> Rc<context::Context> {
self.context.clone()
}
pub fn graph(&mut self) -> &mut transform::TransformSystem {
&mut self.transform_system
}
pub fn renderer(&mut self) -> &mut RenderSystem {
&mut self.render_system
}
pub fn is_pressed(&self, key: Key) -> bool {
self.pressed.contains(&key)
}
pub fn none(&self) -> Transition {
Transition(TransitionKind::None)
}
pub fn quit(&self) -> Transition {
Transition(TransitionKind::Quit)
}
pub fn pop(&self) -> Transition {
Transition(TransitionKind::Pop)
}
pub fn push<S: Scene + 'static>(&self) -> Transition {
Transition(TransitionKind::Push(Box::new(GenericScene::<S>::new(self.context.clone()))))
}
pub fn switch<S: Scene + 'static>(&self) -> Transition {
Transition(TransitionKind::Switch(Box::new(GenericScene::<S>::new(self.context.clone()))))
}
}
pub trait Scene {
type Action;
fn new(state: &mut State<Self::Action>) -> Self where Self: Sized;
fn event(&mut self, _event: Event) -> Option<Self::Action> { None }
fn action(&mut self, _action: Self::Action, _state: &mut State<Self::Action>) -> Transition {
Transition(TransitionKind::None)
}
fn update(&mut self, _state: &mut State<Self::Action>) -> Transition {
Transition(TransitionKind::None)
}
}
struct GenericScene<S: Scene> {
scene: S,
state: State<S::Action>,
}
impl<S: Scene> GenericScene<S> {
fn new(context: Rc<context::Context>) -> Self {
let ui = ui::Ui::new(context.clone());
let mut state = State {
ui,
context: context.clone(),
transform_system: transform::TransformSystem::new(),
render_system: RenderSystem::new(context.clone()),
pressed: HashSet::new(),
};
let scene = S::new(&mut state);
Self {
scene: scene,
state: state,
}
}
}
trait ErasedScene {
fn event(&mut self, event: Event) -> Transition;
fn update(&mut self) -> Transition;
fn draw(&self, frame: &mut frame::Frame);
}
impl<S: Scene> ErasedScene for GenericScene<S> {
fn event(&mut self, event: Event) -> Transition {
match self.state.ui.event(event) {
Ok(action) => self.scene.action(action, &mut self.state),
Err(event) => {
match event {
Event::KeyPressed(key) => {
if self.state.pressed.contains(&key) {
return Transition(TransitionKind::None);
} else {
self.state.pressed.insert(key);
}
},
Event::KeyReleased(key) => {
self.state.pressed.remove(&key);
},
_ => {},
}
if let Some(action) = self.scene.event(event) {
self.scene.action(action, &mut self.state)
} else {
Transition(TransitionKind::None)
}
}
}
}
fn update(&mut self) -> Transition {
self.state.transform_system.update();
self.state.ui.update();
self.scene.update(&mut self.state)
}
fn draw(&self, frame: &mut frame::Frame) {
self.state.render_system.draw(&self.state.transform_system, frame);
self.state.ui.draw(frame);
}
}
#[derive(Copy, Clone, Debug)]
pub enum Event {
None,
KeyPressed(Key),
KeyReleased(Key),
MouseMoved(math::Vec2),
Resized(math::Vec2),
MousePressed,
MouseReleased,
}
pub fn run<S: Scene + 'static>(title: &str, size: (u32, u32)) {
let context = Rc::new(context::Context::new(title, size));
let mut scenes: Vec<Box<ErasedScene>> = vec![Box::new(GenericScene::<S>::new(context.clone()))];
let mut prev_time = time::Instant::now();
'run: loop {
for event in context.display.poll_events() {
let event = match event {
GliumEvent::KeyboardInput(ElementState::Pressed, _, Some(key)) => Event::KeyPressed(key),
GliumEvent::KeyboardInput(ElementState::Released, _, Some(key)) => Event::KeyReleased(key),
GliumEvent::MouseMoved(x, y) => {
let mouse = math::Vec2::new(x as f32, y as f32);
context.mouse.set(mouse);
Event::MouseMoved(mouse)
},
GliumEvent::Resized(w, h) => {
let size = math::Vec2::new(w as f32, h as f32);
context.size.set(size);
Event::Resized(size)
}
GliumEvent::MouseInput(ElementState::Pressed, ..) => Event::MousePressed,
GliumEvent::MouseInput(ElementState::Released, ..) => Event::MouseReleased,
GliumEvent::Closed => break 'run,
_ => Event::None,
};
let transition = {
let scene = scenes.last_mut().unwrap();
scene.event(event).0
};
match transition {
TransitionKind::None => {},
TransitionKind::Quit => break 'run,
TransitionKind::Pop => {
scenes.pop();
},
TransitionKind::Push(scene) => {
scenes.push(scene);
}
TransitionKind::Switch(scene) => {
scenes.pop();
scenes.push(scene);
},
}
}
let time = time::Instant::now();
context.dt.set(time.duration_since(prev_time));
prev_time = time;
let scene = scenes.last_mut().unwrap();
scene.update();
let mut frame = frame::Frame::new(context.clone());
scene.draw(&mut frame);
frame.finish();
}
}
struct Item {
transform: Transform,
}
pub struct RenderSystem {
context: Rc<context::Context>,
items: Vec<Item>,
}
impl RenderSystem {
fn new(context: Rc<context::Context>) -> Self {
Self { context, items: Vec::new() }
}
fn draw(&self, transform_system: &transform::TransformSystem, frame: &mut frame::Frame) {
for item in self.items.iter() {
frame.draw_mesh(&self.context.quad, transform_system.global(item.transform), &self.context.default_shader, &self.context.white);
}
}
pub fn add(&mut self, transform: Transform) {
self.items.push(Item { transform });
}
}
enum TransitionKind {
None,
Quit,
Pop,
Push(Box<ErasedScene>),
Switch(Box<ErasedScene>),
}
pub struct Transition(TransitionKind);