another scene graph refactoring, changed fake inheritance to composition

This commit is contained in:
Dmitry
2019-10-20 16:21:18 +03:00
parent f21935883d
commit 072e42cc37
21 changed files with 550 additions and 672 deletions
+16 -14
View File
@@ -7,21 +7,23 @@
<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$/src/gui/border.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/border.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/builder.rs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/button.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/button.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/canvas.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/canvas.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/event.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/event.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/grid.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/grid.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/gui/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/node.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/node.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/scroll_bar.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/scroll_bar.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/scroll_content_presenter.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/scroll_content_presenter.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/scroll_viewer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/scroll_viewer.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/text.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/text.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/window.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/window.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/renderer/deferred_light_renderer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/deferred_light_renderer.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/renderer/gbuffer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/gbuffer.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/renderer/particle_system_renderer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/particle_system_renderer.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/renderer/shadow_map_renderer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shadow_map_renderer.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/renderer/sprite_renderer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/sprite_renderer.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/model.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/model.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/camera.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/camera.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/graph.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/graph.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/light.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/light.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/mesh.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/mesh.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/scene/particle_system.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/particle_system.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/pivot.rs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/sprite.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/sprite.rs" afterDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
Generated
+7 -7
View File
@@ -883,7 +883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rg3d"
version = "0.1.10"
version = "0.2.0"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -892,14 +892,14 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lexical 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rg3d-core 0.1.5",
"rg3d-physics 0.1.5",
"rg3d-core 0.1.6",
"rg3d-physics 0.1.6",
"rg3d-sound 0.1.3",
]
[[package]]
name = "rg3d-core"
version = "0.1.5"
version = "0.1.6"
dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -908,10 +908,10 @@ dependencies = [
[[package]]
name = "rg3d-physics"
version = "0.1.5"
version = "0.1.6"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rg3d-core 0.1.5",
"rg3d-core 0.1.6",
]
[[package]]
@@ -919,7 +919,7 @@ name = "rg3d-sound"
version = "0.1.3"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rg3d-core 0.1.5",
"rg3d-core 0.1.6",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "rg3d"
version = "0.2.0"
version = "0.2.1"
authors = ["Dmitry Stepanov <[email protected]>"]
edition = "2018"
license = "MIT"
+16 -14
View File
@@ -1,8 +1,17 @@
use std::ffi::CString;
use rg3d_core::{
color::Color,
math::{vec3::Vec3, mat4::Mat4},
};
use crate::{
renderer::gpu_texture::GpuTexture,
scene::{
camera::Camera, Scene,
node::Node, SceneInterface,
camera::Camera,
Scene,
node::Node,
SceneInterface,
light::LightKind,
base::AsBase
},
renderer::{
surface::SurfaceSharedData,
@@ -12,13 +21,6 @@ use crate::{
shadow_map_renderer::SpotShadowMapRenderer,
},
};
use rg3d_core::{
color::Color,
math::{vec3::Vec3, mat4::Mat4},
};
use crate::scene::light::LightKind;
use crate::renderer::gpu_texture::GpuTexture;
use crate::scene::node::NodeTrait;
struct AmbientLightShader {
program: GpuProgram,
@@ -241,7 +243,7 @@ impl DeferredLightRenderer {
let SceneInterface { graph, .. } = scene.interface();
for light_node in graph.linear_iter() {
if !light_node.get_global_visibility() {
if !light_node.base().get_global_visibility() {
continue;
}
@@ -255,12 +257,12 @@ impl DeferredLightRenderer {
LightKind::Point(point_light) => point_light.get_radius(),
};
let light_position = light_node.get_global_position();
let light_radius_scale = light_node.get_local_transform().get_scale().max_value();
let light_position = light_node.base().get_global_position();
let light_radius_scale = light_node.base().get_local_transform().get_scale().max_value();
let light_radius = light_radius_scale * raw_radius;
let light_r_inflate = 1.05 * light_radius;
let light_radius_vec = Vec3::new(light_r_inflate, light_r_inflate, light_r_inflate);
let light_emit_direction = light_node.get_up_vector().normalized().unwrap_or(Vec3::UP);
let light_emit_direction = light_node.base().get_up_vector().normalized().unwrap_or(Vec3::UP);
match light.get_kind() {
LightKind::Spot(_) => {
@@ -318,7 +320,7 @@ impl DeferredLightRenderer {
self.shader.set_light_cone_angle_cos(cone_angle_cos);
self.shader.set_wvp_matrix(&frame_matrix);
self.shader.set_shadow_map_inv_size(0.0); // TODO
self.shader.set_camera_position(&camera.get_global_position());
self.shader.set_camera_position(&camera.base().get_global_position());
self.shader.set_depth_sampler_id(0);
self.shader.set_color_sampler_id(1);
self.shader.set_normal_sampler_id(2);
+5 -5
View File
@@ -11,7 +11,7 @@ use crate::{
node::Node,
graph::Graph,
camera::Camera,
node::NodeTrait
base::AsBase
},
renderer::{
gl::types::GLuint, gl,
@@ -239,7 +239,7 @@ impl GBuffer {
for node in graph.linear_iter() {
if let Node::Mesh(mesh) = node {
if !node.get_global_visibility() {
if !node.base().get_global_visibility() {
continue;
}
@@ -249,7 +249,7 @@ impl GBuffer {
let world = if is_skinned {
Mat4::IDENTITY
} else {
node.get_global_transform()
node.base().get_global_transform()
};
let mvp = view_projection * world;
@@ -263,8 +263,8 @@ impl GBuffer {
for bone_handle in surface.bones.iter() {
let bone_node = graph.get(*bone_handle);
self.bone_matrices.push(
bone_node.get_global_transform() *
bone_node.get_inv_bind_pose_transform());
bone_node.base().get_global_transform() *
bone_node.base().get_inv_bind_pose_transform());
}
self.shader.set_bone_matrices(&self.bone_matrices);
+5 -5
View File
@@ -13,13 +13,13 @@ use crate::{
gpu_texture::GpuTexture,
},
scene::{
node::Node,
particle_system,
SceneInterface,
SceneContainer,
node::NodeTrait,
},
base::AsBase
}
};
use crate::scene::node::Node;
struct ParticleSystemShader {
program: GpuProgram,
@@ -154,7 +154,7 @@ impl ParticleSystemRenderer {
particle_system.generate_draw_data(&mut self.sorted_particles,
&mut self.draw_data,
&camera.get_global_position());
&camera.base().get_global_position());
self.geometry_buffer.set_triangles(self.draw_data.get_triangles());
self.geometry_buffer.set_vertices(self.draw_data.get_vertices());
@@ -172,7 +172,7 @@ impl ParticleSystemRenderer {
self.shader.set_diffuse_texture(0);
self.shader.set_view_projection_matrix(&camera.get_view_projection_matrix());
self.shader.set_world_matrix(&node.get_global_transform());
self.shader.set_world_matrix(&node.base().get_global_transform());
self.shader.set_camera_up_vector(&camera_up);
self.shader.set_camera_side_vector(&camera_side);
self.shader.set_depth_buffer_texture(1);
+6 -6
View File
@@ -4,7 +4,7 @@ use crate::{
scene::{
node::Node,
graph::Graph,
node::NodeTrait
base::AsBase
},
renderer::{
gpu_texture::GpuTexture,
@@ -12,7 +12,7 @@ use crate::{
gpu_program::{GpuProgram, UniformLocation},
error::RendererError,
gl
}
},
};
pub struct SpotShadowMapShader {
@@ -130,7 +130,7 @@ impl SpotShadowMapRenderer {
for node in graph.linear_iter() {
if let Node::Mesh(mesh) = node {
if !node.get_global_visibility() {
if !node.base().get_global_visibility() {
continue;
}
@@ -140,7 +140,7 @@ impl SpotShadowMapRenderer {
let world = if is_skinned {
Mat4::IDENTITY
} else {
node.get_global_transform()
node.base().get_global_transform()
};
let mvp = *light_view_projection * world;
@@ -152,8 +152,8 @@ impl SpotShadowMapRenderer {
for bone_handle in surface.bones.iter() {
let bone_node = graph.get(*bone_handle);
self.bone_matrices.push(
bone_node.get_global_transform() *
bone_node.get_inv_bind_pose_transform());
bone_node.base().get_global_transform() *
bone_node.base().get_inv_bind_pose_transform());
}
self.shader.set_bone_matrices(&self.bone_matrices);
+8 -5
View File
@@ -3,18 +3,21 @@ use rg3d_core::{
math::mat4::Mat4,
math::vec3::Vec3,
};
use rg3d_core::color::Color;
use crate::{
scene::SceneContainer,
scene::{
SceneContainer,
node::Node,
SceneInterface,
base::AsBase
},
renderer::{
surface::SurfaceSharedData,
gpu_program::{GpuProgram, UniformLocation},
error::RendererError,
gl, gpu_texture::GpuTexture,
},
scene::{SceneInterface},
};
use rg3d_core::color::Color;
use crate::scene::node::{NodeTrait, Node};
pub struct SpriteShader {
program: GpuProgram,
@@ -143,7 +146,7 @@ impl SpriteRenderer {
self.shader.set_diffuse_texture(0);
self.shader.set_view_projection_matrix(&camera.get_view_projection_matrix());
self.shader.set_world_matrix(&node.get_global_transform());
self.shader.set_world_matrix(&node.base().get_global_transform());
self.shader.set_camera_up_vector(&camera_up);
self.shader.set_camera_side_vector(&camera_side);
self.shader.set_size(sprite.get_size());
+10 -14
View File
@@ -32,31 +32,27 @@ use crate::{
texture::FbxTexture,
attribute::FbxAttribute,
error::FbxError,
}
},
},
scene::{
animation::{
AnimationContainer,
Track,
KeyFrame,
Animation
Animation,
},
graph::Graph,
SceneInterfaceMut,
Scene,
node::{
Node,
NodeTrait,
NodeTraitPrivate
},
node::Node,
mesh::Mesh,
light::{
Light,
LightKind,
PointLight,
SpotLight
SpotLight,
},
pivot::Pivot,
base::{Base, AsBase},
},
engine::resource_manager::ResourceManager,
renderer::{
@@ -1164,12 +1160,12 @@ impl Fbx {
let fbx_light_component = self.component_pool.borrow(model.light);
Node::Light(self.convert_light(fbx_light_component.as_light()?))
} else {
Node::Pivot(Pivot::default())
Node::Base(Base::default())
};
node.set_name(model.name.as_str());
node.base_mut().set_name(model.name.as_str());
let node_local_rotation = quat_from_euler(model.rotation);
let transform = node.get_local_transform_mut();
let transform = node.base_mut().get_local_transform_mut();
transform.set_rotation(node_local_rotation);
transform.set_scale(model.scale);
transform.set_position(model.translation);
@@ -1179,7 +1175,7 @@ impl Fbx {
transform.set_rotation_pivot(model.rotation_pivot);
transform.set_scaling_offset(model.scaling_offset);
transform.set_scaling_pivot(model.scaling_pivot);
node.get_data_mut().inv_bind_pose_transform = model.inv_bind_transform;
node.base_mut().inv_bind_pose_transform = model.inv_bind_transform;
let node_handle = graph.add_node(node);
@@ -1268,7 +1264,7 @@ impl Fbx {
pub fn convert(&self, resource_manager: &mut ResourceManager, scene: &mut Scene) -> Result<Handle<Node>, FbxError> {
let SceneInterfaceMut { animations, graph, .. } = scene.interface_mut();
let mut instantiated_nodes = Vec::new();
let root = graph.add_node(Node::Pivot(Pivot::default()));
let root = graph.add_node(Node::Base(Base::default()));
let animation_handle = animations.add(Animation::default());
let mut fbx_model_to_node_map = HashMap::new();
for component_handle in self.components.iter() {
+13 -8
View File
@@ -1,5 +1,12 @@
use crate::{
scene::{Scene, node::Node, animation::Animation},
scene::{
Scene,
node::Node,
animation::Animation,
SceneInterface,
SceneInterfaceMut,
base::AsBase
},
resource::{fbx, fbx::error::FbxError},
engine::resource_manager::ResourceManager,
};
@@ -11,8 +18,6 @@ use rg3d_core::{
pool::Handle,
visitor::{Visit, VisitResult, Visitor},
};
use crate::scene::node::{NodeTrait, NodeTraitPrivate};
use crate::scene::{SceneInterface, SceneInterfaceMut};
pub struct Model {
pub(in crate) path: PathBuf,
@@ -62,17 +67,17 @@ impl Model {
let SceneInterface { graph: resource_graph, .. } = model.scene.interface();
let root = resource_graph.copy_node(resource_graph.get_root(), dest_graph);
dest_graph.get_mut(root).get_data_mut().is_resource_instance = true;
dest_graph.get_mut(root).base_mut().is_resource_instance = true;
// Notify instantiated nodes about resource they were created from.
let mut stack = Vec::new();
stack.push(root);
while let Some(node_handle) = stack.pop() {
let node = dest_graph.get_mut(node_handle);
node.get_data_mut().resource = Some(Arc::clone(&model_rc));
node.base_mut().resource = Some(Arc::clone(&model_rc));
// Continue on children.
for child_handle in node.get_children() {
for child_handle in node.base().get_children() {
stack.push(child_handle.clone());
}
}
@@ -138,9 +143,9 @@ impl Model {
for (i, ref_track) in ref_anim.get_tracks().iter().enumerate() {
let ref_node = resource_graph.get(ref_track.get_node());
// Find instantiated node that corresponds to node in resource
let instance_node = dest_graph.find_by_name(root, ref_node.get_name());
let instance_node = dest_graph.find_by_name(root, ref_node.base().get_name());
if instance_node.is_none() {
println!("Failed to retarget animation for node {}", ref_node.get_name())
println!("Failed to retarget animation for node {}", ref_node.base().get_name())
}
// One-to-one track mapping so there is [i] indexing.
anim_copy.get_tracks_mut()[i].set_node(instance_node);
+8 -7
View File
@@ -22,8 +22,9 @@ use std::sync::{Mutex, Arc};
use crate::{
scene::{
SceneInterface,
node::{Node, NodeTrait},
node::{Node},
graph::Graph,
base::AsBase
},
resource::model::Model,
};
@@ -333,7 +334,7 @@ impl Animation {
} = resource.get_scene().interface();
if let Some(ref_animation) = resource_animations.pool.at(0) {
for track in self.get_tracks_mut() {
let track_node = graph.get(track.get_node());
let track_node = graph.get(track.get_node()).base();
// Find corresponding track in resource using names of nodes, not
// original handles of instantiated nodes. We can't use original
// handles here because animation can be targetted to a node that
@@ -346,7 +347,7 @@ impl Animation {
// animation targetted to character instance.
let mut found = false;
for ref_track in ref_animation.get_tracks().iter() {
if track_node.get_name() == resource_graph.get(ref_track.get_node()).get_name() {
if track_node.get_name() == resource_graph.get(ref_track.get_node()).base().get_name() {
track.set_key_frames(ref_track.get_key_frames());
found = true;
break;
@@ -462,8 +463,8 @@ impl AnimationContainer {
// Reset local transform of animated nodes first
for animation in self.pool.iter() {
for track in animation.get_tracks() {
let node = graph.get_mut(track.get_node());
let transform = node.get_local_transform_mut();
let base = graph.get_mut(track.get_node()).base_mut();
let transform = base.get_local_transform_mut();
transform.set_position(Default::default());
transform.set_rotation(Default::default());
// TODO: transform.set_scale(Vec3::new(1.0, 1.0, 1.0));
@@ -486,8 +487,8 @@ impl AnimationContainer {
}
if let Some(keyframe) = track.get_key_frame(animation.get_time_position()) {
let node = graph.get_mut(track.get_node());
let transform = node.get_local_transform_mut();
let base = graph.get_mut(track.get_node()).base_mut();
let transform = base.get_local_transform_mut();
transform.set_rotation(transform.get_rotation().nlerp(&keyframe.rotation, weight));
transform.set_position(transform.get_position() + keyframe.position.scale(weight));
// TODO: transform.set_scale(transform.get_scale().lerp(&keyframe.scale, weight));
+289
View File
@@ -0,0 +1,289 @@
use std::sync::{Arc, Mutex};
use crate::{
resource::model::Model,
scene::{
node::Node,
transform::Transform
}
};
use rg3d_core::{
math::{vec3::Vec3, mat4::Mat4},
visitor::{Visit, VisitResult, Visitor},
pool::Handle,
};
pub struct Base {
pub name: String,
pub local_transform: Transform,
pub visibility: bool,
pub global_visibility: bool,
pub parent: Handle<Node>,
pub children: Vec<Handle<Node>>,
pub global_transform: Mat4,
/// Bone-specific matrix. Non-serializable.
pub inv_bind_pose_transform: Mat4,
/// A resource from which this node was instantiated from, can work in pair
/// with `original` handle to get corresponding node from resource.
pub resource: Option<Arc<Mutex<Model>>>,
/// Handle to node in scene of model resource from which this node
/// was instantiated from.
pub original: Handle<Node>,
/// When `true` it means that this node is instance of `resource`.
/// More precisely - this node is root of whole descendant nodes
/// hierarchy which was instantiated from resource.
pub is_resource_instance: bool,
/// Maximum amount of Some(time) that node will "live" or None
/// if node has undefined lifetime.
pub lifetime: Option<f32>,
}
pub trait AsBase {
fn base(&self) -> &Base;
fn base_mut(&mut self) -> &mut Base;
}
impl Base {
/// Sets name of node. Can be useful to mark a node to be able to find it later on.
pub fn set_name(&mut self, name: &str) {
self.name = name.to_owned();
}
/// Returns name of node.
pub fn get_name(&self) -> &str {
self.name.as_str()
}
/// Returns shared reference to local transform of a node, can be used to fetch
/// some local spatial properties, such as position, rotation, scale, etc.
pub fn get_local_transform(&self) -> &Transform {
&self.local_transform
}
/// Returns mutable reference to local transform of a node, can be used to set
/// some local spatial properties, such as position, rotation, scale, etc.
pub fn get_local_transform_mut(&mut self) -> &mut Transform {
&mut self.local_transform
}
/// Sets lifetime of node in seconds, lifetime is useful for temporary objects.
/// Example - you firing a gun, it produces two particle systems for each shot:
/// one for gunpowder fumes and one when bullet hits some surface. These particle
/// systems won't last very long - usually they will disappear in 1-2 seconds
/// but nodes will still be in scene consuming precious CPU clocks. This is where
/// lifetimes become handy - you just set appropriate lifetime for a particle
/// system node and it will be removed from scene when time will end. This is
/// efficient algorithm because scene holds every object in pool and allocation
/// or deallocation of node takes very little amount of time.
pub fn set_lifetime(&mut self, time_seconds: f32) {
self.lifetime = Some(time_seconds);
}
/// Returns current lifetime of a node. Will be None if node has undefined lifetime.
/// For more info about lifetimes see [`set_lifetime`].
pub fn get_lifetime(&self) -> Option<f32> {
self.lifetime.clone()
}
/// Returns handle of parent node.
pub fn get_parent(&self) -> rg3d_core::pool::Handle<Node> {
self.parent
}
/// Returns slice of handles to children nodes. This can be used, for example, to
/// traverse tree starting from some node.
pub fn get_children(&self) -> &[Handle<Node>] {
self.children.as_slice()
}
/// Returns global transform matrix, such matrix contains combined transformation
/// of transforms of parent nodes. This is the final matrix that describes real
/// location of object in the world.
pub fn get_global_transform(&self) -> Mat4 {
self.global_transform
}
/// Returns inverse of bind pose matrix. Bind pose matrix - is special matrix
/// for bone nodes, it stores initial transform of bone node at the moment
/// of "binding" vertices to bones.
pub fn get_inv_bind_pose_transform(&self) -> Mat4 {
self.inv_bind_pose_transform
}
pub fn is_resource_instance(&self) -> bool {
self.is_resource_instance
}
/// Returns resource from which this node was instantiated from.
pub fn get_resource(&self) -> Option<Arc<Mutex<Model>>> {
self.resource.clone()
}
/// Sets local visibility of a node.
pub fn set_visibility(&mut self, visibility: bool) {
self.visibility = visibility;
}
/// Returns local visibility of a node.
pub fn get_visibility(&self) -> bool {
self.visibility
}
/// Returns combined visibility of an node. This is the final visibility of a node.
/// Global visibility calculated using visibility of all parent nodes until root one,
/// so if some parent node upper on tree is invisible then all its children will be
/// invisible. It defines if object will be rendered. It is *not* the same as real
/// visibility point of view of some camera. To check if object is visible from some
/// camera, use appropriate method (TODO: which one?)
pub fn get_global_visibility(&self) -> bool {
self.global_visibility
}
/// Handle to node in scene of model resource from which this node
/// was instantiated from.
pub fn get_original_handle(&self) -> Handle<Node> {
self.original
}
/// Returns position of the node in absolute coordinates.
pub fn get_global_position(&self) -> Vec3 {
self.global_transform.position()
}
/// Returns "look" vector of global transform basis, in most cases return vector
/// will be non-normalized.
pub fn get_look_vector(&self) -> Vec3 {
self.global_transform.look()
}
/// Returns "side" vector of global transform basis, in most cases return vector
/// will be non-normalized.
pub fn get_side_vector(&self) -> Vec3 {
self.global_transform.side()
}
/// Returns "up" vector of global transform basis, in most cases return vector
/// will be non-normalized.
pub fn get_up_vector(&self) -> Vec3 {
self.global_transform.up()
}
}
/// Shallow copy of node data.
impl Clone for Base {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
local_transform: self.local_transform.clone(),
global_transform: self.global_transform,
visibility: self.visibility,
global_visibility: self.global_visibility,
inv_bind_pose_transform: self.inv_bind_pose_transform,
resource: self.resource.clone(),
is_resource_instance: self.is_resource_instance,
lifetime: self.lifetime,
// Rest of data is *not* copied!
..Default::default()
}
}
}
impl Default for Base {
fn default() -> Self {
BaseBuilder::new().build()
}
}
impl AsBase for Base {
fn base(&self) -> &Base {
self
}
fn base_mut(&mut self) -> &mut Base {
self
}
}
impl Visit for Base {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.name.visit("Name", visitor)?;
self.local_transform.visit("Transform", visitor)?;
self.visibility.visit("Visibility", visitor)?;
self.parent.visit("Parent", visitor)?;
self.children.visit("Children", visitor)?;
self.resource.visit("Resource", visitor)?;
self.is_resource_instance.visit("IsResourceInstance", visitor)?;
self.lifetime.visit("Lifetime", visitor)?;
visitor.leave_region()
}
}
pub struct BaseBuilder {
name: Option<String>,
visibility: Option<bool>,
local_transform: Option<Transform>,
children: Option<Vec<Handle<Node>>>,
lifetime: Option<f32>,
}
impl Default for BaseBuilder {
fn default() -> Self {
Self::new()
}
}
impl BaseBuilder {
pub fn new() -> Self {
Self {
name: None,
visibility: None,
local_transform: None,
children: None,
lifetime: None,
}
}
pub fn with_name(mut self, name: &str) -> Self {
self.name = Some(name.to_owned());
self
}
pub fn with_visibility(mut self, visibility: bool) -> Self {
self.visibility = Some(visibility);
self
}
pub fn with_local_transform(mut self, transform: Transform) -> Self {
self.local_transform = Some(transform);
self
}
pub fn with_children(mut self, children: Vec<Handle<Node>>) -> Self {
self.children = Some(children);
self
}
pub fn with_lifetime(mut self, time_seconds: f32) -> Self {
self.lifetime = Some(time_seconds);
self
}
pub fn build(self) -> Base {
Base {
name: self.name.unwrap_or_default(),
children: self.children.unwrap_or_default(),
local_transform: self.local_transform.unwrap_or_else(Transform::identity),
lifetime: self.lifetime,
visibility: self.visibility.unwrap_or(true),
global_visibility: true,
parent: Handle::NONE,
global_transform: Mat4::IDENTITY,
inv_bind_pose_transform: Mat4::IDENTITY,
resource: None,
original: Handle::NONE,
is_resource_instance: false,
}
}
}
+18 -11
View File
@@ -6,11 +6,11 @@ use rg3d_core::{
vec2::Vec2
}
};
use crate::scene::node::{CommonNodeData, NodeTrait};
use crate::scene::base::{Base, AsBase};
#[derive(Clone)]
pub struct Camera {
common: CommonNodeData,
base: Base,
fov: f32,
z_near: f32,
z_far: f32,
@@ -19,6 +19,16 @@ pub struct Camera {
projection_matrix: Mat4,
}
impl AsBase for Camera {
fn base(&self) -> &Base {
&self.base
}
fn base_mut(&mut self) -> &mut Base {
&mut self.base
}
}
impl Default for Camera {
fn default() -> Camera {
let fov: f32 = 75.0;
@@ -26,7 +36,7 @@ impl Default for Camera {
let z_far: f32 = 2048.0;
Camera {
common: Default::default(),
base: Base::default(),
fov,
z_near,
z_far,
@@ -49,7 +59,7 @@ impl Visit for Camera {
self.z_near.visit("ZNear", visitor)?;
self.z_far.visit("ZFar", visitor)?;
self.viewport.visit("Viewport", visitor)?;
self.common.visit("Common", visitor)?;
self.base.visit("Base", visitor)?;
visitor.leave_region()
}
}
@@ -57,9 +67,9 @@ impl Visit for Camera {
impl Camera {
#[inline]
pub fn calculate_matrices(&mut self, aspect: f32) {
let pos = self.get_global_position();
let look = self.get_look_vector();
let up = self.get_up_vector();
let pos = self.base.get_global_position();
let look = self.base.get_look_vector();
let up = self.base.get_up_vector();
if let Some(view_matrix) = Mat4::look_at(pos, pos + look, up) {
self.view_matrix = view_matrix;
@@ -103,7 +113,4 @@ impl Camera {
pub fn get_z_near(&self) -> f32 {
self.z_near
}
}
impl_node_trait!(Camera);
impl_node_trait_private!(Camera);
}
+35 -35
View File
@@ -5,9 +5,9 @@ use rg3d_core::{
pool::{PoolIterator, PoolIteratorMut, PoolPairIterator},
};
use crate::scene::{
node::{Node, NodeTrait},
node::Node,
SceneInterface,
node::NodeTraitPrivate,
base::AsBase,
};
use std::collections::HashMap;
@@ -31,8 +31,8 @@ impl Graph {
/// Creates new graph instance with single root node.
pub fn new() -> Self {
let mut pool: Pool<Node> = Pool::new();
let mut root = Node::Pivot(Default::default());
root.set_name("__ROOT__");
let mut root = Node::Base(Default::default());
root.base_mut().set_name("__ROOT__");
let root = pool.spawn(root);
Self {
stack: Vec::new(),
@@ -99,8 +99,8 @@ impl Graph {
self.stack.clear();
self.stack.push(node_handle);
while let Some(handle) = self.stack.pop() {
let node = self.pool.borrow(handle);
for child in node.get_children().iter() {
let base = self.pool.borrow(handle).base();
for child in base.get_children().iter() {
self.stack.push(*child);
}
self.pool.free(handle);
@@ -112,9 +112,9 @@ impl Graph {
pub fn link_nodes(&mut self, child_handle: Handle<Node>, parent_handle: Handle<Node>) {
self.unlink_nodes(child_handle);
let child = self.pool.borrow_mut(child_handle);
child.get_data_mut().parent = parent_handle;
child.base_mut().parent = parent_handle;
let parent = self.pool.borrow_mut(parent_handle);
parent.get_data_mut().children.push(child_handle);
parent.base_mut().children.push(child_handle);
}
/// Unlinks specified node from its parent, so node will become root.
@@ -122,14 +122,14 @@ impl Graph {
pub fn unlink_nodes(&mut self, node_handle: Handle<Node>) {
// Replace parent handle of child
let node = self.pool.borrow_mut(node_handle);
let parent_handle = node.get_parent();
node.get_data_mut().parent = Handle::NONE;
let parent_handle = node.base().parent;
node.base_mut().parent = Handle::NONE;
// Remove child from parent's children list
if parent_handle.is_some() {
let parent = self.pool.borrow_mut(parent_handle);
if let Some(i) = parent.get_children().iter().position(|h| *h == node_handle) {
parent.get_data_mut().children.remove(i);
if let Some(i) = parent.base().get_children().iter().position(|h| *h == node_handle) {
parent.base_mut().children.remove(i);
}
}
}
@@ -137,11 +137,11 @@ impl Graph {
/// Tries to find a copy of `node_handle` in hierarchy tree starting from `root_handle`.
pub fn find_copy_of(&self, root_handle: Handle<Node>, node_handle: Handle<Node>) -> Handle<Node> {
let root = self.pool.borrow(root_handle);
if root.get_original_handle() == node_handle {
if root.base().get_original_handle() == node_handle {
return root_handle;
}
for child_handle in root.get_children() {
for child_handle in root.base().get_children() {
let out = self.find_copy_of(*child_handle, node_handle);
if out.is_some() {
return out;
@@ -154,12 +154,12 @@ impl Graph {
/// Searches node with specified name starting from specified node. If nothing was found,
/// [`Handle::NONE`] is returned.
pub fn find_by_name(&self, root_node: Handle<Node>, name: &str) -> Handle<Node> {
let node = self.pool.borrow(root_node);
if node.get_name() == name {
let base = self.pool.borrow(root_node).base();
if base.get_name() == name {
root_node
} else {
let mut result: Handle<Node> = Handle::NONE;
for child in node.get_children() {
for child in base.get_children() {
let child_handle = self.find_by_name(*child, name);
if !child_handle.is_none() {
result = child_handle;
@@ -202,10 +202,10 @@ impl Graph {
fn copy_node_raw(&self, root_handle: Handle<Node>, dest_graph: &mut Graph, old_new_mapping: &mut HashMap<Handle<Node>, Handle<Node>>) -> Handle<Node> {
let src_node = self.pool.borrow(root_handle);
let mut dest_node = src_node.clone();
dest_node.get_data_mut().original = root_handle;
dest_node.base_mut().original = root_handle;
let dest_copy_handle = dest_graph.add_node(dest_node);
old_new_mapping.insert(root_handle, dest_copy_handle);
for src_child_handle in src_node.get_children() {
for src_child_handle in src_node.base().get_children() {
let dest_child_handle = self.copy_node_raw(*src_child_handle, dest_graph, old_new_mapping);
if !dest_child_handle.is_none() {
dest_graph.link_nodes(dest_child_handle, dest_copy_handle);
@@ -217,7 +217,7 @@ impl Graph {
fn find_model_root(&self, from: Handle<Node>) -> Handle<Node> {
let mut model_root_handle = from;
while model_root_handle.is_some() {
let model_node = self.pool.borrow(model_root_handle);
let model_node = self.pool.borrow(model_root_handle).base();
if model_node.get_parent().is_none() {
// We have no parent on node, then it must be root.
@@ -244,14 +244,14 @@ impl Graph {
// objects, but here we'll assume that modellers will not create models with duplicated
// names.
for node in self.pool.iter_mut() {
if let Some(model) = node.get_resource() {
let base = node.base_mut();
if let Some(model) = base.get_resource() {
let model = model.lock().unwrap();
let SceneInterface { graph: resource_graph, .. } = model.get_scene().interface();
for (handle, resource_node) in resource_graph.pair_iter() {
if resource_node.get_name() == node.get_name() {
let data = node.get_data_mut();
data.original = handle;
data.inv_bind_pose_transform = resource_node.get_inv_bind_pose_transform();
if resource_node.base().get_name() == base.get_name() {
base.original = handle;
base.inv_bind_pose_transform = resource_node.base().get_inv_bind_pose_transform();
break;
}
}
@@ -282,8 +282,8 @@ impl Graph {
if let Some(node) = self.pool.at_mut(i) {
if let Node::Mesh(mesh) = node {
let node_name = String::from(mesh.get_name());
if let Some(model) = mesh.get_resource() {
let node_name = String::from(mesh.base().get_name());
if let Some(model) = mesh.base().get_resource() {
let model = model.lock().unwrap();
let resource_node_handle = model.find_node_by_name(node_name.as_str());
let SceneInterface { graph: resource_graph, .. } = model.get_scene().interface();
@@ -315,22 +315,22 @@ impl Graph {
self.stack.push(self.root);
while let Some(handle) = self.stack.pop() {
// Calculate local transform and get parent handle
let parent_handle = self.pool.borrow_mut(handle).get_parent();
let parent_handle = self.pool.borrow_mut(handle).base().get_parent();
let (parent_global_transform, parent_visibility) =
if parent_handle.is_some() {
let parent = self.pool.borrow(parent_handle);
(parent.get_global_transform(), parent.get_global_visibility())
(parent.base().get_global_transform(), parent.base().get_global_visibility())
} else {
(Mat4::IDENTITY, true)
};
let node = self.pool.borrow_mut(handle);
node.get_data_mut().global_transform = parent_global_transform * node.get_local_transform().get_matrix();
node.get_data_mut().global_visibility = parent_visibility && node.get_visibility();
node.base_mut().global_transform = parent_global_transform * node.base().get_local_transform().get_matrix();
node.base_mut().global_visibility = parent_visibility && node.base().get_visibility();
// Queue children and continue traversal on them
for child_handle in node.get_children() {
for child_handle in node.base().get_children() {
self.stack.push(child_handle.clone());
}
}
@@ -344,8 +344,8 @@ impl Graph {
self.update_transforms();
for node in self.pool.iter_mut() {
if let Some(lifetime) = node.get_lifetime() {
node.set_lifetime(lifetime - dt);
if let Some(lifetime) = node.base().get_lifetime() {
node.base_mut().set_lifetime(lifetime - dt);
}
match node {
@@ -357,7 +357,7 @@ impl Graph {
for i in 0..self.pool.get_capacity() {
let remove = if let Some(node) = self.pool.at(i) {
if let Some(lifetime) = node.get_lifetime() {
if let Some(lifetime) = node.base().get_lifetime() {
lifetime <= 0.0
} else {
false
+19 -14
View File
@@ -6,7 +6,7 @@ use rg3d_core::{
VisitResult
}
};
use crate::scene::node::{CommonNodeData, CommonNodeBuilderData};
use crate::scene::base::{BaseBuilder, Base, AsBase};
#[derive(Clone)]
pub struct SpotLight {
@@ -146,15 +146,25 @@ impl Visit for LightKind {
#[derive(Clone)]
pub struct Light {
common: CommonNodeData,
base: Base,
kind: LightKind,
color: Color,
}
impl AsBase for Light {
fn base(&self) -> &Base {
&self.base
}
fn base_mut(&mut self) -> &mut Base {
&mut self.base
}
}
impl Default for Light {
fn default() -> Self {
Self {
common: Default::default(),
base: Default::default(),
kind: LightKind::Point(Default::default()),
color: Color::WHITE,
}
@@ -172,7 +182,7 @@ impl Visit for Light {
}
self.kind.visit("Kind", visitor)?;
self.color.visit("Color", visitor)?;
self.common.visit("Common", visitor)?;
self.base.visit("Base", visitor)?;
visitor.leave_region()
}
@@ -181,7 +191,7 @@ impl Visit for Light {
impl Light {
pub fn new(kind: LightKind) -> Self {
Self {
common: Default::default(),
base: Default::default(),
kind,
color: Color::WHITE,
}
@@ -208,26 +218,21 @@ impl Light {
}
}
impl_node_trait!(Light);
impl_node_trait_private!(Light);
pub struct LightBuilder {
common: CommonNodeBuilderData,
base_builder: BaseBuilder,
kind: LightKind,
color: Option<Color>,
}
impl LightBuilder {
pub fn new(kind: LightKind) -> Self {
pub fn new(kind: LightKind, base_builder: BaseBuilder) -> Self {
Self {
common: Default::default(),
base_builder,
kind,
color: None
}
}
impl_common_node_builder_methods!();
pub fn with_color(mut self, color: Color) -> Self {
self.color = Some(color);
self
@@ -235,7 +240,7 @@ impl LightBuilder {
pub fn build(self) -> Light {
Light {
common: From::from(self.common),
base: self.base_builder.build(),
kind: self.kind,
color: self.color.unwrap_or(Color::WHITE)
}
+14 -7
View File
@@ -1,6 +1,6 @@
use crate::{
renderer::surface::Surface,
scene::node::CommonNodeData
scene::base::{Base, AsBase}
};
use rg3d_core::visitor::{
Visit,
@@ -10,24 +10,34 @@ use rg3d_core::visitor::{
#[derive(Clone)]
pub struct Mesh {
common: CommonNodeData,
base: Base,
surfaces: Vec<Surface>,
}
impl Default for Mesh {
fn default() -> Mesh {
Mesh {
common: Default::default(),
base: Default::default(),
surfaces: Vec::new()
}
}
}
impl AsBase for Mesh {
fn base(&self) -> &Base {
&self.base
}
fn base_mut(&mut self) -> &mut Base {
&mut self.base
}
}
impl Visit for Mesh {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.common.visit("Common", visitor)?;
self.base.visit("Common", visitor)?;
// No need to serialize surfaces, correct ones will be assigned on resolve stage.
visitor.leave_region()
@@ -50,6 +60,3 @@ impl Mesh {
self.surfaces.push(surface);
}
}
impl_node_trait!(Mesh);
impl_node_trait_private!(Mesh);
+4 -3
View File
@@ -8,12 +8,13 @@ pub mod particle_system;
pub mod transform;
pub mod sprite;
pub mod graph;
pub mod pivot;
pub mod base;
use crate::scene::{
animation::AnimationContainer,
graph::Graph,
node::{Node, NodeTrait},
node::Node,
base::AsBase,
};
use rg3d_physics::{Physics, rigid_body::RigidBody};
use rg3d_core::{
@@ -94,7 +95,7 @@ impl Scene {
// Sync node positions with assigned physics bodies
for (node, body) in self.node_rigid_body_map.iter() {
if self.graph.is_valid_handle(*node) {
let node = self.graph.get_mut(*node);
let node = self.graph.get_mut(*node).base_mut();
if self.physics.is_valid_body_handle(*body) {
let body = self.physics.borrow_body(*body);
node.get_local_transform_mut().set_position(body.get_position());
+39 -446
View File
@@ -1,303 +1,14 @@
use std::sync::{Arc, Mutex};
use crate::{
scene::{
camera::Camera,
mesh::Mesh,
light::Light,
particle_system::ParticleSystem,
transform::Transform,
sprite::Sprite,
pivot::Pivot
},
resource::model::Model,
};
use rg3d_core::{
math::{vec3::Vec3, mat4::Mat4},
visitor::{Visit, VisitResult, Visitor},
pool::Handle,
};
pub trait NodeTrait {
/// Sets name of node. Can be useful to mark a node to be able to find it later on.
fn set_name(&mut self, name: &str);
/// Returns name of node.
fn get_name(&self) -> &str;
/// Returns shared reference to local transform of a node, can be used to fetch
/// some local spatial properties, such as position, rotation, scale, etc.
fn get_local_transform(&self) -> &Transform;
/// Returns mutable reference to local transform of a node, can be used to set
/// some local spatial properties, such as position, rotation, scale, etc.
fn get_local_transform_mut(&mut self) -> &mut Transform;
/// Sets lifetime of node in seconds, lifetime is useful for temporary objects.
/// Example - you firing a gun, it produces two particle systems for each shot:
/// one for gunpowder fumes and one when bullet hits some surface. These particle
/// systems won't last very long - usually they will disappear in 1-2 seconds
/// but nodes will still be in scene consuming precious CPU clocks. This is where
/// lifetimes become handy - you just set appropriate lifetime for a particle
/// system node and it will be removed from scene when time will end. This is
/// efficient algorithm because scene holds every object in pool and allocation
/// or deallocation of node takes very little amount of time.
fn set_lifetime(&mut self, time_seconds: f32);
/// Returns current lifetime of a node. Will be None if node has undefined lifetime.
/// For more info about lifetimes see [`set_lifetime`].
fn get_lifetime(&self) -> Option<f32>;
/// Returns handle of parent node.
fn get_parent(&self) -> Handle<Node>;
/// Returns slice of handles to children nodes. This can be used, for example, to
/// traverse tree starting from some node.
fn get_children(&self) -> &[Handle<Node>];
/// Returns global transform matrix, such matrix contains combined transformation
/// of transforms of parent nodes. This is the final matrix that describes real
/// location of object in the world.
fn get_global_transform(&self) -> Mat4;
/// Returns inverse of bind pose matrix. Bind pose matrix - is special matrix
/// for bone nodes, it stores initial transform of bone node at the moment
/// of "binding" vertices to bones.
fn get_inv_bind_pose_transform(&self) -> Mat4;
/// Returns resource from which this node was instantiated from.
fn get_resource(&self) -> Option<Arc<Mutex<Model>>>;
/// Sets local visibility of a node.
fn set_visibility(&mut self, visibility: bool);
/// Returns local visibility of a node.
fn get_visibility(&self) -> bool;
/// Returns combined visibility of an node. This is the final visibility of a node.
/// Global visibility calculated using visibility of all parent nodes until root one,
/// so if some parent node upper on tree is invisible then all its children will be
/// invisible. It defines if object will be rendered. It is *not* the same as real
/// visibility point of view of some camera. To check if object is visible from some
/// camera, use appropriate method (TODO: which one?)
fn get_global_visibility(&self) -> bool;
fn is_resource_instance(&self) -> bool;
/// Handle to node in scene of model resource from which this node
/// was instantiated from.
fn get_original_handle(&self) -> Handle<Node>;
/// Returns position of the node in absolute coordinates.
fn get_global_position(&self) -> Vec3 {
self.get_global_transform().position()
}
/// Returns "look" vector of global transform basis, in most cases return vector
/// will be non-normalized.
fn get_look_vector(&self) -> Vec3 {
self.get_global_transform().look()
}
/// Returns "side" vector of global transform basis, in most cases return vector
/// will be non-normalized.
fn get_side_vector(&self) -> Vec3 {
self.get_global_transform().side()
}
/// Returns "up" vector of global transform basis, in most cases return vector
/// will be non-normalized.
fn get_up_vector(&self) -> Vec3 {
self.get_global_transform().up()
}
}
/// Provides default implementation for all methods of NodeTrait.
///
/// # Notes
///
/// Target type must contain `common` field of [`CommonNodeData`] type!
macro_rules! impl_node_trait {
($ty_name:ident) => {
impl $crate::scene::node::NodeTrait for $ty_name {
fn set_name(&mut self, name: &str) {
self.common.name = name.to_owned();
}
fn get_name(&self) -> &str {
self.common.name.as_str()
}
fn get_local_transform(&self) -> &$crate::scene::transform::Transform {
&self.common.local_transform
}
fn get_local_transform_mut(&mut self) -> &mut $crate::scene::transform::Transform {
&mut self.common.local_transform
}
fn set_lifetime(&mut self, time_seconds: f32) {
self.common.lifetime = Some(time_seconds);
}
fn get_lifetime(&self) -> Option<f32> {
self.common.lifetime.clone()
}
fn get_parent(&self) -> rg3d_core::pool::Handle<crate::scene::node::Node> {
self.common.parent
}
fn get_children(&self) -> &[rg3d_core::pool::Handle<$crate::scene::node::Node>] {
self.common.children.as_slice()
}
fn get_global_transform(&self) -> rg3d_core::math::mat4::Mat4 {
self.common.global_transform
}
fn get_inv_bind_pose_transform(&self) -> rg3d_core::math::mat4::Mat4 {
self.common.inv_bind_pose_transform
}
fn is_resource_instance(&self) -> bool {
self.common.is_resource_instance
}
fn get_resource(&self) -> Option<std::sync::Arc<std::sync::Mutex<$crate::resource::model::Model>>> {
self.common.resource.clone()
}
fn set_visibility(&mut self, visibility: bool) {
self.common.visibility = visibility;
}
fn get_visibility(&self) -> bool {
self.common.visibility
}
fn get_global_visibility(&self) -> bool {
self.common.global_visibility
}
fn get_original_handle(&self) -> rg3d_core::pool::Handle<$crate::scene::node::Node> {
self.common.original
}
}
}
}
/// Provides default implementation of [`NodeTraitPrivate`].
macro_rules! impl_node_trait_private {
($ty_name:ident) => {
impl $crate::scene::node::NodeTraitPrivate for $ty_name {
fn get_data(&self) -> &CommonNodeData {
&self.common
}
fn get_data_mut(&mut self) -> &mut CommonNodeData {
&mut self.common
}
}
}
}
/// Private trait that gives direct access to common node data,
/// it helps preserve encapsulation and does not exposes private
/// data to outer world.
pub(in crate) trait NodeTraitPrivate {
fn get_data(&self) -> &CommonNodeData;
fn get_data_mut(&mut self) -> &mut CommonNodeData;
}
/// Struct with common node fields to be able to create composite nodes
/// faster. It will just require to define common field and expose its
/// data via NodeTrait.
pub(in crate) struct CommonNodeData {
pub name: String,
pub local_transform: Transform,
pub visibility: bool,
pub global_visibility: bool,
pub parent: Handle<Node>,
pub children: Vec<Handle<Node>>,
pub global_transform: Mat4,
/// Bone-specific matrix. Non-serializable.
pub inv_bind_pose_transform: Mat4,
/// A resource from which this node was instantiated from, can work in pair
/// with `original` handle to get corresponding node from resource.
pub resource: Option<Arc<Mutex<Model>>>,
/// Handle to node in scene of model resource from which this node
/// was instantiated from.
pub original: Handle<Node>,
/// When `true` it means that this node is instance of `resource`.
/// More precisely - this node is root of whole descendant nodes
/// hierarchy which was instantiated from resource.
pub is_resource_instance: bool,
/// Maximum amount of Some(time) that node will "live" or None
/// if node has undefined lifetime.
pub lifetime: Option<f32>,
}
impl From<CommonNodeBuilderData> for CommonNodeData {
fn from(data: CommonNodeBuilderData) -> Self {
Self {
name: data.name.unwrap_or_default(),
children: data.children.unwrap_or_default(),
local_transform: data.local_transform.unwrap_or_else(Transform::identity),
lifetime: data.lifetime,
visibility: data.visibility.unwrap_or(true),
global_visibility: true,
parent: Handle::NONE,
global_transform: Mat4::IDENTITY,
inv_bind_pose_transform: Mat4::IDENTITY,
resource: None,
original: Handle::NONE,
is_resource_instance: false,
}
}
}
/// Shallow copy of node data.
impl Clone for CommonNodeData {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
local_transform: self.local_transform.clone(),
global_transform: self.global_transform,
visibility: self.visibility,
global_visibility: self.global_visibility,
inv_bind_pose_transform: self.inv_bind_pose_transform,
resource: self.resource.clone(),
is_resource_instance: self.is_resource_instance,
lifetime: self.lifetime,
// Rest of data is *not* copied!
.. Default::default()
}
}
}
impl Default for CommonNodeData {
fn default() -> Self {
Self::from(CommonNodeBuilderData::default())
}
}
impl Visit for CommonNodeData {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.name.visit("Name", visitor)?;
self.local_transform.visit("Transform", visitor)?;
self.visibility.visit("Visibility", visitor)?;
self.parent.visit("Parent", visitor)?;
self.children.visit("Children", visitor)?;
self.resource.visit("Resource", visitor)?;
self.is_resource_instance.visit("IsResourceInstance", visitor)?;
self.lifetime.visit("Lifetime", visitor)?;
visitor.leave_region()
}
}
use crate::scene::{
light::Light,
camera::Camera,
base::{Base, AsBase},
mesh::Mesh,
sprite::Sprite,
particle_system::ParticleSystem,
};
impl Visit for Node {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
@@ -309,7 +20,7 @@ impl Visit for Node {
// Call appropriate visit method based on actual variant.
match self {
Node::Pivot(pivot) => pivot.visit(name, visitor),
Node::Base(base) => base.visit(name, visitor),
Node::Light(light) => light.visit(name, visitor),
Node::Camera(camera) => camera.visit(name, visitor),
Node::Mesh(mesh) => mesh.visit(name, visitor),
@@ -321,7 +32,7 @@ impl Visit for Node {
#[derive(Clone)]
pub enum Node {
Pivot(Pivot),
Base(Base),
Light(Light),
Camera(Camera),
Mesh(Mesh),
@@ -329,9 +40,34 @@ pub enum Node {
ParticleSystem(ParticleSystem),
}
/// Helper macros to reduce code bloat - its purpose it to dispatch
/// specified call by actual enum variant.
macro_rules! dispatch {
($self:ident, $func:ident, $($args:expr),*) => {
match $self {
Node::Base(v) => v.$func($($args),*),
Node::Mesh(v) => v.$func($($args),*),
Node::Camera(v) => v.$func($($args),*),
Node::Light(v) => v.$func($($args),*),
Node::ParticleSystem(v) => v.$func($($args),*),
Node::Sprite(v) => v.$func($($args),*),
}
};
}
impl AsBase for Node {
fn base(&self) -> &Base {
dispatch!(self, base, )
}
fn base_mut(&mut self) -> &mut Base {
dispatch!(self, base_mut, )
}
}
impl Default for Node {
fn default() -> Self {
Node::Pivot(Default::default())
Node::Base(Default::default())
}
}
@@ -365,7 +101,7 @@ impl Node {
/// Creates new Node based on variant id.
pub fn from_id(id: u8) -> Result<Self, String> {
match id {
0 => Ok(Node::Pivot(Default::default())),
0 => Ok(Node::Base(Default::default())),
1 => Ok(Node::Light(Default::default())),
2 => Ok(Node::Camera(Default::default())),
3 => Ok(Node::Mesh(Default::default())),
@@ -378,7 +114,7 @@ impl Node {
/// Returns actual variant id.
pub fn id(&self) -> u8 {
match self {
Node::Pivot(_) => 0,
Node::Base(_) => 0,
Node::Light(_) => 1,
Node::Camera(_) => 2,
Node::Mesh(_) => 3,
@@ -392,147 +128,4 @@ impl Node {
define_is_as!(is_light, as_light, as_light_mut, Light, Light);
define_is_as!(is_particle_system, as_particle_system, as_particle_system_mut, ParticleSystem, ParticleSystem);
define_is_as!(is_sprite, as_sprite, as_sprite_mut, Sprite, Sprite);
}
/// Helper macros to reduce code bloat - its purpose it to dispatch
/// specified call by actual enum variant.
macro_rules! dispatch {
($self:ident, $func:ident, $($args:expr),*) => {
match $self {
Node::Pivot(v) => v.$func($($args),*),
Node::Mesh(v) => v.$func($($args),*),
Node::Camera(v) => v.$func($($args),*),
Node::Light(v) => v.$func($($args),*),
Node::ParticleSystem(v) => v.$func($($args),*),
Node::Sprite(v) => v.$func($($args),*),
}
};
}
/// Implement dispatcher for Node variants. This allows Node behave like base
/// class of any other specialized nodes.
impl NodeTrait for Node {
fn set_name(&mut self, name: &str) {
dispatch!(self, set_name, name)
}
fn get_name(&self) -> &str {
dispatch!(self, get_name,)
}
fn get_local_transform(&self) -> &Transform {
dispatch!(self, get_local_transform,)
}
fn get_local_transform_mut(&mut self) -> &mut Transform {
dispatch!(self, get_local_transform_mut,)
}
fn set_lifetime(&mut self, time_seconds: f32) {
dispatch!(self, set_lifetime, time_seconds)
}
fn get_lifetime(&self) -> Option<f32> {
dispatch!(self, get_lifetime,)
}
fn get_parent(&self) -> Handle<Node> {
dispatch!(self, get_parent,)
}
fn get_children(&self) -> &[Handle<Node>] {
dispatch!(self, get_children,)
}
fn get_global_transform(&self) -> Mat4 {
dispatch!(self, get_global_transform,)
}
fn get_inv_bind_pose_transform(&self) -> Mat4 {
dispatch!(self, get_inv_bind_pose_transform,)
}
fn get_resource(&self) -> Option<Arc<Mutex<Model>>> {
dispatch!(self, get_resource,)
}
fn set_visibility(&mut self, visibility: bool) {
dispatch!(self, set_visibility, visibility)
}
fn get_visibility(&self) -> bool {
dispatch!(self, get_visibility,)
}
fn get_global_visibility(&self) -> bool {
dispatch!(self, get_global_visibility,)
}
fn is_resource_instance(&self) -> bool {
dispatch!(self, is_resource_instance,)
}
fn get_original_handle(&self) -> Handle<Node> {
dispatch!(self, get_original_handle,)
}
}
impl NodeTraitPrivate for Node {
fn get_data(&self) -> &CommonNodeData {
dispatch!(self, get_data,)
}
fn get_data_mut(&mut self) -> &mut CommonNodeData {
dispatch!(self, get_data_mut,)
}
}
pub(in crate) struct CommonNodeBuilderData {
pub name: Option<String>,
pub visibility: Option<bool>,
pub local_transform: Option<Transform>,
pub children: Option<Vec<Handle<Node>>>,
pub lifetime: Option<f32>,
}
impl Default for CommonNodeBuilderData {
fn default() -> Self {
Self {
name: None,
visibility: None,
local_transform: None,
children: None,
lifetime: None,
}
}
}
macro_rules! impl_common_node_builder_methods {
() => {
pub fn with_name(mut self, name: &str) -> Self {
self.common.name = Some(name.to_owned());
self
}
pub fn with_visibility(mut self, visibility: bool) -> Self {
self.common.visibility = Some(visibility);
self
}
pub fn with_local_transform(mut self, transform: $crate::scene::transform::Transform) -> Self {
self.common.local_transform = Some(transform);
self
}
pub fn with_children(mut self, children: Vec<rg3d_core::pool::Handle<$crate::scene::node::Node>>) -> Self {
self.common.children = Some(children);
self
}
pub fn with_lifetime(mut self, time_seconds: f32) -> Self {
self.common.lifetime = Some(time_seconds);
self
}
}
}
}
+19 -23
View File
@@ -27,11 +27,7 @@ use rg3d_core::{
use crate::{
resource::texture::Texture,
renderer::TriangleDefinition,
scene::node::{
CommonNodeData,
CommonNodeBuilderData,
NodeTrait,
},
scene::base::{BaseBuilder, Base, AsBase}
};
/// OpenGL expects this structure packed as in C.
@@ -642,7 +638,7 @@ impl Default for Emitter {
#[derive(Clone)]
pub struct ParticleSystem {
common: CommonNodeData,
base: Base,
particles: Vec<Particle>,
free_particles: Vec<u32>,
emitters: Vec<Emitter>,
@@ -651,6 +647,16 @@ pub struct ParticleSystem {
color_over_lifetime: Option<ColorGradient>,
}
impl AsBase for ParticleSystem {
fn base(&self) -> &Base {
&self.base
}
fn base_mut(&mut self) -> &mut Base {
&mut self.base
}
}
impl ParticleSystem {
pub fn add_emitter(&mut self, emitter: Emitter) {
self.emitters.push(emitter)
@@ -715,7 +721,7 @@ impl ParticleSystem {
sorted_particles.clear();
for (i, particle) in self.particles.iter().enumerate() {
if particle.alive {
let actual_position = particle.position + self.get_global_position();
let actual_position = particle.position + self.base.get_global_position();
particle.sqr_distance_to_camera.set(camera_pos.sqr_distance(&actual_position));
sorted_particles.push(i as u32);
}
@@ -801,8 +807,6 @@ impl ParticleSystem {
}
}
impl_node_trait!(ParticleSystem);
impl_node_trait_private!(ParticleSystem);
impl Visit for ParticleSystem {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
@@ -814,7 +818,7 @@ impl Visit for ParticleSystem {
self.emitters.visit("Emitters", visitor)?;
self.acceleration.visit("Acceleration", visitor)?;
self.color_over_lifetime.visit("ColorGradient", visitor)?;
self.common.visit("Common", visitor)?;
self.base.visit("Base", visitor)?;
visitor.leave_region()
}
@@ -822,28 +826,22 @@ impl Visit for ParticleSystem {
impl Default for ParticleSystem {
fn default() -> Self {
ParticleSystemBuilder::new().build()
ParticleSystemBuilder::new(BaseBuilder::new()).build()
}
}
pub struct ParticleSystemBuilder {
common: CommonNodeBuilderData,
base_builder: BaseBuilder,
emitters: Option<Vec<Emitter>>,
texture: Option<Arc<Mutex<Texture>>>,
acceleration: Option<Vec3>,
color_over_lifetime: Option<ColorGradient>,
}
impl Default for ParticleSystemBuilder {
fn default() -> Self {
Self::new()
}
}
impl ParticleSystemBuilder {
pub fn new() -> Self {
pub fn new(base_builder: BaseBuilder) -> Self {
Self {
common: Default::default(),
base_builder,
emitters: None,
texture: None,
acceleration: None,
@@ -851,8 +849,6 @@ impl ParticleSystemBuilder {
}
}
impl_common_node_builder_methods!();
pub fn with_emitters(mut self, emitters: Vec<Emitter>) -> Self {
self.emitters = Some(emitters);
self
@@ -880,7 +876,7 @@ impl ParticleSystemBuilder {
pub fn build(self) -> ParticleSystem {
ParticleSystem {
common: From::from(self.common),
base: self.base_builder.build(),
particles: Vec::new(),
free_particles: Vec::new(),
emitters: self.emitters.unwrap_or_default(),
-28
View File
@@ -1,28 +0,0 @@
use crate::scene::node::{CommonNodeData};
use rg3d_core::visitor::{Visit, Visitor, VisitResult};
#[derive(Clone)]
pub struct Pivot {
common: CommonNodeData
}
impl Default for Pivot {
fn default() -> Self {
Self {
common: Default::default()
}
}
}
impl Visit for Pivot {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.common.visit("Common", visitor)?;
visitor.leave_region()
}
}
impl_node_trait!(Pivot);
impl_node_trait_private!(Pivot);
+18 -19
View File
@@ -1,25 +1,35 @@
use std::sync::{Arc, Mutex};
use crate::{
resource::texture::Texture,
scene::node::{CommonNodeData, CommonNodeBuilderData}
};
use rg3d_core::{
color::Color,
visitor::{Visit, VisitResult, Visitor}
};
use crate::scene::base::{BaseBuilder, Base, AsBase};
#[derive(Clone)]
pub struct Sprite {
common: CommonNodeData,
base: Base,
texture: Option<Arc<Mutex<Texture>>>,
color: Color,
size: f32,
rotation: f32,
}
impl AsBase for Sprite {
fn base(&self) -> &Base {
&self.base
}
fn base_mut(&mut self) -> &mut Base {
&mut self.base
}
}
impl Default for Sprite {
fn default() -> Self {
SpriteBuilder::new().build()
SpriteBuilder::new(BaseBuilder::new()).build()
}
}
@@ -58,9 +68,6 @@ impl Sprite {
}
}
impl_node_trait!(Sprite);
impl_node_trait_private!(Sprite);
impl Visit for Sprite {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
@@ -69,30 +76,24 @@ impl Visit for Sprite {
self.color.visit("Color", visitor)?;
self.size.visit("Size", visitor)?;
self.rotation.visit("Rotation", visitor)?;
self.common.visit("Common", visitor)?;
self.base.visit("Base", visitor)?;
visitor.leave_region()
}
}
pub struct SpriteBuilder {
common: CommonNodeBuilderData,
base_builder: BaseBuilder,
texture: Option<Arc<Mutex<Texture>>>,
color: Option<Color>,
size: Option<f32>,
rotation: Option<f32>,
}
impl Default for SpriteBuilder {
fn default() -> Self {
Self::new()
}
}
impl SpriteBuilder {
pub fn new() -> Self {
pub fn new(base_builder: BaseBuilder) -> Self {
Self {
common: Default::default(),
base_builder,
texture: None,
color: None,
size: None,
@@ -100,8 +101,6 @@ impl SpriteBuilder {
}
}
impl_common_node_builder_methods!();
pub fn with_texture(mut self, texture: Arc<Mutex<Texture>>) -> Self {
self.texture = Some(texture);
self
@@ -129,7 +128,7 @@ impl SpriteBuilder {
pub fn build(self) -> Sprite {
Sprite {
common: From::from(self.common),
base: self.base_builder.build(),
texture: self.texture,
color: self.color.unwrap_or(Color::WHITE),
size: self.size.unwrap_or(0.2),