<commit_before>use piston_window;
use gfx_device_gl::{Resources, Output, CommandBuffer};
use gfx_graphics::GfxGraphics;

use piston_window::Transformed;
use piston_window::ImageSize;

#[derive(Debug)]
pub struct Object {
    x: f64,
    y: f64,
    sprite: piston_window::Texture<Resources>,
}

impl Object {
    pub fn new(sprite: piston_window::Texture<Resources>) -> Object {
        Object { x: 0., y: 0., sprite: sprite }
    }

    pub fn mov(&mut self, x: f64, y: f64) {
        self.x += x;
        self.y += y;
    }

    pub fn mov_to(&mut self, x: f64, y: f64) {
        self.x = x;
        self.y = y;
    }

    pub fn render(&self, graphic: &mut GfxGraphics<Resources, CommandBuffer<Resources>, Output>, view: &piston_window::math::Matrix2d) {
        let (x, y) = self.sprite.get_size();
        let (x, y) = (x / 2, y / 2);
        piston_window::image(&self.sprite, view.trans(self.x, self.y).trans(-(x as f64), -(y as f64)), graphic);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn create_object() -> Object {
        Object::new()
    }

    #[test]
    fn object_new() {
        let object = create_object();
        assert_eq!(object.x, 0.0);
        assert_eq!(object.y, 0.0);
    }

    #[test]
    fn object_mov() {
        let mut object = create_object();
        assert_eq!(object.x, 0.);
        assert_eq!(object.y, 0.);

        object.mov(0., 0.);
        assert_eq!(object.x, 0.);
        assert_eq!(object.y, 0.);

        object.mov(1., 1.);
        assert_eq!(object.x, 1.);
        assert_eq!(object.y, 1.);

        object.mov(-3., -3.);
        assert_eq!(object.x, -2.);
        assert_eq!(object.y, -2.);
    }

    #[test]
    fn object_mov_to() {
        let mut object = create_object();
        assert_eq!(object.x, 0.);
        assert_eq!(object.y, 0.);

        object.mov_to(0., 0.);
        assert_eq!(object.x, 0.);
        assert_eq!(object.y, 0.);

        object.mov_to(10., 10.);
        assert_eq!(object.x, 10.);
        assert_eq!(object.y, 10.);

        object.mov_to(-30., -30.);
        assert_eq!(object.x, -30.);
        assert_eq!(object.y, -30.);
    }
}
<commit_msg>Tests fix (create_object)<commit_after>use piston_window;
use gfx_device_gl::{Resources, Output, CommandBuffer};
use gfx_graphics::GfxGraphics;

use piston_window::Transformed;
use piston_window::ImageSize;

#[derive(Debug)]
pub struct Object {
    x: f64,
    y: f64,
    sprite: piston_window::Texture<Resources>,
}

impl Object {
    pub fn new(sprite: piston_window::Texture<Resources>) -> Object {
        Object { x: 0., y: 0., sprite: sprite }
    }

    pub fn mov(&mut self, x: f64, y: f64) {
        self.x += x;
        self.y += y;
    }

    pub fn mov_to(&mut self, x: f64, y: f64) {
        self.x = x;
        self.y = y;
    }

    pub fn render(&self, graphic: &mut GfxGraphics<Resources, CommandBuffer<Resources>, Output>, view: &piston_window::math::Matrix2d) {
        let (x, y) = self.sprite.get_size();
        let (x, y) = (x / 2, y / 2);
        piston_window::image(&self.sprite, view.trans(self.x, self.y).trans(-(x as f64), -(y as f64)), graphic);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn create_object() -> Object {
        let window: ::piston_window::PistonWindow = ::piston_window::WindowSettings::new("", [0, 0]).build().unwrap();
        let sprite = ::piston_window::Texture::empty(&mut *window.factory.borrow_mut()).unwrap();
        Object::new(sprite)
    }

    #[test]
    fn object_new() {
        let object = create_object();
        assert_eq!(object.x, 0.0);
        assert_eq!(object.y, 0.0);
    }

    #[test]
    fn object_mov() {
        let mut object = create_object();
        assert_eq!(object.x, 0.);
        assert_eq!(object.y, 0.);

        object.mov(0., 0.);
        assert_eq!(object.x, 0.);
        assert_eq!(object.y, 0.);

        object.mov(1., 1.);
        assert_eq!(object.x, 1.);
        assert_eq!(object.y, 1.);

        object.mov(-3., -3.);
        assert_eq!(object.x, -2.);
        assert_eq!(object.y, -2.);
    }

    #[test]
    fn object_mov_to() {
        let mut object = create_object();
        assert_eq!(object.x, 0.);
        assert_eq!(object.y, 0.);

        object.mov_to(0., 0.);
        assert_eq!(object.x, 0.);
        assert_eq!(object.y, 0.);

        object.mov_to(10., 10.);
        assert_eq!(object.x, 10.);
        assert_eq!(object.y, 10.);

        object.mov_to(-30., -30.);
        assert_eq!(object.x, -30.);
        assert_eq!(object.y, -30.);
    }
}
<|endoftext|>


<commit_before>/// The event system will have a trigger function that takes an
/// argument that decides if the event will be triggered this tick
/// or the next tick. The default should be next tick to prevent
/// inadvertent infinite loop bugs.
///
/// The event system can then schedule all events handlers that
/// do not mutate components to be run in parallel.
/// All handlers that do mutate the component list can be run
/// sequentially after that. Perhaps we can even schedule
/// those with non-overlapping mutable component lists to
/// run in parallel.
///
/// The event loop should trigger every n ms and execute any
/// events that are queued up. Every event has a function
/// that is called by the trigger! macro that puts the event
/// on the queue.
///
use std::collections::{ HashSet, HashMap };
use std::any::{ Any, TypeId };
use shared_mutex::{ SharedMutex, MappedSharedMutexReadGuard, MappedSharedMutexWriteGuard };

use components;

pub mod example;

pub trait Handler {
	fn run(&self, Vec<MappedSharedMutexReadGuard<Any>>, Vec<MappedSharedMutexWriteGuard<Any>>);
	fn component_types(&self) -> Vec<TypeId>;
	fn mut_component_types(&self) -> Vec<TypeId>;
}

#[derive(Clone)]
pub struct Event {
	pub name: String,
	pub get_handler_instances: fn () -> Vec<Box<Handler>>
}

// The new events sets contain the events that have data in their queues so
// are ready to be ran.
lazy_static! {
	pub static ref THIS_TICK_NEW_EVENTS: SharedMutex<HashSet<String>> = SharedMutex::new(HashSet::new());
	pub static ref NEXT_TICK_NEW_EVENTS: SharedMutex<HashSet<String>> = SharedMutex::new(HashSet::new());
	pub static ref REGISTERED_EVENTS: SharedMutex<HashMap<String, Event>> = SharedMutex::new(HashMap::new());
}

pub fn trigger_this_tick(event_name: &String) {
	let mut new_events_set = THIS_TICK_NEW_EVENTS.write().expect("THIS_TICK_NEW_EVENTS mutex was corrupted.");
	new_events_set.insert(event_name.clone());
}

pub fn trigger_next_tick(event_name: &String) {
	let mut new_events_set = NEXT_TICK_NEW_EVENTS.write().expect("NEXT_TICK_NEW_EVENTS mutex was corrupted.");
	new_events_set.insert(event_name.clone());
}

pub fn register_event(event : Event) {
	let mut events = REGISTERED_EVENTS.write().expect("REGISTERED_EVENTS mutex was corrupted.");
	events.insert(event.name.clone(), event);
}

// Runs a single iteration of the event system. Can be run in a loop to process events
// continuously, but should be interleaved with `next_tick` to progress properly.
pub fn run_events() {
	let events : Vec<Event>;
	{
		let event_names : Vec<String>;
		{
			let mut event_names_lock = THIS_TICK_NEW_EVENTS.write().expect("THIS_TICK_NEW_EVENTS mutex was corrupted");
			event_names = event_names_lock.drain().collect();
		}

		let events_lock = REGISTERED_EVENTS.read().expect("REGISTERED_EVENTS mutex was corrupted");
		events = event_names.iter().map(|n|
			events_lock.get(&*n).cloned().expect("Unknown event triggered")
		).collect();
	}

	let handlers = events.iter().flat_map(|e| (e.get_handler_instances)() );

	// TODO sort and parellize handler invocations
	for handler in handlers {
		let component_types = handler.component_types();
		let mut_component_types = handler.mut_component_types();

		let mut locks : Vec<MappedSharedMutexReadGuard<Any>>= vec![];
		let mut mut_locks : Vec<MappedSharedMutexWriteGuard<Any>>= vec![];

		// we obtain the correct component locks
		for typ in component_types {
			locks.push(components::get_components_read_lock(typ));
		}
		for typ in mut_component_types {
			mut_locks.push(components::get_components_write_lock(typ));
		}

		// we run the handlers
		handler.run(locks, mut_locks)
	}
}

// Progresses the system to the next tick.
// Interleave `next_tick` between `run_events` invocations to make sure events that are
// scheduled to run only once per tick are triggered.
// A good scheme could be to run `next_tick` every 16ms, while `run_events` is ran continuously.
pub fn next_tick() {
	// get NEXT_TICK_NEW_EVENTS
	// get THIS_TICK_NEW_EVENTS
	// append NEXT_TICK_NEW_EVENTS to THIS_TICK_NEW_EVENTS
	// same for queues
}

#[macro_export]
macro_rules! event {
	( $name:ident, $( $field_name:ident : $field_typ:ty ),* ) => (
		pub mod $name {
			use shared_mutex::{ SharedMutex, MappedSharedMutexWriteGuard, MappedSharedMutexReadGuard };
			use std::any::{ Any, TypeId };
			use entity_rust::events;
			use uuid::Uuid;

			/// Example component
			#[derive(PartialEq,Eq,Clone)]
			pub struct Data {
				$(pub $field_name : $field_typ),*
			}

			pub type HandlerFn = fn(&Vec<Data>, Vec<MappedSharedMutexReadGuard<Any>>, Vec<MappedSharedMutexWriteGuard<Any>>);

			pub struct Handler {
				handler_fn: HandlerFn,
				component_types: Vec<TypeId>,
				mut_component_types: Vec<TypeId>
			}

			pub struct HandlerInstance {
				handler_fn: HandlerFn,
				component_types: Vec<TypeId>,
				mut_component_types: Vec<TypeId>,
				data: Vec<Data>
			}

			impl HandlerInstance {
				pub fn new(h: &Handler, d: Vec<Data>) -> HandlerInstance {
					HandlerInstance {
						handler_fn: h.handler_fn,
						// TODO are these clones really necessary? would be cool if they could be static refs
						component_types: h.component_types.clone(),
						mut_component_types: h.mut_component_types.clone(),
						data: d
					}
				}
			}

			impl events::Handler for HandlerInstance {
				fn run(&self, components: Vec<MappedSharedMutexReadGuard<Any>>, mut_components: Vec<MappedSharedMutexWriteGuard<Any>>) {
					let handler_fn = self.handler_fn;
					let data = &self.data;
					handler_fn(data, components, mut_components)
				}

				fn component_types(&self) -> Vec<TypeId> { self.component_types.clone() }
				fn mut_component_types(&self) -> Vec<TypeId> { self.mut_component_types.clone() }
			}

			lazy_static! {
				/// EVENT_UUID is used internally to index events, is randomly
				/// generated at first access.
				pub static ref EVENT_UUID: String = Uuid::new_v4().simple().to_string();
				pub static ref HANDLERS: SharedMutex<Vec<Handler>> = SharedMutex::new(vec![]);
				pub static ref THIS_TICK_DATA: SharedMutex<Vec<Data>> = SharedMutex::new(vec![]);
				pub static ref NEXT_TICK_DATA: SharedMutex<Vec<Data>> = SharedMutex::new(vec![]);
			}

			/// Listeners are a list of functions that should be called by trigger
			pub fn trigger(argument: Data) {
				let mut data = THIS_TICK_DATA.write().expect("THIS_TICK_DATA mutex corrupted");
				data.push(argument);

				events::trigger_this_tick(&*EVENT_UUID);
			}

			pub fn register_handler(handler_fn: HandlerFn, component_types: Vec<TypeId>, mut_component_types: Vec<TypeId>) {
				let mut handlers = HANDLERS.write().expect("Events HANDLERS mutex corrupted");
				let handler = Handler {
					handler_fn : handler_fn,
					// TODO are these clones really necessary? would be cool if they could be static refs
					component_types : component_types.clone(),
					mut_component_types : mut_component_types.clone()
				};
				handlers.push(handler);

				let event = events::Event {
					name: (&*EVENT_UUID).clone(),
					get_handler_instances: get_handler_instances
				};

				events::register_event(event)
			}

			pub fn get_handler_instances() -> Vec<Box<events::Handler>> {
				let mut data_old = THIS_TICK_DATA.write().expect("TICK DATA mutex corrupted");
				let data : Vec<Data> = data_old.drain(..).collect();

				let handlers_lock = HANDLERS.read().expect("HANDLERS mutex corrupted");
				handlers_lock.iter().map(|h|
					//TODO eliminate this data.clone
					Box::new(HandlerInstance::new(h, data.clone())) as Box<events::Handler>
				).collect()
			}
		}
	)
}

/// Queues an event to be dispatched.
/// This means that the argument is put into the trigger queue for the
/// event and the event handlers will be invoked either at the next run loop.
/// or immediately.
macro_rules! trigger {
	() => ()
}
<commit_msg>implement next_tick<commit_after>/// The event system will have a trigger function that takes an
/// argument that decides if the event will be triggered this tick
/// or the next tick. The default should be next tick to prevent
/// inadvertent infinite loop bugs.
///
/// The event system can then schedule all events handlers that
/// do not mutate components to be run in parallel.
/// All handlers that do mutate the component list can be run
/// sequentially after that. Perhaps we can even schedule
/// those with non-overlapping mutable component lists to
/// run in parallel.
///
/// The event loop should trigger every n ms and execute any
/// events that are queued up. Every event has a function
/// that is called by the trigger! macro that puts the event
/// on the queue.
///
use std::collections::{ HashSet, HashMap };
use std::any::{ Any, TypeId };
use shared_mutex::{ SharedMutex, MappedSharedMutexReadGuard, MappedSharedMutexWriteGuard };

use components;

pub mod example;

pub trait Handler {
	fn run(&self, Vec<MappedSharedMutexReadGuard<Any>>, Vec<MappedSharedMutexWriteGuard<Any>>);
	fn component_types(&self) -> Vec<TypeId>;
	fn mut_component_types(&self) -> Vec<TypeId>;
}

#[derive(Clone)]
pub struct Event {
	pub name: String,
	pub get_handler_instances: fn () -> Vec<Box<Handler>>
}

// The new events sets contain the events that have data in their queues so
// are ready to be ran.
lazy_static! {
	pub static ref THIS_TICK_NEW_EVENTS: SharedMutex<HashSet<String>> = SharedMutex::new(HashSet::new());
	pub static ref NEXT_TICK_NEW_EVENTS: SharedMutex<HashSet<String>> = SharedMutex::new(HashSet::new());
	pub static ref REGISTERED_EVENTS: SharedMutex<HashMap<String, Event>> = SharedMutex::new(HashMap::new());
}

pub fn trigger_this_tick(event_name: &String) {
	let mut new_events_set = THIS_TICK_NEW_EVENTS.write().expect("THIS_TICK_NEW_EVENTS mutex was corrupted.");
	new_events_set.insert(event_name.clone());
}

pub fn trigger_next_tick(event_name: &String) {
	let mut new_events_set = NEXT_TICK_NEW_EVENTS.write().expect("NEXT_TICK_NEW_EVENTS mutex was corrupted.");
	new_events_set.insert(event_name.clone());
}

pub fn register_event(event : Event) {
	let mut events = REGISTERED_EVENTS.write().expect("REGISTERED_EVENTS mutex was corrupted.");
	events.insert(event.name.clone(), event);
}

// Runs a single iteration of the event system. Can be run in a loop to process events
// continuously, but should be interleaved with `next_tick` to progress properly.
pub fn run_events() {
	let events : Vec<Event>;
	{
		let event_names : Vec<String>;
		{
			let mut event_names_lock = THIS_TICK_NEW_EVENTS.write().expect("THIS_TICK_NEW_EVENTS mutex was corrupted");
			event_names = event_names_lock.drain().collect();
		}

		let events_lock = REGISTERED_EVENTS.read().expect("REGISTERED_EVENTS mutex was corrupted");
		events = event_names.iter().map(|n|
			events_lock.get(&*n).cloned().expect("Unknown event triggered")
		).collect();
	}

	let handlers = events.iter().flat_map(|e| (e.get_handler_instances)() );

	// TODO sort and parellize handler invocations
	for handler in handlers {
		let component_types = handler.component_types();
		let mut_component_types = handler.mut_component_types();

		let mut locks : Vec<MappedSharedMutexReadGuard<Any>>= vec![];
		let mut mut_locks : Vec<MappedSharedMutexWriteGuard<Any>>= vec![];

		// we obtain the correct component locks
		for typ in component_types {
			locks.push(components::get_components_read_lock(typ));
		}
		for typ in mut_component_types {
			mut_locks.push(components::get_components_write_lock(typ));
		}

		// we run the handlers
		handler.run(locks, mut_locks)
	}
}

// Progresses the system to the next tick.
// Interleave `next_tick` between `run_events` invocations to make sure events that are
// scheduled to run only once per tick are triggered.
// A good scheme could be to run `next_tick` every 16ms, while `run_events` is ran continuously.
pub fn next_tick() {
	// get NEXT_TICK_NEW_EVENTS
	let mut this_tick_events = THIS_TICK_NEW_EVENTS.write().expect("THIS_TICK_NEW_EVENTS mutex was corrupted");
	let mut next_events_lock = NEXT_TICK_NEW_EVENTS.write().expect("THIS_TICK_NEW_EVENTS mutex was corrupted");

	for next_event in next_events_lock.drain() {
		this_tick_events.insert(next_event);
	}
}

#[macro_export]
macro_rules! event {
	( $name:ident, $( $field_name:ident : $field_typ:ty ),* ) => (
		pub mod $name {
			use shared_mutex::{ SharedMutex, MappedSharedMutexWriteGuard, MappedSharedMutexReadGuard };
			use std::any::{ Any, TypeId };
			use entity_rust::events;
			use uuid::Uuid;

			/// Example component
			#[derive(PartialEq,Eq,Clone)]
			pub struct Data {
				$(pub $field_name : $field_typ),*
			}

			pub type HandlerFn = fn(&Vec<Data>, Vec<MappedSharedMutexReadGuard<Any>>, Vec<MappedSharedMutexWriteGuard<Any>>);

			pub struct Handler {
				handler_fn: HandlerFn,
				component_types: Vec<TypeId>,
				mut_component_types: Vec<TypeId>
			}

			pub struct HandlerInstance {
				handler_fn: HandlerFn,
				component_types: Vec<TypeId>,
				mut_component_types: Vec<TypeId>,
				data: Vec<Data>
			}

			impl HandlerInstance {
				pub fn new(h: &Handler, d: Vec<Data>) -> HandlerInstance {
					HandlerInstance {
						handler_fn: h.handler_fn,
						// TODO are these clones really necessary? would be cool if they could be static refs
						component_types: h.component_types.clone(),
						mut_component_types: h.mut_component_types.clone(),
						data: d
					}
				}
			}

			impl events::Handler for HandlerInstance {
				fn run(&self, components: Vec<MappedSharedMutexReadGuard<Any>>, mut_components: Vec<MappedSharedMutexWriteGuard<Any>>) {
					let handler_fn = self.handler_fn;
					let data = &self.data;
					handler_fn(data, components, mut_components)
				}

				fn component_types(&self) -> Vec<TypeId> { self.component_types.clone() }
				fn mut_component_types(&self) -> Vec<TypeId> { self.mut_component_types.clone() }
			}

			lazy_static! {
				/// EVENT_UUID is used internally to index events, is randomly
				/// generated at first access.
				pub static ref EVENT_UUID: String = Uuid::new_v4().simple().to_string();
				pub static ref HANDLERS: SharedMutex<Vec<Handler>> = SharedMutex::new(vec![]);
				pub static ref THIS_TICK_DATA: SharedMutex<Vec<Data>> = SharedMutex::new(vec![]);
				pub static ref NEXT_TICK_DATA: SharedMutex<Vec<Data>> = SharedMutex::new(vec![]);
			}

			/// Listeners are a list of functions that should be called by trigger
			pub fn trigger(argument: Data) {
				let mut data = THIS_TICK_DATA.write().expect("THIS_TICK_DATA mutex corrupted");
				data.push(argument);

				events::trigger_this_tick(&*EVENT_UUID);
			}

			pub fn register_handler(handler_fn: HandlerFn, component_types: Vec<TypeId>, mut_component_types: Vec<TypeId>) {
				let mut handlers = HANDLERS.write().expect("Events HANDLERS mutex corrupted");
				let handler = Handler {
					handler_fn : handler_fn,
					// TODO are these clones really necessary? would be cool if they could be static refs
					component_types : component_types.clone(),
					mut_component_types : mut_component_types.clone()
				};
				handlers.push(handler);

				let event = events::Event {
					name: (&*EVENT_UUID).clone(),
					get_handler_instances: get_handler_instances
				};

				events::register_event(event)
			}

			pub fn get_handler_instances() -> Vec<Box<events::Handler>> {
				let mut data_old = THIS_TICK_DATA.write().expect("TICK DATA mutex corrupted");
				let data : Vec<Data> = data_old.drain(..).collect();

				let handlers_lock = HANDLERS.read().expect("HANDLERS mutex corrupted");
				handlers_lock.iter().map(|h|
					//TODO eliminate this data.clone
					Box::new(HandlerInstance::new(h, data.clone())) as Box<events::Handler>
				).collect()
			}
		}
	)
}

/// Queues an event to be dispatched.
/// This means that the argument is put into the trigger queue for the
/// event and the event handlers will be invoked either at the next run loop.
/// or immediately.
macro_rules! trigger {
	() => ()
}
<|endoftext|>


<commit_before>extern crate sb;
use sb::options_parse::parse_options;
use sb::commands::command::Command;
use sb::commands::fetch_command::FetchCommand;
use sb::commands::find_command::FindCommand;
use sb::commands::make_command::MakeCommand;
use std::env::current_dir;
use std::path::PathBuf;

const DEFAULT_OS: &'static str = "debian";
const DEFAULT_LAYER: &'static str = "jekyll";

fn main() {
    let (app_path, options, mut arguments) = parse_options();

    let root_directory = get_root_directory(&app_path);
    let slice_root_directory = get_slice_root_directory(&root_directory);

    if arguments.is_empty() {
        panic!("Command expected")
    } else {
        let command = arguments.remove(0);
        let command: &str = &command;
        match command {
            "find" => {
                let os = get_os_from_arguments_or_default(&mut arguments);
                let layers = get_layers_from_arguments_or_default(&mut arguments);
                run_command(FindCommand {
                    layers: layers,
                    os: os,
                    slice_root_directory: &slice_root_directory,
                })
            }
            "fetch" => {
                run_command(FetchCommand { slice_root_directory: &slice_root_directory })
            }
            "make" => {
                let os = get_os_from_arguments_or_default(&mut arguments);
                let layers = get_layers_from_arguments_or_default(&mut arguments);
                run_command(MakeCommand {
                    layers: layers,
                    os: os,
                    root_directory: &root_directory,
                    slice_root_directory: &slice_root_directory,
                    options: options
                })
            }
            _ => panic!("Unknown command \"{}\"", command)
        }
    }
}

fn pop_first_argument_or_take_default(arguments: &mut Vec<String>, default_value: String) -> String {
    if arguments.len() == 0 {
        default_value
    } else {
        arguments.remove(0)
    }
}

fn get_os_from_arguments_or_default(arguments: &mut Vec<String>) -> String {
    pop_first_argument_or_take_default(arguments, DEFAULT_OS.to_string())
}

fn get_layers_from_arguments_or_default(arguments: &mut Vec<String>) -> Vec<String> {
    let argument = pop_first_argument_or_take_default(arguments, DEFAULT_LAYER.to_string());
    argument.split(',')
            .map(|layer| layer.to_string())
            .collect()
}

fn run_command<T>(mut command: T)
    where T: Command {
    command.run()
}

fn get_root_directory(app_path: &str) -> PathBuf {
    let mut root_directory = PathBuf::new();
    root_directory.push(app_path);
    if root_directory.is_relative() {
        let mut new_root_directory = current_dir().unwrap();
        new_root_directory.push(root_directory);
        root_directory = new_root_directory;
    }
    assert_eq!(root_directory.pop(), true);
    root_directory.push(".sb");
    root_directory
}

fn get_slice_root_directory(root_directory: &PathBuf) -> PathBuf {
    let mut slice_root_directory = root_directory.clone();
    slice_root_directory.push("slices");
    slice_root_directory
}
<commit_msg>Argument order changed. Layer before os<commit_after>extern crate sb;
use sb::options_parse::parse_options;
use sb::commands::command::Command;
use sb::commands::fetch_command::FetchCommand;
use sb::commands::find_command::FindCommand;
use sb::commands::make_command::MakeCommand;
use std::env::current_dir;
use std::path::PathBuf;

const DEFAULT_OS: &'static str = "debian";
const DEFAULT_LAYER: &'static str = "jekyll";

fn main() {
    let (app_path, options, mut arguments) = parse_options();

    let root_directory = get_root_directory(&app_path);
    let slice_root_directory = get_slice_root_directory(&root_directory);

    if arguments.is_empty() {
        panic!("Command expected")
    } else {
        let command = arguments.remove(0);
        let command: &str = &command;
        match command {
            "find" => {
                let layers = get_layers_from_arguments_or_default(&mut arguments);
                let os = get_os_from_arguments_or_default(&mut arguments);
                run_command(FindCommand {
                    layers: layers,
                    os: os,
                    slice_root_directory: &slice_root_directory,
                })
            }
            "fetch" => {
                run_command(FetchCommand { slice_root_directory: &slice_root_directory })
            }
            "make" => {
                let layers = get_layers_from_arguments_or_default(&mut arguments);
                let os = get_os_from_arguments_or_default(&mut arguments);
                run_command(MakeCommand {
                    layers: layers,
                    os: os,
                    root_directory: &root_directory,
                    slice_root_directory: &slice_root_directory,
                    options: options
                })
            }
            _ => panic!("Unknown command \"{}\"", command)
        }
    }
}

fn pop_first_argument_or_take_default(arguments: &mut Vec<String>, default_value: String) -> String {
    if arguments.len() == 0 {
        default_value
    } else {
        arguments.remove(0)
    }
}

fn get_os_from_arguments_or_default(arguments: &mut Vec<String>) -> String {
    pop_first_argument_or_take_default(arguments, DEFAULT_OS.to_string())
}

fn get_layers_from_arguments_or_default(arguments: &mut Vec<String>) -> Vec<String> {
    let argument = pop_first_argument_or_take_default(arguments, DEFAULT_LAYER.to_string());
    argument.split(',')
            .map(|layer| layer.to_string())
            .collect()
}

fn run_command<T>(mut command: T)
    where T: Command {
    command.run()
}

fn get_root_directory(app_path: &str) -> PathBuf {
    let mut root_directory = PathBuf::new();
    root_directory.push(app_path);
    if root_directory.is_relative() {
        let mut new_root_directory = current_dir().unwrap();
        new_root_directory.push(root_directory);
        root_directory = new_root_directory;
    }
    assert_eq!(root_directory.pop(), true);
    root_directory.push(".sb");
    root_directory
}

fn get_slice_root_directory(root_directory: &PathBuf) -> PathBuf {
    let mut slice_root_directory = root_directory.clone();
    slice_root_directory.push("slices");
    slice_root_directory
}
<|endoftext|>


<commit_before>//! Set up resource content for game.

use brush::{Brush, Builder, Geom};
use cache;
use calx::Rgba;
use calx::color::*;
use euclid::vec2;
use std::collections::HashMap;
use std::rc::Rc;
use std::str::FromStr;
use vec_map::VecMap;
use vitral;

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn terrain_brushes() -> VecMap<Rc<Brush>> {
    use world::Terrain::*;
    let mut ret = VecMap::new();

    ret.insert(Empty as usize, Builder::new("assets/floors.png").tile(0, 0).finish());
    ret.insert(Gate as usize, Builder::new("assets/portals.png")
        .color(LIGHTCYAN)
        .tile(0, 0).merge()
        .tile(32, 0).merge()
        .tile(64, 0).merge()
        .tile(96, 0).merge()
        .tile(128, 0).merge()
        .tile(160, 0).merge()
        .tile(192, 0).merge()
        .tile(224, 0).merge()
        .tile(256, 0).merge()
        .tile(288, 0).merge()
        .tile(320, 0).merge()
        .tile(352, 0).merge()
        .tile(384, 0).finish());
    ret.insert(Ground as usize, Builder::new("assets/floors.png").color(SLATEGRAY).tile(32, 0).finish());
    ret.insert(Grass as usize, Builder::new("assets/floors.png").color(DARKGREEN).tile(32, 0).finish());
    ret.insert(Snow as usize, Builder::new("assets/floors.png").color(WHITE).tile(32, 0).finish());
    ret.insert(Sand as usize, Builder::new("assets/floors.png").color(YELLOW).tile(32, 0).finish());
    ret.insert(Water as usize, Builder::new("assets/floors.png").colors(MIDNIGHTBLUE, ROYALBLUE).tile(96, 0).finish());
    ret.insert(Shallows as usize, Builder::new("assets/floors.png").colors(CORNFLOWERBLUE, ALICEBLUE).tile(96, 0).finish());
    ret.insert(Magma as usize, Builder::new("assets/floors.png").colors(YELLOW, DARKRED).tile(96, 0).finish());
    ret.insert(Tree as usize, Builder::new("assets/props.png")
        .color(SADDLEBROWN).tile(160, 64)
        .color(GREEN).tile(192, 64).finish());
    ret.insert(Wall as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 32, 0).finish());
    ret.insert(Rock as usize, Builder::new("assets/blobs.png").color(DARKGOLDENROD).blob(0, 0, 0, 32, 0, 160).finish());
    ret.insert(Door as usize, Builder::new("assets/walls.png")
               .color(SADDLEBROWN).wall(128, 0, 160, 0)
               .color(LIGHTSLATEGRAY).wall(0, 0, 96, 0).finish());
    ret.insert(OpenDoor as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 96, 0).finish());
    ret.insert(Window as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 64, 0).finish());
    ret.insert(Grass2 as usize, Builder::new("assets/floors.png").color(DARKGREEN).tile(64, 0).finish());

    ret
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn entity_brushes() -> VecMap<Rc<Brush>> {
    use world::Icon::*;
    let mut ret = VecMap::new();

    ret.insert(Player as usize, Builder::new("assets/mobs.png").color(AZURE).mob(0, 0).finish());
    ret.insert(Snake as usize, Builder::new("assets/mobs.png").color(GREEN).mob(1*32, 0).finish());
    ret.insert(Dreg as usize, Builder::new("assets/mobs.png").color(OLIVE).mob(2*32, 0).finish());
    ret.insert(Ogre as usize, Builder::new("assets/mobs.png").color(DARKCYAN).mob(3*32, 0).finish());
    ret.insert(Wraith as usize, Builder::new("assets/mobs.png").color(GRAY).mob(4*32, 0).finish());
    ret.insert(Octopus as usize, Builder::new("assets/mobs.png").color(WHEAT).mob(5*32, 0).finish());
    ret.insert(Bug as usize, Builder::new("assets/mobs.png").color(0xFF00FFFF).mob(6*32, 0).finish());
    ret.insert(Ooze as usize, Builder::new("assets/mobs.png").color(LIGHTSKYBLUE).mob(7*32, 0).finish());
    ret.insert(Efreet as usize, Builder::new("assets/mobs.png").color(ORANGE).mob(0, 1*32).finish());

    // The serpent has a special sprite structure where it's split to the head and mound parts,
    // and the mound part doesn't move during the idle animation.
    ret.insert(Serpent as usize, Builder::new("assets/mobs.png").color(CORAL)
               .splat(Some(Geom::new(16, 14, 1*32, 32, 32, 32))).tile(2*32, 32).merge()
               .tile(1*32, 32).tile(2*32, 32).merge()
               .finish());

    ret.insert(Sword as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(4*32, 1*32).finish());
    ret.insert(Helmet as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(5*32, 1*32).finish());
    ret.insert(Armor as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(2*32, 2*32).finish());

    ret.insert(Scroll1 as usize, Builder::new("assets/props.png").color(LIGHTYELLOW).tile(7*32, 2*32).finish());
    ret.insert(Wand1 as usize, Builder::new("assets/props.png").color(RED).tile(7*32, 1*32).finish());
    ret.insert(Wand2 as usize, Builder::new("assets/props.png").color(CYAN).tile(7*32, 1*32).finish());
    ret
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn misc_brushes() -> VecMap<Rc<Brush>> {
    use Icon::*;
    let mut ret = VecMap::new();

    ret.insert(SolidBlob as usize, Builder::new("assets/blobs.png").colors(BLACK, BLACK).blob(0, 64, 0, 96, 0, 128).finish());
    ret.insert(CursorTop as usize, Builder::new("assets/props.png").color(RED).tile(32, 0).finish());
    ret.insert(CursorBottom as usize, Builder::new("assets/props.png").color(RED).tile(0, 0).finish());
    ret.insert(Portal as usize, Builder::new("assets/props.png").color(Rgba::from_str("#fa08").unwrap()).tile(0, 0).finish());
    ret.insert(HealthPip as usize, Builder::new("assets/gui.png").color(LIMEGREEN).rect(0, 8, 4, 4).finish());
    ret.insert(DarkHealthPip as usize, Builder::new("assets/gui.png").color(DARKSLATEGRAY).rect(0, 8, 4, 4).finish());
    ret.insert(BlockedOffSectorCell as usize, Builder::new("assets/floors.png").color(LIGHTGRAY).tile(0, 32).finish());

    ret
}

pub fn font<I: Iterator<Item = char>>(
    name: String,
    data: &[u8],
    span: I,
) -> vitral::FontData<usize> {
    let glyphs = cache::ATLAS.with(|a| a.borrow_mut().load_tilesheet(name, data).unwrap());

    let mut glyphs = glyphs
        .into_iter()
        .map(|i| vitral::CharData {
            image: cache::get(&i),
            draw_offset: vec2(0.0, 0.0),
            advance: i.bounds.size.width as f32,
        })
        .collect::<Vec<_>>();

    assert!(!glyphs.is_empty());
    let font_height = glyphs[0].image.size.height as f32;

    glyphs.reverse();

    let mut chars = HashMap::new();
    for c in span {
        chars.insert(
            c,
            glyphs
                .pop()
                .expect("Not enough glyphs in font sheet for all chars"),
        );
    }

    vitral::FontData {
        chars: chars,
        height: font_height,
    }
}
<commit_msg>Tone down the shallow water color a bit<commit_after>//! Set up resource content for game.

use brush::{Brush, Builder, Geom};
use cache;
use calx::Rgba;
use calx::color::*;
use euclid::vec2;
use std::collections::HashMap;
use std::rc::Rc;
use std::str::FromStr;
use vec_map::VecMap;
use vitral;

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn terrain_brushes() -> VecMap<Rc<Brush>> {
    use world::Terrain::*;
    let mut ret = VecMap::new();

    ret.insert(Empty as usize, Builder::new("assets/floors.png").tile(0, 0).finish());
    ret.insert(Gate as usize, Builder::new("assets/portals.png")
        .color(LIGHTCYAN)
        .tile(0, 0).merge()
        .tile(32, 0).merge()
        .tile(64, 0).merge()
        .tile(96, 0).merge()
        .tile(128, 0).merge()
        .tile(160, 0).merge()
        .tile(192, 0).merge()
        .tile(224, 0).merge()
        .tile(256, 0).merge()
        .tile(288, 0).merge()
        .tile(320, 0).merge()
        .tile(352, 0).merge()
        .tile(384, 0).finish());
    ret.insert(Ground as usize, Builder::new("assets/floors.png").color(SLATEGRAY).tile(32, 0).finish());
    ret.insert(Grass as usize, Builder::new("assets/floors.png").color(DARKGREEN).tile(32, 0).finish());
    ret.insert(Snow as usize, Builder::new("assets/floors.png").color(WHITE).tile(32, 0).finish());
    ret.insert(Sand as usize, Builder::new("assets/floors.png").color(YELLOW).tile(32, 0).finish());
    ret.insert(Water as usize, Builder::new("assets/floors.png").colors(MIDNIGHTBLUE, ROYALBLUE).tile(96, 0).finish());
    ret.insert(Shallows as usize, Builder::new("assets/floors.png").colors(STEELBLUE, ROYALBLUE).tile(96, 0).finish());
    ret.insert(Magma as usize, Builder::new("assets/floors.png").colors(YELLOW, DARKRED).tile(96, 0).finish());
    ret.insert(Tree as usize, Builder::new("assets/props.png")
        .color(SADDLEBROWN).tile(160, 64)
        .color(GREEN).tile(192, 64).finish());
    ret.insert(Wall as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 32, 0).finish());
    ret.insert(Rock as usize, Builder::new("assets/blobs.png").color(DARKGOLDENROD).blob(0, 0, 0, 32, 0, 160).finish());
    ret.insert(Door as usize, Builder::new("assets/walls.png")
               .color(SADDLEBROWN).wall(128, 0, 160, 0)
               .color(LIGHTSLATEGRAY).wall(0, 0, 96, 0).finish());
    ret.insert(OpenDoor as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 96, 0).finish());
    ret.insert(Window as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 64, 0).finish());
    ret.insert(Grass2 as usize, Builder::new("assets/floors.png").color(DARKGREEN).tile(64, 0).finish());

    ret
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn entity_brushes() -> VecMap<Rc<Brush>> {
    use world::Icon::*;
    let mut ret = VecMap::new();

    ret.insert(Player as usize, Builder::new("assets/mobs.png").color(AZURE).mob(0, 0).finish());
    ret.insert(Snake as usize, Builder::new("assets/mobs.png").color(GREEN).mob(1*32, 0).finish());
    ret.insert(Dreg as usize, Builder::new("assets/mobs.png").color(OLIVE).mob(2*32, 0).finish());
    ret.insert(Ogre as usize, Builder::new("assets/mobs.png").color(DARKCYAN).mob(3*32, 0).finish());
    ret.insert(Wraith as usize, Builder::new("assets/mobs.png").color(GRAY).mob(4*32, 0).finish());
    ret.insert(Octopus as usize, Builder::new("assets/mobs.png").color(WHEAT).mob(5*32, 0).finish());
    ret.insert(Bug as usize, Builder::new("assets/mobs.png").color(0xFF00FFFF).mob(6*32, 0).finish());
    ret.insert(Ooze as usize, Builder::new("assets/mobs.png").color(LIGHTSKYBLUE).mob(7*32, 0).finish());
    ret.insert(Efreet as usize, Builder::new("assets/mobs.png").color(ORANGE).mob(0, 1*32).finish());

    // The serpent has a special sprite structure where it's split to the head and mound parts,
    // and the mound part doesn't move during the idle animation.
    ret.insert(Serpent as usize, Builder::new("assets/mobs.png").color(CORAL)
               .splat(Some(Geom::new(16, 14, 1*32, 32, 32, 32))).tile(2*32, 32).merge()
               .tile(1*32, 32).tile(2*32, 32).merge()
               .finish());

    ret.insert(Sword as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(4*32, 1*32).finish());
    ret.insert(Helmet as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(5*32, 1*32).finish());
    ret.insert(Armor as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(2*32, 2*32).finish());

    ret.insert(Scroll1 as usize, Builder::new("assets/props.png").color(LIGHTYELLOW).tile(7*32, 2*32).finish());
    ret.insert(Wand1 as usize, Builder::new("assets/props.png").color(RED).tile(7*32, 1*32).finish());
    ret.insert(Wand2 as usize, Builder::new("assets/props.png").color(CYAN).tile(7*32, 1*32).finish());
    ret
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn misc_brushes() -> VecMap<Rc<Brush>> {
    use Icon::*;
    let mut ret = VecMap::new();

    ret.insert(SolidBlob as usize, Builder::new("assets/blobs.png").colors(BLACK, BLACK).blob(0, 64, 0, 96, 0, 128).finish());
    ret.insert(CursorTop as usize, Builder::new("assets/props.png").color(RED).tile(32, 0).finish());
    ret.insert(CursorBottom as usize, Builder::new("assets/props.png").color(RED).tile(0, 0).finish());
    ret.insert(Portal as usize, Builder::new("assets/props.png").color(Rgba::from_str("#fa08").unwrap()).tile(0, 0).finish());
    ret.insert(HealthPip as usize, Builder::new("assets/gui.png").color(LIMEGREEN).rect(0, 8, 4, 4).finish());
    ret.insert(DarkHealthPip as usize, Builder::new("assets/gui.png").color(DARKSLATEGRAY).rect(0, 8, 4, 4).finish());
    ret.insert(BlockedOffSectorCell as usize, Builder::new("assets/floors.png").color(LIGHTGRAY).tile(0, 32).finish());

    ret
}

pub fn font<I: Iterator<Item = char>>(
    name: String,
    data: &[u8],
    span: I,
) -> vitral::FontData<usize> {
    let glyphs = cache::ATLAS.with(|a| a.borrow_mut().load_tilesheet(name, data).unwrap());

    let mut glyphs = glyphs
        .into_iter()
        .map(|i| vitral::CharData {
            image: cache::get(&i),
            draw_offset: vec2(0.0, 0.0),
            advance: i.bounds.size.width as f32,
        })
        .collect::<Vec<_>>();

    assert!(!glyphs.is_empty());
    let font_height = glyphs[0].image.size.height as f32;

    glyphs.reverse();

    let mut chars = HashMap::new();
    for c in span {
        chars.insert(
            c,
            glyphs
                .pop()
                .expect("Not enough glyphs in font sheet for all chars"),
        );
    }

    vitral::FontData {
        chars: chars,
        height: font_height,
    }
}
<|endoftext|>


<commit_before>use core::{make_shared, Shared};
use fa::{Approximator, EvaluationResult, QFunction, UpdateResult, VFunction};
use geometry::Vector;
use std::marker::PhantomData;

pub struct MockQ {
    output: Option<Vector<f64>>,
}

impl MockQ {
    pub fn new(output: Option<Vector<f64>>) -> Self { MockQ { output: output } }

    pub fn new_shared(output: Option<Vector<f64>>) -> Shared<Self> {
        make_shared(Self::new(output))
    }

    pub fn set_output(&mut self, output: Vector<f64>) { self.output = Some(output) }

    pub fn clear_output(&mut self) { self.output = None }
}

impl Approximator<Vec<f64>> for MockQ {
    type Value = Vector<f64>;

    fn evaluate(&self, s: &Vec<f64>) -> EvaluationResult<Vector<f64>> {
        Ok(match self.output {
            Some(ref vector) => vector.clone(),
            None => s.clone().into(),
        })
    }

    fn update(&mut self, p: &Vec<f64>, errors: Vector<f64>) -> UpdateResult<()> { Ok(()) }
}

impl QFunction<Vec<f64>> for MockQ {
    fn n_actions(&self) -> usize {
        match self.output {
            Some(ref vector) => vector.len(),
            None => 0,
        }
    }
}
<commit_msg>style(fa): allow dead code in fa/mocking.rs<commit_after>use core::{make_shared, Shared};
use fa::{Approximator, EvaluationResult, QFunction, UpdateResult, VFunction};
use geometry::Vector;
use std::marker::PhantomData;

pub struct MockQ {
    output: Option<Vector<f64>>,
}

impl MockQ {
    pub fn new(output: Option<Vector<f64>>) -> Self { MockQ { output: output } }

    pub fn new_shared(output: Option<Vector<f64>>) -> Shared<Self> {
        make_shared(Self::new(output))
    }

    #[allow(dead_code)]
    pub fn set_output(&mut self, output: Vector<f64>) { self.output = Some(output) }

    #[allow(dead_code)]
    pub fn clear_output(&mut self) { self.output = None }
}

impl Approximator<Vec<f64>> for MockQ {
    type Value = Vector<f64>;

    fn evaluate(&self, s: &Vec<f64>) -> EvaluationResult<Vector<f64>> {
        Ok(match self.output {
            Some(ref vector) => vector.clone(),
            None => s.clone().into(),
        })
    }

    fn update(&mut self, _: &Vec<f64>, _: Vector<f64>) -> UpdateResult<()> { Ok(()) }
}

impl QFunction<Vec<f64>> for MockQ {
    fn n_actions(&self) -> usize {
        match self.output {
            Some(ref vector) => vector.len(),
            None => 0,
        }
    }
}
<|endoftext|>


<commit_before>//! Read and draw terrain data in 3D.

use gl;
use yaglw::gl_context::GLContext;
use yaglw::shader::Shader;

#[allow(missing_docs)]
pub struct TerrainShader<'a> {
  #[allow(missing_docs)]
  pub shader: Shader<'a>,
}

impl<'a> TerrainShader<'a> {
  #[allow(missing_docs)]
  pub fn new<'b:'a>(gl: &'a GLContext) -> TerrainShader<'b> {
    let components = vec!(
      (gl::VERTEX_SHADER, "
        #version 330 core

        uniform mat4 projection_matrix;

        uniform samplerBuffer positions;
        uniform samplerBuffer normals;

        flat out int face_id;
        out vec3 world_position;
        out vec3 normal;

        void main() {
          // Mutiply by 3 because there are 3 components for each normal vector.
          int position_id = gl_VertexID * 3;
          world_position.x = texelFetch(positions, position_id + 0).r;
          world_position.y = texelFetch(positions, position_id + 1).r;
          world_position.z = texelFetch(positions, position_id + 2).r;

          int normal_id = position_id;
          normal.x = texelFetch(normals, normal_id + 0).r;
          normal.y = texelFetch(normals, normal_id + 1).r;
          normal.z = texelFetch(normals, normal_id + 2).r;

          face_id = gl_VertexID / 3;

          gl_Position = projection_matrix * vec4(world_position, 1.0);
        }".to_string()),
      (gl::FRAGMENT_SHADER, format!("
        #version 330 core

        uniform struct Sun {{
          vec3 direction;
          vec3 intensity;
        }} sun;

        uniform vec3 ambient_light;

        uniform samplerBuffer positions;

        flat in int face_id;
        in vec3 world_position;
        in vec3 normal;

        out vec4 frag_color;

        // include cnoise
        {}

        vec3 grass() {{
          {}
        }}

        vec3 dirt() {{
          {}
        }}

        void main() {{
          int color_id = face_id * 3;

          vec4 base_color;

          float grad = (cnoise(world_position / 32) + 1) / 2;
          base_color = vec4(mix(grass(), dirt(), grad), 1);

          float brightness = dot(normal, sun.direction);
          brightness = clamp(brightness, 0, 1);
          vec3 lighting = brightness * sun.intensity + ambient_light;

          float fog_factor = gl_FragCoord.z / gl_FragCoord.w / 768;
          float fog_density = 1 - exp(-fog_factor);
          vec3 fog_color = sun.intensity;
          vec4 fog_component = vec4(fog_color, 1) * fog_density;
          vec4 material_component =
            vec4(clamp(lighting, 0, 1), 1) * base_color * vec4(1, 1, 1, 1 - fog_density);

          frag_color = fog_component + material_component;
        }}", ::shaders::noise::cnoise(), ::shaders::grass::grass(), ::shaders::dirt::dirt(),
        )),
    );
    TerrainShader {
      shader: Shader::new(gl, components.into_iter()),
    }
  }
}
<commit_msg>change grass/dirt balance<commit_after>//! Read and draw terrain data in 3D.

use gl;
use yaglw::gl_context::GLContext;
use yaglw::shader::Shader;

#[allow(missing_docs)]
pub struct TerrainShader<'a> {
  #[allow(missing_docs)]
  pub shader: Shader<'a>,
}

impl<'a> TerrainShader<'a> {
  #[allow(missing_docs)]
  pub fn new<'b:'a>(gl: &'a GLContext) -> TerrainShader<'b> {
    let components = vec!(
      (gl::VERTEX_SHADER, "
        #version 330 core

        uniform mat4 projection_matrix;

        uniform samplerBuffer positions;
        uniform samplerBuffer normals;

        flat out int face_id;
        out vec3 world_position;
        out vec3 normal;

        void main() {
          // Mutiply by 3 because there are 3 components for each normal vector.
          int position_id = gl_VertexID * 3;
          world_position.x = texelFetch(positions, position_id + 0).r;
          world_position.y = texelFetch(positions, position_id + 1).r;
          world_position.z = texelFetch(positions, position_id + 2).r;

          int normal_id = position_id;
          normal.x = texelFetch(normals, normal_id + 0).r;
          normal.y = texelFetch(normals, normal_id + 1).r;
          normal.z = texelFetch(normals, normal_id + 2).r;

          face_id = gl_VertexID / 3;

          gl_Position = projection_matrix * vec4(world_position, 1.0);
        }".to_string()),
      (gl::FRAGMENT_SHADER, format!("
        #version 330 core

        uniform struct Sun {{
          vec3 direction;
          vec3 intensity;
        }} sun;

        uniform vec3 ambient_light;

        uniform samplerBuffer positions;

        flat in int face_id;
        in vec3 world_position;
        in vec3 normal;

        out vec4 frag_color;

        // include cnoise
        {}

        vec3 grass() {{
          {}
        }}

        vec3 dirt() {{
          {}
        }}

        void main() {{
          int color_id = face_id * 3;

          vec4 base_color;

          float grass_amount =
            (cnoise(world_position / 32) + 1) / 2 *
            dot(normal, vec3(0, 1, 0)) *
            1.5;
          grass_amount = clamp(grass_amount, 0, 1);
          base_color = vec4(mix(dirt(), grass(), grass_amount), 1);

          float brightness = dot(normal, sun.direction);
          brightness = clamp(brightness, 0, 1);
          vec3 lighting = brightness * sun.intensity + ambient_light;

          float fog_factor = gl_FragCoord.z / gl_FragCoord.w / 768;
          float fog_density = 1 - exp(-fog_factor);
          vec3 fog_color = sun.intensity;
          vec4 fog_component = vec4(fog_color, 1) * fog_density;
          vec4 material_component =
            vec4(clamp(lighting, 0, 1), 1) * base_color * vec4(1, 1, 1, 1 - fog_density);

          frag_color = fog_component + material_component;
        }}", ::shaders::noise::cnoise(), ::shaders::grass::grass(), ::shaders::dirt::dirt(),
        )),
    );
    TerrainShader {
      shader: Shader::new(gl, components.into_iter()),
    }
  }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#[doc = "Rust wrappers around the raw JS apis"];

use std::libc;
use std::libc::types::os::arch::c95::{size_t, c_uint};
use std::libc::c_char;
use std::hashmap::HashMap;
use jsapi::*;
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use JSVAL_NULL;
use ERR;
use name_pool::*;
use std::ptr;
use std::ptr::null;
use result;
use result_obj;
use std::uint;
use std::str::raw::from_c_str;
use std::cast;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = @rt_rsrc;

pub struct rt_rsrc {
    ptr : *JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *JSRuntime) -> rt {
    return @rt_rsrc {
        ptr: p
    }
}

impl rt_rsrc {
    pub fn cx(@self) -> @Cx {
        unsafe {
            new_context(JS_NewContext(self.ptr, default_stacksize as size_t), self)
        }
    }
}

// FIXME: Copied from old std::gc; is this still valid?
pub struct StackSegment {
    prev: *StackSegment,
    next: *StackSegment,
    end: libc::uintptr_t,
    // And other fields which we don't care about...
}

extern {
    fn rust_get_c_stack() -> *StackSegment;
}

extern fn gc_callback(rt: *JSRuntime, _status: JSGCStatus) {
    unsafe {
        let c_stack = rust_get_c_stack();
        let first = c_stack as libc::uintptr_t;
        let second = (*c_stack).end;
        JS_SetNativeStackBounds(rt, uint::min(first, second), uint::max(first, second));
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        JS_SetGCCallback(runtime, gc_callback);
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    ptr: *JSContext,
    rt: rt,
    classes: @mut HashMap<~str, @JSClass>,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *JSContext, rt: rt) -> @Cx {
    return @Cx {
        ptr: ptr,
        rt: rt,
        classes: @mut HashMap::new()
    }
}

impl Cx {
    pub fn rooted_obj(@self, obj: *JSObject) -> jsobj {
        let jsobj = @jsobj_rsrc {cx: self, cxptr: self.ptr, ptr: obj};
        unsafe {
            JS_AddObjectRoot(self.ptr, ptr::to_unsafe_ptr(&jsobj.ptr));
        }
        jsobj
    }

    pub fn set_default_options_and_version(@self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(@self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(@self, v: i32) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(@self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportError);
        }
    }

    pub fn set_error_reporter(@self, reportfn: *u8) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportfn);
        }
    }

    pub fn new_compartment(@self,
                       globclsfn: &fn(@mut NamePool) -> JSClass)
                    -> Result<@mut Compartment,()> {
        unsafe {
            let np = NamePool();
            let globcls = @globclsfn(np);
            let globobj = JS_NewGlobalObject(self.ptr, ptr::to_unsafe_ptr(&*globcls), null());
            result(JS_InitStandardClasses(self.ptr, globobj)).chain(|_ok| {
                let compartment = @mut Compartment {
                    cx: self,
                    name_pool: np,
                    global_funcs: ~[],
                    global_props: ~[],
                    global_class: globcls,
                    global_obj: self.rooted_obj(globobj),
                    global_protos: @mut HashMap::new()
                };
                self.set_cx_private(ptr::to_unsafe_ptr(&*compartment) as *());
                Ok(compartment)
            })
        }
    }

    pub fn evaluate_script(@self, glob: jsobj, bytes: ~[u8], filename: ~str, line_num: uint)
                    -> Result<(),()> {
        do bytes.as_imm_buf |bytes_ptr, bytes_len| {
            do filename.as_c_str |filename_cstr| {
                let bytes_ptr = bytes_ptr as *c_char;
                let rval: JSVal = JSVAL_NULL;
                debug!("Evaluating script from %s with bytes %?", filename, bytes);
                unsafe {
                    if JS_EvaluateScript(self.ptr, glob.ptr,
                                         bytes_ptr, bytes_len as c_uint,
                                         filename_cstr, line_num as c_uint,
                                         ptr::to_unsafe_ptr(&rval)) == ERR {
                        debug!("...err!");
                        Err(())
                    } else {
                        // we could return the script result but then we'd have
                        // to root it and so forth and, really, who cares?
                        debug!("...ok!");
                        Ok(())
                    }
                }
            }
        }
    }

    pub fn lookup_class_name(@self, s: ~str) ->  @JSClass {
        // FIXME: expect should really take a lambda...
        let error_msg = fmt!("class %s not found in class table", s);
        let name = self.classes.find(&s);
        *(name.expect(error_msg))
    }

    pub unsafe fn get_cx_private(@self) -> *() {
        cast::transmute(JS_GetContextPrivate(self.ptr))
    }

    pub unsafe fn set_cx_private(@self, data: *()) {
        JS_SetContextPrivate(self.ptr, cast::transmute(data));
    }

    pub unsafe fn get_obj_private(@self, obj: *JSObject) -> *() {
        cast::transmute(JS_GetPrivate(obj))
    }

    pub unsafe fn set_obj_private(@self, obj: *JSObject, data: *()) {
        JS_SetPrivate(obj, cast::transmute(data));
    }
}

pub extern fn reportError(_cx: *JSContext, msg: *c_char, report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {~"none"};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        error!("Error at %s:%?: %s\n", fname, lineno, msg);
    }
}

// ___________________________________________________________________________
// compartment

pub struct Compartment {
    cx: @Cx,
    name_pool: @mut NamePool,
    global_funcs: ~[@~[JSFunctionSpec]],
    global_props: ~[@~[JSPropertySpec]],
    global_class: @JSClass,
    global_obj: jsobj,
    global_protos: @mut HashMap<~str, jsobj>
}

impl Compartment {
    pub fn define_functions(@mut self,
                        specfn: &fn(@mut NamePool) -> ~[JSFunctionSpec])
                     -> Result<(),()> {
        let specvec = @specfn(self.name_pool);
        self.global_funcs.push(specvec);
        do specvec.as_imm_buf |specs, _len| {
            unsafe {
                result(JS_DefineFunctions(self.cx.ptr, self.global_obj.ptr, specs))
            }
        }
    }
    pub fn define_properties(@mut self, specfn: &fn() -> ~[JSPropertySpec]) -> Result<(),()> {
        let specvec = @specfn();
        self.global_props.push(specvec);
        do specvec.as_imm_buf |specs, _len| {
            unsafe {
                result(JS_DefineProperties(self.cx.ptr, self.global_obj.ptr, specs))
            }
        }
    }
    pub fn define_property(@mut self,
                       name: ~str,
                       value: JSVal,
                       getter: JSPropertyOp, setter: JSStrictPropertyOp,
                       attrs: c_uint)
                    -> Result<(),()> {
        unsafe {
            result(JS_DefineProperty(self.cx.ptr,
                                     self.global_obj.ptr,
                                     self.add_name(name),
                                     value,
                                     getter,
                                     setter,
                                     attrs))
        }
    }
    pub fn new_object(@mut self, class_name: ~str, proto: *JSObject, parent: *JSObject)
               -> Result<jsobj, ()> {
        unsafe {
            let classptr = self.cx.lookup_class_name(class_name);
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, &*classptr, proto, parent));
            result_obj(obj)
        }
    }
    pub fn new_object_with_proto(@mut self, class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let proto = self.global_protos.find(&proto_name.clone()).expect(
            fmt!("new_object_with_proto: expected to find %s in the proto \
                  table", proto_name));
        unsafe {
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                      proto.ptr, parent));
            result_obj(obj)
        }
    }
    pub fn get_global_proto(@mut self, name: ~str) -> jsobj {
        let proto = self.global_protos.get(&name);
        *proto
    }
    pub fn stash_global_proto(@mut self, name: ~str, proto: jsobj) {
        let global_protos = self.global_protos;
        if !global_protos.insert(name, proto) {
            fail!(~"Duplicate global prototype registered; you're gonna have a bad time.")
        }
    }
    pub fn register_class(@mut self, class_fn: &fn(x: @mut Compartment) -> JSClass) {
        let classptr = @class_fn(self);
        if !self.cx.classes.insert(
            unsafe { from_c_str(classptr.name) },
            classptr) {
            fail!(~"Duplicate JSClass registered; you're gonna have a bad time.")
        }
    }
    pub fn add_name(@mut self, name: ~str) -> *c_char {
        self.name_pool.add(name.clone())
    }
}

// ___________________________________________________________________________
// objects

pub type jsobj = @jsobj_rsrc;

pub struct jsobj_rsrc {
    cx: @Cx,
    cxptr: *JSContext,
    ptr: *JSObject,
}

#[unsafe_destructor]
impl Drop for jsobj_rsrc {
    fn drop(&self) {
        unsafe {
            JS_RemoveObjectRoot(self.cxptr, ptr::to_unsafe_ptr(&self.ptr));
        }
    }
}

impl jsobj_rsrc {
    fn new_object(&self, cx: @Cx, cxptr: *JSContext, ptr: *JSObject) -> jsobj {
        return @jsobj_rsrc {
            cx: cx,
            cxptr: cxptr,
            ptr: ptr
        }
    }
}

// ___________________________________________________________________________
// random utilities

pub trait to_jsstr {
    fn to_jsstr(self, cx: @Cx) -> *JSString;
}

impl to_jsstr for ~str {
    fn to_jsstr(self, cx: @Cx) -> *JSString {
        do self.as_imm_buf |buf, len| {
            unsafe {
                let cbuf = cast::transmute(buf);
                JS_NewStringCopyN(cx.ptr, cbuf, len as size_t)
            }
        }
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::super::global;
    use super::super::jsapi::{JS_GC, JS_GetRuntime};

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.set_default_options_and_version();
        cx.set_logging_error_reporter();
        cx.new_compartment(global::global_class).chain(|comp| {
            unsafe { JS_GC(JS_GetRuntime(comp.cx.ptr)); }

            comp.define_functions(global::debug_fns);

            let s = ~"debug(22);";
            let bytes = s.as_bytes().to_owned();
            cx.evaluate_script(comp.global_obj, bytes, ~"test", 1u)
        });
    }

}
<commit_msg>Update syntax for new Rust<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#[doc = "Rust wrappers around the raw JS apis"];

use std::libc;
use std::libc::types::os::arch::c95::{size_t, c_uint};
use std::libc::c_char;
use std::hashmap::HashMap;
use jsapi::*;
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use JSVAL_NULL;
use ERR;
use name_pool::*;
use std::ptr;
use std::ptr::null;
use result;
use result_obj;
use std::uint;
use std::str::raw::from_c_str;
use std::cast;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = @rt_rsrc;

pub struct rt_rsrc {
    ptr : *JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *JSRuntime) -> rt {
    return @rt_rsrc {
        ptr: p
    }
}

impl rt_rsrc {
    pub fn cx(@self) -> @Cx {
        unsafe {
            new_context(JS_NewContext(self.ptr, default_stacksize as size_t), self)
        }
    }
}

// FIXME: Copied from old std::gc; is this still valid?
pub struct StackSegment {
    prev: *StackSegment,
    next: *StackSegment,
    end: libc::uintptr_t,
    // And other fields which we don't care about...
}

extern {
    fn rust_get_c_stack() -> *StackSegment;
}

extern fn gc_callback(rt: *JSRuntime, _status: JSGCStatus) {
    unsafe {
        let c_stack = rust_get_c_stack();
        let first = c_stack as libc::uintptr_t;
        let second = (*c_stack).end;
        JS_SetNativeStackBounds(rt, uint::min(first, second), uint::max(first, second));
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        JS_SetGCCallback(runtime, gc_callback);
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    ptr: *JSContext,
    rt: rt,
    classes: @mut HashMap<~str, @JSClass>,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *JSContext, rt: rt) -> @Cx {
    return @Cx {
        ptr: ptr,
        rt: rt,
        classes: @mut HashMap::new()
    }
}

impl Cx {
    pub fn rooted_obj(@self, obj: *JSObject) -> jsobj {
        let jsobj = @jsobj_rsrc {cx: self, cxptr: self.ptr, ptr: obj};
        unsafe {
            JS_AddObjectRoot(self.ptr, ptr::to_unsafe_ptr(&jsobj.ptr));
        }
        jsobj
    }

    pub fn set_default_options_and_version(@self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(@self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(@self, v: i32) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(@self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportError);
        }
    }

    pub fn set_error_reporter(@self, reportfn: *u8) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportfn);
        }
    }

    pub fn new_compartment(@self,
                       globclsfn: &fn(@mut NamePool) -> JSClass)
                    -> Result<@mut Compartment,()> {
        unsafe {
            let np = NamePool();
            let globcls = @globclsfn(np);
            let globobj = JS_NewGlobalObject(self.ptr, ptr::to_unsafe_ptr(&*globcls), null());
            result(JS_InitStandardClasses(self.ptr, globobj)).chain(|_ok| {
                let compartment = @mut Compartment {
                    cx: self,
                    name_pool: np,
                    global_funcs: ~[],
                    global_props: ~[],
                    global_class: globcls,
                    global_obj: self.rooted_obj(globobj),
                    global_protos: @mut HashMap::new()
                };
                self.set_cx_private(ptr::to_unsafe_ptr(&*compartment) as *());
                Ok(compartment)
            })
        }
    }

    pub fn evaluate_script(@self, glob: jsobj, bytes: ~[u8], filename: ~str, line_num: uint)
                    -> Result<(),()> {
        do bytes.as_imm_buf |bytes_ptr, bytes_len| {
            do filename.to_c_str().with_ref |filename_cstr| {
                let bytes_ptr = bytes_ptr as *c_char;
                let rval: JSVal = JSVAL_NULL;
                debug!("Evaluating script from %s with bytes %?", filename, bytes);
                unsafe {
                    if JS_EvaluateScript(self.ptr, glob.ptr,
                                         bytes_ptr, bytes_len as c_uint,
                                         filename_cstr, line_num as c_uint,
                                         ptr::to_unsafe_ptr(&rval)) == ERR {
                        debug!("...err!");
                        Err(())
                    } else {
                        // we could return the script result but then we'd have
                        // to root it and so forth and, really, who cares?
                        debug!("...ok!");
                        Ok(())
                    }
                }
            }
        }
    }

    pub fn lookup_class_name(@self, s: ~str) ->  @JSClass {
        // FIXME: expect should really take a lambda...
        let error_msg = fmt!("class %s not found in class table", s);
        let name = self.classes.find(&s);
        *(name.expect(error_msg))
    }

    pub unsafe fn get_cx_private(@self) -> *() {
        cast::transmute(JS_GetContextPrivate(self.ptr))
    }

    pub unsafe fn set_cx_private(@self, data: *()) {
        JS_SetContextPrivate(self.ptr, cast::transmute(data));
    }

    pub unsafe fn get_obj_private(@self, obj: *JSObject) -> *() {
        cast::transmute(JS_GetPrivate(obj))
    }

    pub unsafe fn set_obj_private(@self, obj: *JSObject, data: *()) {
        JS_SetPrivate(obj, cast::transmute(data));
    }
}

pub extern fn reportError(_cx: *JSContext, msg: *c_char, report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {~"none"};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        error!("Error at %s:%?: %s\n", fname, lineno, msg);
    }
}

// ___________________________________________________________________________
// compartment

pub struct Compartment {
    cx: @Cx,
    name_pool: @mut NamePool,
    global_funcs: ~[@~[JSFunctionSpec]],
    global_props: ~[@~[JSPropertySpec]],
    global_class: @JSClass,
    global_obj: jsobj,
    global_protos: @mut HashMap<~str, jsobj>
}

impl Compartment {
    pub fn define_functions(@mut self,
                        specfn: &fn(@mut NamePool) -> ~[JSFunctionSpec])
                     -> Result<(),()> {
        let specvec = @specfn(self.name_pool);
        self.global_funcs.push(specvec);
        do specvec.as_imm_buf |specs, _len| {
            unsafe {
                result(JS_DefineFunctions(self.cx.ptr, self.global_obj.ptr, specs))
            }
        }
    }
    pub fn define_properties(@mut self, specfn: &fn() -> ~[JSPropertySpec]) -> Result<(),()> {
        let specvec = @specfn();
        self.global_props.push(specvec);
        do specvec.as_imm_buf |specs, _len| {
            unsafe {
                result(JS_DefineProperties(self.cx.ptr, self.global_obj.ptr, specs))
            }
        }
    }
    pub fn define_property(@mut self,
                       name: ~str,
                       value: JSVal,
                       getter: JSPropertyOp, setter: JSStrictPropertyOp,
                       attrs: c_uint)
                    -> Result<(),()> {
        unsafe {
            result(JS_DefineProperty(self.cx.ptr,
                                     self.global_obj.ptr,
                                     self.add_name(name),
                                     value,
                                     getter,
                                     setter,
                                     attrs))
        }
    }
    pub fn new_object(@mut self, class_name: ~str, proto: *JSObject, parent: *JSObject)
               -> Result<jsobj, ()> {
        unsafe {
            let classptr = self.cx.lookup_class_name(class_name);
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, &*classptr, proto, parent));
            result_obj(obj)
        }
    }
    pub fn new_object_with_proto(@mut self, class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let proto = self.global_protos.find(&proto_name.clone()).expect(
            fmt!("new_object_with_proto: expected to find %s in the proto \
                  table", proto_name));
        unsafe {
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                      proto.ptr, parent));
            result_obj(obj)
        }
    }
    pub fn get_global_proto(@mut self, name: ~str) -> jsobj {
        let proto = self.global_protos.get(&name);
        *proto
    }
    pub fn stash_global_proto(@mut self, name: ~str, proto: jsobj) {
        let global_protos = self.global_protos;
        if !global_protos.insert(name, proto) {
            fail!(~"Duplicate global prototype registered; you're gonna have a bad time.")
        }
    }
    pub fn register_class(@mut self, class_fn: &fn(x: @mut Compartment) -> JSClass) {
        let classptr = @class_fn(self);
        if !self.cx.classes.insert(
            unsafe { from_c_str(classptr.name) },
            classptr) {
            fail!(~"Duplicate JSClass registered; you're gonna have a bad time.")
        }
    }
    pub fn add_name(@mut self, name: ~str) -> *c_char {
        self.name_pool.add(name.clone())
    }
}

// ___________________________________________________________________________
// objects

pub type jsobj = @jsobj_rsrc;

pub struct jsobj_rsrc {
    cx: @Cx,
    cxptr: *JSContext,
    ptr: *JSObject,
}

#[unsafe_destructor]
impl Drop for jsobj_rsrc {
    fn drop(&self) {
        unsafe {
            JS_RemoveObjectRoot(self.cxptr, ptr::to_unsafe_ptr(&self.ptr));
        }
    }
}

impl jsobj_rsrc {
    fn new_object(&self, cx: @Cx, cxptr: *JSContext, ptr: *JSObject) -> jsobj {
        return @jsobj_rsrc {
            cx: cx,
            cxptr: cxptr,
            ptr: ptr
        }
    }
}

// ___________________________________________________________________________
// random utilities

pub trait to_jsstr {
    fn to_jsstr(self, cx: @Cx) -> *JSString;
}

impl to_jsstr for ~str {
    fn to_jsstr(self, cx: @Cx) -> *JSString {
        do self.as_imm_buf |buf, len| {
            unsafe {
                let cbuf = cast::transmute(buf);
                JS_NewStringCopyN(cx.ptr, cbuf, len as size_t)
            }
        }
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::super::global;
    use super::super::jsapi::{JS_GC, JS_GetRuntime};

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.set_default_options_and_version();
        cx.set_logging_error_reporter();
        cx.new_compartment(global::global_class).chain(|comp| {
            unsafe { JS_GC(JS_GetRuntime(comp.cx.ptr)); }

            comp.define_functions(global::debug_fns);

            let s = ~"debug(22);";
            let bytes = s.as_bytes().to_owned();
            cx.evaluate_script(comp.global_obj, bytes, ~"test", 1u)
        });
    }

}
<|endoftext|>


<commit_before>use redox::{Box, String, ToString, Vec};
use redox::fs::File;
use redox::io::Read;

use orbital::{BmpFile, Color, Point, Size, Event, EventOption, KeyEvent, MouseEvent};

use super::display::Display;
use super::package::*;
use super::window::Window;

/// A session
pub struct Session {
    /// The display
    pub display: Box<Display>,
    /// The background image
    pub background: BmpFile,
    /// The cursor icon
    pub cursor: BmpFile,
    /// The mouse point
    pub mouse_point: Point,
    last_mouse_event: MouseEvent,
    /// The packages (applications)
    pub packages: Vec<Box<Package>>,
    /// Open windows
    pub windows: Vec<*mut Window>,
    /// Ordered windows
    pub windows_ordered: Vec<*mut Window>,
    /// Redraw
    pub redraw: bool,
}

impl Session {
    /// Create new session
    pub fn new() -> Box<Self> {
        let mut ret = box Session {
            display: unsafe { Display::root() },
            background: BmpFile::default(),
            cursor: BmpFile::default(),
            mouse_point: Point::new(0, 0),
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                middle_button: false,
                right_button: false,
            },
            packages: Vec::new(),
            windows: Vec::new(),
            windows_ordered: Vec::new(),
            redraw: true,
        };

        if let Some(mut file) = File::open("file:/ui/cursor.bmp") {
            let mut vec = Vec::new();
            file.read_to_end(&mut vec);
            ret.cursor = BmpFile::from_data(&vec);
        } else {
            debugln!("Failed to read cursor");
        }

        if let Some(mut file) = File::open("file:/ui/background.bmp") {
            let mut vec = Vec::new();
            file.read_to_end(&mut vec);
            ret.background = BmpFile::from_data(&vec);
        } else {
            debugln!("Failed to read background");
        }

        //TODO: Open fonts, packages
        unsafe { ret.redraw() };

        ret
    }

    pub unsafe fn add_window(&mut self, add_window_ptr: *mut Window) {
        self.windows.push(add_window_ptr);
        self.windows_ordered.push(add_window_ptr);
        self.redraw = true;
    }

    /// Remove a window
    pub unsafe fn remove_window(&mut self, remove_window_ptr: *mut Window) {
        let mut i = 0;
        while i < self.windows.len() {
            let mut remove = false;

            match self.windows.get(i) {
                Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                None => break,
            }

            if remove{
                self.windows.remove(i);
            }
        }

        i = 0;
        while i < self.windows_ordered.len() {
            let mut remove = false;

            match self.windows_ordered.get(i) {
                Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                None => break,
            }

            if remove {
                self.windows_ordered.remove(i);
            }
        }

        self.redraw = true;
    }

    fn on_key(&mut self, key_event: KeyEvent) {
        if !self.windows.is_empty() {
            match self.windows.get(self.windows.len() - 1) {
                Some(window_ptr) => {
                    unsafe {
                        (**window_ptr).on_key(key_event);
                        self.redraw = true;
                    }
                }
                None => (),
            }
        }
    }

    fn on_mouse(&mut self, mouse_event: MouseEvent) {
        let mut catcher = -1;

        if mouse_event.y >= self.display.height as isize - 32 {
            if !mouse_event.left_button && self.last_mouse_event.left_button {
                let mut x = 0;
                for package in self.packages.iter() {
                    if !package.icon.as_slice().is_empty() {
                        if mouse_event.x >= x &&
                           mouse_event.x < x + package.icon.width() as isize {
                            //TODO: execute(&package.binary, &package.url, Vec::new());
                        }
                        x = x + package.icon.width() as isize;
                    }
                }

                let mut chars = 32;
                while chars > 4 &&
                      (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                      self.display.width + 32 {
                    chars -= 1;
                }

                x += 4;
                for window_ptr in self.windows_ordered.iter() {
                    let w = (chars*8 + 2*4) as usize;
                    if mouse_event.x >= x && mouse_event.x < x + w as isize {
                        for j in 0..self.windows.len() {
                            match self.windows.get(j) {
                                Some(catcher_window_ptr) =>
                                    if catcher_window_ptr == window_ptr {
                                    unsafe {
                                        if j == self.windows.len() - 1 {
                                            (**window_ptr).minimized = !(**window_ptr).minimized;
                                        } else {
                                            catcher = j as isize;
                                            (**window_ptr).minimized = false;
                                        }
                                    }
                                    break;
                                },
                                None => break,
                            }
                        }
                        self.redraw = true;
                        break;
                    }
                    x += w as isize;
                }
            }
        } else {
            for reverse_i in 0..self.windows.len() {
                let i = self.windows.len() - 1 - reverse_i;
                match self.windows.get(i) {
                    Some(window_ptr) => unsafe {
                        if (**window_ptr).on_mouse(mouse_event, catcher < 0) {
                            catcher = i as isize;

                            self.redraw = true;
                        }
                    },
                    None => (),
                }
            }
        }

        if catcher >= 0 && catcher < self.windows.len() as isize - 1 {
            let window_ptr = self.windows.remove(catcher as usize);
            self.windows.push(window_ptr);
        }

        self.last_mouse_event = mouse_event;
    }

    /// Redraw screen
    pub unsafe fn redraw(&mut self) {
        if self.redraw {
            self.display.set(Color::rgb(75, 163, 253));
            if !self.background.as_slice().is_empty() {
                self.display.image(Point::new((self.display.width as isize -
                                                 self.background.width() as isize) /
                                                2,
                                                (self.display.height as isize -
                                                 self.background.height() as isize) /
                                                2),
                                    self.background.as_slice().as_ptr(),
                                    Size::new(self.background.width(), self.background.height()));
            }

            for i in 0..self.windows.len() {
                match self.windows.get(i) {
                    Some(window_ptr) => {
                        (**window_ptr).focused = i == self.windows.len() - 1;
                        (**window_ptr).draw(&self.display);
                    }
                    None => (),
                }
            }

            self.display.rect(Point::new(0, self.display.height as isize - 32),
                              Size::new(self.display.width, 32),
                              Color::rgba(0, 0, 0, 128));

            let mut x = 0;
            for package in self.packages.iter() {
                if !package.icon.as_slice().is_empty() {
                    let y = self.display.height as isize - package.icon.height() as isize;
                    if self.mouse_point.y >= y && self.mouse_point.x >= x &&
                       self.mouse_point.x < x + package.icon.width() as isize {
                        self.display.rect(Point::new(x, y),
                                          Size::new(package.icon.width(), package.icon.height()),
                                          Color::rgba(128, 128, 128, 128));

                       self.display.rect(Point::new(x, y - 16),
                                         Size::new(package.name.len() * 8, 16),
                                         Color::rgba(0, 0, 0, 128));

                        let mut c_x = x;
                        for c in package.name.chars() {
                            self.display
                                .char(Point::new(c_x, y - 16), c, Color::rgb(255, 255, 255));
                            c_x += 8;
                        }
                    }

                    self.display.image_alpha(Point::new(x, y),
                                             package.icon.as_slice().as_ptr(),
                                             Size::new(package.icon.width(), package.icon.height()));
                    x = x + package.icon.width() as isize;
                }
            }

            let mut chars = 32;
            while chars > 4 &&
                  (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                  self.display.width + 32 {
                chars -= 1;
            }

            x += 4;
            for window_ptr in self.windows_ordered.iter() {
                let w = (chars*8 + 2*4) as usize;
                self.display.rect(Point::new(x, self.display.height as isize - 32),
                                  Size::new(w, 32),
                                  (**window_ptr).border_color);
                x += 4;

                let mut i = 0;
                for c in (**window_ptr).title.chars() {
                    if c != '\0' {
                        self.display.char(Point::new(x, self.display.height as isize - 24),
                                          c,
                                          (**window_ptr).title_color);
                    }
                    x += 8;
                    i += 1;
                    if i >= chars {
                        break;
                    }
                }
                while i < chars {
                    x += 8;
                    i += 1;
                }
                x += 8;
            }

            if !self.cursor.as_slice().is_empty() {
                self.display.image_alpha(self.mouse_point,
                                         self.cursor.as_slice().as_ptr(),
                                         Size::new(self.cursor.width(), self.cursor.height()));
            } else {
                self.display.char(Point::new(self.mouse_point.x - 3, self.mouse_point.y - 9),
                                  'X',
                                  Color::rgb(255, 255, 255));
            }

            //let reenable = scheduler::start_no_ints();

            self.display.flip();

            self.redraw = false;

            //scheduler::end_no_ints(reenable);
        }
    }

    pub fn event(&mut self, event: Event) {
        match event.to_option() {
            EventOption::Mouse(mouse_event) => self.on_mouse(mouse_event),
            EventOption::Key(key_event) => self.on_key(key_event),
            _ => (),
        }
    }
}
<commit_msg>Add packages<commit_after>use redox::{Box, String, ToString, Vec, Url};
use redox::fs::File;
use redox::io::Read;

use orbital::{BmpFile, Color, Point, Size, Event, EventOption, KeyEvent, MouseEvent};

use super::display::Display;
use super::package::*;
use super::window::Window;

/// A session
pub struct Session {
    /// The display
    pub display: Box<Display>,
    /// The background image
    pub background: BmpFile,
    /// The cursor icon
    pub cursor: BmpFile,
    /// The mouse point
    pub mouse_point: Point,
    last_mouse_event: MouseEvent,
    /// The packages (applications)
    pub packages: Vec<Box<Package>>,
    /// Open windows
    pub windows: Vec<*mut Window>,
    /// Ordered windows
    pub windows_ordered: Vec<*mut Window>,
    /// Redraw
    pub redraw: bool,
}

impl Session {
    /// Create new session
    pub fn new() -> Box<Self> {
        let mut ret = box Session {
            display: unsafe { Display::root() },
            background: BmpFile::default(),
            cursor: BmpFile::default(),
            mouse_point: Point::new(0, 0),
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                middle_button: false,
                right_button: false,
            },
            packages: Vec::new(),
            windows: Vec::new(),
            windows_ordered: Vec::new(),
            redraw: true,
        };

        if let Some(mut file) = File::open("file:/ui/cursor.bmp") {
            let mut vec = Vec::new();
            file.read_to_end(&mut vec);
            ret.cursor = BmpFile::from_data(&vec);
        } else {
            debugln!("Failed to read cursor");
        }

        if let Some(mut file) = File::open("file:/ui/background.bmp") {
            let mut vec = Vec::new();
            file.read_to_end(&mut vec);
            ret.background = BmpFile::from_data(&vec);
        } else {
            debugln!("Failed to read background");
        }

        if let Some(mut file) = File::open("file:/apps/") {
            let mut string = String::new();
            file.read_to_string(&mut string);

            for folder in string.lines() {
                if folder.ends_with('/') {
                    ret.packages.push(Package::from_url(&Url::from_string("file:/apps/".to_string() + &folder)));
                }
            }
        } else {
            debugln!("Failed to open apps")
        }

        //TODO: Open packages
        unsafe { ret.redraw() };

        ret
    }

    pub unsafe fn add_window(&mut self, add_window_ptr: *mut Window) {
        self.windows.push(add_window_ptr);
        self.windows_ordered.push(add_window_ptr);
        self.redraw = true;
    }

    /// Remove a window
    pub unsafe fn remove_window(&mut self, remove_window_ptr: *mut Window) {
        let mut i = 0;
        while i < self.windows.len() {
            let mut remove = false;

            match self.windows.get(i) {
                Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                None => break,
            }

            if remove{
                self.windows.remove(i);
            }
        }

        i = 0;
        while i < self.windows_ordered.len() {
            let mut remove = false;

            match self.windows_ordered.get(i) {
                Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                None => break,
            }

            if remove {
                self.windows_ordered.remove(i);
            }
        }

        self.redraw = true;
    }

    fn on_key(&mut self, key_event: KeyEvent) {
        if !self.windows.is_empty() {
            match self.windows.get(self.windows.len() - 1) {
                Some(window_ptr) => {
                    unsafe {
                        (**window_ptr).on_key(key_event);
                        self.redraw = true;
                    }
                }
                None => (),
            }
        }
    }

    fn on_mouse(&mut self, mouse_event: MouseEvent) {
        let mut catcher = -1;

        if mouse_event.y >= self.display.height as isize - 32 {
            if !mouse_event.left_button && self.last_mouse_event.left_button {
                let mut x = 0;
                for package in self.packages.iter() {
                    if !package.icon.as_slice().is_empty() {
                        if mouse_event.x >= x &&
                           mouse_event.x < x + package.icon.width() as isize {
                            //TODO: execute(&package.binary, &package.url, Vec::new());
                        }
                        x = x + package.icon.width() as isize;
                    }
                }

                let mut chars = 32;
                while chars > 4 &&
                      (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                      self.display.width + 32 {
                    chars -= 1;
                }

                x += 4;
                for window_ptr in self.windows_ordered.iter() {
                    let w = (chars*8 + 2*4) as usize;
                    if mouse_event.x >= x && mouse_event.x < x + w as isize {
                        for j in 0..self.windows.len() {
                            match self.windows.get(j) {
                                Some(catcher_window_ptr) =>
                                    if catcher_window_ptr == window_ptr {
                                    unsafe {
                                        if j == self.windows.len() - 1 {
                                            (**window_ptr).minimized = !(**window_ptr).minimized;
                                        } else {
                                            catcher = j as isize;
                                            (**window_ptr).minimized = false;
                                        }
                                    }
                                    break;
                                },
                                None => break,
                            }
                        }
                        self.redraw = true;
                        break;
                    }
                    x += w as isize;
                }
            }
        } else {
            for reverse_i in 0..self.windows.len() {
                let i = self.windows.len() - 1 - reverse_i;
                match self.windows.get(i) {
                    Some(window_ptr) => unsafe {
                        if (**window_ptr).on_mouse(mouse_event, catcher < 0) {
                            catcher = i as isize;

                            self.redraw = true;
                        }
                    },
                    None => (),
                }
            }
        }

        if catcher >= 0 && catcher < self.windows.len() as isize - 1 {
            let window_ptr = self.windows.remove(catcher as usize);
            self.windows.push(window_ptr);
        }

        self.last_mouse_event = mouse_event;
    }

    /// Redraw screen
    pub unsafe fn redraw(&mut self) {
        if self.redraw {
            self.display.set(Color::rgb(75, 163, 253));
            if !self.background.as_slice().is_empty() {
                self.display.image(Point::new((self.display.width as isize -
                                                 self.background.width() as isize) /
                                                2,
                                                (self.display.height as isize -
                                                 self.background.height() as isize) /
                                                2),
                                    self.background.as_slice().as_ptr(),
                                    Size::new(self.background.width(), self.background.height()));
            }

            for i in 0..self.windows.len() {
                match self.windows.get(i) {
                    Some(window_ptr) => {
                        (**window_ptr).focused = i == self.windows.len() - 1;
                        (**window_ptr).draw(&self.display);
                    }
                    None => (),
                }
            }

            self.display.rect(Point::new(0, self.display.height as isize - 32),
                              Size::new(self.display.width, 32),
                              Color::rgba(0, 0, 0, 128));

            let mut x = 0;
            for package in self.packages.iter() {
                if !package.icon.as_slice().is_empty() {
                    let y = self.display.height as isize - package.icon.height() as isize;
                    if self.mouse_point.y >= y && self.mouse_point.x >= x &&
                       self.mouse_point.x < x + package.icon.width() as isize {
                        self.display.rect(Point::new(x, y),
                                          Size::new(package.icon.width(), package.icon.height()),
                                          Color::rgba(128, 128, 128, 128));

                       self.display.rect(Point::new(x, y - 16),
                                         Size::new(package.name.len() * 8, 16),
                                         Color::rgba(0, 0, 0, 128));

                        let mut c_x = x;
                        for c in package.name.chars() {
                            self.display
                                .char(Point::new(c_x, y - 16), c, Color::rgb(255, 255, 255));
                            c_x += 8;
                        }
                    }

                    self.display.image_alpha(Point::new(x, y),
                                             package.icon.as_slice().as_ptr(),
                                             Size::new(package.icon.width(), package.icon.height()));
                    x = x + package.icon.width() as isize;
                }
            }

            let mut chars = 32;
            while chars > 4 &&
                  (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                  self.display.width + 32 {
                chars -= 1;
            }

            x += 4;
            for window_ptr in self.windows_ordered.iter() {
                let w = (chars*8 + 2*4) as usize;
                self.display.rect(Point::new(x, self.display.height as isize - 32),
                                  Size::new(w, 32),
                                  (**window_ptr).border_color);
                x += 4;

                let mut i = 0;
                for c in (**window_ptr).title.chars() {
                    if c != '\0' {
                        self.display.char(Point::new(x, self.display.height as isize - 24),
                                          c,
                                          (**window_ptr).title_color);
                    }
                    x += 8;
                    i += 1;
                    if i >= chars {
                        break;
                    }
                }
                while i < chars {
                    x += 8;
                    i += 1;
                }
                x += 8;
            }

            if !self.cursor.as_slice().is_empty() {
                self.display.image_alpha(self.mouse_point,
                                         self.cursor.as_slice().as_ptr(),
                                         Size::new(self.cursor.width(), self.cursor.height()));
            } else {
                self.display.char(Point::new(self.mouse_point.x - 3, self.mouse_point.y - 9),
                                  'X',
                                  Color::rgb(255, 255, 255));
            }

            //let reenable = scheduler::start_no_ints();

            self.display.flip();

            self.redraw = false;

            //scheduler::end_no_ints(reenable);
        }
    }

    pub fn event(&mut self, event: Event) {
        match event.to_option() {
            EventOption::Mouse(mouse_event) => self.on_mouse(mouse_event),
            EventOption::Key(key_event) => self.on_key(key_event),
            _ => (),
        }
    }
}
<|endoftext|>