added key frame animations

This commit is contained in:
Dmitry
2019-08-22 17:57:48 +03:00
parent ec652d0551
commit 3655f0b202
20 changed files with 6662 additions and 896 deletions
+16
View File
@@ -6,7 +6,23 @@
<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$/save.bin" beforeDir="false" afterPath="$PROJECT_DIR$/save.bin" afterDir="false" />
<change beforePath="$PROJECT_DIR$/save.txt" beforeDir="false" afterPath="$PROJECT_DIR$/save.txt" afterDir="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/math/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/math/mod.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/vec3.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/math/vec3.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/renderer/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/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/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/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/pool.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/pool.rs" afterDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
BIN
View File
Binary file not shown.
+5599 -636
View File
File diff suppressed because it is too large Load Diff
+26 -14
View File
@@ -1,32 +1,44 @@
use crate::{
scene::*,
scene::{
node::NodeKind,
Scene
},
gui::UserInterface,
math::vec2::Vec2,
resource::{
Resource,
ResourceKind,
model::Model,
ttf::Font,
texture::Texture
},
utils::{
pool::*,
pool::{
Pool,
Handle
},
visitor::{
Visitor,
VisitResult,
Visit,
},
},
renderer::render::*,
resource::{
*,
texture::*,
model::Model,
ttf::Font,
renderer::render::{
Renderer,
Statistics
},
gui::UserInterface,
math::vec2::Vec2,
};
use std::{
path::*,
collections::VecDeque,
time::Duration,
cell::RefCell,
rc::Rc,
any::TypeId,
path::{
PathBuf,
Path
}
};
use crate::scene::node::NodeKind;
use std::any::TypeId;
pub struct ResourceManager {
resources: Vec<Rc<RefCell<Resource>>>,
@@ -192,7 +204,7 @@ impl State {
}
for scene in self.scenes.iter_mut() {
for node in scene.nodes.iter_mut() {
for node in scene.get_nodes_mut().iter_mut() {
let node_name = String::from(node.get_name());
if let Some(resource) = node.get_resource() {
if let NodeKind::Mesh(mesh) = node.borrow_kind_mut() {
+2 -2
View File
@@ -4,8 +4,8 @@ use crate::{
visitor::{
Visit,
VisitResult,
},
visitor::Visitor,
Visitor
}
},
math::vec3::*,
scene::{
+17 -5
View File
@@ -8,18 +8,31 @@ use crate::{
duration_to_seconds_f64,
},
game::level::Level,
utils::pool::Handle,
utils::{
pool::Handle,
visitor::{
Visitor,
VisitResult,
Visit
}
},
math::vec2::Vec2,
gui::{
button::ButtonBuilder,
Thickness,
scroll_viewer::ScrollViewerBuilder,
grid::{GridBuilder, Column, Row},
grid::{
GridBuilder,
Column,
Row
},
text::TextBuilder,
scroll_bar::ScrollBarBuilder,
},
gui::node::{UINode, UINodeKind},
utils::visitor::Visitor
gui::node::{
UINode,
UINodeKind
},
};
use std::{
cell::RefCell,
@@ -29,7 +42,6 @@ use std::{
rc::Rc,
io::Write
};
use crate::utils::visitor::{VisitResult, Visit};
pub struct MenuState {
save_game: Option<()>,
+26 -13
View File
@@ -1,22 +1,35 @@
use crate::{
utils::pool::*,
math::{
vec2::*,
vec3::*,
quat::*,
},
scene::{
node::*,
*,
},
physics::Body,
game::{
weapon::{Weapon, WeaponKind},
weapon::{
Weapon,
WeaponKind,
},
GameTime,
},
engine::State,
utils::{
visitor::{
Visit,
Visitor,
VisitResult,
},
pool::Handle,
},
math::{
vec2::Vec2,
vec3::Vec3,
quat::Quat,
},
scene::{
node::{
Node,
NodeKind,
Camera,
},
Scene,
},
};
use crate::utils::visitor::{Visit, Visitor, VisitResult};
pub struct Controller {
move_forward: bool,
@@ -87,7 +100,7 @@ impl Default for Player {
weapons: vec![],
camera_offset: Default::default(),
camera_dest_offset: Default::default(),
current_weapon: 0
current_weapon: 0,
}
}
}
+33 -3
View File
@@ -20,7 +20,7 @@ pub struct Rect<T> {
pub h: T,
}
impl<T> Rect<T> where T: Default + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Copy {
impl<T> Rect<T> where T: Default + Add<Output=T> + Sub<Output=T> + Mul<Output=T> + Copy {
pub fn new(x: T, y: T, w: T, h: T) -> Rect<T> {
Rect { x, y, w, h }
}
@@ -39,7 +39,7 @@ impl<T> Rect<T> where T: Default + Add<Output = T> + Sub<Output = T> + Mul<Outpu
x: self.x - dw,
y: self.y - dh,
w: self.w + dw + dw,
h: self.h + dh + dh
h: self.h + dh + dh,
}
}
@@ -48,7 +48,7 @@ impl<T> Rect<T> where T: Default + Add<Output = T> + Sub<Output = T> + Mul<Outpu
x: self.x + dw,
y: self.y + dh,
w: self.w - (dw + dw),
h: self.h - (dh + dh)
h: self.h - (dh + dh),
}
}
}
@@ -154,4 +154,34 @@ pub fn clampf(v: f32, min: f32, max: f32) -> f32 {
} else {
v
}
}
pub fn wrapf(mut n: f32, mut min_limit: f32, mut max_limit: f32) -> f32 {
if n >= min_limit && n <= max_limit {
return n;
}
if max_limit == 0.0 && min_limit == 0.0 {
return 0.0;
}
max_limit = max_limit - min_limit;
let offset = min_limit;
min_limit = 0.0;
n = n - offset;
let num_of_max = (n / max_limit).abs().floor();
if n >= max_limit {
n = n - num_of_max * max_limit;
} else if n < min_limit {
n = ((num_of_max + 1.0) * max_limit) + n;
}
return n + offset;
}
pub fn lerpf(a: f32, b: f32, t: f32) -> f32 {
a + (b - a) * t
}
+41
View File
@@ -18,6 +18,12 @@ pub enum RotationOrder {
ZYX,
}
impl Default for Quat {
fn default() -> Self {
Self::new()
}
}
impl Quat {
pub fn new() -> Self {
Quat {
@@ -61,6 +67,41 @@ impl Quat {
RotationOrder::ZYX => qx * qy * qz,
}
}
pub fn dot(&self, other: &Quat) -> f32 {
self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
}
pub fn angle(&self, other: &Quat) -> f32 {
let s = (self.sqr_len() * other.sqr_len()).sqrt();
return (self.dot(other) / s).acos();
}
pub fn slerp(&self, other: &Quat, t: f32) -> Quat {
let theta = self.angle(other);
if theta.abs() > 0.00001 {
let d = 1.0 / theta.sin();
let s0 = ((1.0 - t) * theta).sin();
let s1 = (t * theta).sin();
if self.dot(other) < 0.0 {
return Self {
x: (self.x * s0 - other.x * s1) * d,
y: (self.y * s0 - other.y * s1) * d,
z: (self.z * s0 - other.z * s1) * d,
w: (self.w * s0 - other.w * s1) * d,
};
} else {
return Self {
x: (self.x * s0 + other.x * s1) * d,
y: (self.y * s0 + other.y * s1) * d,
z: (self.z * s0 + other.z * s1) * d,
w: (self.w * s0 + other.w * s1) * d,
};
}
}
// Fallback
*self
}
}
impl ops::Mul<Self> for Quat {
+27 -6
View File
@@ -1,4 +1,5 @@
use std::ops;
use crate::math::lerpf;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vec3 {
@@ -90,11 +91,11 @@ impl Vec3 {
}
#[inline]
pub fn normalized(&self) -> Option<Vec3> {
pub fn normalized(&self) -> Option<Self> {
let len = self.len();
if len >= std::f32::EPSILON {
let inv_len = 1.0 / len;
return Some(Vec3 {
return Some(Self {
x: self.x * inv_len,
y: self.y * inv_len,
z: self.z * inv_len,
@@ -106,13 +107,13 @@ impl Vec3 {
/// Returns normalized vector and its original length. May fail if vector is
/// degenerate.
#[inline]
pub fn normalized_ex(&self) -> (Option<Vec3>, f32) {
pub fn normalized_ex(&self) -> (Option<Self>, f32) {
let len = self.len();
let normalized =
if len >= std::f32::EPSILON {
let inv_len = 1.0 / len;
Some(Vec3 {
Some(Self {
x: self.x * inv_len,
y: self.y * inv_len,
z: self.z * inv_len,
@@ -125,14 +126,22 @@ impl Vec3 {
}
#[inline]
pub fn normalized_unchecked(&self) -> Vec3 {
pub fn normalized_unchecked(&self) -> Self {
let inv_len = 1.0 / self.len();
Vec3 {
Self {
x: self.x * inv_len,
y: self.y * inv_len,
z: self.z * inv_len,
}
}
pub fn lerp(&self, other: &Self, t: f32) -> Self {
Self {
x: lerpf(self.x, other.x, t),
y: lerpf(self.y, other.y, t),
z: lerpf(self.z, other.z, t),
}
}
}
impl ops::Add<Self> for Vec3 {
@@ -156,6 +165,18 @@ impl ops::AddAssign<Self> for Vec3 {
}
}
impl ops::Mul<Self> for Vec3 {
type Output = Self;
fn mul(self, rhs: Vec3) -> Self::Output {
Self {
x: self.x * rhs.x,
y: self.y * rhs.y,
z: self.z * rhs.z
}
}
}
impl ops::Sub<Self> for Vec3 {
type Output = Self;
#[inline]
+82
View File
@@ -0,0 +1,82 @@
use crate::{
renderer::{
gl::types::GLuint,
gl,
gl::types::GLint
}
};
use std::ffi::CStr;
pub struct GpuProgram {
pub(in crate::renderer) id: GLuint,
name_buf: Vec<u8>,
}
impl GpuProgram {
pub fn create_shader(actual_type: GLuint, source: &CStr) -> Result<GLuint, String> {
unsafe {
let shader = gl::CreateShader(actual_type);
gl::ShaderSource(shader, 1, &source.as_ptr(), std::ptr::null());
gl::CompileShader(shader);
let mut status = 1;
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
if status == 0 {
let mut log_len = 0;
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
let mut buffer: Vec<u8> = Vec::with_capacity(log_len as usize);
gl::GetShaderInfoLog(shader, log_len, std::ptr::null_mut(), buffer.as_mut_ptr() as *mut i8);
Err(String::from_utf8_unchecked(buffer))
} else {
println!("Shader compiled!");
Ok(shader)
}
}
}
pub fn from_source(vertex_source: &CStr, fragment_source: &CStr) -> Result<GpuProgram, String> {
unsafe {
let vertex_shader = Self::create_shader(gl::VERTEX_SHADER, vertex_source).unwrap();
let fragment_shader = Self::create_shader(gl::FRAGMENT_SHADER, fragment_source).unwrap();
let program: GLuint = gl::CreateProgram();
gl::AttachShader(program, vertex_shader);
gl::DeleteShader(vertex_shader);
gl::AttachShader(program, fragment_shader);
gl::DeleteShader(fragment_shader);
gl::LinkProgram(program);
let mut status = 1;
gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
if status == 0 {
let mut log_len = 0;
gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut log_len);
let mut buffer: Vec<u8> = Vec::with_capacity(log_len as usize);
gl::GetProgramInfoLog(program, log_len, std::ptr::null_mut(), buffer.as_mut_ptr() as *mut i8);
Err(String::from_utf8_unchecked(buffer))
} else {
Ok(Self {
id: program,
name_buf: Vec::new(),
})
}
}
}
pub fn get_uniform_location(&mut self, name: &str) -> GLint {
// Form c string in special buffer to reduce memory allocations
let buf = &mut self.name_buf;
buf.clear();
buf.extend_from_slice(name.as_bytes());
buf.push(0);
unsafe {
gl::GetUniformLocation(self.id, buf.as_ptr() as *const i8)
}
}
}
impl Drop for GpuProgram {
fn drop(&mut self) {
unsafe {
gl::DeleteProgram(self.id);
}
}
}
+2 -1
View File
@@ -1,4 +1,5 @@
pub mod render;
pub mod surface;
#[allow(clippy::all)]
pub mod gl;
pub mod gl;
pub mod gpu_program;
+107 -166
View File
@@ -1,17 +1,21 @@
use glutin::ContextTrait;
use std::{
ffi::{
CString,
c_void,
},
mem::size_of,
time::{
Instant,
Duration,
},
thread,
};
use crate::{
renderer::{
gl,
gl::types::*,
surface::*,
utils::pool::{
Handle,
Pool,
},
math::{
vec2::*,
vec3::*,
mat4::Mat4,
},
utils::pool::*,
scene::node::*,
engine::{
State,
duration_to_seconds_f32,
@@ -25,19 +29,24 @@ use crate::{
CommandKind,
Color,
},
};
use std::{
ffi::{
CStr,
CString,
c_void,
scene::node::{
Node,
NodeKind,
},
mem::size_of,
time::{
Instant,
Duration,
renderer::{
surface::{
Surface,
Vertex,
},
gl,
gl::types::*,
gpu_program::GpuProgram,
},
math::{
vec3::Vec3,
mat4::Mat4,
vec2::Vec2,
},
thread,
};
// Welcome to the kingdom of Unsafe Code
@@ -51,80 +60,6 @@ pub fn check_gl_error() {
}
}
pub struct GpuProgram {
id: GLuint,
name_buf: Vec<u8>,
}
impl GpuProgram {
pub fn create_shader(actual_type: GLuint, source: &CStr) -> Result<GLuint, String> {
unsafe {
let shader = gl::CreateShader(actual_type);
gl::ShaderSource(shader, 1, &source.as_ptr(), std::ptr::null());
gl::CompileShader(shader);
let mut status = 1;
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
if status == 0 {
let mut log_len = 0;
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
let mut buffer: Vec<u8> = Vec::with_capacity(log_len as usize);
gl::GetShaderInfoLog(shader, log_len, std::ptr::null_mut(), buffer.as_mut_ptr() as *mut i8);
Err(String::from_utf8_unchecked(buffer))
} else {
println!("Shader compiled!");
Ok(shader)
}
}
}
pub fn from_source(vertex_source: &CStr, fragment_source: &CStr) -> Result<GpuProgram, String> {
unsafe {
let vertex_shader = Self::create_shader(gl::VERTEX_SHADER, vertex_source).unwrap();
let fragment_shader = Self::create_shader(gl::FRAGMENT_SHADER, fragment_source).unwrap();
let program: GLuint = gl::CreateProgram();
gl::AttachShader(program, vertex_shader);
gl::DeleteShader(vertex_shader);
gl::AttachShader(program, fragment_shader);
gl::DeleteShader(fragment_shader);
gl::LinkProgram(program);
let mut status = 1;
gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
if status == 0 {
let mut log_len = 0;
gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut log_len);
let mut buffer: Vec<u8> = Vec::with_capacity(log_len as usize);
gl::GetProgramInfoLog(program, log_len, std::ptr::null_mut(), buffer.as_mut_ptr() as *mut i8);
Err(String::from_utf8_unchecked(buffer))
} else {
Ok(Self {
id: program,
name_buf: Vec::new(),
})
}
}
}
pub fn get_uniform_location(&mut self, name: &str) -> GLint {
// Form c string in special buffer to reduce memory allocations
let buf = &mut self.name_buf;
buf.clear();
buf.extend_from_slice(name.as_bytes());
buf.push(0);
unsafe {
gl::GetUniformLocation(self.id, buf.as_ptr() as *const i8)
}
}
}
impl Drop for GpuProgram {
fn drop(&mut self) {
unsafe {
gl::DeleteProgram(self.id);
}
}
}
struct UIShader {
program: GpuProgram,
wvp_matrix: GLint,
@@ -523,79 +458,10 @@ impl Renderer {
});
}
pub fn render(&mut self, state: &State, drawing_context: &DrawingContext) {
let frame_start_time = Instant::now();
fn render_ui(&mut self, drawing_context: &DrawingContext) {
unsafe {
let client_size = self.context.get_inner_size().unwrap();
gl::ClearColor(0.0, 0.63, 0.91, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
for scene in state.get_scenes().iter() {
// Prepare for render - fill lists of nodes participating in rendering
// by traversing scene graph
self.meshes.clear();
self.lights.clear();
self.cameras.clear();
self.traversal_stack.clear();
self.traversal_stack.push(scene.root.clone());
while let Some(node_handle) = self.traversal_stack.pop() {
if let Some(node) = scene.get_node(&node_handle) {
match node.borrow_kind() {
NodeKind::Mesh(_) => self.meshes.push(node_handle),
NodeKind::Light(_) => self.lights.push(node_handle),
NodeKind::Camera(_) => self.cameras.push(node_handle),
_ => ()
}
// Queue children for render
for child_handle in node.get_children() {
self.traversal_stack.push(child_handle.clone());
}
}
}
gl::UseProgram(self.flat_shader.program.id);
// Render scene from each camera
for camera_handle in self.cameras.iter() {
if let Some(camera_node) = scene.get_node(&camera_handle) {
if let NodeKind::Camera(camera) = camera_node.borrow_kind() {
// Setup viewport
let viewport = camera.get_viewport_pixels(
Vec2 {
x: client_size.width as f32,
y: client_size.height as f32,
});
gl::Viewport(viewport.x, viewport.y, viewport.w, viewport.h);
let view_projection = camera.get_view_projection_matrix();
for mesh_handle in self.meshes.iter() {
if let Some(node) = scene.get_node(&mesh_handle) {
if !node.get_global_visibility() {
continue;
}
let mvp = view_projection * *node.get_global_transform();
gl::UseProgram(self.flat_shader.program.id);
gl::UniformMatrix4fv(self.flat_shader.wvp_matrix, 1, gl::FALSE, &mvp.f as *const GLfloat);
if let NodeKind::Mesh(mesh) = node.borrow_kind() {
for surface in mesh.get_surfaces().iter() {
self.draw_surface(surface);
}
}
}
}
}
}
}
}
// Render UI on top of everything
gl::Disable(gl::DEPTH_TEST);
gl::Enable(gl::BLEND);
@@ -691,6 +557,81 @@ impl Renderer {
gl::Disable(gl::BLEND);
gl::Enable(gl::DEPTH_TEST);
}
}
pub fn render(&mut self, state: &State, drawing_context: &DrawingContext) {
let frame_start_time = Instant::now();
unsafe {
let client_size = self.context.get_inner_size().unwrap();
gl::ClearColor(0.0, 0.63, 0.91, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
for scene in state.get_scenes().iter() {
// Prepare for render - fill lists of nodes participating in rendering
// by traversing scene graph
self.meshes.clear();
self.lights.clear();
self.cameras.clear();
self.traversal_stack.clear();
self.traversal_stack.push(scene.get_root().clone());
while let Some(node_handle) = self.traversal_stack.pop() {
if let Some(node) = scene.get_node(&node_handle) {
match node.borrow_kind() {
NodeKind::Mesh(_) => self.meshes.push(node_handle),
NodeKind::Light(_) => self.lights.push(node_handle),
NodeKind::Camera(_) => self.cameras.push(node_handle),
_ => ()
}
// Queue children for render
for child_handle in node.get_children() {
self.traversal_stack.push(child_handle.clone());
}
}
}
gl::UseProgram(self.flat_shader.program.id);
// Render scene from each camera
for camera_handle in self.cameras.iter() {
if let Some(camera_node) = scene.get_node(&camera_handle) {
if let NodeKind::Camera(camera) = camera_node.borrow_kind() {
// Setup viewport
let viewport = camera.get_viewport_pixels(
Vec2 {
x: client_size.width as f32,
y: client_size.height as f32,
});
gl::Viewport(viewport.x, viewport.y, viewport.w, viewport.h);
let view_projection = camera.get_view_projection_matrix();
for mesh_handle in self.meshes.iter() {
if let Some(node) = scene.get_node(&mesh_handle) {
if !node.get_global_visibility() {
continue;
}
let mvp = view_projection * *node.get_global_transform();
gl::UseProgram(self.flat_shader.program.id);
gl::UniformMatrix4fv(self.flat_shader.wvp_matrix, 1, gl::FALSE, &mvp.f as *const GLfloat);
if let NodeKind::Mesh(mesh) = node.borrow_kind() {
for surface in mesh.get_surfaces().iter() {
self.draw_surface(surface);
}
}
}
}
}
}
}
}
self.render_ui(drawing_context);
}
check_gl_error();
+72 -6
View File
@@ -2,13 +2,13 @@ use crate::{
math::{vec2::*, vec3::*, vec4::*},
renderer::{
gl,
gl::types::*
gl::types::*,
},
resource::*,
};
use std::{
rc::Rc,
cell::RefCell
cell::RefCell,
};
#[derive(Copy, Clone, Debug)]
@@ -27,8 +27,6 @@ pub struct SurfaceSharedData {
vbo: GLuint,
vao: GLuint,
ebo: GLuint,
// Skip vertices and indices for now, later it can be useful for dynamic surfaces.
vertices: Vec<Vertex>,
indices: Vec<i32>,
}
@@ -104,8 +102,76 @@ impl SurfaceSharedData {
self.indices.as_slice()
}
pub fn calculate_tangents(&self) {
pub fn calculate_tangents(&mut self) {
let mut tan1 = vec![Vec3::new(); self.vertices.len()];
let mut tan2 = vec![Vec3::new(); self.vertices.len()];
for i in (0..self.indices.len()).step_by(3) {
let i1 = self.indices[i] as usize;
let i2 = self.indices[i + 1] as usize;
let i3 = self.indices[i + 2] as usize;
let v1 = &self.vertices[i1].position;
let v2 = &self.vertices[i2].position;
let v3 = &self.vertices[i3].position;
let w1 = &self.vertices[i1].tex_coord;
let w2 = &self.vertices[i2].tex_coord;
let w3 = &self.vertices[i3].tex_coord;
let x1 = v2.x - v1.x;
let x2 = v3.x - v1.x;
let y1 = v2.y - v1.y;
let y2 = v3.y - v1.y;
let z1 = v2.z - v1.z;
let z2 = v3.z - v1.z;
let s1 = w2.x - w1.x;
let s2 = w3.x - w1.x;
let t1 = w2.y - w1.y;
let t2 = w3.y - w1.y;
let r = 1.0 / (s1 * t2 - s2 * t1);
let sdir = Vec3::make(
(t2 * x1 - t1 * x2) * r,
(t2 * y1 - t1 * y2) * r,
(t2 * z1 - t1 * z2) * r,
);
tan1[i1] += sdir;
tan1[i2] += sdir;
tan1[i3] += sdir;
let tdir = Vec3::make(
(s1 * x2 - s2 * x1) * r,
(s1 * y2 - s2 * y1) * r,
(s1 * z2 - s2 * z1) * r,
);
tan2[i1] += tdir;
tan2[i2] += tdir;
tan2[i3] += tdir;
}
for i in 0..self.vertices.len() {
let n = &self.vertices[i].normal;
let t = tan1[i];
// Gram-Schmidt orthogonalize
let tangent = (t - n.scale(n.dot(&t))).normalized().unwrap();
self.vertices[i].tangent = Vec4 {
x: tangent.x,
y: tangent.y,
z: tangent.z,
// Handedness
w: if n.cross(&t).dot(&tan2[i]) < 0.0 {
-1.0
} else {
1.0
},
};
}
}
pub fn make_cube() -> Self {
@@ -385,7 +451,7 @@ impl Surface {
texture: match &self.texture {
Some(resource) => Some(Rc::clone(resource)),
None => None
}
},
}
}
}
+194 -15
View File
@@ -1,14 +1,37 @@
use std::{path::{PathBuf, Path}, fs::File, io::Read, collections::HashMap, time::Instant};
use std::{
path::{PathBuf, Path},
fs::File,
io::Read,
collections::HashMap,
time::Instant,
any::{Any, TypeId},
cell::RefCell,
rc::Rc,
};
use crate::{
utils::pool::*,
math::{vec4::*, vec3::*, vec2::*, mat4::*, quat::*, triangulator::*},
math::{
vec4::Vec4,
vec3::Vec3,
vec2::Vec2,
mat4::Mat4,
quat::{
Quat,
RotationOrder,
},
triangulator::triangulate,
},
scene::{*, node::*},
renderer::surface::{SurfaceSharedData, Surface, Vertex},
renderer::surface::{
SurfaceSharedData,
Surface,
Vertex,
},
engine::State,
};
use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::rc::Rc;
use crate::scene::animation::{Track, KeyFrame, Animation};
// TODO: Add binary FBX support
pub enum FbxAttribute {
Double(f64),
@@ -234,8 +257,46 @@ impl FbxAnimationCurve {
Ok(curve)
}
fn eval(&self, time: f32) -> f32 {
if self.keys.is_empty() {
println!("FBX: Trying to evaluate curve with no keys!");
return 0.0;
}
if time <= self.keys[0].time {
return self.keys[0].value;
}
if time >= self.keys[self.keys.len() - 1].time {
return self.keys[self.keys.len() - 1].value;
}
// Do linear search for span
for i in 0..self.keys.len() {
let cur = &self.keys[i];
if cur.time >= time {
let next = &self.keys[i + 1];
// calculate interpolation coefficient
let time_span = next.time - cur.time;
let k = (time - cur.time) / time_span;
// TODO: for now assume that we have only linear transitions
let val_span = next.value - cur.value;
return cur.value + k * val_span;
}
}
// Must be unreached
println!("FBX: How the hell did you get here?!");
return 0.0;
}
}
#[derive(PartialEq)]
enum FbxAnimationCurveNodeType {
Unknown,
Translation,
@@ -255,17 +316,51 @@ impl FbxAnimationCurveNode {
match nodes.borrow(node_handle) {
Some(node) =>
Ok(FbxAnimationCurveNode {
actual_type: match node.get_attrib(0)?.as_string().as_str() {
"T" | "AnimCurveNode::T" => FbxAnimationCurveNodeType::Translation,
"R" | "AnimCurveNode::R" => FbxAnimationCurveNodeType::Rotation,
"S" | "AnimCurveNode::S" => FbxAnimationCurveNodeType::Scale,
_ => FbxAnimationCurveNodeType::Unknown
actual_type: match node.get_attrib(1)?.as_string().as_str() {
"T" | "AnimCurveNode::T" => { FbxAnimationCurveNodeType::Translation }
"R" | "AnimCurveNode::R" => { FbxAnimationCurveNodeType::Rotation }
"S" | "AnimCurveNode::S" => { FbxAnimationCurveNodeType::Scale }
_ => { FbxAnimationCurveNodeType::Unknown }
},
curves: Vec::new(),
}),
None => Err(String::from("Invalid FBX node handle!"))
}
}
pub fn eval_vec3(&self, components: &Pool<FbxComponent>, time: f32) -> Vec3 {
let x = if let Some(x) = components.borrow(&self.curves[0]) {
if let FbxComponent::AnimationCurve(curve) = x {
curve.eval(time)
} else {
0.0
}
} else {
0.0
};
let y = if let Some(y) = components.borrow(&self.curves[1]) {
if let FbxComponent::AnimationCurve(curve) = y {
curve.eval(time)
} else {
0.0
}
} else {
0.0
};
let z = if let Some(z) = components.borrow(&self.curves[2]) {
if let FbxComponent::AnimationCurve(curve) = z {
curve.eval(time)
} else {
0.0
}
} else {
0.0
};
Vec3::make(x, y, z)
}
}
#[derive(Copy, Clone, PartialEq)]
@@ -821,8 +916,7 @@ fn string_to_mapping(value: &str) -> FbxMapping {
match value {
"ByPolygon" => FbxMapping::ByPolygon,
"ByPolygonVertex" => FbxMapping::ByPolygonVertex,
"ByVertex" => FbxMapping::ByVertex,
"ByVertice" => FbxMapping::ByVertex,
"ByVertex" | "ByVertice" => FbxMapping::ByVertex,
"ByEdge" => FbxMapping::ByEdge,
"AllSame" => FbxMapping::AllSame,
_ => FbxMapping::Unknown
@@ -1130,7 +1224,8 @@ impl Fbx {
};
node.set_name(model.name.clone());
node.set_local_rotation(quat_from_euler(model.rotation));
let node_local_rotation = quat_from_euler(model.rotation);
node.set_local_rotation(node_local_rotation);
node.set_local_scale(model.scale);
node.set_local_position(model.translation);
node.set_post_rotation(quat_from_euler(model.post_rotation));
@@ -1153,7 +1248,90 @@ impl Fbx {
_ => ()
}
Ok(scene.add_node(node))
let node_handle = scene.add_node(node);
// Convert animations
if !model.animation_curve_nodes.is_empty() {
// Find supported curve nodes (translation, rotation, scale)
let mut lcl_translation = None;
let mut lcl_rotation = None;
let mut lcl_scale = None;
for anim_curve_node_handle in model.animation_curve_nodes.iter() {
if let Some(component) = self.component_pool.borrow(anim_curve_node_handle) {
if let FbxComponent::AnimationCurveNode(curve_node) = component {
if curve_node.actual_type == FbxAnimationCurveNodeType::Rotation {
lcl_rotation = Some(curve_node);
} else if curve_node.actual_type == FbxAnimationCurveNodeType::Translation {
lcl_translation = Some(curve_node);
} else if curve_node.actual_type == FbxAnimationCurveNodeType::Scale {
lcl_scale = Some(curve_node);
}
}
}
}
// Convert to engine format
let mut track = Track::new();
track.set_node(node_handle.clone());
let mut time = 0.0;
loop {
let translation =
if let Some(curve) = lcl_translation {
curve.eval_vec3(&self.component_pool, time)
} else {
model.translation
};
let rotation =
if let Some(curve) = lcl_rotation {
quat_from_euler(curve.eval_vec3(&self.component_pool, time))
} else {
node_local_rotation
};
let scale = if let Some(curve) = lcl_scale {
curve.eval_vec3(&self.component_pool, time)
} else {
model.scale
};
track.add_key_frame(KeyFrame::new(time, translation, scale, rotation));
let mut next_time = std::f32::MAX;
for node in &[lcl_translation, lcl_rotation, lcl_scale] {
if let Some(node) = node {
for curve_handle in node.curves.iter() {
if let Some(curve_component) = self.component_pool.borrow(curve_handle) {
if let FbxComponent::AnimationCurve(curve) = curve_component {
for key in curve.keys.iter() {
if key.time > time {
let distance = key.time - time;
if distance < next_time - key.time {
next_time = key.time;
}
}
}
}
}
}
}
}
if next_time >= std::f32::MAX {
break;
}
time = next_time;
}
let animation_handle = scene.get_animations().handle_from_index(0);
if let Some(animation) = scene.get_animation_mut(&animation_handle) {
animation.add_track(track);
}
}
Ok(node_handle)
}
///
@@ -1164,6 +1342,7 @@ impl Fbx {
scene: &mut Scene)
-> Result<Handle<Node>, String> {
let root = scene.add_node(Node::new(NodeKind::Base));
scene.add_animation(Animation::default());
let mut fbx_model_to_node_map: HashMap<Handle<FbxComponent>, Handle<Node>> = HashMap::new();
for component_handle in self.components.iter() {
if let Some(component) = self.component_pool.borrow(&component_handle) {
+22 -1
View File
@@ -46,13 +46,34 @@ impl Model {
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) {
if let Some(node) = dest_scene.get_nodes_mut().borrow_mut(&node_handle) {
node.set_resource(Rc::clone(&resource_rc));
for child_handle in node.get_children() {
stack.push(child_handle.clone());
}
}
}
// Instantiate animations
for ref_anim in model.scene.get_animations().iter() {
let mut anim_copy = ref_anim.clone();
// Remap animation track nodes.
for (i, ref_track) in ref_anim.get_tracks().iter().enumerate() {
// Find instantiated node that corresponds to node in resource
let nodes = dest_scene.get_nodes();
for k in 0..nodes.get_capacity() {
if let Some(node) = nodes.at(k) {
if node.get_original_handle() == ref_track.get_node() {
anim_copy.get_tracks_mut()[i].set_node(nodes.handle_from_index(k));
}
}
}
}
dest_scene.add_animation(anim_copy);
}
return Ok(root);
}
Err(())
+279 -10
View File
@@ -1,24 +1,179 @@
use crate::{
math::{
vec3::Vec3,
quat::Quat
quat::Quat,
},
resource::Resource
resource::Resource,
utils::visitor::{
Visit,
VisitResult,
Visitor,
},
scene::node::Node,
utils::pool::Handle,
math::clampf,
};
use std::{
rc::Weak,
cell::RefCell
rc::Rc,
cell::RefCell,
};
use crate::math::{lerpf, wrapf};
#[derive(Copy, Clone)]
pub struct KeyFrame {
position: Vec3,
scale: Vec3,
rotation: Quat,
time: f32,
pub position: Vec3,
pub scale: Vec3,
pub rotation: Quat,
pub time: f32,
}
impl KeyFrame {
pub fn new(time: f32, position: Vec3, scale: Vec3, rotation: Quat) -> Self {
Self {
time,
position,
scale,
rotation
}
}
}
impl Default for KeyFrame {
fn default() -> Self {
Self {
position: Default::default(),
scale: Default::default(),
rotation: Default::default(),
time: 0.0,
}
}
}
impl Visit for KeyFrame {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.position.visit("Position", visitor)?;
self.scale.visit("Scale", visitor)?;
self.rotation.visit("Rotation", visitor)?;
self.time.visit("Time", visitor)?;
visitor.leave_region()
}
}
pub struct Track {
frames: Vec<KeyFrame>
frames: Vec<KeyFrame>,
enabled: bool,
max_time: f32,
node: Handle<Node>,
}
impl Clone for Track {
fn clone(&self) -> Self {
Self {
frames: self.frames.clone(),
enabled: self.enabled,
max_time: self.max_time,
node: self.node.clone(),
}
}
}
impl Default for Track {
fn default() -> Self {
Self {
frames: Vec::new(),
enabled: true,
max_time: 0.0,
node: Default::default(),
}
}
}
impl Visit for Track {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.frames.visit("Frames", visitor)?;
self.enabled.visit("Enabled", visitor)?;
self.max_time.visit("MaxTime", visitor)?;
self.node.visit("Node", visitor)?;
visitor.leave_region()
}
}
impl Track {
pub fn new() -> Track {
Default::default()
}
pub fn set_node(&mut self, node: Handle<Node>) {
self.node = node;
}
pub fn get_node(&self) -> Handle<Node> {
self.node.clone()
}
pub fn add_key_frame(&mut self, key_frame: KeyFrame) {
if key_frame.time > self.max_time {
self.frames.push(key_frame);
self.max_time = key_frame.time;
} else {
// Find a place to insert
let mut index = 0;
for (i, other_key_frame) in self.frames.iter().enumerate() {
if key_frame.time < other_key_frame.time {
index = i;
break;
}
}
self.frames.insert(index, key_frame)
}
}
pub fn get_key_frame(&self, mut time: f32) -> Option<KeyFrame> {
if self.frames.is_empty() {
return None;
}
if time >= self.max_time {
return Some(*self.frames.last().unwrap());
}
time = clampf(time, 0.0, self.max_time);
let mut right_index = 0;
for (i, keyframe) in self.frames.iter().enumerate() {
if keyframe.time >= time {
right_index = i;
break;
}
}
if right_index == 0 {
return Some(*self.frames.first().unwrap());
} else {
if let Some(left) = self.frames.get(right_index - 1) {
if let Some(right) = self.frames.get(right_index) {
let interpolator = (time - left.time) / (right.time - left.time);
return Some(KeyFrame {
time: lerpf(left.time, right.time, interpolator),
position: left.position.lerp(&right.position, interpolator),
scale: left.scale.lerp(&right.scale, interpolator),
rotation: left.rotation.slerp(&right.rotation, interpolator),
});
}
}
}
None
}
}
pub struct Animation {
@@ -26,7 +181,121 @@ pub struct Animation {
speed: f32,
length: f32,
time_position: f32,
looped: bool,
weight: f32,
fade_step: f32,
resource: Weak<RefCell<Resource>>
enabled: bool,
resource: Option<Rc<RefCell<Resource>>>,
}
impl Clone for Animation {
fn clone(&self) -> Self {
Self {
tracks: self.tracks.clone(),
speed: self.speed,
length: self.length,
time_position: self.time_position,
weight: self.weight,
fade_step: self.fade_step,
looped: self.looped,
enabled: self.enabled,
resource: self.resource.clone()
}
}
}
impl Animation {
pub fn add_track(&mut self, track: Track) {
self.tracks.push(track);
for track in self.tracks.iter_mut() {
if track.max_time > self.length {
self.length = track.max_time;
}
}
}
pub fn get_tracks(&self) -> &[Track] {
&self.tracks
}
pub fn set_time_position(&mut self, time: f32) {
if self.looped {
self.time_position = wrapf(time, 0.0, self.length);
} else {
self.time_position = clampf(time, 0.0, self.length);
}
}
pub fn get_time_position(&self) -> f32 {
self.time_position
}
pub fn get_speed(&self) -> f32 {
self.speed
}
pub fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
pub fn is_enabled(&self) -> bool {
self.enabled
}
pub fn set_speed(&mut self, speed: f32) {
self.speed = speed;
}
pub fn get_tracks_mut(&mut self) -> &mut [Track] {
&mut self.tracks
}
pub fn update_fading(&mut self, dt: f32) {
if self.fade_step != 0.0 {
self.weight += self.fade_step * dt;
if self.fade_step < 0.0 && self.weight <= 0.0 {
self.weight = 0.0;
self.enabled = false;
self.fade_step = 0.0;
} else if self.fade_step > 0.0 && self.weight >= 1.0 {
self.weight = 1.0;
self.fade_step = 0.0;
}
}
}
}
impl Default for Animation {
fn default() -> Self {
Self {
tracks: Vec::new(),
speed: 1.0,
length: 0.0,
time_position: 0.0,
weight: 0.0,
enabled: true,
fade_step: 0.0,
looped: true,
resource: Default::default(),
}
}
}
impl Visit for Animation {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.tracks.visit("Tracks", visitor)?;
self.speed.visit("Speed", visitor)?;
self.length.visit("Length", visitor)?;
self.time_position.visit("TimePosition", visitor)?;
self.weight.visit("Weight", visitor)?;
self.fade_step.visit("FadeStep", visitor)?;
self.resource.visit("Resource", visitor)?;
self.looped.visit("Looped", visitor)?;
self.enabled.visit("Enabled", visitor)?;
visitor.leave_region()
}
}
+89 -17
View File
@@ -7,39 +7,46 @@ use crate::{
visitor::{
Visit,
VisitResult,
Visitor
}
Visitor,
},
pool::{
Handle,
Pool,
},
},
math::mat4::*,
math::mat4::Mat4,
physics::Physics,
engine::State,
scene::{
animation::Animation,
node::Node,
node::NodeKind,
},
};
use node::*;
use crate::utils::pool::{Handle, Pool};
use crate::math::vec3::Vec3;
pub struct Scene {
/// Nodes pool, every node lies inside pool. User-code may borrow
/// a reference to a node using handle.
pub(crate) nodes: Pool<Node>,
nodes: Pool<Node>,
/// Root node of scene. Each node added to scene will be attached
/// to root.
pub(crate) root: Handle<Node>,
root: Handle<Node>,
animations: Pool<Animation>,
physics: Physics,
/// Tree traversal stack.
stack: Vec<Handle<Node>>,
}
impl Default for Scene {
fn default() -> Self {
Self {
nodes: Pool::new(),
root: Default::default(),
physics: Physics::new(),
stack: Vec::new()
}
Self {
nodes: Pool::new(),
root: Default::default(),
physics: Physics::new(),
stack: Vec::new(),
animations: Pool::new(),
}
}
}
@@ -52,6 +59,7 @@ impl Scene {
nodes,
stack: Vec::new(),
root,
animations: Pool::new(),
physics: Physics::new(),
}
}
@@ -65,6 +73,16 @@ impl Scene {
handle
}
#[inline]
pub fn get_nodes(&mut self) -> &Pool<Node> {
&self.nodes
}
#[inline]
pub fn get_nodes_mut(&mut self) -> &mut Pool<Node> {
&mut self.nodes
}
/// Destroys node and its children recursively.
#[inline]
pub fn remove_node(&mut self, node_handle: Handle<Node>, state: &mut State) {
@@ -103,6 +121,26 @@ impl Scene {
&mut self.physics
}
#[inline]
pub fn add_animation(&mut self, animation: Animation) -> Handle<Animation> {
self.animations.spawn(animation)
}
#[inline]
pub fn get_animation(&self, handle: &Handle<Animation>) -> Option<&Animation> {
self.animations.borrow(handle)
}
#[inline]
pub fn get_animation_mut(&mut self, handle: &Handle<Animation>) -> Option<&mut Animation> {
self.animations.borrow_mut(handle)
}
#[inline]
pub fn get_animations(&self) -> &Pool<Animation> {
&self.animations
}
/// Links specified child with specified parent.
#[inline]
pub fn link_nodes(&mut self, child_handle: &Handle<Node>, parent_handle: &Handle<Node>) {
@@ -160,7 +198,7 @@ impl Scene {
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();
let mut dest_node = src_node.make_copy(root_handle.clone());
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()));
}
@@ -177,6 +215,7 @@ impl Scene {
}
}
#[inline]
pub fn get_root(&self) -> Handle<Node> {
self.root.clone()
}
@@ -224,9 +263,41 @@ impl Scene {
}
}
pub fn update_animations(&mut self, dt: f32) {
// Reset local transform of animated nodes first
for animation in self.animations.iter() {
for track in animation.get_tracks() {
if let Some(node) = self.nodes.borrow_mut(&track.get_node()) {
node.set_local_position(Default::default());
node.set_local_rotation(Default::default());
node.set_local_scale(Vec3::make(1.0, 1.0, 1.0));
}
}
}
// Then apply animation.
for animation in self.animations.iter_mut() {
let next_time_pos = animation.get_time_position() + dt * animation.get_speed();
for track in animation.get_tracks() {
if let Some(keyframe) = track.get_key_frame(animation.get_time_position()) {
if let Some(node) = self.nodes.borrow_mut(&track.get_node()) {
node.set_local_position(node.get_local_position() + keyframe.position);
node.set_local_rotation(node.get_local_rotation() * keyframe.rotation);
node.set_local_scale(node.get_local_scale() * keyframe.scale);
}
}
}
animation.set_time_position(next_time_pos);
animation.update_fading(dt);
}
}
pub fn update(&mut self, aspect_ratio: f32, dt: f64) {
self.update_physics(dt);
self.update_animations(dt as f32);
self.update_nodes();
for node in self.nodes.iter_mut() {
@@ -245,6 +316,7 @@ impl Visit for Scene {
visitor.enter_region(name)?;
self.root.visit("Root", visitor)?;
self.nodes.visit("Nodes", visitor)?;
self.animations.visit("Animations", visitor)?;
self.physics.visit("Physics", visitor)?;
visitor.leave_region()
}
+27 -1
View File
@@ -227,6 +227,9 @@ pub struct Node {
pub(in crate::scene) global_transform: Mat4,
body: Handle<Body>,
resource: Option<Rc<RefCell<Resource>>>,
/// Handle to node in scene of model resource from which this node
/// was instantiated from.
original: Handle<Node>
}
impl Default for Node {
@@ -251,6 +254,7 @@ impl Default for Node {
global_transform: Mat4::identity(),
body: Handle::none(),
resource: None,
original: Handle::none()
}
}
}
@@ -277,6 +281,7 @@ impl Node {
global_transform: Mat4::identity(),
body: Handle::none(),
resource: None,
original: Handle::none()
}
}
@@ -300,7 +305,7 @@ 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) -> Node {
pub fn make_copy(&self, original: Handle<Node>) -> Node {
Node {
kind: match &self.kind {
NodeKind::Camera(camera) => NodeKind::Camera(camera.make_copy()),
@@ -329,9 +334,15 @@ impl Node {
Some(resource) => Some(Rc::clone(resource)),
None => None
},
original
}
}
#[inline]
pub fn get_original_handle(&self) -> Handle<Node> {
self.original.clone()
}
#[inline]
pub fn set_body(&mut self, body: Handle<Body>) {
self.body = body;
@@ -360,6 +371,21 @@ impl Node {
}
}
#[inline]
pub fn get_local_position(&self) -> Vec3 {
self.local_position
}
#[inline]
pub fn get_local_rotation(&self) -> Quat {
self.local_rotation
}
#[inline]
pub fn get_local_scale(&self) -> Vec3 {
self.local_scale
}
#[inline]
pub fn borrow_kind_mut(&mut self) -> &mut NodeKind {
&mut self.kind
+1
View File
@@ -19,6 +19,7 @@ pub struct Pool<T: Sized> {
/// It stores index of object and additional information that
/// allows to ensure that handle is still valid.
///
#[derive(Copy)]
pub struct Handle<T> {
/// Index of object in pool.
index: u32,