replaced serde with built-in serializer, working save/load

This commit is contained in:
Dmitry
2019-08-21 17:05:09 +03:00
parent 3181e4945f
commit e2d18ed56c
35 changed files with 13974 additions and 31236 deletions
+30 -1
View File
@@ -6,6 +6,35 @@
<component name="ChangeListManager">
<list default="true" id="1932b2c4-d6ff-413c-9558-19959667326b" name="Default Changelist" comment="scene graph">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/save.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/engine/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/engine/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/game/level.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/game/level.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/game/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/game/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/game/player.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/game/player.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/game/weapon.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/game/weapon.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/image.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/image.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/math/mat4.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/math/mat4.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/math/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/math/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/math/plane.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/math/plane.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/math/quat.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/math/quat.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/math/ray.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/math/ray.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/math/vec3.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/math/vec3.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/physics/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/physics/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/renderer/render.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/render.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/renderer/surface.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/surface.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/resource/fbx/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/fbx/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/resource/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/resource/model.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/model.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/resource/texture.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/texture.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/animation.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/animation.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/node.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/node.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils/pool.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/pool.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils/rcpool.rs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils/visitor.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/visitor.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test.bin" beforeDir="false" afterPath="$PROJECT_DIR$/test.bin" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test.txt" beforeDir="false" afterPath="$PROJECT_DIR$/test.txt" afterDir="false" />
@@ -62,7 +91,7 @@
</list>
</option>
</component>
<component name="RunManager" selected="Cargo Command.Test">
<component name="RunManager" selected="Cargo Command.Release">
<configuration name="Clippy" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="channel" value="DEFAULT" />
<option name="command" value="clippy" />
Generated
-39
View File
@@ -353,11 +353,6 @@ dependencies = [
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "jpeg-decoder"
version = "0.1.15"
@@ -765,8 +760,6 @@ dependencies = [
"glutin 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -834,34 +827,6 @@ name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "shared_library"
version = "0.1.9"
@@ -1133,7 +1098,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum glutin_wgl_sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d0f023d00cfb4a100f6af038c9d03e182daa328796a915b56b0d69942066c8d"
"checksum image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "52fb0666a1273dac46f9725aa4859bcd5595fc3554cf3495051b4de8db745e7d"
"checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d"
"checksum khronos_api 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62237e6d326bd5871cd21469323bf096de81f1618cd82cbaf5d87825335aeb49"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
@@ -1191,9 +1155,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be"
"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e"
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
"checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
"checksum smithay-client-toolkit 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aa4899558362a65589b53313935099835acf999740915e134dff20cca7c6a28b"
-2
View File
@@ -14,7 +14,5 @@ opt-level = 3
glutin = "*"
image = "*"
lexical = "*"
serde = { version = "*", features = ["derive"] }
serde_json = "*"
byteorder = "*"
base64="*"
BIN
View File
Binary file not shown.
-30115
View File
File diff suppressed because it is too large Load Diff
+12659
View File
File diff suppressed because it is too large Load Diff
+128 -158
View File
@@ -1,20 +1,14 @@
use crate::{
scene::{
*,
node::NodeKind
},
scene::*,
utils::{
pool::*,
rcpool::{
RcPool,
RcHandle,
visitor::{
Visitor,
VisitResult,
Visit,
},
},
renderer::{
render::*,
surface::SurfaceSharedData,
surface::Surface
},
renderer::render::*,
resource::{
*,
texture::*,
@@ -28,96 +22,78 @@ use std::{
path::*,
collections::VecDeque,
time::Duration,
any::TypeId
};
use serde::{
Serialize,
Deserialize,
cell::RefCell,
rc::Rc,
};
use crate::scene::node::NodeKind;
use std::any::TypeId;
#[derive(Serialize, Deserialize)]
pub struct ResourceManager {
resources: RcPool<Resource>,
resources: Vec<Rc<RefCell<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 {
impl ResourceManager {
pub fn new() -> ResourceManager {
Self {
resources: RcPool::new(),
resources: Vec::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() {
pub fn for_each_texture_mut<Func>(&self, mut func: Func) where Func: FnMut(&mut Texture) {
for resource in self.resources.iter() {
if let ResourceKind::Texture(texture) = resource.borrow_mut().borrow_kind_mut() {
func(texture);
}
}
}
#[inline]
fn add_resource(&mut self, resource: Resource) -> RcHandle<Resource> {
self.resources.spawn(resource)
fn add_resource(&mut self, resource: Rc<RefCell<Resource>>) {
self.resources.push(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);
}
fn find_resource(&mut self, path: &Path) -> Option<Rc<RefCell<Resource>>> {
for resource in self.resources.iter() {
if resource.borrow().get_path() == path {
return Some(resource.clone());
}
}
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)
None
}
#[inline]
pub fn get_textures_path(&self) -> &Path {
self.textures_path.as_path()
}
pub fn update(&mut self) {
self.resources.retain(|resource| {
Rc::strong_count(resource) > 1
})
}
}
impl Visit for ResourceManager {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.resources.visit("Resources", visitor)?;
visitor.leave_region()
}
}
#[derive(Serialize, Deserialize)]
pub struct State {
scenes: Pool<Scene>,
#[serde(skip)]
surf_data_storage: RcPool<SurfaceSharedData>,
resource_manager: ResourceManager,
}
@@ -127,70 +103,50 @@ impl State {
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);
pub fn request_resource(&mut self, path: &Path) -> Option<Rc<RefCell<Resource>>> {
match self.resource_manager.find_resource(path) {
Some(resource) => Some(resource),
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());
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) {
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)))
let resource = Rc::new(RefCell::new(Resource::new(path, ResourceKind::Texture(texture))));
self.resource_manager.add_resource(resource.clone());
println!("Texture {} is loaded!", path.display());
Some(resource)
}
Err(_) => {
println!("Unable to load texture {}!", path.display());
RcHandle::none()
None
}
}
}
"fbx" => {
match Model::load(path, self) {
"fbx" => match Model::load(path, self) {
Ok(model) => {
self.resource_manager.add_resource(Resource::new(path, ResourceKind::Model(model)))
let resource = Rc::new(RefCell::new(Resource::new(path, ResourceKind::Model(model))));
self.resource_manager.add_resource(resource.clone());
println!("Model {} is loaded!", path.display());
Some(resource)
}
Err(_) => {
println!("Unable to load model from {}!", path.display());
RcHandle::none()
None
}
},
_ => {
println!("Unknown resource type {}!", path.display());
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) {
@@ -199,53 +155,55 @@ impl State {
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);
}
}
let resources_to_reload = self.resource_manager.resources.clone();
// 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;
};
for resource in resources_to_reload {
let path = PathBuf::from(resource.borrow().get_path());
let id = resource.borrow().get_kind_id();
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>() {}
let new_model = match Model::load(path.as_path(), self) {
Ok(new_model) => new_model,
Err(e) => {
println!("Unable to reload {:?} model! Reason: {}", path, e);
continue;
}
};
if let ResourceKind::Model(model) = resource.borrow_mut().borrow_kind_mut() {
*model = new_model;
}
} else if id == TypeId::of::<Texture>() {
let new_texture = match Texture::load(path.as_path()) {
Ok(texture) => texture,
Err(e) => {
println!("Unable to reload {:?} texture! Reason: {}", path, e);
continue;
}
};
if let ResourceKind::Texture(texture) = resource.borrow_mut().borrow_kind_mut() {
*texture = new_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 Some(resource) = node.get_resource() {
if let NodeKind::Mesh(mesh) = node.borrow_kind_mut() {
if let ResourceKind::Model(model) = resource.borrow_kind() {
if let ResourceKind::Model(model) = resource.borrow().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()),
});
surfaces.push(resource_surface.make_copy());
}
}
}
@@ -266,11 +224,6 @@ impl State {
&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
@@ -281,11 +234,6 @@ impl State {
&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)
@@ -320,6 +268,17 @@ impl State {
}
}
impl Visit for State {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.resource_manager.visit("ResourceManager", visitor)?;
self.scenes.visit("Scenes", visitor)?;
visitor.leave_region()
}
}
pub struct Engine {
renderer: Renderer,
pub state: State,
@@ -370,6 +329,8 @@ impl Engine {
let client_size = self.renderer.context.get_inner_size().unwrap();
let aspect_ratio = (client_size.width / client_size.height) as f32;
self.state.resource_manager.update();
for scene in self.state.scenes.iter_mut() {
scene.update(aspect_ratio, dt);
}
@@ -410,16 +371,6 @@ impl Engine {
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);
@@ -438,6 +389,25 @@ impl Engine {
}
}
impl Visit for Engine {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
// Make sure to delete unused resources.
if visitor.is_reading() {
self.state.resource_manager.update();
}
self.state.visit("State", visitor)?;
if visitor.is_reading() {
self.state.resolve();
}
visitor.leave_region()
}
}
pub fn duration_to_seconds_f64(duration: Duration) -> f64 {
duration.as_secs() as f64 + f64::from(duration.subsec_nanos()) / 1_000_000_000.0
}
+56 -22
View File
@@ -1,21 +1,56 @@
use crate::{
utils::pool::*,
utils::{
pool::*,
visitor::{
Visit,
VisitResult,
},
visitor::Visitor,
},
math::vec3::*,
scene::{
node::*,
*
*,
},
engine::*,
physics::{StaticGeometry, StaticTriangle},
game::player::Player,
game::GameTime
physics::{
StaticGeometry,
StaticTriangle,
},
game::{
player::Player,
GameTime,
},
resource::model::Model,
};
use std::{
path::Path,
rc::Rc,
};
use std::path::Path;
use crate::resource::model::Model;
pub struct Level {
scene: Handle<Scene>,
player: Player,
player: Option<Player>,
}
impl Default for Level {
fn default() -> Self {
Self {
scene: Handle::none(),
player: None,
}
}
}
impl Visit for Level {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.scene.visit("Scene", visitor)?;
self.player.visit("Player", visitor)?;
visitor.leave_region()
}
}
impl Level {
@@ -26,7 +61,7 @@ impl Level {
let map_model_handle = engine.get_state_mut().request_resource(Path::new("data/models/map.fbx"));
if map_model_handle.is_some() {
// Instantiate map
let map_root_handle = Model::instantiate(&map_model_handle, engine.get_state(), &mut scene).unwrap_or(Handle::none());
let map_root_handle = Model::instantiate(map_model_handle.unwrap(), &mut scene).unwrap_or(Handle::none());
// Create collision geometry
let polygon_handle = scene.find_node_by_name(&map_root_handle, "Polygon");
@@ -35,8 +70,8 @@ impl Level {
let mut static_geometry = StaticGeometry::new();
if let NodeKind::Mesh(mesh) = polygon.borrow_kind() {
for surface in mesh.get_surfaces() {
let data_storage = engine.get_state_mut().get_surface_data_storage();
let shared_data = data_storage.borrow(surface.get_data_handle()).unwrap();
let data_rc = surface.get_data();
let shared_data = data_rc.borrow();
let vertices = shared_data.get_vertices();
let indices = shared_data.get_indices();
@@ -60,17 +95,14 @@ impl Level {
}
scene.get_physics_mut().add_static_geometry(static_geometry);
}
engine.get_state_mut().release_resource(&map_model_handle);
}
let mut ripper_handles: Vec<Handle<Node>> = Vec::new();
let ripper_model_handle = engine.get_state_mut().request_resource(Path::new("data/models/ripper.fbx"));
if ripper_model_handle.is_some() {
if let Some(ripper_model_resource) = ripper_model_handle {
for _ in 0..4 {
ripper_handles.push(Model::instantiate(&ripper_model_handle, engine.get_state(), &mut scene).unwrap_or(Handle::none()));
ripper_handles.push(Model::instantiate(Rc::clone(&ripper_model_resource), &mut scene).unwrap_or(Handle::none()));
}
engine.get_state_mut().release_resource(&ripper_model_handle);
}
for (i, handle) in ripper_handles.iter().enumerate() {
if let Some(node) = scene.get_node_mut(&handle) {
@@ -79,7 +111,7 @@ impl Level {
}
Level {
player: Player::new(engine.get_state_mut(), &mut scene),
player: Some(Player::new(engine.get_state_mut(), &mut scene)),
scene: engine.get_state_mut().add_scene(scene),
}
}
@@ -88,17 +120,19 @@ impl Level {
engine.get_state_mut().destroy_scene(&self.scene);
}
pub fn get_player(&self) -> &Player {
&self.player
pub fn get_player(&self) -> Option<&Player> {
self.player.as_ref()
}
pub fn get_player_mut(&mut self) -> &mut Player {
&mut self.player
pub fn get_player_mut(&mut self) -> Option<&mut Player> {
self.player.as_mut()
}
pub fn update(&mut self, engine: &mut Engine, time: &GameTime) {
if let Some(scene) = engine.get_state_mut().get_scene_mut(&self.scene) {
self.player.update(scene, time);
if let Some(ref mut player) = self.player {
player.update(scene, time);
}
}
}
}
+43 -14
View File
@@ -18,15 +18,18 @@ use crate::{
text::TextBuilder,
scroll_bar::ScrollBarBuilder,
},
gui::node::{UINode, UINodeKind},
utils::visitor::Visitor
};
use crate::gui::node::{UINode, UINodeKind};
use std::{
cell::RefCell,
fs::File,
path::Path,
time::Instant,
rc::Rc,
io::Write
};
use crate::utils::visitor::{VisitResult, Visit};
pub struct MenuState {
save_game: Option<()>,
@@ -51,7 +54,6 @@ pub struct GameTime {
delta: f64,
}
impl Game {
pub fn new() -> Game {
let engine = Engine::new();
@@ -176,21 +178,43 @@ impl Game {
.build(ui);
}
pub fn save_game(&self) {
match File::create(Path::new("save.json")) {
Ok(file) => {
self.engine.save(file)
}
Err(_) => println!("unable to create a save"),
pub fn save_game(&mut self) -> VisitResult {
let mut visitor = Visitor::new();
// Visit engine state first.
self.engine.visit("Engine", &mut visitor)?;
self.level.visit("Level", &mut visitor)?;
// Debug output
if let Ok(mut file) = File::create(Path::new("save.txt")) {
file.write_all(visitor.save_text().as_bytes()).unwrap();
}
visitor.save_binary(Path::new("save.bin"))
}
pub fn load_game(&mut self) {
match File::open(Path::new("save.json")) {
Ok(file) => {
self.engine.load(file)
match Visitor::load_binary(Path::new("save.bin")) {
Ok(mut visitor) => {
// Clean up.
self.destroy_level();
// Load engine state first
match self.engine.visit("Engine", &mut visitor) {
Ok(_) => println!("Engine state successfully loaded!"),
Err(e) => println!("Failed to load engine state! Reason: {}", e)
}
// Then load game state.
match self.level.visit("Level", &mut visitor) {
Ok(_) => println!("Game state successfully loaded!"),
Err(e) => println!("Failed to load game state! Reason: {}", e)
}
}
Err(e) => {
println!("failed to load a save, reason: {}", e);
}
Err(_) => println!("failed to load a save!")
}
}
@@ -217,7 +241,10 @@ impl Game {
}
if state.save_game.take().is_some() {
self.save_game();
match self.save_game() {
Ok(_) => println!("successfully saved"),
Err(e) => println!("failed to make a save, reason: {}", e),
}
}
if state.load_game.take().is_some() {
@@ -250,7 +277,9 @@ impl Game {
while let Some(event) = self.engine.pop_event() {
if let glutin::Event::WindowEvent { event, .. } = event {
if let Some(ref mut level) = self.level {
level.get_player_mut().process_event(&event);
if let Some(player) = level.get_player_mut(){
player.process_event(&event);
}
}
match event {
glutin::WindowEvent::CloseRequested => self.engine.stop(),
+56 -4
View File
@@ -16,6 +16,7 @@ use crate::{
},
engine::State,
};
use crate::utils::visitor::{Visit, Visitor, VisitResult};
pub struct Controller {
move_forward: bool,
@@ -63,7 +64,58 @@ pub struct Player {
weapons: Vec<Weapon>,
camera_offset: Vec3,
camera_dest_offset: Vec3,
current_weapon: usize,
current_weapon: u32,
}
impl Default for Player {
fn default() -> Self {
Self {
camera: Default::default(),
camera_pivot: Default::default(),
pivot: Default::default(),
body: Default::default(),
weapon_pivot: Default::default(),
controller: Default::default(),
yaw: 0.0,
dest_yaw: 0.0,
pitch: 0.0,
dest_pitch: 0.0,
run_speed_multiplier: 0.0,
stand_body_radius: 0.0,
crouch_body_radius: 0.0,
move_speed: 0.0,
weapons: vec![],
camera_offset: Default::default(),
camera_dest_offset: Default::default(),
current_weapon: 0
}
}
}
impl Visit for Player {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.camera.visit("Camera", visitor)?;
self.camera_pivot.visit("CameraPivot", visitor)?;
self.pivot.visit("Pivot", visitor)?;
self.body.visit("Body", visitor)?;
self.weapon_pivot.visit("WeaponPivot", visitor)?;
self.yaw.visit("Yaw", visitor)?;
self.dest_yaw.visit("DestYaw", visitor)?;
self.pitch.visit("Pitch", visitor)?;
self.dest_pitch.visit("DestPitch", visitor)?;
self.run_speed_multiplier.visit("RunSpeedMultiplier", visitor)?;
self.stand_body_radius.visit("StandBodyRadius", visitor)?;
self.crouch_body_radius.visit("CrouchBodyRadius", visitor)?;
self.move_speed.visit("MoveSpeed", visitor)?;
self.weapons.visit("Weapons", visitor)?;
self.camera_offset.visit("CameraOffset", visitor)?;
self.camera_dest_offset.visit("CameraDestOffset", visitor)?;
self.current_weapon.visit("CurrentWeapon", visitor)?;
visitor.leave_region()
}
}
impl Player {
@@ -128,7 +180,7 @@ impl Player {
}
pub fn next_weapon(&mut self) {
if !self.weapons.is_empty() && self.current_weapon < self.weapons.len() - 1 {
if !self.weapons.is_empty() && (self.current_weapon as usize) < self.weapons.len() - 1 {
self.current_weapon += 1;
}
}
@@ -215,7 +267,7 @@ impl Player {
for (i, weapon) in self.weapons.iter().enumerate() {
if let Some(model) = scene.get_node_mut(&weapon.get_model()) {
model.set_visibility(i == self.current_weapon);
model.set_visibility(i == self.current_weapon as usize);
}
}
@@ -230,7 +282,7 @@ impl Player {
camera_pivot.set_local_rotation(Quat::from_axis_angle(Vec3::right(), self.pitch.to_radians()));
}
if let Some(current_weapon) = self.weapons.get_mut(self.current_weapon) {
if let Some(current_weapon) = self.weapons.get_mut(self.current_weapon as usize) {
if self.controller.shoot {
current_weapon.shoot(time);
}
+60 -6
View File
@@ -1,17 +1,26 @@
use std::path::Path;
use crate::{
utils::pool::Handle,
resource::model::Model,
utils::{
pool::Handle,
visitor::{
Visit,
VisitResult,
Visitor,
VisitError
}
},
scene::{
node::Node,
Scene
},
engine::State,
math::vec3::Vec3,
game::GameTime
game::GameTime,
};
use std::path::Path;
use crate::resource::model::Model;
pub enum WeaponKind {
Unknown,
M4,
Ak47,
}
@@ -24,9 +33,55 @@ pub struct Weapon {
last_shot_time: f64
}
impl Default for Weapon {
fn default() -> Self {
Self {
kind: WeaponKind::Unknown,
model: Handle::none(),
offset: Vec3::new(),
dest_offset: Vec3::new(),
last_shot_time: 0.0
}
}
}
impl Visit for Weapon {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut kind_id: u8 = if visitor.is_reading() {
0
} else {
match self.kind {
WeaponKind::Unknown => return Err(VisitError::User(String::from("unknown weapon kind on save???"))),
WeaponKind::M4 => 0,
WeaponKind::Ak47 => 1,
}
};
kind_id.visit("KindId", visitor)?;
if visitor.is_reading() {
self.kind = match kind_id {
0 => WeaponKind::M4,
1 => WeaponKind::Ak47,
_ => return Err(VisitError::User(format!("unknown weapon kind {}", kind_id)))
}
}
self.model.visit("Model", visitor)?;
self.offset.visit("Offset", visitor)?;
self.dest_offset.visit("DestOffset", visitor)?;
self.last_shot_time.visit("LastShotTime", visitor)?;
visitor.leave_region()
}
}
impl Weapon {
pub fn new(kind: WeaponKind, state: &mut State, scene: &mut Scene) -> Weapon {
let model_path = match kind {
WeaponKind::Unknown => panic!("must not be here"),
WeaponKind::Ak47 => Path::new("data/models/ak47.fbx"),
WeaponKind::M4 => Path::new("data/models/m4.fbx"),
};
@@ -34,8 +89,7 @@ impl Weapon {
let mut weapon_model = Handle::none();
let model_resource_handle = state.request_resource(model_path);
if model_resource_handle.is_some() {
weapon_model = Model::instantiate(&model_resource_handle, state, scene).unwrap_or(Handle::none());
state.release_resource(&model_resource_handle);
weapon_model = Model::instantiate(model_resource_handle.unwrap(), scene).unwrap_or(Handle::none());
}
Weapon {
+5 -2
View File
@@ -1,13 +1,16 @@
use crate::{
utils::{
pool::Handle,
rcpool::RcHandle
},
resource::Resource,
gui::node::UINode
};
use std::{
rc::Weak,
cell::RefCell
};
pub struct Image {
pub(in crate::gui) owner_handle: Handle<UINode>,
texture: RcHandle<Resource>,
texture: Weak<RefCell<Resource>>,
}
-4
View File
@@ -10,10 +10,6 @@ extern crate lexical;
extern crate byteorder;
extern crate base64;
// Serialization
extern crate serde;
extern crate serde_json;
mod utils;
mod math;
mod scene;
+1 -2
View File
@@ -5,9 +5,8 @@ use crate::{
quat::*
}
};
use serde::{Serialize, Deserialize};
#[derive(Copy, Clone, Serialize, Deserialize)]
#[derive(Copy, Clone)]
pub struct Mat4 {
pub f: [f32; 16]
}
+15 -2
View File
@@ -7,12 +7,12 @@ pub mod ray;
pub mod plane;
pub mod triangulator;
use serde::{Serialize, Deserialize};
use vec2::*;
use vec3::*;
use std::ops::{Add, Sub, Mul};
use crate::utils::visitor::{Visit, VisitResult, Visitor};
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
#[derive(Copy, Clone, Debug)]
pub struct Rect<T> {
pub x: T,
pub y: T,
@@ -53,6 +53,19 @@ impl<T> Rect<T> where T: Default + Add<Output = T> + Sub<Output = T> + Mul<Outpu
}
}
impl<T> Visit for Rect<T> where T: Default + Visit + 'static {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.x.visit("X", visitor)?;
self.y.visit("Y", visitor)?;
self.w.visit("W", visitor)?;
self.h.visit("H", visitor)?;
visitor.leave_region()
}
}
#[derive(Copy, Clone)]
pub enum PlaneClass {
XY,
-2
View File
@@ -1,7 +1,5 @@
use crate::math::vec3::Vec3;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Plane {
pub normal: Vec3,
pub d: f32,
+1 -2
View File
@@ -1,8 +1,7 @@
use crate::math::vec3::*;
use std::ops;
use serde::{Serialize, Deserialize};
#[derive(Copy, Clone, Serialize, Deserialize)]
#[derive(Copy, Clone)]
pub struct Quat {
pub x: f32,
pub y: f32,
-2
View File
@@ -1,7 +1,5 @@
use crate::math::vec3::Vec3;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Ray {
pub origin: Vec3,
pub dir: Vec3,
+1 -2
View File
@@ -1,7 +1,6 @@
use std::ops;
use serde::{Serialize, Deserialize};
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vec3 {
pub x: f32,
pub y: f32,
+141 -30
View File
@@ -4,19 +4,49 @@ use crate::{
ray::Ray,
plane::Plane
},
utils::pool::{Pool, Handle},
utils::pool::{
Pool,
Handle
},
utils::visitor::{
Visit,
VisitResult,
Visitor
}
};
use serde::{Serialize, Deserialize};
use crate::utils::visitor::VisitError;
#[derive(Serialize, Deserialize)]
pub struct Contact {
pub body: Handle<Body>,
pub position: Vec3,
pub normal: Vec3,
pub triangle_index: usize,
pub triangle_index: u32,
}
impl Default for Contact {
fn default() -> Self {
Self {
body: Handle::none(),
position: Vec3::new(),
normal: Vec3::make(0.0, 1.0, 0.0),
triangle_index: 0,
}
}
}
impl Visit for Contact {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.body.visit("Body", visitor)?;
self.position.visit("Position", visitor)?;
self.normal.visit("Normal", visitor)?;
self.triangle_index.visit("TriangleIndex", visitor)?;
visitor.leave_region()
}
}
#[derive(Serialize, Deserialize)]
pub struct StaticGeometry {
triangles: Vec<StaticTriangle>
}
@@ -33,28 +63,74 @@ impl StaticGeometry {
}
}
#[derive(Serialize, Deserialize)]
impl Default for StaticGeometry {
fn default() -> Self {
Self {
triangles: Vec::new(),
}
}
}
impl Visit for StaticGeometry {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.triangles.visit("Triangles", visitor)?;
visitor.leave_region()
}
}
pub struct StaticTriangle {
#[serde(skip)]
points: [Vec3; 3],
#[serde(skip)]
ca: Vec3,
#[serde(skip)]
ba: Vec3,
#[serde(skip)]
ca_dot_ca: f32,
#[serde(skip)]
ca_dot_ba: f32,
#[serde(skip)]
ba_dot_ba: f32,
#[serde(skip)]
edges: [Ray; 3],
#[serde(skip)]
inv_denom: f32,
#[serde(skip)]
plane: Plane,
}
impl Default for StaticTriangle {
fn default() -> Self {
Self {
points: Default::default(),
ca: Default::default(),
ba: Default::default(),
ca_dot_ca: 0.0,
ca_dot_ba: 0.0,
ba_dot_ba: 0.0,
edges: Default::default(),
inv_denom: 0.0,
plane: Default::default()
}
}
}
impl Visit for StaticTriangle {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut a = self.points[0];
a.visit("A", visitor)?;
let mut b = self.points[1];
b.visit("B", visitor)?;
let mut c = self.points[2];
c.visit("C", visitor)?;
*self = match Self::from_points(a, b, c) {
None => return Err(VisitError::User(String::from("invalid triangle"))),
Some(triangle) => triangle,
};
visitor.leave_region()
}
}
impl StaticTriangle {
///
/// Creates static triangle from tree points and precomputes some data
@@ -98,7 +174,6 @@ impl StaticTriangle {
}
}
#[derive(Serialize, Deserialize)]
pub struct Body {
position: Vec3,
last_position: Vec3,
@@ -111,6 +186,32 @@ pub struct Body {
speed_limit: f32,
}
impl Default for Body {
fn default() -> Self {
Self::new()
}
}
impl Visit for Body {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.position.visit("Position", visitor)?;
self.last_position.visit("LastPosition", visitor)?;
self.acceleration.visit("Acceleration", visitor)?;
self.contacts.visit("Contacts", visitor)?;
self.friction.visit("Friction", visitor)?;
self.gravity.visit("Gravity", visitor)?;
self.radius.visit("Radius", visitor)?;
if visitor.is_reading() {
self.sqr_radius = self.radius * self.radius;
}
self.speed_limit.visit("SpeedLimit", visitor)?;
visitor.leave_region()
}
}
impl Body {
pub fn new() -> Body {
Body {
@@ -277,62 +378,72 @@ impl Body {
body: Handle::none(),
position: intersection_point,
normal: push_vector,
triangle_index,
triangle_index: triangle_index as u32,
})
}
}
}
}
#[derive(Serialize, Deserialize)]
pub struct Physics {
body_pool: Pool<Body>,
static_geom_pool: Pool<StaticGeometry>,
bodies: Pool<Body>,
static_geoms: Pool<StaticGeometry>,
}
impl Visit for Physics {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.bodies.visit("Bodies", visitor)?;
self.static_geoms.visit("StaticGeoms", visitor)?;
visitor.leave_region()
}
}
impl Physics {
pub fn new() -> Physics {
Physics {
body_pool: Pool::new(),
static_geom_pool: Pool::new(),
bodies: Pool::new(),
static_geoms: Pool::new(),
}
}
pub fn add_body(&mut self, body: Body) -> Handle<Body> {
self.body_pool.spawn(body)
self.bodies.spawn(body)
}
pub fn remove_body(&mut self, body_handle: Handle<Body>) {
self.body_pool.free(body_handle);
self.bodies.free(body_handle);
}
pub fn add_static_geometry(&mut self, static_geom: StaticGeometry) -> Handle<StaticGeometry> {
self.static_geom_pool.spawn(static_geom)
self.static_geoms.spawn(static_geom)
}
pub fn remove_static_geometry(&mut self, static_geom: Handle<StaticGeometry>) {
self.static_geom_pool.free(static_geom);
self.static_geoms.free(static_geom);
}
pub fn borrow_body(&self, handle: &Handle<Body>) -> Option<&Body> {
self.body_pool.borrow(handle)
self.bodies.borrow(handle)
}
pub fn borrow_body_mut(&mut self, handle: &Handle<Body>) -> Option<&mut Body> {
self.body_pool.borrow_mut(handle)
self.bodies.borrow_mut(handle)
}
pub fn step(&mut self, delta_time: f32) {
let dt2 = delta_time * delta_time;
let air_friction = 0.003;
for body in self.body_pool.iter_mut() {
for body in self.bodies.iter_mut() {
body.acceleration += body.gravity;
body.verlet(dt2, air_friction);
body.contacts.clear();
for static_geometry in self.static_geom_pool.iter() {
for static_geometry in self.static_geoms.iter() {
for (n, triangle) in static_geometry.triangles.iter().enumerate() {
body.solve_triangle_collision(&triangle, n);
}
+59 -65
View File
@@ -13,7 +13,6 @@ use crate::{
utils::pool::*,
scene::node::*,
engine::{
ResourceManager,
State,
duration_to_seconds_f32,
},
@@ -369,10 +368,10 @@ impl Renderer {
&self.statistics
}
fn draw_surface(&self, surf: &Surface, data: &SurfaceSharedData, resource_manager: &ResourceManager) {
fn draw_surface(&self, surf: &Surface) {
unsafe {
if let Some(resource) = resource_manager.borrow_resource(surf.get_texture_resource_handle()) {
if let ResourceKind::Texture(texture) = resource.borrow_kind() {
if let Some(resource) = surf.get_texture() {
if let ResourceKind::Texture(texture) = resource.borrow().borrow_kind() {
gl::BindTexture(gl::TEXTURE_2D, texture.gpu_tex);
} else {
gl::BindTexture(gl::TEXTURE_2D, self.white_dummy);
@@ -380,6 +379,61 @@ impl Renderer {
} else {
gl::BindTexture(gl::TEXTURE_2D, self.white_dummy);
}
let data_rc = surf.get_data();
let mut data = data_rc.borrow_mut();
if data.need_upload {
let total_size_bytes = data.get_vertices().len() * std::mem::size_of::<Vertex>();
gl::BindVertexArray(data.get_vertex_array_object());
// Upload indices
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, data.get_element_buffer_object());
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
(data.get_indices().len() * std::mem::size_of::<i32>()) as GLsizeiptr,
data.get_indices().as_ptr() as *const GLvoid,
gl::STATIC_DRAW);
// Upload vertices
gl::BindBuffer(gl::ARRAY_BUFFER, data.get_vertex_buffer_object());
gl::BufferData(gl::ARRAY_BUFFER,
total_size_bytes as GLsizeiptr,
data.get_vertices().as_ptr() as *const GLvoid,
gl::STATIC_DRAW);
let mut offset = 0;
// Positions
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(0);
offset += size_of::<Vec3>();
// Texture coordinates
gl::VertexAttribPointer(1, 2, gl::FLOAT, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(1);
offset += size_of::<Vec2>();
// Normals
gl::VertexAttribPointer(2, 3, gl::FLOAT, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(2);
offset += size_of::<Vec3>();
// Tangents
gl::VertexAttribPointer(3, 4, gl::FLOAT, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(3);
gl::BindVertexArray(0);
check_gl_error();
data.need_upload = false;
}
gl::BindVertexArray(data.get_vertex_array_object());
gl::DrawElements(gl::TRIANGLES,
data.get_indices().len() as GLint,
@@ -388,57 +442,6 @@ impl Renderer {
}
}
fn upload_surface_data(&self, ssd: &mut SurfaceSharedData) {
let total_size_bytes = ssd.get_vertices().len() * std::mem::size_of::<Vertex>();
unsafe {
gl::BindVertexArray(ssd.get_vertex_array_object());
// Upload indices
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ssd.get_element_buffer_object());
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
(ssd.get_indices().len() * std::mem::size_of::<i32>()) as GLsizeiptr,
ssd.get_indices().as_ptr() as *const GLvoid,
gl::STATIC_DRAW);
// Upload vertices
gl::BindBuffer(gl::ARRAY_BUFFER, ssd.get_vertex_buffer_object());
gl::BufferData(gl::ARRAY_BUFFER,
total_size_bytes as GLsizeiptr,
ssd.get_vertices().as_ptr() as *const GLvoid,
gl::STATIC_DRAW);
let mut offset = 0;
// Positions
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(0);
offset += size_of::<Vec3>();
// Texture coordinates
gl::VertexAttribPointer(1, 2, gl::FLOAT, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(1);
offset += size_of::<Vec2>();
// Normals
gl::VertexAttribPointer(2, 3, gl::FLOAT, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(2);
offset += size_of::<Vec3>();
// Tangents
gl::VertexAttribPointer(3, 4, gl::FLOAT, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(3);
gl::BindVertexArray(0);
check_gl_error();
}
}
pub fn upload_font_cache(&mut self, font_cache: &mut Pool<Font>) {
unsafe {
for font in font_cache.iter_mut() {
@@ -518,13 +521,6 @@ impl Renderer {
}
}
});
for data in state.get_surface_data_storage_mut().iter_mut() {
if data.need_upload {
self.upload_surface_data(data);
data.need_upload = false;
}
}
}
pub fn render(&mut self, state: &State, drawing_context: &DrawingContext) {
@@ -590,9 +586,7 @@ impl Renderer {
if let NodeKind::Mesh(mesh) = node.borrow_kind() {
for surface in mesh.get_surfaces().iter() {
if let Some(data) = state.get_surface_data_storage().borrow(surface.get_data_handle()) {
self.draw_surface(surface, data, state.get_resource_manager());
}
self.draw_surface(surface);
}
}
}
+23 -23
View File
@@ -5,10 +5,11 @@ use crate::{
gl::types::*
},
resource::*,
utils::rcpool::{RcHandle},
engine::State
};
use serde::{Serialize, Deserialize};
use std::{
rc::Rc,
cell::RefCell
};
#[derive(Copy, Clone, Debug)]
#[repr(C)] // OpenGL expects this structure packed as in C
@@ -21,20 +22,14 @@ pub struct Vertex {
pub bone_indices: [u8; 4],
}
#[derive(Serialize, Deserialize)]
pub struct SurfaceSharedData {
pub need_upload: bool,
#[serde(skip)]
vbo: GLuint,
#[serde(skip)]
vao: GLuint,
#[serde(skip)]
ebo: GLuint,
// Skip vertices and indices for now, later it can be useful for dynamic surfaces.
#[serde(skip)]
vertices: Vec<Vertex>,
#[serde(skip)]
indices: Vec<i32>,
}
@@ -351,41 +346,46 @@ impl Drop for SurfaceSharedData {
}
}
#[derive(Serialize, Deserialize)]
pub struct Surface {
pub data: RcHandle<SurfaceSharedData>,
pub texture: RcHandle<Resource>,
pub data: Rc<RefCell<SurfaceSharedData>>,
pub texture: Option<Rc<RefCell<Resource>>>,
}
impl Surface {
#[inline]
pub fn new(data: RcHandle<SurfaceSharedData>) -> Self {
pub fn new(data: Rc<RefCell<SurfaceSharedData>>) -> Self {
Self {
data,
texture: RcHandle::none(),
texture: None,
}
}
#[inline]
pub fn get_data_handle(&self) -> &RcHandle<SurfaceSharedData> {
&self.data
pub fn get_data(&self) -> Rc<RefCell<SurfaceSharedData>> {
Rc::clone(&self.data)
}
#[inline]
pub fn get_texture_resource_handle(&self) -> &RcHandle<Resource> {
&self.texture
pub fn get_texture(&self) -> Option<Rc<RefCell<Resource>>> {
match &self.texture {
Some(resource) => Some(Rc::clone(resource)),
None => None
}
}
#[inline]
pub fn set_texture(&mut self, tex: RcHandle<Resource>) {
self.texture = tex;
pub fn set_texture(&mut self, tex: Rc<RefCell<Resource>>) {
self.texture = Some(tex);
}
#[inline]
pub fn make_copy(&self, state: &State) -> Surface {
pub fn make_copy(&self) -> Surface {
Surface {
data: state.get_surface_data_storage().share_handle(&self.data),
texture: state.get_resource_manager().share_resource_handle(&self.texture)
data: Rc::clone(&self.data),
texture: match &self.texture {
Some(resource) => Some(Rc::clone(resource)),
None => None
}
}
}
}
+20 -23
View File
@@ -7,6 +7,8 @@ use crate::{
engine::State,
};
use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::rc::Rc;
pub enum FbxAttribute {
Double(f64),
@@ -652,7 +654,7 @@ fn link_child_with_parent_component(parent: &mut FbxComponent, child_handle: &Ha
model.materials.push(child_handle.clone())
} else if child_type_id == TypeId::of::<FbxAnimationCurveNode>() {
model.animation_curve_nodes.push(child_handle.clone())
}else if child_type_id == TypeId::of::<FbxLight>() {
} else if child_type_id == TypeId::of::<FbxLight>() {
model.light = child_handle.clone()
} else if child_type_id == TypeId::of::<FbxModel>() {
model.children.push(child_handle.clone())
@@ -905,7 +907,6 @@ fn prepare_next_face(geom: &FbxGeometry,
fn convert_vertex(geom: &FbxGeometry,
mesh: &mut Mesh,
state: &mut State,
geometric_transform: &Mat4,
material_index: usize,
origin: usize,
@@ -943,21 +944,15 @@ fn convert_vertex(geom: &FbxGeometry,
};
let surface = mesh.get_surfaces_mut().get_mut(material).unwrap();
let data_storage = state.get_surface_data_storage_mut();
match data_storage.borrow_mut(surface.get_data_handle()) {
Some(surface_data) => {
surface_data.insert_vertex(Vertex {
position,
normal,
tex_coord: uv,
tangent: Vec4 { x: tangent.x, y: tangent.y, z: tangent.z, w: 1.0 },
// FIXME
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_indices: [0, 0, 0, 0], // Correct indices will be calculated later
});
}
None => println!("Unable to get surface data!")
}
surface.get_data().borrow_mut().insert_vertex(Vertex {
position,
normal,
tex_coord: uv,
tangent: Vec4 { x: tangent.x, y: tangent.y, z: tangent.z, w: 1.0 },
// FIXME
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_indices: [0, 0, 0, 0], // Correct indices will be calculated later
});
}
impl Fbx {
@@ -1061,16 +1056,18 @@ impl Fbx {
model: &FbxModel) {
// Create surfaces per material
if model.materials.is_empty() {
mesh.add_surface(Surface::new(state.get_surface_data_storage_mut().spawn(SurfaceSharedData::new())));
mesh.add_surface(Surface::new(Rc::new(RefCell::new(SurfaceSharedData::new()))));
} else {
for material_handle in model.materials.iter() {
let mut surface = Surface::new(state.get_surface_data_storage_mut().spawn(SurfaceSharedData::new()));
let mut surface = Surface::new(Rc::new(RefCell::new(SurfaceSharedData::new())));
if let FbxComponent::Material(material) = self.component_pool.borrow(&material_handle).unwrap() {
if let Some(texture_handle) = self.component_pool.borrow(&material.diffuse_texture) {
if let FbxComponent::Texture(texture) = texture_handle {
if texture.filename.is_relative() {
let fullpath = state.get_resource_manager_mut().get_textures_path().join(&texture.filename);
surface.set_texture(state.request_resource(fullpath.as_path()));
if let Some(texture_resource) = state.request_resource(fullpath.as_path()) {
surface.set_texture(texture_resource);
}
}
}
}
@@ -1106,9 +1103,9 @@ impl Fbx {
let triangle = &triangles[i];
let relative_triangle = &relative_triangles[i];
convert_vertex(geom, mesh, state, &geometric_transform, material_index, origin, triangle.0, relative_triangle.0);
convert_vertex(geom, mesh, state, &geometric_transform, material_index, origin, triangle.1, relative_triangle.1);
convert_vertex(geom, mesh, state, &geometric_transform, material_index, origin, triangle.2, relative_triangle.2);
convert_vertex(geom, mesh, &geometric_transform, material_index, origin, triangle.0, relative_triangle.0);
convert_vertex(geom, mesh, &geometric_transform, material_index, origin, triangle.1, relative_triangle.1);
convert_vertex(geom, mesh, &geometric_transform, material_index, origin, triangle.2, relative_triangle.2);
}
if geom.material_mapping == FbxMapping::ByPolygon {
material_index += 1;
+50 -7
View File
@@ -3,23 +3,24 @@ pub mod fbx;
pub mod model;
pub mod ttf;
use serde::{Serialize, Deserialize};
use std::path::*;
use std::{
path::*,
any::{TypeId, Any}
};
use crate::{
resource::{
texture::*,
model::{Model}
}
};
use std::any::{TypeId, Any};
use crate::utils::visitor::{Visit, Visitor, VisitResult};
#[derive(Serialize, Deserialize)]
pub enum ResourceKind {
Unknown,
Texture(Texture),
Model(Model),
}
#[derive(Serialize, Deserialize)]
pub struct Resource {
path: PathBuf,
kind: ResourceKind
@@ -50,12 +51,54 @@ impl Resource {
pub fn get_kind_id(&self) -> TypeId {
match &self.kind {
ResourceKind::Unknown => panic!("must not get here"),
ResourceKind::Model(model) => model.type_id(),
ResourceKind::Texture(texture) => texture.type_id()
}
}
}
pub trait ResourceBehavior {
fn load(&self);
impl Default for Resource {
fn default() -> Self {
Self {
kind: ResourceKind::Unknown,
path: PathBuf::new(),
}
}
}
impl Visit for Resource {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut kind: u8 = if visitor.is_reading() {
0
} else {
match &mut self.kind {
ResourceKind::Unknown => panic!("must not get here"),
ResourceKind::Model(_) => 0,
ResourceKind::Texture(_) => 1
}
};
kind.visit("Kind", visitor)?;
if visitor.is_reading() {
self.kind = match kind {
0 => ResourceKind::Model(Default::default()),
1 => ResourceKind::Texture(Default::default()),
_ => panic!("must not get here"),
};
}
self.path.visit("Path", visitor)?;
visitor.leave_region()
}
}
impl Drop for Resource {
fn drop(&mut self) {
println!("Resource {:?} was destroyed!", self.path);
}
}
+28 -22
View File
@@ -1,27 +1,34 @@
use crate::{
scene::{
Scene,
node::Node
node::Node,
},
utils::pool::Handle,
engine::State,
resource::{
fbx,
Resource,
ResourceKind
ResourceKind,
},
utils::rcpool::RcHandle,
};
use std::path::Path;
use std::{
path::Path,
cell::RefCell,
rc::Rc
};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Model {
#[serde(skip)]
scene: Scene,
}
impl Default for Model {
fn default() -> Self {
Self {
scene: Scene::new(),
}
}
}
impl Model {
pub fn load(path: &Path, state: &mut State) -> Result<Model, String> {
let mut scene = Scene::new();
@@ -30,24 +37,23 @@ impl Model {
}
/// Tries to instantiate model from given resource. Returns non-none handle on success.
pub fn instantiate(resource_handle: &RcHandle<Resource>, state: &State, dest_scene: &mut Scene) -> Result<Handle<Node>, ()> {
if let Some(resource) = state.get_resource_manager().borrow_resource(resource_handle) {
if let ResourceKind::Model(model) = resource.borrow_kind() {
let root = model.scene.copy_node(&model.scene.get_root(), state, dest_scene);
pub fn instantiate(resource_rc: Rc<RefCell<Resource>>, dest_scene: &mut Scene) -> Result<Handle<Node>, ()> {
let resource = resource_rc.borrow();
if let ResourceKind::Model(model) = resource.borrow_kind() {
let root = model.scene.copy_node(&model.scene.get_root(), dest_scene);
// Notify instantiated nodes about resource they were created from.
let mut stack = Vec::new();
stack.push(root.clone());
while let Some(node_handle) = stack.pop() {
if let Some(node) = dest_scene.nodes.borrow_mut(&node_handle) {
node.set_resource(state.get_resource_manager().share_resource_handle(resource_handle));
for child_handle in node.get_children() {
stack.push(child_handle.clone());
}
// Notify instantiated nodes about resource they were created from.
let mut stack = Vec::new();
stack.push(root.clone());
while let Some(node_handle) = stack.pop() {
if let Some(node) = dest_scene.nodes.borrow_mut(&node_handle) {
node.set_resource(Rc::clone(&resource_rc));
for child_handle in node.get_children() {
stack.push(child_handle.clone());
}
}
return Ok(root);
}
return Ok(root);
}
Err(())
}
+12 -8
View File
@@ -1,7 +1,5 @@
use std::path::*;
use serde::{Serialize, Deserialize};
pub struct Rgba8 {
pub r: u8,
pub g: u8,
@@ -9,20 +7,26 @@ pub struct Rgba8 {
pub a: u8,
}
#[derive(Serialize, Deserialize)]
pub struct Texture {
#[serde(skip)]
pub(crate) width: u32,
#[serde(skip)]
pub(crate) height: u32,
#[serde(skip)]
pub(crate) gpu_tex: u32,
#[serde(skip)]
pub(crate) need_upload: bool,
#[serde(skip)]
pub(crate) pixels: Vec<Rgba8>,
}
impl Default for Texture {
fn default() -> Self {
Self {
width: 0,
height: 0,
gpu_tex: 0,
need_upload: false,
pixels: Vec::new()
}
}
}
impl Texture {
pub fn load(path: &Path) -> Result<Texture, image::ImageError> {
let image = match image::open(path)? {
+5 -2
View File
@@ -3,9 +3,12 @@ use crate::{
vec3::Vec3,
quat::Quat
},
utils::rcpool::RcHandle,
resource::Resource
};
use std::{
rc::Weak,
cell::RefCell
};
pub struct KeyFrame {
position: Vec3,
@@ -25,5 +28,5 @@ pub struct Animation {
time_position: f32,
weight: f32,
fade_step: f32,
resource: RcHandle<Resource>
resource: Weak<RefCell<Resource>>
}
+34 -28
View File
@@ -2,17 +2,21 @@ pub mod node;
pub mod animation;
use crate::{
utils::pool::*,
utils::{
UnsafeCollectionView,
visitor::{
Visit,
VisitResult,
Visitor
}
},
math::mat4::*,
physics::Physics,
engine::State
engine::State,
};
use node::*;
use crate::utils::pool::{Handle, Pool};
use serde::{Serialize, Deserialize};
use crate::utils::UnsafeCollectionView;
#[derive(Serialize, Deserialize)]
pub struct Scene {
/// Nodes pool, every node lies inside pool. User-code may borrow
/// a reference to a node using handle.
@@ -25,12 +29,23 @@ pub struct Scene {
physics: Physics,
/// Tree traversal stack.
#[serde(skip)]
stack: Vec<Handle<Node>>,
}
impl Default for Scene {
fn default() -> Self {
Self {
nodes: Pool::new(),
root: Default::default(),
physics: Physics::new(),
stack: Vec::new()
}
}
}
impl Scene {
#[inline]
pub fn new() -> Scene {
let mut nodes: Pool<Node> = Pool::new();
let root = nodes.spawn(Node::new(NodeKind::Base));
Scene {
@@ -40,13 +55,6 @@ impl Default for Scene {
physics: Physics::new(),
}
}
}
impl Scene {
#[inline]
pub fn new() -> Scene {
Scene::default()
}
/// Transfers ownership of node into scene.
/// Returns handle to node.
@@ -64,17 +72,6 @@ impl Scene {
if let Some(node) = self.nodes.borrow_mut(&node_handle) {
self.physics.remove_body(node.get_body());
if let NodeKind::Mesh(mesh) = node.borrow_kind_mut() {
for surf in mesh.get_surfaces() {
state.release_resource(surf.get_texture_resource_handle());
state.get_surface_data_storage_mut().release(surf.get_data_handle());
}
}
state.release_resource(node.get_resource());
children = UnsafeCollectionView::from_slice(&node.children);
}
@@ -160,16 +157,16 @@ impl Scene {
/// Creates a full copy of node with all children.
/// This is relatively heavy operation!
/// In case if some error happened it returns Handle::none
pub fn copy_node(&self, root_handle: &Handle<Node>, state: &State, dest_scene: &mut Scene) -> Handle<Node> {
pub fn copy_node(&self, root_handle: &Handle<Node>, dest_scene: &mut Scene) -> Handle<Node> {
match self.get_node(root_handle) {
Some(src_node) => {
let mut dest_node = src_node.make_copy(state);
let mut dest_node = src_node.make_copy();
if let Some(src_body) = self.physics.borrow_body(&src_node.get_body()) {
dest_node.set_body(dest_scene.physics.add_body(src_body.make_copy()));
}
let dest_copy_handle = dest_scene.add_node(dest_node);
for src_child_handle in &src_node.children {
let dest_child_handle = self.copy_node(src_child_handle, state, dest_scene);
let dest_child_handle = self.copy_node(src_child_handle, dest_scene);
if !dest_child_handle.is_none() {
dest_scene.link_nodes(&dest_child_handle, &dest_copy_handle);
}
@@ -243,3 +240,12 @@ impl Scene {
}
}
impl Visit for Scene {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.root.visit("Root", visitor)?;
self.nodes.visit("Nodes", visitor)?;
self.physics.visit("Physics", visitor)?;
visitor.leave_region()
}
}
+140 -28
View File
@@ -4,21 +4,26 @@ use crate::{
mat4::*,
quat::*,
*,
vec2::*
vec2::*,
},
renderer::surface::*,
utils::{
pool::*,
rcpool::RcHandle
visitor::{
Visit,
VisitResult,
Visitor,
},
},
physics::Body,
engine::State,
resource::Resource
resource::Resource,
};
use std::{
cell::RefCell,
rc::Rc,
};
use crate::utils::visitor::VisitError;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Light {
radius: f32,
color: Vec3,
@@ -33,6 +38,17 @@ impl Default for Light {
}
}
impl Visit for Light {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.radius.visit("Radius", visitor)?;
self.color.visit("Color", visitor)?;
visitor.leave_region()
}
}
impl Light {
#[inline]
pub fn set_radius(&mut self, radius: f32) {
@@ -48,12 +64,11 @@ impl Light {
pub fn make_copy(&self) -> Light {
Light {
radius: self.radius,
color: self.color
color: self.color,
}
}
}
#[derive(Serialize, Deserialize)]
pub struct Camera {
fov: f32,
z_near: f32,
@@ -80,6 +95,17 @@ impl Default for Camera {
}
}
impl Visit for Camera {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.fov.visit("Fov", visitor)?;
self.z_near.visit("ZNear", visitor)?;
self.z_far.visit("ZFar", visitor)?;
self.viewport.visit("Viewport", visitor)?;
visitor.leave_region()
}
}
impl Camera {
#[inline]
pub fn calculate_matrices(&mut self, pos: Vec3, look: Vec3, up: Vec3, aspect: f32) {
@@ -119,7 +145,6 @@ impl Camera {
}
}
#[derive(Serialize, Deserialize)]
pub struct Mesh {
surfaces: Vec<Surface>,
}
@@ -132,6 +157,14 @@ impl Default for Mesh {
}
}
impl Visit for Mesh {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
// No need to serialize surfaces, correct ones will be assigned on resolve stage.
visitor.leave_region()
}
}
impl Mesh {
#[inline]
pub fn get_surfaces(&self) -> &Vec<Surface> {
@@ -148,25 +181,32 @@ impl Mesh {
self.surfaces.push(surface);
}
#[inline]
pub fn make_copy(&self, state: &State) -> Mesh {
pub fn make_copy(&self) -> Mesh {
Mesh {
surfaces: self.surfaces.iter().map(|surf| surf.make_copy(state)).collect()
surfaces: self.surfaces.iter().map(|surf| surf.make_copy()).collect()
}
}
}
#[derive(Serialize, Deserialize)]
pub enum NodeKind {
Base,
Light(Light),
Camera(Camera),
Mesh(Mesh)
Mesh(Mesh),
}
impl Visit for NodeKind {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
match self {
NodeKind::Base => Ok(()),
NodeKind::Light(light) => light.visit(name, visitor),
NodeKind::Camera(camera) => camera.visit(name, visitor),
NodeKind::Mesh(mesh) => mesh.visit(name, visitor),
}
}
}
#[derive(Serialize, Deserialize)]
pub struct Node {
name: String,
kind: NodeKind,
@@ -183,12 +223,36 @@ pub struct Node {
pub(in crate::scene) global_visibility: bool,
pub(in crate::scene) parent: Handle<Node>,
pub(in crate::scene) children: Vec<Handle<Node>>,
#[serde(skip)]
pub(in crate::scene) local_transform: Mat4,
#[serde(skip)]
pub(in crate::scene) global_transform: Mat4,
body: Handle<Body>,
resource: RcHandle<Resource>
resource: Option<Rc<RefCell<Resource>>>,
}
impl Default for Node {
fn default() -> Self {
Self {
kind: NodeKind::Base,
name: String::new(),
children: Vec::new(),
parent: Handle::none(),
local_position: Vec3::new(),
local_scale: Vec3 { x: 1.0, y: 1.0, z: 1.0 },
local_rotation: Quat::new(),
pre_rotation: Quat::new(),
post_rotation: Quat::new(),
rotation_offset: Vec3::new(),
rotation_pivot: Vec3::new(),
scaling_offset: Vec3::new(),
scaling_pivot: Vec3::new(),
visibility: true,
global_visibility: true,
local_transform: Mat4::identity(),
global_transform: Mat4::identity(),
body: Handle::none(),
resource: None,
}
}
}
impl Node {
@@ -212,7 +276,7 @@ impl Node {
local_transform: Mat4::identity(),
global_transform: Mat4::identity(),
body: Handle::none(),
resource: RcHandle::none()
resource: None,
}
}
@@ -236,12 +300,12 @@ impl Node {
/// Creates copy of node without copying children nodes and physics body.
/// Children nodes has to be copied explicitly.
pub fn make_copy(&self, state: &State) -> Node {
pub fn make_copy(&self) -> Node {
Node {
kind: match &self.kind {
NodeKind::Camera(camera) => NodeKind::Camera(camera.make_copy()),
NodeKind::Light(light) => NodeKind::Light(light.make_copy()),
NodeKind::Mesh(mesh) => NodeKind::Mesh(mesh.make_copy(state)),
NodeKind::Mesh(mesh) => NodeKind::Mesh(mesh.make_copy()),
NodeKind::Base => NodeKind::Base
},
name: self.name.clone(),
@@ -261,7 +325,10 @@ impl Node {
children: Vec::new(),
parent: Handle::none(),
body: Handle::none(),
resource: state.get_resource_manager().share_resource_handle(&self.resource)
resource: match &self.resource {
Some(resource) => Some(Rc::clone(resource)),
None => None
},
}
}
@@ -281,13 +348,16 @@ impl Node {
}
#[inline]
pub fn set_resource(&mut self, resource_handle: RcHandle<Resource>) {
self.resource = resource_handle;
pub fn set_resource(&mut self, resource_handle: Rc<RefCell<Resource>>) {
self.resource = Some(resource_handle);
}
#[inline]
pub fn get_resource(&mut self) -> &RcHandle<Resource> {
&self.resource
pub fn get_resource(&mut self) -> Option<Rc<RefCell<Resource>>> {
match &self.resource {
Some(resource) => Some(Rc::clone(resource)),
None => None
}
}
#[inline]
@@ -416,3 +486,45 @@ impl Node {
}
}
}
impl Visit for Node {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut kind_id: u8 = match &self.kind {
NodeKind::Base => 0,
NodeKind::Light(_) => 1,
NodeKind::Camera(_) => 2,
NodeKind::Mesh(_) => 3,
};
kind_id.visit("KindId", visitor)?;
if visitor.is_reading() {
self.kind = match kind_id {
0 => NodeKind::Base,
1 => NodeKind::Light(Default::default()),
2 => NodeKind::Camera(Default::default()),
3 => NodeKind::Mesh(Default::default()),
_ => return Err(VisitError::User(format!("invalid node kind {}", kind_id)))
}
}
self.kind.visit("Kind", visitor)?;
self.name.visit("Name", visitor)?;
self.local_scale.visit("LocalScale", visitor)?;
self.local_position.visit("LocalPosition", visitor)?;
self.local_rotation.visit("LocalRotation", visitor)?;
self.pre_rotation.visit("PreRotation", visitor)?;
self.post_rotation.visit("PostRotation", visitor)?;
self.rotation_offset.visit("RotationOffset", visitor)?;
self.rotation_pivot.visit("RotationPivot", visitor)?;
self.scaling_offset.visit("ScalingOffset", visitor)?;
self.scaling_pivot.visit("ScalingPivot", visitor)?;
self.visibility.visit("Visibility", visitor)?;
self.parent.visit("Parent", visitor)?;
self.children.visit("Children", visitor)?;
self.body.visit("Body", visitor)?;
self.resource.visit("Resource", visitor)?;
visitor.leave_region()
}
}
-1
View File
@@ -1,7 +1,6 @@
use std::marker::PhantomData;
pub mod pool;
pub mod rcpool;
pub mod visitor;
pub struct UnsafeCollectionView<T> {
+84 -35
View File
@@ -1,15 +1,14 @@
use std::{
marker::PhantomData,
hash::{Hash, Hasher},
fmt::{Debug, Formatter},
};
use serde::{Serialize, Deserialize};
use std::fmt::{Debug, Formatter};
use crate::utils::visitor::{Visit, VisitResult, Visitor};
///
/// Pool allows to create as many objects as you want in contiguous memory
/// block. It allows to create and delete objects very fast.
///
#[derive(Serialize, Deserialize)]
pub struct Pool<T: Sized> {
records: Vec<PoolRecord<T>>,
free_stack: Vec<u32>,
@@ -20,7 +19,6 @@ pub struct Pool<T: Sized> {
/// It stores index of object and additional information that
/// allows to ensure that handle is still valid.
///
#[derive(Serialize, Deserialize)]
pub struct Handle<T> {
/// Index of object in pool.
index: u32,
@@ -28,17 +26,32 @@ pub struct Handle<T> {
/// index of handle then this is valid handle.
generation: u32,
/// Type holder.
#[serde(skip)]
type_marker: PhantomData<T>,
}
impl<T> Visit for Handle<T> {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.index.visit("Index", visitor)?;
self.generation.visit("Generation", visitor)?;
visitor.leave_region()
}
}
impl<T> Default for Handle<T> {
fn default() -> Self {
Self::none()
}
}
impl<T> Debug for Handle<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "[{} {}]", self.index, self.generation)
}
}
#[derive(Serialize, Deserialize)]
struct PoolRecord<T: Sized> {
/// Generation number, used to keep info about lifetime.
/// The handle is valid only if record it points to is of the
@@ -49,6 +62,26 @@ struct PoolRecord<T: Sized> {
payload: Option<T>,
}
impl<T> Default for PoolRecord<T> {
fn default() -> Self {
Self {
generation: Pool::<T>::INVALID_GENERATION,
payload: None,
}
}
}
impl<T> Visit for PoolRecord<T> where T: Visit + Default + 'static {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.generation.visit("Generation", visitor)?;
self.payload.visit("Payload", visitor)?;
visitor.leave_region()
}
}
impl<T> Clone for Handle<T> {
fn clone(&self) -> Handle<T> {
Handle {
@@ -65,6 +98,15 @@ impl<T> PartialEq for Handle<T> {
}
}
impl<T> Visit for Pool<T> where T: Default + Visit + 'static {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.records.visit("Records", visitor)?;
self.free_stack.visit("FreeStack", visitor)?;
visitor.leave_region()
}
}
impl<T> Eq for Handle<T> {}
impl<T> Hash for Handle<T> {
@@ -356,35 +398,42 @@ impl<'a, T> Iterator for PoolIteratorMut<'a, T> {
}
}
fn pool_sanity_tests() {
let mut pool: Pool<String> = Pool::new();
let foobar_handle = pool.spawn(String::from("Foobar"));
assert_eq!(foobar_handle.index, 0);
assert_ne!(foobar_handle.generation, Pool::<String>::INVALID_GENERATION);
let foobar_handle_copy = foobar_handle.clone();
assert_eq!(foobar_handle.index, foobar_handle_copy.index);
assert_eq!(foobar_handle.generation, foobar_handle_copy.generation);
let baz_handle = pool.spawn(String::from("Baz"));
assert_eq!(pool.borrow(&foobar_handle).unwrap(), "Foobar");
assert_eq!(pool.borrow(&baz_handle).unwrap(), "Baz");
pool.free(foobar_handle);
assert_eq!(pool.is_valid_handle(&foobar_handle_copy), false);
assert_eq!(pool.is_valid_handle(&baz_handle), true);
let at_foobar_index = pool.spawn(String::from("AtFoobarIndex"));
assert_eq!(at_foobar_index.index, 0);
assert_ne!(at_foobar_index.generation, Pool::<String>::INVALID_GENERATION);
assert_eq!(pool.borrow(&at_foobar_index).unwrap(), "AtFoobarIndex");
}
#[cfg(test)]
mod test {
use crate::utils::pool::Pool;
fn pool_iterator_mut_test() {
let mut pool: Pool<String> = Pool::new();
let foobar = pool.spawn(format!("Foobar"));
let d = pool.spawn(format!("Foo"));
pool.free(d);
let baz = pool.spawn(format!("Baz"));
for s in pool.iter_mut() {
println!("{}", s);
#[test]
fn pool_sanity_tests() {
let mut pool: Pool<String> = Pool::new();
let foobar_handle = pool.spawn(String::from("Foobar"));
assert_eq!(foobar_handle.index, 0);
assert_ne!(foobar_handle.generation, Pool::<String>::INVALID_GENERATION);
let foobar_handle_copy = foobar_handle.clone();
assert_eq!(foobar_handle.index, foobar_handle_copy.index);
assert_eq!(foobar_handle.generation, foobar_handle_copy.generation);
let baz_handle = pool.spawn(String::from("Baz"));
assert_eq!(pool.borrow(&foobar_handle).unwrap(), "Foobar");
assert_eq!(pool.borrow(&baz_handle).unwrap(), "Baz");
pool.free(foobar_handle);
assert_eq!(pool.is_valid_handle(&foobar_handle_copy), false);
assert_eq!(pool.is_valid_handle(&baz_handle), true);
let at_foobar_index = pool.spawn(String::from("AtFoobarIndex"));
assert_eq!(at_foobar_index.index, 0);
assert_ne!(at_foobar_index.generation, Pool::<String>::INVALID_GENERATION);
assert_eq!(pool.borrow(&at_foobar_index).unwrap(), "AtFoobarIndex");
}
#[test]
fn pool_iterator_mut_test() {
let mut pool: Pool<String> = Pool::new();
let foobar = pool.spawn(format!("Foobar"));
let d = pool.spawn(format!("Foo"));
pool.free(d);
let baz = pool.spawn(format!("Baz"));
for s in pool.iter_mut() {
println!("{}", s);
}
pool.free(foobar);
pool.free(baz);
}
pool.free(foobar);
pool.free(baz);
}
-376
View File
@@ -1,376 +0,0 @@
use std::{
marker::PhantomData,
hash::{Hash, Hasher},
};
use serde::{Serialize, Deserialize};
use std::cell::Cell;
///
/// RcPool allows to create as many objects as you want in contiguous memory
/// block. It allows to create and delete objects very fast.
///
/// Main difference between RcPool and Pool is that RcPool stores reference
/// count for every object in pool so it can be used as storage for shared
/// resources.
///
#[derive(Serialize, Deserialize)]
pub struct RcPool<T: Sized> {
records: Vec<RcPoolRecord<T>>,
free_stack: Vec<u32>,
}
impl<T> Default for RcPool<T> {
fn default() -> Self {
RcPool::new()
}
}
///
/// Handle is some sort of non-owning reference to content in a pool.
/// It stores index of object and additional information that
/// allows to ensure that handle is still valid.
///
/// IMPORTANT: Handle is non-owning index of record in pool so it can't
/// automatically decrease reference count when it dies. Design your
/// program properly!
///
#[derive(Serialize, Deserialize)]
pub struct RcHandle<T> {
/// Index of object in pool.
index: u32,
/// Generation number, if it is same as generation of pool record at
/// index of handle then this is valid handle.
generation: u32,
/// Type holder.
#[serde(skip)]
type_marker: PhantomData<T>,
}
#[derive(Serialize, Deserialize)]
struct RcPoolRecord<T: Sized> {
/// Generation number, used to keep info about lifetime.
/// The handle is valid only if record it points to is of the
/// same generation as the pool record.
/// Notes: Zero is unknown generation used for None handles.
generation: u32,
/// Actual amount of handles created for this record.
/// Record will die only if there is no handles left.
ref_count: Cell<u32>,
/// Actual payload.
payload: Option<T>,
}
impl<T> PartialEq for RcHandle<T> {
fn eq(&self, other: &RcHandle<T>) -> bool {
self.generation == other.generation && self.index == other.index
}
}
impl<T> Eq for RcHandle<T> {}
impl<T> Hash for RcHandle<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.index.hash(state);
self.generation.hash(state);
}
}
impl<T> RcHandle<T> {
#[inline]
pub fn none() -> Self {
RcHandle {
index: 0,
generation: RcPool::<T>::INVALID_GENERATION,
type_marker: PhantomData,
}
}
#[inline]
pub fn is_none(&self) -> bool {
self.index == 0 && self.generation == RcPool::<T>::INVALID_GENERATION
}
pub fn is_some(&self) -> bool {
!self.is_none()
}
fn make(index: u32, generation: u32) -> Self {
RcHandle {
index,
generation,
type_marker: PhantomData,
}
}
}
impl<T> RcPool<T> {
const INVALID_GENERATION: u32 = 0;
#[inline]
#[must_use]
pub fn new() -> Self {
RcPool {
records: Vec::<RcPoolRecord<T>>::new(),
free_stack: Vec::new(),
}
}
#[inline]
#[must_use]
pub fn spawn(&mut self, payload: T) -> RcHandle<T> {
if let Some(free_index) = self.free_stack.pop() {
let record = &mut self.records[free_index as usize];
record.generation += 1;
record.ref_count.set(1);
record.payload.replace(payload);
return RcHandle {
index: free_index,
generation: record.generation,
type_marker: PhantomData,
};
}
// No free records, create new one
let record = RcPoolRecord {
generation: 1,
ref_count: Cell::new(1),
payload: Some(payload),
};
let handle = RcHandle {
index: self.records.len() as u32,
generation: record.generation,
type_marker: PhantomData,
};
self.records.push(record);
handle
}
/// Creates copy of specified handle.
/// Internally increases reference count of record.
/// If input handle was invalid then RcHandle::none will be returned.
#[must_use]
pub fn share_handle(&self, handle: &RcHandle<T>) -> RcHandle<T> {
if let Some(record) = self.records.get(handle.index as usize) {
record.ref_count.set(record.ref_count.get() + 1);
return RcHandle {
index: handle.index,
generation: handle.generation,
type_marker: PhantomData,
};
}
RcHandle::none()
}
#[inline]
#[must_use]
pub fn borrow(&self, handle: &RcHandle<T>) -> Option<&T> {
if let Some(record) = self.records.get(handle.index as usize) {
if record.generation == handle.generation {
if let Some(payload) = &record.payload {
return Some(payload);
} else {
println!("RcPool: Payload was empty!");
}
} else if handle.generation != RcPool::<T>::INVALID_GENERATION {
println!("RcPool: Generation does not match: record has {} generation, but handle has {}", record.generation, handle.generation);
}
} else {
println!("RcPool: Invalid index: got {}, but valid range is 0..{}", handle.index, self.records.len());
}
None
}
#[inline]
#[must_use]
pub fn borrow_mut(&mut self, handle: &RcHandle<T>) -> Option<&mut T> {
let record_count = self.records.len();
if let Some(record) = self.records.get_mut(handle.index as usize) {
if record.generation == handle.generation {
if let Some(payload) = &mut record.payload {
return Some(payload);
} else {
println!("RcPool: Payload was empty!");
}
} else if handle.generation != RcPool::<T>::INVALID_GENERATION {
println!("RcPool: Generation does not match: record has {} generation, but handle has {}", record.generation, handle.generation);
}
} else {
println!("RcPool: Invalid index: got {}, but valid range is 0..{}", handle.index, record_count);
}
None
}
/// Decreases reference count of record and if it is zero - moves out of pool.
#[inline]
#[must_use]
pub fn release(&mut self, handle: &RcHandle<T>) -> Option<T> {
if let Some(record) = self.records.get_mut(handle.index as usize) {
if record.generation == handle.generation {
record.ref_count.set(record.ref_count.get() - 1);
if record.ref_count.get() == 0 {
// Remember this index as free
self.free_stack.push(handle.index);
return record.payload.take();
}
} else if handle.generation != RcPool::<T>::INVALID_GENERATION {
println!("RcPool: Generation does not match: record has {} generation, but handle has {}", record.generation, handle.generation);
}
} else {
println!("RcPool: Invalid index: got {}, but valid range is 0..{}", handle.index, self.records.len());
}
None
}
pub fn replace(&mut self, handle: &RcHandle<T>, payload: T) -> Option<T> {
if let Some(record) = self.records.get_mut(handle.index as usize) {
if record.generation == handle.generation {
return record.payload.replace(payload);
} else if handle.generation != RcPool::<T>::INVALID_GENERATION {
println!("RcPool: Generation does not match: record has {} generation, but handle has {}", record.generation, handle.generation);
}
} else {
println!("RcPool: Invalid index: got {}, but valid range is 0..{}", handle.index, self.records.len());
}
None
}
#[inline]
#[must_use]
pub fn get_capacity(&self) -> usize {
self.records.len()
}
#[inline]
#[must_use]
pub fn get_ref_count(&self, handle: &RcHandle<T>) -> Option<u32> {
if let Some(record) = self.records.get(handle.index as usize) {
Some(record.ref_count.get())
} else {
None
}
}
#[inline]
#[must_use]
pub fn alive_count(&self) -> usize {
self.records.iter().count()
}
#[inline]
#[must_use]
pub fn at_mut(&mut self, n: usize) -> Option<&mut T> {
if let Some(record) = self.records.get_mut(n) {
if let Some(ref mut payload) = record.payload {
return Some(payload);
}
}
None
}
#[inline]
#[must_use]
pub fn at(&self, n: usize) -> Option<&T> {
if let Some(record) = self.records.get(n) {
if let Some(ref payload) = record.payload {
return Some(payload);
}
}
None
}
#[inline]
#[must_use]
pub fn handle_from_index(&mut self, n: usize) -> RcHandle<T> {
if let Some(record) = self.records.get_mut(n) {
if record.generation != 0 {
record.ref_count.set(record.ref_count.get() + 1);
return RcHandle::make(n as u32, record.generation);
}
}
RcHandle::none()
}
#[inline]
#[must_use]
pub fn is_valid_handle(&self, handle: &RcHandle<T>) -> bool {
if let Some(record) = self.records.get(handle.index as usize) {
return record.payload.is_some() && record.generation == handle.generation;
}
false
}
#[inline]
#[must_use]
pub fn iter(&self) -> RcPoolIterator<T> {
RcPoolIterator {
pool: self,
current: 0,
}
}
#[inline]
#[must_use]
pub fn iter_mut(&mut self) -> RcPoolIteratorMut<T> {
unsafe {
RcPoolIteratorMut {
ptr: self.records.as_mut_ptr(),
end: self.records.as_mut_ptr().add(self.records.len()),
marker: PhantomData,
}
}
}
}
pub struct RcPoolIterator<'a, T> {
pool: &'a RcPool<T>,
current: usize,
}
impl<'a, T> Iterator for RcPoolIterator<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
loop {
match self.pool.records.get(self.current) {
Some(record) => {
if let Some(payload) = &record.payload {
self.current += 1;
return Some(payload);
}
self.current += 1;
}
None => {
return None;
}
}
}
}
}
pub struct RcPoolIteratorMut<'a, T> {
ptr: *mut RcPoolRecord<T>,
end: *mut RcPoolRecord<T>,
marker: PhantomData<&'a mut T>,
}
impl<'a, T> Iterator for RcPoolIteratorMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<&'a mut T> {
unsafe {
while self.ptr != self.end {
let current = &mut *self.ptr;
if let Some(ref mut payload) = current.payload {
self.ptr = self.ptr.offset(1);
return Some(payload);
}
self.ptr = self.ptr.offset(1);
}
None
}
}
}
+320 -206
View File
@@ -3,13 +3,21 @@ use std::{
collections::HashMap,
fs::File,
any::Any,
path::Path,
path::{
Path,
PathBuf,
},
cell::RefCell,
io::{
Write,
Read,
},
string::FromUtf8Error,
fmt::{
Display,
Formatter,
},
rc::Weak,
};
use byteorder::{
ReadBytesExt,
@@ -31,6 +39,7 @@ use crate::{
};
pub enum FieldKind {
Bool(bool),
U8(u8),
I8(i8),
U16(u16),
@@ -50,6 +59,7 @@ pub enum FieldKind {
impl FieldKind {
fn as_string(&self) -> String {
match self {
FieldKind::Bool(data) => format!("<bool = {}", data),
FieldKind::U8(data) => format!("<u8 = {}>, ", data),
FieldKind::I8(data) => format!("<i8 = {}>, ", data),
FieldKind::U16(data) => format!("<u16 = {}>, ", data),
@@ -74,20 +84,24 @@ impl FieldKind {
out
}
FieldKind::Data(data) => {
base64::encode(data)
let out = match String::from_utf8(data.clone()) {
Ok(s) => s,
Err(_) => base64::encode(data)
};
format!("<data = {}>, ", out)
}
}
}
}
trait FieldData {
pub trait FieldData {
fn read(&mut self, kind: &FieldKind) -> VisitResult;
fn write(&self) -> FieldKind;
}
macro_rules! impl_field_data (($type_name:ty, $($kind:tt)*) => {
impl FieldData for $type_name {
fn read(&mut self, kind: &FieldKind) -> VisitResult {
fn read(& mut self, kind: &FieldKind) -> VisitResult {
match kind {
$($kind)*(data) => {
*self = data.clone();
@@ -103,6 +117,12 @@ macro_rules! impl_field_data (($type_name:ty, $($kind:tt)*) => {
}
});
/// Proxy struct for plain data, we can't use Vec<u8> directly,
/// because it will serialize each byte as separate node.
pub struct Data<'a> {
vec: &'a mut Vec<u8>
}
impl_field_data!(u64, FieldKind::U64);
impl_field_data!(i64, FieldKind::I64);
impl_field_data!(u32, FieldKind::U32);
@@ -116,7 +136,51 @@ impl_field_data!(f64, FieldKind::F64);
impl_field_data!(Vec3, FieldKind::Vec3);
impl_field_data!(Quat, FieldKind::Quat);
impl_field_data!(Mat4, FieldKind::Mat4);
impl_field_data!(Vec<u8>, FieldKind::Data);
impl_field_data!(bool, FieldKind::Bool);
impl<T> Visit for T where T: FieldData + 'static {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
if visitor.reading {
if let Some(field) = visitor.find_field(name) {
self.read(&field.kind)
} else {
Err(VisitError::FieldDoesNotExist(name.to_owned()))
}
} else if visitor.find_field(name).is_some() {
Err(VisitError::FieldAlreadyExists(name.to_owned()))
} else if let Some(node) = visitor.current_node() {
node.fields.push(Field::new(name, self.write()));
Ok(())
} else {
Err(VisitError::NoActiveNode)
}
}
}
impl<'a> Visit for Data<'a> {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
if visitor.reading {
if let Some(field) = visitor.find_field(name) {
match &field.kind {
FieldKind::Data(data) => {
*self.vec = data.clone();
Ok(())
}
_ => Err(VisitError::FieldTypeDoesNotMatch)
}
} else {
Err(VisitError::FieldDoesNotExist(name.to_owned()))
}
} else if visitor.find_field(name).is_some() {
Err(VisitError::FieldAlreadyExists(name.to_owned()))
} else if let Some(node) = visitor.current_node() {
node.fields.push(Field::new(name, FieldKind::Data(self.vec.clone())));
Ok(())
} else {
Err(VisitError::NoActiveNode)
}
}
}
pub struct Field {
name: String,
@@ -140,6 +204,30 @@ pub enum VisitError {
RcIsNonUnique,
RefCellAlreadyMutableBorrowed,
User(String),
UnexpectedRcNullIndex,
}
impl Display for VisitError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
VisitError::Io(io) => write!(f, "io error: {}", io),
VisitError::UnknownFieldType(type_index) => write!(f, "unknown field type {}", type_index),
VisitError::FieldDoesNotExist(name) => write!(f, "field does not exists {}", name),
VisitError::FieldAlreadyExists(name) => write!(f, "field already exists {}", name),
VisitError::RegionAlreadyExists(name) => write!(f, "region already exists {}", name),
VisitError::InvalidCurrentNode => write!(f, "invalid current node"),
VisitError::FieldTypeDoesNotMatch => write!(f, "field type does not match"),
VisitError::RegionDoesNotExist(name) => write!(f, "region does not exists {}", name),
VisitError::NoActiveNode => write!(f, "no active node"),
VisitError::NotSupportedFormat => write!(f, "not supported format"),
VisitError::InvalidName => write!(f, "invalid name"),
VisitError::TypeMismatch => write!(f, "type mismatch"),
VisitError::RcIsNonUnique => write!(f, "rc is non unique"),
VisitError::RefCellAlreadyMutableBorrowed => write!(f, "ref cell already mutable borrowed"),
VisitError::User(msg) => write!(f, "user defined error: {}", msg),
VisitError::UnexpectedRcNullIndex => write!(f, "unexpected rc null index")
}
}
}
impl From<std::io::Error> for VisitError {
@@ -233,6 +321,10 @@ impl Field {
file.write_u32::<LittleEndian>(data.len() as u32)?;
file.write_all(data.as_slice())?;
}
FieldKind::Bool(data) => {
file.write_u8(15)?;
file.write_u8(if *data { 1 } else { 0 })?;
}
}
Ok(())
}
@@ -283,6 +375,7 @@ impl Field {
}
vec
}),
15 => FieldKind::Bool(file.read_u8()? != 0),
_ => return Err(VisitError::UnknownFieldType(id))
}))
}
@@ -333,16 +426,10 @@ pub trait Visit {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult;
}
macro_rules! impl_generic_visit (($name:ident, $type_name:ty) => {
pub fn $name(&mut self, name: &str, value: &mut $type_name) -> VisitResult {
self.visit_generic(name, value)
}
});
impl Visitor {
const MAGIC: &'static str = "RG3D";
fn new() -> Self {
pub fn new() -> Self {
let mut nodes = Pool::new();
let root = nodes.spawn(Node::new("__ROOT__", Handle::none()));
Self {
@@ -365,43 +452,14 @@ impl Visitor {
None
}
pub fn is_reading(&self) -> bool {
self.reading
}
fn current_node(&mut self) -> Option<&mut Node> {
self.nodes.borrow_mut(&self.current_node)
}
fn visit_generic<T>(&mut self, name: &str, value: &mut T) -> VisitResult
where T: FieldData {
if self.reading {
if let Some(field) = self.find_field(name) {
value.read(&field.kind)
} else {
Err(VisitError::FieldDoesNotExist(name.to_owned()))
}
} else if self.find_field(name).is_some() {
Err(VisitError::FieldAlreadyExists(name.to_owned()))
} else if let Some(node) = self.current_node() {
node.fields.push(Field::new(name, value.write()));
Ok(())
} else {
Err(VisitError::NoActiveNode)
}
}
impl_generic_visit!(visit_u64, u64);
impl_generic_visit!(visit_i64, i64);
impl_generic_visit!(visit_u32, u32);
impl_generic_visit!(visit_i32, i32);
impl_generic_visit!(visit_u16, u16);
impl_generic_visit!(visit_i16, i16);
impl_generic_visit!(visit_u8, u8);
impl_generic_visit!(visit_i8, i8);
impl_generic_visit!(visit_f32, f32);
impl_generic_visit!(visit_f64, f64);
impl_generic_visit!(visit_vec3, Vec3);
impl_generic_visit!(visit_quat, Quat);
impl_generic_visit!(visit_mat4, Mat4);
impl_generic_visit!(visit_data, Vec<u8>);
pub fn enter_region(&mut self, name: &str) -> VisitResult {
if self.reading {
if let Some(node) = self.nodes.borrow(&self.current_node) {
@@ -454,158 +512,15 @@ impl Visitor {
Ok(())
}
pub fn visit_rc<T>(&mut self, name: &str, rc: &mut Rc<T>) -> VisitResult
where T: Visit + 'static {
self.enter_region(name)?;
if self.reading {
let mut raw = 0;
self.visit_u64("Id", &mut raw)?;
if let Some(ptr) = self.rc_map.get(&raw) {
if let Ok(res) = Rc::downcast::<T>(ptr.clone()) {
*rc = res;
} else {
return Err(VisitError::TypeMismatch);
}
} else {
// Deserialize inner data. At this point Rc must be unique.
if let Some(data) = Rc::get_mut(rc) {
data.visit("Data", self)?;
} else {
return Err(VisitError::RcIsNonUnique);
}
// Remember that we already visited data Rc store.
self.rc_map.insert(raw as u64, rc.clone());
}
} else {
// Take raw pointer to inner data.
let raw = Rc::into_raw(rc.clone()) as *const T as *mut T;
unsafe { Rc::from_raw(raw); };
// Save it as id.
let mut index = raw as u64;
self.visit_u64("Id", &mut index)?;
if !self.rc_map.contains_key(&index) {
// Serialize inner data using raw pointer. This violates borrowing rules,
// but should be fine since visitor is not multithreaded (it simply cannot
// be multithreaded by its nature)
unsafe { &mut *raw }.visit("Data", self)?;
self.rc_map.insert(index, rc.clone());
}
}
self.leave_region()?;
Ok(())
}
pub fn visit_vec<T>(&mut self, name: &str, vec: &mut Vec<T>) -> VisitResult
where T: Default + Visit + 'static {
self.enter_region(name)?;
let mut len = vec.len() as u32;
self.visit_u32("Length", &mut len)?;
if self.reading {
for index in 0..len {
let region_name = format!("Item{}", index);
self.enter_region(region_name.as_str())?;
let mut object = T::default();
object.visit("Data", self)?;
vec.push(object);
self.leave_region()?;
}
} else {
for (index, item) in vec.iter_mut().enumerate() {
let region_name = format!("Item{}", index);
self.enter_region(region_name.as_str())?;
item.visit("Data", self)?;
self.leave_region()?;
}
}
self.leave_region()?;
Ok(())
}
pub fn visit_string(&mut self, name: &str, string: &mut String) -> VisitResult {
self.enter_region(name)?;
let mut len = string.as_bytes().len() as u32;
self.visit_u32("Length", &mut len)?;
let mut data = if self.reading {
Vec::new()
} else {
Vec::from(string.as_bytes())
};
self.visit_data("Data", &mut data)?;
if self.reading {
*string = String::from_utf8(data)?;
}
self.leave_region()
}
pub fn visit_option<T>(&mut self, name: &str, opt: &mut Option<T>) -> VisitResult
where T: Default + Visit + 'static {
self.enter_region(name)?;
let mut is_some = if opt.is_some() { 1 } else { 0 };
self.visit_u8("IsSome", &mut is_some)?;
if is_some != 0 {
if self.reading {
let mut value = T::default();
value.visit("Data", self)?;
*opt = Some(value);
} else {
opt.as_mut().unwrap().visit("Data", self)?;
}
}
self.leave_region()?;
Ok(())
}
fn print_node(&self, node_handle: &Handle<Node>, nesting: usize, out_string: &mut String) {
let offset = (0..nesting).map(|_| { "\t" }).collect::<String>();
if let Some(node) = self.nodes.borrow(&node_handle) {
*out_string += format!("{}{}[Fields={}, Children={}]: ", offset, node.name, node.fields.len(), node.children.len()).as_str();
for field in node.fields.iter() {
*out_string += field.name.as_str();
match &field.kind {
FieldKind::U8(data) => *out_string += format!("<u8 = {}>, ", data).as_str(),
FieldKind::I8(data) => *out_string += format!("<i8 = {}>, ", data).as_str(),
FieldKind::U16(data) => *out_string += format!("<u16 = {}>, ", data).as_str(),
FieldKind::I16(data) => *out_string += format!("<i16 = {}>, ", data).as_str(),
FieldKind::U32(data) => *out_string += format!("<u32 = {}>, ", data).as_str(),
FieldKind::I32(data) => *out_string += format!("<i32 = {}>, ", data).as_str(),
FieldKind::U64(data) => *out_string += format!("<u64 = {}>, ", data).as_str(),
FieldKind::I64(data) => *out_string += format!("<i64 = {}>, ", data).as_str(),
FieldKind::F32(data) => *out_string += format!("<f32 = {}>, ", data).as_str(),
FieldKind::F64(data) => *out_string += format!("<f64 = {}>, ", data).as_str(),
FieldKind::Vec3(data) => {
*out_string += format!("<vec3 = {}; {}; {}>, ", data.x, data.y, data.z).as_str()
}
FieldKind::Quat(data) => {
*out_string += format!("<quat = {}; {}; {}; {}>, ", data.x, data.y, data.z, data.w).as_str()
}
FieldKind::Mat4(data) => {
// Lazy
*out_string += format!("<mat4>, ").as_str()
}
FieldKind::Data(data) => {
*out_string += base64::encode(data).as_str();
}
}
*out_string += field.as_string().as_str();
}
*out_string += format!("\n").as_str();
*out_string += "\n";
for child_handle in node.children.iter() {
self.print_node(child_handle, nesting + 1, out_string);
@@ -653,12 +568,10 @@ impl Visitor {
let mut node = Node::default();
node.name = String::from_utf8(raw_name)?;
println!("{}", node.name);
let field_count = file.read_u32::<LittleEndian>()? as usize;
for _ in 0..field_count {
let field = Field::load(file)?;
println!("Field: {}", field.as_string());
node.fields.push(field);
}
@@ -710,9 +623,210 @@ impl<T> Visit for RefCell<T> where T: Visit + 'static {
}
}
impl<T> Visit for Vec<T> where T: Default + Visit + 'static {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut len = self.len() as u32;
len.visit("Length", visitor)?;
if visitor.reading {
for index in 0..len {
let region_name = format!("Item{}", index);
visitor.enter_region(region_name.as_str())?;
let mut object = T::default();
object.visit("ItemData", visitor)?;
self.push(object);
visitor.leave_region()?;
}
} else {
for (index, item) in self.iter_mut().enumerate() {
let region_name = format!("Item{}", index);
visitor.enter_region(region_name.as_str())?;
item.visit("ItemData", visitor)?;
visitor.leave_region()?;
}
}
visitor.leave_region()?;
Ok(())
}
}
impl<T> Visit for Option<T> where T: Default + Visit + 'static {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut is_some = if self.is_some() { 1u8 } else { 0u8 };
is_some.visit("IsSome", visitor)?;
if is_some != 0 {
if visitor.reading {
let mut value = T::default();
value.visit("Data", visitor)?;
*self = Some(value);
} else {
self.as_mut().unwrap().visit("Data", visitor)?;
}
}
visitor.leave_region()?;
Ok(())
}
}
impl Visit for String {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut len = self.as_bytes().len() as u32;
len.visit("Length", visitor)?;
let mut data = if visitor.reading {
Vec::new()
} else {
Vec::from(self.as_bytes())
};
let mut proxy = Data { vec: &mut data };
proxy.visit("Data", visitor)?;
if visitor.reading {
*self = String::from_utf8(data)?;
}
visitor.leave_region()
}
}
impl Visit for PathBuf {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let bytes = if let Some(path_str) = self.as_os_str().to_str() {
path_str.as_bytes()
} else {
return Err(VisitError::InvalidName);
};
let mut len = bytes.len() as u32;
len.visit("Length", visitor)?;
let mut data = if visitor.reading {
Vec::new()
} else {
Vec::from(bytes)
};
let mut proxy = Data { vec: &mut data };
proxy.visit("Data", visitor)?;
if visitor.reading {
*self = PathBuf::from(String::from_utf8(data)?);
}
visitor.leave_region()
}
}
impl<T> Visit for Rc<T> where T: Default + Visit + 'static {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.visit_rc(name, self)
visitor.enter_region(name)?;
if visitor.reading {
let mut raw = 0u64;
raw.visit("Id", visitor)?;
if raw == 0 {
return Err(VisitError::UnexpectedRcNullIndex);
}
if let Some(ptr) = visitor.rc_map.get(&raw) {
if let Ok(res) = Rc::downcast::<T>(ptr.clone()) {
*self = res;
} else {
return Err(VisitError::TypeMismatch);
}
} else {
// Deserialize inner data. At this point Rc must be unique.
if let Some(data) = Rc::get_mut(self) {
data.visit("RcData", visitor)?;
} else {
return Err(VisitError::RcIsNonUnique);
}
// Remember that we already visited data Rc store.
visitor.rc_map.insert(raw as u64, self.clone());
}
} else {
// Take raw pointer to inner data.
let raw = Rc::into_raw(self.clone()) as *const T as *mut T;
unsafe { Rc::from_raw(raw); };
// Save it as id.
let mut index = raw as u64;
index.visit("Id", visitor)?;
if !visitor.rc_map.contains_key(&index) {
// Serialize inner data using raw pointer. This violates borrowing rules,
// but should be fine since visitor is not multithreaded (it simply cannot
// be multithreaded by its nature)
unsafe { &mut *raw }.visit("RcData", visitor)?;
visitor.rc_map.insert(index, self.clone());
}
}
visitor.leave_region()?;
Ok(())
}
}
impl<T> Visit for Weak<T> where T: Default + Visit + 'static {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
if visitor.reading {
let mut raw = 0u64;
raw.visit("Id", visitor)?;
if raw != 0 {
if let Some(ptr) = visitor.rc_map.get(&raw) {
if let Ok(res) = Rc::downcast::<T>(ptr.clone()) {
*self = Rc::downgrade(&res);
} else {
return Err(VisitError::TypeMismatch);
}
} else {
// Create new value wrapped into Rc and deserialize it.
let mut rc = Rc::new(T::default());
Rc::get_mut(&mut rc).unwrap().visit("RcData", visitor)?;
visitor.rc_map.insert(raw as u64, rc.clone());
*self = Rc::downgrade(&rc);
}
}
} else if let Some(rc) = Weak::upgrade(self) {
// Take raw pointer to inner data.
let raw = Rc::into_raw(rc.clone()) as *const T as *mut T;
unsafe { Rc::from_raw(raw); };
// Save it as id.
let mut index = raw as u64;
index.visit("Id", visitor)?;
if !visitor.rc_map.contains_key(&index) {
// Serialize inner data using raw pointer. This violates borrowing rules,
// but should be fine since visitor is not multithreaded (it simply cannot
// be multithreaded by its nature)
unsafe { &mut *raw }.visit("RcData", visitor)?;
visitor.rc_map.insert(index, rc.clone());
}
} else {
let mut index = 0u64;
index.visit("Id", visitor)?;
}
visitor.leave_region()?;
Ok(())
}
}
@@ -724,7 +838,7 @@ mod test {
fs::File,
io::Write,
};
use crate::utils::visitor::{Visitor, Visit, VisitResult, VisitError};
use crate::utils::visitor::{Visitor, Visit, VisitResult, VisitError, Data};
pub struct Model {
data: u64
@@ -737,7 +851,8 @@ mod test {
impl Visit for Texture {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
visitor.visit_data("Data", &mut self.data)?;
let mut proxy = Data { vec: &mut self.data };
proxy.visit("Data", visitor)?;
visitor.leave_region()
}
}
@@ -745,7 +860,7 @@ mod test {
impl Visit for Model {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
visitor.visit_u64("Data", &mut self.data)?;
self.data.visit("Data", visitor)?;
visitor.leave_region()
}
}
@@ -792,16 +907,15 @@ mod test {
impl Visit for Resource {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
if visitor.reading {} else {
let mut kind_id = match &self.kind {
let mut kind_id: u8 = match &self.kind {
ResourceKind::Unknown => return Err(VisitError::User(format!("Invalid resource!"))),
ResourceKind::Model(model) => 0,
ResourceKind::Texture(texture) => 1
};
visitor.visit_u8("KindId", &mut kind_id)?;
kind_id.visit("KindId", visitor)?;
self.kind.visit("KindData", visitor)?;
}
visitor.visit_u16("ResData", &mut self.data)
self.data.visit("ResData", visitor)
}
}
@@ -830,8 +944,8 @@ mod test {
impl Visit for Foo {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.visit_u64("Bar", &mut self.bar)?;
visitor.visit_option("SharedResource", &mut self.shared_resource)?;
self.bar.visit("Bar", visitor)?;
self.shared_resource.visit("SharedResource", visitor)?;
Ok(())
}
}
@@ -844,14 +958,14 @@ mod test {
{
let mut visitor = Visitor::new();
let mut resource = Rc::new(Resource::new(ResourceKind::Model(Model { data: 555 })));
visitor.visit_rc("SharedResource", &mut resource).unwrap();
resource.visit("SharedResource", &mut visitor).unwrap();
let mut objects = vec![
Foo::new(resource.clone()),
Foo::new(resource)
];
visitor.visit_vec("Objects", &mut objects).unwrap();
objects.visit("Objects", &mut visitor).unwrap();
visitor.save_binary(path).unwrap();
if let Ok(mut file) = File::create(Path::new("test.txt")) {
@@ -863,10 +977,10 @@ mod test {
{
let mut visitor = Visitor::load_binary(path).unwrap();
let mut resource: Rc<Resource> = Rc::new(Default::default());
visitor.visit_rc("SharedResource", &mut resource).unwrap();
resource.visit("SharedResource", &mut visitor).unwrap();
let mut objects: Vec<Foo> = Vec::new();
visitor.visit_vec("Objects", &mut objects).unwrap();
objects.visit("Objects", &mut visitor).unwrap();
}
}
}
BIN
View File
Binary file not shown.
+3 -3
View File
@@ -1,10 +1,10 @@
__ROOT__[Fields=0, Children=2]:
SharedResource[Fields=3, Children=1]: Id<u64 = 1800001388368>, KindId<u8 = 0>, ResData<u16 = 0>,
SharedResource[Fields=3, Children=1]: Id<u64 = 2145246739536>, KindId<u8 = 0>, ResData<u16 = 0>,
KindData[Fields=1, Children=0]: Data<u64 = 555>,
Objects[Fields=1, Children=2]: Length<u32 = 2>,
Item0[Fields=1, Children=1]: Bar<u64 = 123>,
SharedResource[Fields=1, Children=1]: IsSome<u8 = 1>,
Data[Fields=1, Children=0]: Id<u64 = 1800001388368>,
Data[Fields=1, Children=0]: Id<u64 = 2145246739536>,
Item1[Fields=1, Children=1]: Bar<u64 = 123>,
SharedResource[Fields=1, Children=1]: IsSome<u8 = 1>,
Data[Fields=1, Children=0]: Id<u64 = 1800001388368>,
Data[Fields=1, Children=0]: Id<u64 = 2145246739536>,