Files
Fyrox/src/engine/mod.rs
T
2019-08-20 14:20:04 +03:00

448 lines
14 KiB
Rust

use crate::{
scene::{
*,
node::NodeKind
},
utils::{
pool::*,
rcpool::{
RcPool,
RcHandle,
},
},
renderer::{
render::*,
surface::SurfaceSharedData,
surface::Surface
},
resource::{
*,
texture::*,
model::Model,
ttf::Font,
},
gui::UserInterface,
math::vec2::Vec2,
};
use std::{
path::*,
collections::VecDeque,
time::Duration,
any::TypeId
};
use serde::{
Serialize,
Deserialize,
};
#[derive(Serialize, Deserialize)]
pub struct ResourceManager {
resources: RcPool<Resource>,
/// Path to textures, extensively used for resource files
/// which stores path in weird format (either relative or absolute) which
/// is obviously not good for engine.
textures_path: PathBuf,
}
impl Default for ResourceManager {
fn default() -> Self {
Self {
resources: RcPool::new(),
textures_path: PathBuf::from("data/textures/"),
}
}
}
impl ResourceManager {
pub fn new() -> ResourceManager {
ResourceManager::default()
}
#[inline]
pub fn for_each_texture_mut<Func>(&mut self, mut func: Func) where Func: FnMut(&mut Texture) {
for resource in self.resources.iter_mut() {
if let ResourceKind::Texture(texture) = resource.borrow_kind_mut() {
func(texture);
}
}
}
#[inline]
fn add_resource(&mut self, resource: Resource) -> RcHandle<Resource> {
self.resources.spawn(resource)
}
/// Searches for a resource of specified path, if found - returns handle to resource
/// and increases reference count of resource.
#[inline]
fn find_resource(&mut self, path: &Path) -> RcHandle<Resource> {
for i in 0..self.resources.get_capacity() {
if let Some(resource) = self.resources.at(i) {
if resource.get_path() == path {
return self.resources.handle_from_index(i);
}
}
}
RcHandle::none()
}
#[inline]
pub fn borrow_resource(&self, resource_handle: &RcHandle<Resource>) -> Option<&Resource> {
self.resources.borrow(resource_handle)
}
#[inline]
pub fn borrow_resource_mut(&mut self, resource_handle: &RcHandle<Resource>) -> Option<&mut Resource> {
self.resources.borrow_mut(resource_handle)
}
#[inline]
pub fn share_resource_handle(&self, resource_handle: &RcHandle<Resource>) -> RcHandle<Resource> {
self.resources.share_handle(resource_handle)
}
#[inline]
#[must_use]
pub fn release_resource(&mut self, resource_handle: &RcHandle<Resource>) -> Option<Resource> {
self.resources.release(resource_handle)
}
#[inline]
pub fn get_textures_path(&self) -> &Path {
self.textures_path.as_path()
}
}
#[derive(Serialize, Deserialize)]
pub struct State {
scenes: Pool<Scene>,
#[serde(skip)]
surf_data_storage: RcPool<SurfaceSharedData>,
resource_manager: ResourceManager,
}
impl State {
#[inline]
pub fn new() -> Self {
State {
scenes: Pool::new(),
resource_manager: ResourceManager::new(),
surf_data_storage: RcPool::new(),
}
}
/// Returns handle of existing resource, or if resource is not loaded yet,
/// loads it and returns it handle. If resource could not be loaded, returns
/// none handle.
pub fn request_resource(&mut self, path: &Path) -> RcHandle<Resource> {
let mut resource_handle = self.resource_manager.find_resource(path);
if resource_handle.is_none() {
// No such resource, try to load it.
let extension = path.extension().
and_then(|os| os.to_str()).
map_or(String::from(""), |s| s.to_ascii_lowercase());
resource_handle = match extension.as_str() {
"jpg" | "jpeg" | "png" | "tif" | "tiff" | "tga" | "bmp" => {
match Texture::load(path) {
Ok(texture) => {
self.resource_manager.add_resource(Resource::new(path, ResourceKind::Texture(texture)))
}
Err(_) => {
println!("Unable to load texture {}!", path.display());
RcHandle::none()
}
}
}
"fbx" => {
match Model::load(path, self) {
Ok(model) => {
self.resource_manager.add_resource(Resource::new(path, ResourceKind::Model(model)))
}
Err(_) => {
println!("Unable to load model from {}!", path.display());
RcHandle::none()
}
}
}
_ => {
println!("Unknown resource type {}!", path.display());
RcHandle::none()
}
}
}
if resource_handle.is_some() {
println!("Resource {} is loaded!", path.display());
}
resource_handle
}
#[inline]
pub fn release_resource(&mut self, handle: &RcHandle<Resource>) {
if let Some(mut resource) = self.resource_manager.release_resource(handle) {
match resource.borrow_kind_mut() {
ResourceKind::Model(model) => {
self.destroy_scene_internal(model.get_scene_mut());
}
ResourceKind::Texture(texture) => ()
}
println!("Resource destroyed: {}!", resource.get_path().display());
}
}
fn clear(&mut self) {
for i in 0..self.scenes.get_capacity() {
if let Some(mut scene) = self.scenes.take_at(i) {
self.destroy_scene_internal(&mut scene);
}
}
if self.surf_data_storage.alive_count() != 0 {
println!("Not all shared surface data was freed! {} left alive!", self.surf_data_storage.alive_count());
}
}
fn resolve(&mut self) {
let mut resources_to_reload = Vec::new();
for i in 0..self.resource_manager.resources.get_capacity() {
let handle = self.resource_manager.resources.handle_from_index(i);
if handle.is_some() {
resources_to_reload.push(handle);
}
}
// Reload all resources first.
for resource_handle in resources_to_reload.iter() {
let (path, id) =
if let Some(resource) = self.resource_manager.resources.borrow(resource_handle) {
(PathBuf::from(resource.get_path()), resource.get_kind_id())
} else {
continue;
};
if id == TypeId::of::<Model>() {
let model = Model::load(path.as_path(), self).unwrap();
let resource = Resource::new(path.as_path(), ResourceKind::Model(model));
self.resource_manager.resources.replace(&resource_handle, resource);
} else if id == TypeId::of::<Texture>() {}
}
for scene in self.scenes.iter_mut() {
for node in scene.nodes.iter_mut() {
let node_name = String::from(node.get_name());
if let Some(resource) = self.resource_manager.borrow_resource(node.get_resource()) {
if let NodeKind::Mesh(mesh) = node.borrow_kind_mut() {
if let ResourceKind::Model(model) = resource.borrow_kind() {
let resource_node_handle = model.find_node_by_name(node_name.as_str());
if let Some(resource_node) = model.get_scene().get_node(&resource_node_handle) {
if let NodeKind::Mesh(resource_mesh) = resource_node.borrow_kind() {
let surfaces = mesh.get_surfaces_mut();
surfaces.clear();
for resource_surface in resource_mesh.get_surfaces() {
surfaces.push(Surface {
data: self.surf_data_storage.share_handle(&resource_surface.get_data_handle()),
texture: self.resource_manager.share_resource_handle(&resource_surface.get_texture_resource_handle()),
});
}
}
}
}
}
}
}
}
}
#[inline]
pub fn get_scenes(&self) -> &Pool<Scene> {
&self.scenes
}
#[inline]
pub fn get_scenes_mut(&mut self) -> &mut Pool<Scene> {
&mut self.scenes
}
#[inline]
pub fn get_surface_data_storage(&self) -> &RcPool<SurfaceSharedData> {
&self.surf_data_storage
}
#[inline]
pub fn get_resource_manager_mut(&mut self) -> &mut ResourceManager {
&mut self.resource_manager
}
#[inline]
pub fn get_resource_manager(&self) -> &ResourceManager {
&self.resource_manager
}
#[inline]
pub fn get_surface_data_storage_mut(&mut self) -> &mut RcPool<SurfaceSharedData> {
&mut self.surf_data_storage
}
#[inline]
pub fn add_scene(&mut self, scene: Scene) -> Handle<Scene> {
self.scenes.spawn(scene)
}
#[inline]
pub fn get_scene(&self, handle: &Handle<Scene>) -> Option<&Scene> {
if let Some(scene) = self.scenes.borrow(handle) {
return Some(scene);
}
None
}
#[inline]
pub fn get_scene_mut(&mut self, handle: &Handle<Scene>) -> Option<&mut Scene> {
if let Some(scene) = self.scenes.borrow_mut(handle) {
return Some(scene);
}
None
}
#[inline]
fn destroy_scene_internal(&mut self, scene: &mut Scene) {
scene.remove_node(scene.get_root(), self);
}
#[inline]
pub fn destroy_scene(&mut self, handle: &Handle<Scene>) {
if let Some(mut scene) = self.scenes.take(handle) {
self.destroy_scene_internal(&mut scene);
}
}
}
pub struct Engine {
renderer: Renderer,
pub state: State,
events: VecDeque<glutin::Event>,
running: bool,
font_cache: Pool<Font>,
default_font: Handle<Font>,
user_interface: UserInterface,
}
impl Engine {
#[inline]
pub fn new() -> Engine {
let mut font_cache = Pool::new();
let default_font = font_cache.spawn(Font::load(
Path::new("data/fonts/font.ttf"),
20.0,
(0..255).collect()).unwrap());
let mut renderer = Renderer::new();
renderer.upload_font_cache(&mut font_cache);
Engine {
state: State::new(),
renderer,
events: VecDeque::new(),
running: true,
user_interface: UserInterface::new(default_font.clone()),
default_font,
font_cache,
}
}
#[inline]
pub fn get_state(&self) -> &State {
&self.state
}
#[inline]
pub fn get_state_mut(&mut self) -> &mut State {
&mut self.state
}
#[inline]
pub fn is_running(&self) -> bool {
self.running
}
pub fn update(&mut self, dt: f64) {
let client_size = self.renderer.context.get_inner_size().unwrap();
let aspect_ratio = (client_size.width / client_size.height) as f32;
for scene in self.state.scenes.iter_mut() {
scene.update(aspect_ratio, dt);
}
self.user_interface.update(Vec2::make(client_size.width as f32, client_size.height as f32));
}
pub fn poll_events(&mut self) {
// Gather events
let events = &mut self.events;
events.clear();
self.renderer.events_loop.poll_events(|event| {
events.push_back(event);
});
}
#[inline]
pub fn get_font(&self, font_handle: &Handle<Font>) -> Option<&Font> {
self.font_cache.borrow(font_handle)
}
#[inline]
pub fn get_default_font(&self) -> Handle<Font> {
self.default_font.clone()
}
#[inline]
pub fn get_ui(&self) -> &UserInterface {
&self.user_interface
}
#[inline]
pub fn get_ui_mut(&mut self) -> &mut UserInterface {
&mut self.user_interface
}
pub fn get_rendering_statisting(&self) -> &Statistics {
self.renderer.get_statistics()
}
pub fn save<W>(&self, writer: W) where W: std::io::Write {
serde_json::to_writer_pretty(writer, &self.state).unwrap();
}
pub fn load<R>(&mut self, reader: R) where R: std::io::Read {
self.state.clear();
self.state = serde_json::from_reader(reader).unwrap();
self.state.resolve();
}
pub fn render(&mut self) {
self.renderer.upload_font_cache(&mut self.font_cache);
self.renderer.upload_resources(&mut self.state);
self.user_interface.draw(&self.font_cache);
self.renderer.render(&self.state, &self.user_interface.get_drawing_context());
}
#[inline]
pub fn stop(&mut self) {
self.running = false;
}
#[inline]
pub fn pop_event(&mut self) -> Option<glutin::Event> {
self.events.pop_front()
}
}
pub fn duration_to_seconds_f64(duration: Duration) -> f64 {
duration.as_secs() as f64 + f64::from(duration.subsec_nanos()) / 1_000_000_000.0
}
pub fn duration_to_seconds_f32(duration: Duration) -> f32 {
duration_to_seconds_f64(duration) as f32
}