added skinning

This commit is contained in:
Dmitry
2019-08-28 22:46:08 +03:00
parent ff1b816302
commit 13deabcb57
10 changed files with 435 additions and 270 deletions
+3 -28
View File
@@ -6,39 +6,14 @@
<component name="ChangeListManager">
<list default="true" id="1932b2c4-d6ff-413c-9558-19959667326b" name="Default Changelist" comment="scene graph">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/save.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/game/weapon.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/game/weapon.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/border.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/border.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/builder.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/builder.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/button.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/button.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/canvas.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/canvas.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/draw.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/draw.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/grid.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/grid.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/scroll_bar.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/scroll_bar.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/scroll_content_presenter.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/scroll_content_presenter.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/scroll_viewer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/scroll_viewer.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/text.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/text.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/physics/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/physics/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/renderer/gpu_program.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/gpu_program.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/fbx_ascii.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/fbx/fbx_ascii.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/resource/fbx/fbx_binary.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/fbx/fbx_binary.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/fbx/texture.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/fbx/texture.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/resource/model.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/model.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/resource/ttf.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/ttf.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" />
<change beforePath="$PROJECT_DIR$/src/utils/visitor.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/visitor.rs" afterDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
@@ -77,7 +52,7 @@
<property name="project.structure.proportion" value="0.0" />
<property name="project.structure.side.proportion" value="0.2" />
<property name="run.code.analysis.last.selected.profile" value="pProject Default" />
<property name="settings.editor.selected.configurable" value="editor.preferences.fonts.default" />
<property name="settings.editor.selected.configurable" value="Console" />
<property name="settings.editor.splitter.proportion" value="0.23435949" />
</component>
<component name="RunDashboard">
Binary file not shown.
+7 -5
View File
@@ -1,15 +1,17 @@
use std::ffi::CStr;
use crate::{
math::{
vec4::Vec4,
mat4::Mat4,
vec3::Vec3
},
renderer::{
gl::types::GLuint,
gl,
gl::types::GLint,
gl::types::GLfloat,
},
math::mat4::Mat4,
};
use std::ffi::CStr;
use crate::math::vec4::Vec4;
use crate::math::vec3::Vec3;
pub struct GpuProgram {
id: GLuint,
@@ -98,7 +100,7 @@ impl GpuProgram {
pub fn set_mat4_array(&self, location: UniformLocation, mat: &[Mat4]) {
unsafe {
gl::UniformMatrix4fv(location.id, mat.len() as i32, gl::FALSE, &mat[0].f as *const GLfloat);
gl::UniformMatrix4fv(location.id, mat.len() as i32, gl::FALSE, mat[0].f.as_ptr() as *const GLfloat);
}
}
+58 -49
View File
@@ -1,53 +1,26 @@
use crate::{
utils::pool::{
Handle,
Pool,
},
engine::{
State,
duration_to_seconds_f32,
},
resource::{
ResourceKind,
ttf::Font,
},
gui::draw::{
DrawingContext,
CommandKind,
Color,
},
scene::node::{
Node,
NodeKind,
},
utils::pool::{Handle, Pool},
engine::{State, duration_to_seconds_f32},
resource::{ResourceKind, ttf::Font},
gui::draw::{DrawingContext, CommandKind, Color},
scene::node::{Node, NodeKind},
renderer::{
surface::{
Vertex,
SurfaceSharedData,
},
surface::{Vertex, SurfaceSharedData},
gl,
gl::types::*,
gpu_program::{
GpuProgram,
UniformLocation,
},
gpu_program::{GpuProgram, UniformLocation},
},
math::{
vec3::Vec3,
mat4::Mat4,
vec2::Vec2,
},
vec4::Vec4
}
};
use std::{
ffi::{
CString,
c_void,
},
ffi::{CString, c_void},
mem::size_of,
time::{
Instant,
Duration,
},
time::{Instant, Duration},
thread,
cell::RefCell,
};
@@ -518,6 +491,7 @@ pub struct Renderer {
statistics: Statistics,
quad: RefCell<SurfaceSharedData>,
sphere: RefCell<SurfaceSharedData>,
bone_matrices: Vec<Mat4>,
}
struct FlatShader {
@@ -972,6 +946,7 @@ impl Renderer {
quad: RefCell::new(SurfaceSharedData::make_unit_xy_quad()),
sphere: RefCell::new(SurfaceSharedData::make_sphere(6, 6, 1.0)),
ui_render_buffers: create_ui_render_buffers(),
bone_matrices: Vec::new(),
}
}
}
@@ -1025,6 +1000,18 @@ impl Renderer {
gl::VertexAttribPointer(3, 4, gl::FLOAT, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(3);
offset += size_of::<Vec4>();
// Bone weights
gl::VertexAttribPointer(4, 4, gl::FLOAT, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(4);
offset += size_of::<Vec4>();
// Bone indices
gl::VertexAttribPointer(5, 4, gl::UNSIGNED_BYTE, gl::FALSE,
size_of::<Vertex>() as GLint, offset as *const c_void);
gl::EnableVertexAttribArray(5);
gl::BindVertexArray(0);
@@ -1290,19 +1277,41 @@ impl Renderer {
for mesh_handle in self.meshes.iter() {
if let Some(node) = scene.get_node(*mesh_handle) {
if !node.get_global_visibility() {
continue;
}
let world = *node.get_global_transform();
let mvp = view_projection * world;
self.gbuffer_shader.set_wvp_matrix(&mvp);
self.gbuffer_shader.set_world_matrix(&world);
self.gbuffer_shader.set_use_skeletal_animation(false);
if let NodeKind::Mesh(mesh) = node.borrow_kind() {
if !node.get_global_visibility() {
continue;
}
for surface in mesh.get_surfaces().iter() {
let is_skinned = !surface.bones.is_empty();
let world = if is_skinned {
Mat4::identity()
} else {
*node.get_global_transform()
};
let mvp = view_projection * world;
self.gbuffer_shader.set_wvp_matrix(&mvp);
self.gbuffer_shader.set_world_matrix(&world);
self.gbuffer_shader.set_use_skeletal_animation(is_skinned);
if is_skinned {
self.bone_matrices.clear();
for bone_handle in surface.bones.iter() {
if let Some(bone_node) = scene.get_node(*bone_handle) {
self.bone_matrices.push(
*bone_node.get_global_transform() *
*bone_node.get_inv_bind_pose_transform());
} else {
self.bone_matrices.push(Mat4::identity())
}
}
self.gbuffer_shader.set_bone_matrices(&self.bone_matrices);
}
// Bind diffuse texture.
gl::ActiveTexture(gl::TEXTURE0);
if let Some(resource) = surface.get_diffuse_texture() {
+115 -35
View File
@@ -9,13 +9,13 @@ use crate::{
gl::types::*,
},
resource::*,
scene::node::Node,
utils::pool::{Handle, ErasedHandle}
};
use std::{
rc::Rc,
cell::RefCell,
};
use crate::scene::node::Node;
use crate::utils::pool::Handle;
#[derive(Copy, Clone, Debug)]
#[repr(C)] // OpenGL expects this structure packed as in C
@@ -24,7 +24,7 @@ pub struct Vertex {
pub tex_coord: Vec2,
pub normal: Vec3,
pub tangent: Vec4,
pub bone_weights: Vec4,
pub bone_weights: [f32; 4],
pub bone_indices: [u8; 4],
}
@@ -81,26 +81,35 @@ impl SurfaceSharedData {
/// Inserts vertex or its index. Performs optimizing insertion with checking if such
/// vertex already exists.
/// Returns true if inserted vertex was unique.
#[inline]
pub fn insert_vertex(&mut self, vertex: Vertex) {
pub fn insert_vertex(&mut self, vertex: Vertex) -> bool {
// Reverse search is much faster because it is most likely that we'll find identic
// vertex at the end of the array.
let mut is_unique = false;
self.indices.push(match self.vertices.iter().rposition(|v| {
v.position == vertex.position && v.normal == vertex.normal && v.tex_coord == vertex.tex_coord
}) {
Some(exisiting_index) => exisiting_index as i32, // Already have such vertex
None => { // No such vertex, add it
is_unique = true;
let index = self.vertices.len() as i32;
self.vertices.push(vertex);
index
}
});
self.need_upload = true;
is_unique
}
#[inline]
pub fn get_vertices(&self) -> &[Vertex] {
self.vertices.as_slice()
&self.vertices
}
#[inline]
pub fn get_vertices_mut(&mut self) -> &mut [Vertex] {
&mut self.vertices
}
#[inline]
@@ -189,7 +198,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
tex_coord: Vec2 { x: 0.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -197,7 +206,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
tex_coord: Vec2 { x: 1.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -205,7 +214,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
tex_coord: Vec2 { x: 1.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -213,7 +222,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
tex_coord: Vec2 { x: 0.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
}
];
@@ -232,9 +241,9 @@ impl SurfaceSharedData {
tex_coord: tex,
normal: Vec3::make(0.0, 1.0, 0.0),
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: Default::default(),
})
});
}
pub fn calculate_normals(&mut self) {
@@ -308,7 +317,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
tex_coord: Vec2 { x: 0.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -316,7 +325,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
tex_coord: Vec2 { x: 0.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -324,7 +333,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
tex_coord: Vec2 { x: 1.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -332,7 +341,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
tex_coord: Vec2 { x: 1.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
@@ -342,7 +351,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
tex_coord: Vec2 { x: 0.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -350,7 +359,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
tex_coord: Vec2 { x: 0.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -358,7 +367,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
tex_coord: Vec2 { x: 1.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -366,7 +375,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
tex_coord: Vec2 { x: 1.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
@@ -376,7 +385,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
tex_coord: Vec2 { x: 0.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -384,7 +393,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
tex_coord: Vec2 { x: 0.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -392,7 +401,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
tex_coord: Vec2 { x: 1.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -400,7 +409,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
tex_coord: Vec2 { x: 1.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
@@ -410,7 +419,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
tex_coord: Vec2 { x: 0.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -418,7 +427,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
tex_coord: Vec2 { x: 0.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -426,7 +435,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
tex_coord: Vec2 { x: 1.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -434,7 +443,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
tex_coord: Vec2 { x: 1.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
@@ -444,7 +453,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
tex_coord: Vec2 { x: 0.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -452,7 +461,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
tex_coord: Vec2 { x: 0.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -460,7 +469,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
tex_coord: Vec2 { x: 1.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -468,7 +477,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
tex_coord: Vec2 { x: 1.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
@@ -478,7 +487,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
tex_coord: Vec2 { x: 0.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -486,7 +495,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
tex_coord: Vec2 { x: 0.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -494,7 +503,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
tex_coord: Vec2 { x: 1.0, y: 1.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
Vertex {
@@ -502,7 +511,7 @@ impl SurfaceSharedData {
normal: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
tex_coord: Vec2 { x: 1.0, y: 0.0 },
tangent: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_weights: [ 0.0, 0.0, 0.0, 0.0 ],
bone_indices: [0, 0, 0, 0],
},
];
@@ -522,6 +531,8 @@ impl SurfaceSharedData {
20, 22, 23
];
data.calculate_tangents();
data
}
}
@@ -536,10 +547,77 @@ impl Drop for SurfaceSharedData {
}
}
#[derive(Copy, Clone, Debug)]
pub struct VertexWeight {
pub value: f32,
/// Handle to an entity that affects this vertex. It has double meaning
/// relative to context:
/// 1. When converting fbx model to engine node it points to FbxModel
/// that control this vertex via sub deformer.
/// 2. After conversion is done, on resolve stage it points to a Node
/// in a scene to which converter put all the nodes.
pub effector: ErasedHandle,
}
impl Default for VertexWeight {
fn default() -> Self {
Self {
value: 0.0,
effector: ErasedHandle::none(),
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct VertexWeightSet {
weights: [VertexWeight; 4],
count: usize,
}
impl Default for VertexWeightSet {
fn default() -> Self {
Self {
weights: Default::default(),
count: 0,
}
}
}
impl VertexWeightSet {
pub fn push(&mut self, weight: VertexWeight) -> bool {
if self.count < self.weights.len() {
self.weights[self.count] = weight;
self.count += 1;
true
} else {
false
}
}
pub fn len(&self) -> usize {
self.count
}
pub fn iter(&self) -> std::slice::Iter<VertexWeight>{
self.weights[0..self.count].iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<VertexWeight>{
self.weights[0..self.count].iter_mut()
}
}
pub struct Surface {
data: Rc<RefCell<SurfaceSharedData>>,
diffuse_texture: Option<Rc<RefCell<Resource>>>,
normal_texture: Option<Rc<RefCell<Resource>>>,
/// Temporal array for FBX conversion needs, it holds skinning data (weight + bone handle)
/// and will be used to fill actual bone indices and weight in vertices that will be
/// sent to GPU. The idea is very simple: GPU needs to know only indices of matrices of
/// bones so we can use `bones` array as reference to get those indices. This could be done
/// like so: iterate over all vertices and weight data and calculate index of node handle that
/// associated with vertex in `bones` array and store it as bone index in vertex.
pub vertex_weights: Vec<VertexWeightSet>,
pub bones: Vec<Handle<Node>>
}
@@ -551,6 +629,7 @@ impl Surface {
diffuse_texture: None,
normal_texture: None,
bones: Vec::new(),
vertex_weights: Vec::new(),
}
}
@@ -599,6 +678,7 @@ impl Surface {
},
// Note: Handles will be remapped on Resolve stage.
bones: self.bones.clone(),
vertex_weights: Vec::new(),
}
}
}
+142 -110
View File
@@ -5,49 +5,37 @@ mod texture;
use std::{
path::Path,
fs::File,
io::{
Read,
Cursor,
},
collections::HashMap,
io::{Read, Cursor},
collections::{HashMap, HashSet},
time::Instant,
any::{
Any,
TypeId,
},
any::{Any, TypeId},
cell::RefCell,
rc::Rc,
fmt::Formatter,
};
use crate::{
utils::pool::{
Handle,
Pool,
},
utils::pool::{Handle, Pool},
math::{
vec4::Vec4,
vec3::Vec3,
vec2::Vec2,
mat4::Mat4,
quat::{
Quat,
RotationOrder,
},
quat::{Quat, RotationOrder},
triangulator::triangulate,
},
scene::{
*,
node::*,
animation::{
Track,
KeyFrame,
Animation,
},
animation::{Track, KeyFrame, Animation},
},
renderer::surface::{
SurfaceSharedData,
Surface,
Vertex,
renderer::{
surface::{
SurfaceSharedData,
Surface,
Vertex,
VertexWeightSet,
VertexWeight,
}
},
engine::State,
gui::draw::Color,
@@ -459,35 +447,6 @@ struct FbxGeometry {
deformers: Vec<Handle<FbxComponent>>,
}
#[derive(Copy, Clone)]
struct Weight {
value: f32,
affected_model: Handle<FbxComponent>,
}
impl Default for Weight {
fn default() -> Self {
Self {
value: 0.0,
affected_model: Handle::none()
}
}
}
#[derive(Copy, Clone)]
struct BoneSet {
weights: [Weight; 4],
count: usize
}
impl Default for BoneSet {
fn default() -> Self {
Self {
weights: Default::default(),
count: 0
}
}
}
impl FbxGeometry {
pub fn read(geom_node_handle: Handle<FbxNode>, nodes: &Pool<FbxNode>) -> Result<FbxGeometry, String> {
@@ -563,7 +522,7 @@ impl FbxGeometry {
let count = uvs_array_node.attrib_count() / 2;
for i in 0..count {
let uv = uvs_array_node.get_vec2_at(i * 2)?;
geom.uvs.push(Vec2 { x: uv.x, y: -uv.y }); // Hack
geom.uvs.push(Vec2 { x: uv.x, y: -uv.y }); // Hack FIXME
}
if geom.uv_reference == FbxReference::IndexToDirect {
@@ -593,20 +552,21 @@ impl FbxGeometry {
Ok(geom)
}
fn get_skin_data(&self, components: &Pool<FbxComponent>) -> Result<Vec<BoneSet>, FbxError> {
let mut out = vec![BoneSet::default(); self.vertices.len()];
fn get_skin_data(&self, components: &Pool<FbxComponent>) -> Result<Vec<VertexWeightSet>, FbxError> {
let mut out = vec![VertexWeightSet::default(); self.vertices.len()];
for deformer_handle in self.deformers.iter() {
for sub_deformer_handle in components.borrow(*deformer_handle).ok_or(FbxError::InvalidPoolHandle)?.as_deformer()?.sub_deformers.iter() {
let sub_deformer = components.borrow(*sub_deformer_handle).ok_or(FbxError::InvalidPoolHandle)?.as_sub_deformer()?;
for sub_deformer_handle in components.borrow(*deformer_handle)
.ok_or(FbxError::InvalidPoolHandle)?.as_deformer()?.sub_deformers.iter() {
let sub_deformer = components.borrow(*sub_deformer_handle)
.ok_or(FbxError::InvalidPoolHandle)?.as_sub_deformer()?;
for (index, weight) in sub_deformer.weights.iter() {
let mut bone_set = out.get_mut(*index as usize).ok_or(FbxError::IndexOutOfBounds)?;
if bone_set.count < 4 {
bone_set.weights[bone_set.count] = Weight {
value: *weight,
affected_model: sub_deformer.model
};
bone_set.count += 1;
} else {
let bone_set = out.get_mut(*index as usize)
.ok_or(FbxError::IndexOutOfBounds)?;
if !bone_set.push(VertexWeight {
value: *weight,
effector: sub_deformer.model.into(),
}) {
// TODO: Maybe it is better to ignore excessive bones?
return Err(FbxError::IndexOutOfBounds);
}
}
@@ -872,50 +832,48 @@ fn find_and_borrow_node<'a>(pool: &'a Pool<FbxNode>, root: Handle<FbxNode>, name
}
/// Links child component with parent component so parent will know about child
fn link_child_with_parent_component(parent: &mut FbxComponent, child_handle: Handle<FbxComponent>, child_type_id: TypeId) {
fn link_child_with_parent_component(parent: &mut FbxComponent, child: &mut FbxComponent, child_handle: Handle<FbxComponent>) {
match parent {
// Link model with other components
FbxComponent::Model(model) => {
if child_type_id == TypeId::of::<FbxGeometry>() {
model.geoms.push(child_handle)
} else if child_type_id == TypeId::of::<FbxMaterial>() {
model.materials.push(child_handle)
} else if child_type_id == TypeId::of::<FbxAnimationCurveNode>() {
model.animation_curve_nodes.push(child_handle)
} else if child_type_id == TypeId::of::<FbxLight>() {
model.light = child_handle
} else if child_type_id == TypeId::of::<FbxModel>() {
model.children.push(child_handle)
match child {
FbxComponent::Geometry(_) => model.geoms.push(child_handle),
FbxComponent::Material(_) => model.materials.push(child_handle),
FbxComponent::AnimationCurveNode(_) => model.animation_curve_nodes.push(child_handle),
FbxComponent::Light(_) => model.light = child_handle,
FbxComponent::Model(_) => model.children.push(child_handle),
_ => ()
}
}
// Link material with textures
FbxComponent::Material(material) => {
if child_type_id == TypeId::of::<FbxTexture>() {
if let FbxComponent::Texture(_) = child {
material.diffuse_texture = child_handle;
}
}
// Link animation curve node with animation curve
FbxComponent::AnimationCurveNode(anim_curve_node) => {
if child_type_id == TypeId::of::<FbxAnimationCurve>() {
if let FbxComponent::AnimationCurve(_) = child {
anim_curve_node.curves.push(child_handle);
}
}
// Link deformer with sub-deformers
FbxComponent::Deformer(deformer) => {
if child_type_id == TypeId::of::<FbxSubDeformer>() {
if let FbxComponent::SubDeformer(_) = child {
deformer.sub_deformers.push(child_handle);
}
}
// Link geometry with deformers
FbxComponent::Geometry(geometry) => {
if child_type_id == TypeId::of::<FbxDeformer>() {
if let FbxComponent::Deformer(_) = child {
geometry.deformers.push(child_handle);
}
}
// Link sub-deformer with model
FbxComponent::SubDeformer(sub_deformer) => {
if child_type_id == TypeId::of::<FbxModel>() {
if let FbxComponent::Model(model) = child {
sub_deformer.model = child_handle;
model.inv_bind_transform = sub_deformer.transform;
}
}
// Ignore rest
@@ -934,6 +892,8 @@ pub enum FbxError {
UnexpectedType,
InvalidPath,
IndexOutOfBounds,
UnableToFindBone,
UnableToRemapModelToNode,
}
impl std::fmt::Display for FbxError {
@@ -948,7 +908,9 @@ impl std::fmt::Display for FbxError {
FbxError::InvalidPoolHandle => write!(f, "Invalid pool handle."),
FbxError::UnexpectedType => write!(f, "Unexpected type. This means that invalid cast has occured in fbx component."),
FbxError::InvalidPath => write!(f, "Invalid path. This means that some path was stored in invalid format."),
FbxError::IndexOutOfBounds => write!(f, "Index out of bounds.")
FbxError::IndexOutOfBounds => write!(f, "Index out of bounds."),
FbxError::UnableToFindBone => write!(f, "Unable to find bone."),
FbxError::UnableToRemapModelToNode => write!(f, "Unable to remap model to node."),
}
}
}
@@ -1064,26 +1026,35 @@ fn convert_vertex(geom: &FbxGeometry,
material_index: usize,
origin: usize,
index: usize,
relative_index: usize) {
let position = geometric_transform.transform_vector(geom.vertices[index]);
relative_index: usize,
skin_data: &[VertexWeightSet]) -> Result<(), FbxError> {
let position = geometric_transform.transform_vector(*geom.vertices.get(index)
.ok_or(FbxError::IndexOutOfBounds)?);
let normal = geometric_transform.transform_vector_normal(match geom.normal_mapping {
FbxMapping::ByPolygonVertex => geom.normals[origin + relative_index],
FbxMapping::ByVertex => geom.normals[index],
FbxMapping::ByPolygonVertex => *geom.normals.get(origin + relative_index)
.ok_or(FbxError::IndexOutOfBounds)?,
FbxMapping::ByVertex => *geom.normals.get(index).ok_or(FbxError::IndexOutOfBounds)?,
_ => Vec3 { x: 0.0, y: 1.0, z: 0.0 }
});
let tangent = geometric_transform.transform_vector_normal(match geom.tangent_mapping {
FbxMapping::ByPolygonVertex => geom.tangents[origin + relative_index],
FbxMapping::ByVertex => geom.tangents[index],
FbxMapping::ByPolygonVertex => *geom.tangents.get(origin + relative_index)
.ok_or(FbxError::IndexOutOfBounds)?,
FbxMapping::ByVertex => *geom.tangents.get(index).ok_or(FbxError::IndexOutOfBounds)?,
_ => Vec3 { x: 0.0, y: 1.0, z: 0.0 }
});
let uv = match geom.uv_mapping {
FbxMapping::ByPolygonVertex => {
match geom.uv_reference {
FbxReference::Direct => geom.uvs[origin + relative_index],
FbxReference::IndexToDirect => geom.uvs[geom.uv_index[origin + relative_index] as usize],
FbxReference::Direct => *geom.uvs.get(origin + relative_index)
.ok_or(FbxError::IndexOutOfBounds)?,
FbxReference::IndexToDirect => {
let uv_index = *geom.uv_index.get(origin + relative_index)
.ok_or(FbxError::IndexOutOfBounds)? as usize;
*geom.uvs.get(uv_index).ok_or(FbxError::IndexOutOfBounds)?
}
_ => Vec2 { x: 0.0, y: 0.0 }
}
}
@@ -1091,21 +1062,30 @@ fn convert_vertex(geom: &FbxGeometry,
};
let material = match geom.material_mapping {
FbxMapping::AllSame => geom.materials[0] as usize,
FbxMapping::ByPolygon => geom.materials[material_index] as usize,
FbxMapping::AllSame => *geom.materials.first().ok_or(FbxError::IndexOutOfBounds)? as usize,
FbxMapping::ByPolygon => *geom.materials.get(material_index).ok_or(FbxError::IndexOutOfBounds)? as usize,
_ => 0
};
let surface = mesh.get_surfaces_mut().get_mut(material).unwrap();
surface.get_data().borrow_mut().insert_vertex(Vertex {
let is_unique_vertex = surface.get_data().borrow_mut().insert_vertex(Vertex {
position,
normal,
tex_coord: uv,
tangent: Vec4 { x: tangent.x, y: tangent.y, z: tangent.z, w: 1.0 },
// FIXME
bone_weights: Vec4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 },
bone_indices: [0, 0, 0, 0], // Correct indices will be calculated later
// We can't get correct values for bone weights and indices because
// not all nodes are converted yet at this stage. Actual calculation
// will be performed later on after converting all nodes.
bone_weights: [0.0, 0.0, 0.0, 0.0],
bone_indices: [0, 0, 0, 0],
});
if is_unique_vertex && !skin_data.is_empty() {
surface.vertex_weights.push(*skin_data.get(index).ok_or(FbxError::IndexOutOfBounds)?);
}
Ok(())
}
impl Fbx {
@@ -1188,9 +1168,10 @@ impl Fbx {
let parent_index = connection.get_attrib(2)?.as_i64()?;
if let Some(parent_handle) = self.index_to_component.get(&parent_index) {
if let Some(child_handle) = self.index_to_component.get(&child_index) {
let child_type_id = self.component_pool.borrow(*child_handle).unwrap().type_id();
let parent = self.component_pool.borrow_mut(*parent_handle).unwrap();
link_child_with_parent_component(parent, *child_handle, child_type_id);
let pair = self.component_pool.borrow_two_mut(*child_handle, *parent_handle).unwrap();
let child = pair.0.unwrap();
let parent = pair.1.unwrap();
link_child_with_parent_component(parent, child, *child_handle);
}
}
}
@@ -1259,6 +1240,8 @@ impl Fbx {
let geom = self.component_pool.borrow(*geom_handle).ok_or(FbxError::InvalidPoolHandle)?.as_geometry()?;
self.create_surfaces(mesh, state, model)?;
let skin_data = geom.get_skin_data(&self.component_pool)?;
let mut material_index = 0;
let mut n = 0;
while n < geom.indices.len() {
@@ -1268,9 +1251,9 @@ impl Fbx {
let triangle = &triangles[i];
let relative_triangle = &relative_triangles[i];
convert_vertex(geom, mesh, &geometric_transform, material_index, origin, triangle.0, relative_triangle.0);
convert_vertex(geom, mesh, &geometric_transform, material_index, origin, triangle.1, relative_triangle.1);
convert_vertex(geom, mesh, &geometric_transform, material_index, origin, triangle.2, relative_triangle.2);
convert_vertex(geom, mesh, &geometric_transform, material_index, origin, triangle.0, relative_triangle.0, &skin_data)?;
convert_vertex(geom, mesh, &geometric_transform, material_index, origin, triangle.1, relative_triangle.1, &skin_data)?;
convert_vertex(geom, mesh, &geometric_transform, material_index, origin, triangle.2, relative_triangle.2, &skin_data)?;
}
if geom.material_mapping == FbxMapping::ByPolygon {
material_index += 1;
@@ -1312,6 +1295,7 @@ impl Fbx {
node.set_rotation_pivot(model.rotation_pivot);
node.set_scaling_offset(model.scaling_offset);
node.set_scaling_pivot(model.scaling_pivot);
node.set_inv_bind_pose_transform(model.inv_bind_transform);
match node.borrow_kind_mut() {
NodeKind::Light(light) => {
@@ -1419,16 +1403,17 @@ impl Fbx {
state: &mut State,
scene: &mut Scene)
-> Result<Handle<Node>, FbxError> {
let mut instantiated_nodes = Vec::new();
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();
let mut fbx_model_to_node_map = HashMap::new();
for component_handle in self.components.iter() {
if let Some(component) = self.component_pool.borrow(*component_handle) {
if let FbxComponent::Model(model) = component {
if let Ok(node) = self.convert_model(model, state, scene) {
scene.link_nodes(node, root);
fbx_model_to_node_map.insert(*component_handle, node);
}
let node = self.convert_model(model, state, scene)?;
instantiated_nodes.push(node);
scene.link_nodes(node, root);
fbx_model_to_node_map.insert(*component_handle, node);
}
}
}
@@ -1443,6 +1428,53 @@ impl Fbx {
}
}
scene.update_nodes();
// Remap handles from fbx model to handles of instantiated nodes
// on each surface of each mesh.
for handle in instantiated_nodes.iter() {
let node = scene.get_node_mut(*handle).ok_or(FbxError::InvalidPoolHandle)?;
if let NodeKind::Mesh(mesh) = node.borrow_kind_mut() {
let mut surface_bones = HashSet::new();
for surface in mesh.get_surfaces_mut() {
for weight_set in surface.vertex_weights.iter_mut() {
for weight in weight_set.iter_mut() {
let fbx_model: Handle<FbxComponent> = weight.effector.into();
let bone_handle = fbx_model_to_node_map.get(&fbx_model)
.ok_or(FbxError::UnableToRemapModelToNode)?;
surface_bones.insert(*bone_handle);
weight.effector = (*bone_handle).into();
}
}
surface.bones = surface_bones.iter().map(|h| *h).collect();
// TODO: Add sanity check about unique owner of surface data.
// At this point owner of surface data *must* be only one.
// But who knows.
let data_rc = surface.get_data();
let mut data = data_rc.borrow_mut();
if data.get_vertices().len() == surface.vertex_weights.len() {
for (i, vertex) in data.get_vertices_mut().iter_mut().enumerate() {
let weight_set = surface.vertex_weights.get_mut(i)
.ok_or(FbxError::IndexOutOfBounds)?;
for (k, weight) in weight_set.iter().enumerate() {
vertex.bone_indices[k] = {
let mut index = None;
for (n, bone_handle) in surface.bones.iter().enumerate() {
if *bone_handle == weight.effector.into() {
index = Some(n);
break;
}
}
index.ok_or(FbxError::UnableToFindBone)? as u8
};
vertex.bone_weights[k] = weight.value;
}
}
}
}
}
}
Ok(root)
}
+1 -1
View File
@@ -9,9 +9,9 @@ use crate::{
},
resource::fbx::{
FbxNode,
find_and_borrow_node,
},
};
use crate::resource::fbx::find_and_borrow_node;
pub struct FbxTexture {
filename: PathBuf,
+6 -13
View File
@@ -1,25 +1,21 @@
use crate::{
scene::{
Scene,
node::Node,
},
scene::{Scene, node::Node},
utils::pool::Handle,
engine::State,
resource::{
fbx,
Resource,
ResourceKind,
fbx::FbxError
}
fbx::FbxError,
},
scene::node::NodeKind,
};
use std::{
path::Path,
cell::RefCell,
rc::Rc
rc::Rc,
collections::{HashMap, hash_map::Entry},
};
use crate::scene::node::NodeKind;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
pub struct Model {
scene: Scene,
@@ -47,7 +43,6 @@ impl Model {
let mut old_new_mapping = HashMap::new();
let root = model.scene.copy_node(model.scene.get_root(), dest_scene, &mut old_new_mapping);
println!("mapping size {}", old_new_mapping.len());
// Notify instantiated nodes about resource they were created from. Also do bones
// remapping for meshes.
let mut stack = Vec::new();
@@ -94,8 +89,6 @@ impl Model {
dest_scene.add_animation(anim_copy);
}
return Ok(root);
}
Err(())
+23 -8
View File
@@ -8,7 +8,7 @@ use crate::{
VisitError,
Visit,
VisitResult,
Visitor
Visitor,
},
pool::*,
},
@@ -22,7 +22,7 @@ use crate::{
renderer::surface::*,
physics::Body,
resource::Resource,
gui::draw::Color
gui::draw::Color,
};
pub struct Light {
@@ -38,7 +38,7 @@ impl Default for Light {
radius: 10.0,
color: Color::white(),
cone_angle: std::f32::consts::PI,
cone_angle_cos: -1.0
cone_angle_cos: -1.0,
}
}
}
@@ -93,7 +93,7 @@ impl Light {
radius: self.radius,
color: self.color,
cone_angle: self.cone_angle,
cone_angle_cos: self.cone_angle_cos
cone_angle_cos: self.cone_angle_cos,
}
}
}
@@ -254,11 +254,12 @@ pub struct Node {
pub(in crate::scene) children: Vec<Handle<Node>>,
pub(in crate::scene) local_transform: Mat4,
pub(in crate::scene) global_transform: Mat4,
inv_bind_pose_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>
original: Handle<Node>,
}
impl Default for Node {
@@ -281,9 +282,10 @@ impl Default for Node {
global_visibility: true,
local_transform: Mat4::identity(),
global_transform: Mat4::identity(),
inv_bind_pose_transform: Mat4::identity(),
body: Handle::none(),
resource: None,
original: Handle::none()
original: Handle::none(),
}
}
}
@@ -308,9 +310,10 @@ impl Node {
global_visibility: true,
local_transform: Mat4::identity(),
global_transform: Mat4::identity(),
inv_bind_pose_transform: Mat4::identity(),
body: Handle::none(),
resource: None,
original: Handle::none()
original: Handle::none(),
}
}
@@ -356,6 +359,7 @@ impl Node {
global_transform: self.global_transform,
visibility: self.visibility,
global_visibility: self.global_visibility,
inv_bind_pose_transform: self.inv_bind_pose_transform,
children: Vec::new(),
parent: Handle::none(),
body: Handle::none(),
@@ -363,7 +367,7 @@ impl Node {
Some(resource) => Some(Rc::clone(resource)),
None => None
},
original
original,
}
}
@@ -505,6 +509,14 @@ impl Node {
&self.global_transform
}
pub fn set_inv_bind_pose_transform(&mut self, transform: Mat4) {
self.inv_bind_pose_transform = transform;
}
pub fn get_inv_bind_pose_transform(&self) -> &Mat4 {
&self.inv_bind_pose_transform
}
#[inline]
pub fn get_global_position(&self) -> Vec3 {
Vec3 {
@@ -580,6 +592,9 @@ impl Visit for Node {
self.body.visit("Body", visitor)?;
self.resource.visit("Resource", visitor)?;
// TODO: Is this needed?
self.inv_bind_pose_transform.visit("InvBindPoseTransform", visitor)?;
visitor.leave_region()
}
}
+80 -21
View File
@@ -1,9 +1,21 @@
use std::{
marker::PhantomData,
hash::{Hash, Hasher},
fmt::{Debug, Formatter},
hash::{
Hash,
Hasher
},
fmt::{
Debug,
Formatter
},
};
use crate::utils::visitor::{Visit, VisitResult, Visitor};
use crate::utils::visitor::{
Visit,
VisitResult,
Visitor
};
const INVALID_GENERATION: u32 = 0;
///
/// Pool allows to create as many objects as you want in contiguous memory
@@ -29,6 +41,44 @@ pub struct Handle<T> {
type_marker: PhantomData<T>,
}
/// Type-erased handle.
#[derive(Copy, Clone, Debug)]
pub struct ErasedHandle {
/// Index of object in pool.
index: u32,
/// Generation number, if it is same as generation of pool record at
/// index of handle then this is valid handle.
generation: u32,
}
impl<T> From<ErasedHandle> for Handle<T> {
fn from(erased_handle: ErasedHandle) -> Self {
Handle {
index: erased_handle.index,
generation: erased_handle.generation,
type_marker: PhantomData
}
}
}
impl<T> Into<ErasedHandle> for Handle<T> {
fn into(self) -> ErasedHandle {
ErasedHandle {
index: self.index,
generation: self.generation
}
}
}
impl ErasedHandle {
pub fn none() -> Self {
ErasedHandle {
index: 0,
generation: INVALID_GENERATION
}
}
}
impl<T> Visit for Handle<T> {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
@@ -65,7 +115,7 @@ struct PoolRecord<T: Sized> {
impl<T> Default for PoolRecord<T> {
fn default() -> Self {
Self {
generation: Pool::<T>::INVALID_GENERATION,
generation: INVALID_GENERATION,
payload: None,
}
}
@@ -92,9 +142,7 @@ impl<T> Clone for Handle<T> {
}
}
impl<T> Copy for Handle<T> {
}
impl<T> Copy for Handle<T> {}
impl<T> PartialEq for Handle<T> {
fn eq(&self, other: &Handle<T>) -> bool {
@@ -125,14 +173,14 @@ impl<T> Handle<T> {
pub fn none() -> Self {
Handle {
index: 0,
generation: Pool::<T>::INVALID_GENERATION,
generation: INVALID_GENERATION,
type_marker: PhantomData,
}
}
#[inline]
pub fn is_none(self) -> bool {
self.index == 0 && self.generation == Pool::<T>::INVALID_GENERATION
self.index == 0 && self.generation == INVALID_GENERATION
}
#[inline]
@@ -158,8 +206,6 @@ impl<T> Handle<T> {
}
impl<T> Pool<T> {
const INVALID_GENERATION: u32 = 0;
#[inline]
pub fn new() -> Self {
Pool {
@@ -214,7 +260,7 @@ impl<T> Pool<T> {
} else {
panic!("Pool: Payload was empty!");
}
} else if handle.generation != Pool::<T>::INVALID_GENERATION {
} else if handle.generation != INVALID_GENERATION {
panic!("Pool: Generation does not match: record has {} generation, but handle has {}", record.generation, handle.generation);
}
} else {
@@ -223,6 +269,19 @@ impl<T> Pool<T> {
None
}
pub fn borrow_two_mut(&mut self, a: Handle<T>, b: Handle<T>) -> Result<(Option<&mut T>, Option<&mut T>), ()> {
if a.index == b.index {
// Prevent giving two mutable references to same record.
return Err(());
}
unsafe {
let this = self as *mut Self;
Ok(((*this).borrow_mut(a), (*this).borrow_mut(b)))
}
}
#[inline]
#[must_use]
pub fn borrow_mut(&mut self, handle: Handle<T>) -> Option<&mut T> {
@@ -239,7 +298,7 @@ impl<T> Pool<T> {
} else {
panic!("Pool: Payload was empty!");
}
} else if handle.generation != Pool::<T>::INVALID_GENERATION {
} else if handle.generation != INVALID_GENERATION {
panic!("Pool: Generation does not match: record has {} generation, but handle has {}", record.generation, handle.generation);
}
} else {
@@ -412,27 +471,27 @@ impl<'a, T> Iterator for PoolIteratorMut<'a, T> {
#[cfg(test)]
mod test {
use crate::utils::pool::Pool;
use crate::utils::pool::{Pool, INVALID_GENERATION};
#[test]
fn pool_sanity_tests() {
let mut pool: Pool<String> = Pool::new();
let foobar_handle = pool.spawn(String::from("Foobar"));
assert_eq!(foobar_handle.index, 0);
assert_ne!(foobar_handle.generation, Pool::<String>::INVALID_GENERATION);
assert_ne!(foobar_handle.generation, INVALID_GENERATION);
let foobar_handle_copy = foobar_handle.clone();
assert_eq!(foobar_handle.index, foobar_handle_copy.index);
assert_eq!(foobar_handle.generation, foobar_handle_copy.generation);
let baz_handle = pool.spawn(String::from("Baz"));
assert_eq!(pool.borrow(&foobar_handle).unwrap(), "Foobar");
assert_eq!(pool.borrow(&baz_handle).unwrap(), "Baz");
assert_eq!(pool.borrow(foobar_handle).unwrap(), "Foobar");
assert_eq!(pool.borrow(baz_handle).unwrap(), "Baz");
pool.free(foobar_handle);
assert_eq!(pool.is_valid_handle(&foobar_handle_copy), false);
assert_eq!(pool.is_valid_handle(&baz_handle), true);
assert_eq!(pool.is_valid_handle(foobar_handle_copy), false);
assert_eq!(pool.is_valid_handle(baz_handle), true);
let at_foobar_index = pool.spawn(String::from("AtFoobarIndex"));
assert_eq!(at_foobar_index.index, 0);
assert_ne!(at_foobar_index.generation, Pool::<String>::INVALID_GENERATION);
assert_eq!(pool.borrow(&at_foobar_index).unwrap(), "AtFoobarIndex");
assert_ne!(at_foobar_index.generation, INVALID_GENERATION);
assert_eq!(pool.borrow(at_foobar_index).unwrap(), "AtFoobarIndex");
}
#[test]