mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
added skinning
This commit is contained in:
Generated
+3
-28
@@ -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.
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user