1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::rc::Rc;
use std::path::Path;
use std::{fmt, error};

use rustc_serialize::{Decodable, json};

use animation::{AnimationClip, AnimationClipDef, DifferenceClipDef};
use transform::Transform;
use controller::AnimationControllerDef;

/// A collection of asset definitions, to be loaded from a JSON definition file
#[derive(Debug, RustcDecodable)]
pub struct AssetDefs {
    animation_clips: Option<Vec<AnimationClipDef>>,
    difference_clips: Option<Vec<DifferenceClipDef>>,
    animation_controllers: Option<Vec<AnimationControllerDef>>,
}

///
/// Asset manager - manages memory for loaded assets...?
///
pub struct AssetManager<T: Transform> {
    pub animation_clips: HashMap<String, Rc<AnimationClip<T>>>,
    pub controller_defs: HashMap<String, AnimationControllerDef>
}

/// Created when attempting to load assets from a path that does not have a parent folder (see
/// [`Path::parent` documentation][0])
///
/// [0]: https://doc.rust-lang.org/std/path/struct.Path.html#method.parent
#[derive(Debug)]
pub struct InvalidAssetPathError;

impl fmt::Display for InvalidAssetPathError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        writeln!(fmt, "Asset path must have a parent folder")
    }
}

impl error::Error for InvalidAssetPathError {}

impl<T: Transform> AssetManager<T> {

    pub fn new() -> AssetManager<T> {
        AssetManager {
            animation_clips: HashMap::new(),
            controller_defs: HashMap::new(),
        }
    }

    pub fn load_assets(&mut self, path: &str) -> Result<(), InvalidAssetPathError> {

        let asset_defs: AssetDefs = AssetManager::<T>::load_def_from_path(path).unwrap();
        let parent_path = Path::new(path).parent().ok_or(InvalidAssetPathError)?;

        if let Some(animation_clips) = asset_defs.animation_clips {
            for clip_def in animation_clips.iter() {
                let clip = AnimationClip::from_def(clip_def, parent_path.to_owned());
                self.animation_clips.insert(clip_def.name.clone(), Rc::new(clip));
            }
        }

        if let Some(difference_clips) = asset_defs.difference_clips {
            for difference_clip_def in difference_clips.iter() {

                let clip = {
                    let ref source_clip = self.animation_clips[&difference_clip_def.source_clip[..]];
                    let ref reference_clip = self.animation_clips[&difference_clip_def.reference_clip[..]];
                    AnimationClip::as_difference_clip(source_clip, reference_clip)
                };

                self.animation_clips.insert(difference_clip_def.name.clone(), Rc::new(clip));
            }
        }

        if let Some(animation_controllers) = asset_defs.animation_controllers {
            for controller_def in animation_controllers.iter() {
                self.controller_defs.insert(controller_def.name.clone(), controller_def.clone());
            }
        }

        Ok(())
    }

    pub fn load_def_from_path<D>(path: &str) -> Result<D, &'static str>
        where D: Decodable
    {
        let file_result = File::open(path);

        let mut file = match file_result {
            Ok(file) => file,
            Err(_) => return Err("Failed to open definition file at path.")
        };

        let mut json_string = String::new();
        match file.read_to_string(&mut json_string) {
            Ok(_) => {},
            Err(_) => return Err("Failed to read definition file.")
        };

        Ok(json::decode(&json_string[..]).unwrap())
    }

}