mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
added key frame animations
This commit is contained in:
Generated
+16
@@ -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" />
|
||||
|
||||
+26
-14
@@ -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
@@ -4,8 +4,8 @@ use crate::{
|
||||
visitor::{
|
||||
Visit,
|
||||
VisitResult,
|
||||
},
|
||||
visitor::Visitor,
|
||||
Visitor
|
||||
}
|
||||
},
|
||||
math::vec3::*,
|
||||
scene::{
|
||||
|
||||
+17
-5
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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]
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user