mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
replaced serde with built-in serializer, working save/load
This commit is contained in:
Generated
+30
-1
@@ -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
@@ -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"
|
||||
|
||||
@@ -14,7 +14,5 @@ opt-level = 3
|
||||
glutin = "*"
|
||||
image = "*"
|
||||
lexical = "*"
|
||||
serde = { version = "*", features = ["derive"] }
|
||||
serde_json = "*"
|
||||
byteorder = "*"
|
||||
base64="*"
|
||||
+128
-158
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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>>,
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)? {
|
||||
|
||||
@@ -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
@@ -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
@@ -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,7 +1,6 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub mod pool;
|
||||
pub mod rcpool;
|
||||
pub mod visitor;
|
||||
|
||||
pub struct UnsafeCollectionView<T> {
|
||||
|
||||
+84
-35
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>,
|
||||
|
||||
Reference in New Issue
Block a user