pub mod components;
use crate::{
components::Visible,
transformation::{Transformation, Bone,},
geometry::{GeometryRef, Geometry, VertexGroups},
blender,
};
use rinecs::{Entities, Resources, Read, Write, ReadRef,
WriteAndParent, Entity, ReadOption,
EntitiesThreadLocal, ResourcesThreadLocal, SystemThreadLocal, System };
use self::components::*;
use rin::graphics::{self, NodeRef, Vertex, vertex, Vertex3D};
use rin::math::*;
use rin::events::{Property, Parameter, PropertyT, RangedParameterMut};
use rayon::prelude::*;
use std::marker::PhantomData;
use std::fmt::Debug;
use crate::Scene;
#[cfg(any(feature="gl", feature="gles", feature="webgl"))]
use crate::renderer::{
geometry::{
AnimatedGeometryGpuUpdater, AnimatedGeometryGpuUpdaterSettings, VertexBuffer, GpuGeometryRef,
},
Allocator,
};
#[cfg(any(feature="gl", feature="gles", feature="webgl"))]
use rin::gl;
use serde::{Serialize, Deserialize};
pub struct Noop;
impl<'a> SystemThreadLocal<'a> for Noop{
fn run(&mut self, _: EntitiesThreadLocal, _: ResourcesThreadLocal){}
}
#[cfg_attr(feature="gui", derive(ParameterGroup))]
pub struct Skinning<Vertex = blender::Vertex, W = Noop>{
show_skeletons_geometry: Property<'static, bool>,
update_debug_normals: Property<'static, bool>,
debug_normals_length: RangedParameterMut<'static, f32>,
#[cfg_attr(feature="gui", not_parameter)]
walking_system: W,
#[cfg_attr(feature="gui", not_parameter)]
marker: PhantomData<Vertex>,
}
impl<V,W> Skinning<V,W>{
pub fn new(walking_system: W) -> Skinning<V,W>{
Skinning{
show_skeletons_geometry: Property::new(false),
update_debug_normals: Property::new(false),
debug_normals_length: RangedParameterMut::new_log_scale(0.01, 0. .. 1.),
marker: PhantomData,
walking_system,
}
}
}
#[cfg(feature="gl")]
fn create_animated_geometry_storage_systems<V>(
world: &mut Scene,
show_skeletons_geometry: Property<'static, bool>,
settings: AnimatedGeometryGpuUpdaterSettings)
where V: Send + Clone + Sync + Vertex<Position = Vec4> +
Serialize + Deserialize<'static> + glin::VertexFormat +
vertex::Normal + DefaultWeight + Debug + 'static,
{
let animated_upload = AnimatedGeometryGpuUpdater::<V, glin::SharedBufferStorage<u8>>::new(settings);
world.add_system_with_name_thread_local_gpu(animated_upload, "animated geom upload");
world.add_system_with_name_thread_local_gpu(
SkeletonGeometryUploader::<glin::SharedBufferStorage<u8>>
::new(show_skeletons_geometry), "skeleton geom upload");
}
#[cfg(any(feature="gl", feature="gles", feature="webgl"))]
fn create_animated_geometry_buffer_systems<V>(
world: &mut Scene,
show_skeletons_geometry: Property<'static, bool>,
settings: AnimatedGeometryGpuUpdaterSettings)
where V: Send + Clone + Sync + Vertex<Position = Vec4> +
Serialize + Deserialize<'static> + glin::VertexFormat +
vertex::Normal + DefaultWeight + Debug + 'static,
{
let animated_upload = AnimatedGeometryGpuUpdater::<V, glin::SharedBuffer<u8>>::new(settings);
world.add_system_with_name_thread_local_gpu(animated_upload, "animated geom upload");
world.add_system_with_name_thread_local_gpu(
SkeletonGeometryUploader::<glin::SharedBuffer<u8>>
::new(show_skeletons_geometry), "skeleton geom upload");
}
impl<V,W> crate::Bundle for Skinning<V,W>
where V: Send + Clone + Sync + Vertex<Position = Vec4> +
Serialize + Deserialize<'static> + glin::VertexFormat +
vertex::Normal + DefaultWeight + Debug + 'static,
W: for<'a> SystemThreadLocal<'a> + 'static
{
fn setup(self, world: &mut Scene){
world.add_system_with_name(bone_updater, "bone updater");
world.add_barrier();
world.add_system_with_name(feet_updater, "feet updater");
world.add_barrier();
world.add_system_with_name_thread_local(self.walking_system, "walking system");
world.add_barrier();
world.add_system_with_name(skeleton_cache_updater, "skeleton cache updater");
let mut show_skeletons = self.show_skeletons_geometry.clone().iter_async();
world.add_system_with_name(move|entities: Entities, _: Resources|{
if let Some(show_skeletons) = show_skeletons.by_ref().last(){
for (skeleton, visible) in entities.iter_for::<(Write<Skeleton>, Write<Visible>)>(){
visible.set(show_skeletons);
skeleton.changed = true;
}
}
}, "show / hide skeletons");
world.add_barrier();
world.add_system_with_name(skinning::<V>, "skinning");
world.add_system_with_name(SkeletonGeometryUpdater::new(
self.show_skeletons_geometry.clone().to_parameter()), "skeleton geometry updater");
world.add_barrier();
#[cfg(feature="gl")]
{
let settings = AnimatedGeometryGpuUpdaterSettings{
update_debug_normals: self.update_debug_normals.clone(),
debug_normals_length: self.debug_normals_length.clone().into_property(),
};
#[cfg(feature="gl")]
let supports_storage = {
let gl = world.resource::<gl::Renderer>().unwrap();
unsafe{ gl.context().gl().BufferStorage.is_loaded() }
};
if supports_storage{
create_animated_geometry_storage_systems::<V>(world, self.show_skeletons_geometry, settings)
}else{
create_animated_geometry_buffer_systems::<V>(world, self.show_skeletons_geometry, settings)
}
}
#[cfg(any(feature="gles", feature="webgl"))]
{
let settings = AnimatedGeometryGpuUpdaterSettings{
update_debug_normals: self.update_debug_normals.clone(),
debug_normals_length: self.debug_normals_length.clone().into_property(),
};
create_animated_geometry_buffer_systems::<V>(world, self.show_skeletons_geometry, settings)
}
world.add_barrier();
world.add_system(|entities: Entities, _: Resources|{
for skeleton in entities.iter_for::<Write<Skeleton>>(){
skeleton.changed = false;
}
});
}
fn register(world: &mut Scene){
world.register_component::<components::ArmatureCache>();
world.register_component::<components::ArmatureMatrices>();
world.register_component::<components::BoneBase>();
world.register_component::<components::BoneName>();
world.register_component::<components::RootMotionBone>();
world.register_component::<components::FootBones>();
world.register_component::<components::Skeleton>();
world.register_component::<components::SkeletonName>();
world.register_component::<components::SkeletonRef>();
}
}
pub fn bone_updater(entities: Entities, _resources: Resources){
for ((bone, parent), bone_entity, skeleton) in entities.ordered_iter_for::<(
WriteAndParent<Bone>,
Entity,
Read<SkeletonRef>)>()
{
if !bone.used { continue }
let flags = bone.flags;
bone.has_changed = bone.update_with_parent_flags(parent.map(|p| &p.animated), flags);
if bone.has_changed{
let skeleton_trafo = entities.component_for::<Transformation>(skeleton).unwrap().node.clone();
let mut bone_trafo = entities.component_for_mut::<Transformation>(&bone_entity).unwrap();
bone_trafo.node = graphics::Node::new(
bone.animated.global_position(),
bone.animated.global_orientation(),
bone.animated.global_scale());
bone_trafo.node.update_with_parent(Some(&skeleton_trafo));
}
}
}
pub fn feet_updater(entities: Entities, _resources: Resources){
for (foot_bones, sekeleton_trafo, skeleton) in entities.iter_for::<(
Write<FootBones>,
Read<Transformation>,
Read<Skeleton>)>()
{
if skeleton.changed {
let inverse_skeleton = sekeleton_trafo.local_transformation();
for foot in foot_bones.left.iter_mut(){
let bone = entities.component_for::<Bone>(&foot.entity).unwrap();
let local_foot = inverse_skeleton * bone.animated.global_transformation();
let new_foot_position = local_foot.column(3).xyz();
foot.delta = vec3!(0., new_foot_position.y - foot.position.y, 0.);
foot.position = new_foot_position.to_pnt();
}
for foot in foot_bones.right.iter_mut(){
let bone = entities.component_for::<Bone>(&foot.entity).unwrap();
let local_foot = inverse_skeleton * bone.animated.global_transformation();
let new_foot_position = local_foot.column(3).xyz();
foot.delta = vec3!(0., new_foot_position.y - foot.position.y, 0.);
foot.position = new_foot_position.to_pnt();
}
}
}
}
pub fn skeleton_cache_updater(entities: Entities, _resources: Resources){
let iter = entities.iter_for::<(
Read<Transformation>,
ReadRef<SkeletonRef, Skeleton>,
ReadRef<SkeletonRef, Transformation>,
ReadRef<SkeletonRef, BoneBase>,
Write<ArmatureCache>,
Write<ArmatureMatrices>)>();
for (object_trafo, skeleton, skeleton_trafo, base_bones, armature_cache, matrices) in iter {
let skeleton = skeleton.unwrap();
if skeleton.changed {
let skeleton_trafo = skeleton_trafo.unwrap();
let base_bones = base_bones.unwrap();
let object_inv = object_trafo.inv_global_transformation();
let postmat = object_inv.fast_mul(&skeleton_trafo.global_transformation());
let premat = postmat.fast_affine_inverse().unwrap();
let postmat3 = Mat3::from_iterator(postmat.columns(0,3).rows(0,3).iter().map(|v| *v));
let premat3 = Mat3::from_iterator(premat.columns(0,3).rows(0,3).iter().map(|v| *v));
for base_bone in base_bones.iter() {
for bone in entities.tree_node_for::<Bone>(base_bone).unwrap().descendants_ref(){
if bone.used {
matrices[bone.animated_id].vertices = bone.local_mat().fast_mul(&premat);
matrices[bone.animated_id].normals = bone.normal_mat().fast_mul(&premat3);
}
}
}
armature_cache.postmat = postmat;
armature_cache.postmat3 = postmat3;
armature_cache.changed = true;
}
}
}
pub struct SkeletonGeometryUpdater{
skeletons_rendering: Parameter<'static, bool>,
}
impl SkeletonGeometryUpdater{
pub fn new(skeletons_rendering: Parameter<'static, bool>) -> SkeletonGeometryUpdater{
SkeletonGeometryUpdater{ skeletons_rendering }
}
}
impl<'a> System<'a> for SkeletonGeometryUpdater{
fn run(&mut self, entities: Entities, _resources: Resources){
if *self.skeletons_rendering{
let skeletons = entities
.iter_for::<(Entity, Read<Skeleton>, Read<GeometryRef>, Read<Visible>)>()
.filter(|(_,skeleton,_, visible)| visible.is_visible() && skeleton.changed);
for (entity, _, geometryref, _) in skeletons {
let bones = entities.component_for::<BoneBase>(&entity).unwrap();
let mut geometry = entities.component_for_mut::<Geometry<Vertex3D>>(geometryref).unwrap();
geometry.clear_vertices();
geometry.extend(bones.iter().flat_map(|bone_base|{
if let Some(bone) = entities.tree_node_for::<Bone>(&bone_base.0) {
bone.descendants_ref().flat_map(|bone|{
if bone.used {
vec![graphics::vertex3d(bone.global_head().to_vec()),
graphics::vertex3d(bone.global_tail().to_vec())]
}else{
vec![]
}
}).collect::<Vec<_>>()
}else{
vec![]
}
}));
}
}
}
}
pub fn skinning<V>(entities: Entities, _resources: Resources)
where V: Send + Clone + Sync + Debug + Serialize + Deserialize<'static> +
Vertex<Position = Vec4> + vertex::Normal + DefaultWeight +
'static
{
let iter = entities.iter_for::<(
ReadRef<GeometryRef, Geometry<V>>,
Read<Visible>,
Write<AnimatedGeometry<V>>,
Write<ArmatureCache>,
Read<ArmatureMatrices>,
Write<VertexGroups>,
ReadOption<blender::ShapeKey>,
)>().filter(|(_, visible, _, armature_cache, _, _, _)| visible.is_visible() && armature_cache.changed);
for (geom, _, animated_geom, armature_cache, matrices, vertex_groups, shapekey) in iter{
if vertex_groups.index.is_empty() {
let index = &armature_cache.index;
let vertex_groups_index = vertex_groups.vertex_groups.iter().map(|name|{
index.get(name).map(|i| *i)
}).collect();
vertex_groups.index = vertex_groups_index;
}
let has_shapekey = shapekey.is_some();
let animated_changed = animated_geom.changed;
geom.unwrap().vertices().par_iter()
.zip(animated_geom.par_deform_geom_mut())
.filter_map(|(vertex, animated)| if let Some((weights, animated)) = animated{
if has_shapekey && animated_changed {
Some((animated.clone(), weights, animated))
}else{
Some((vertex.clone(), weights, animated))
}
}else{
None
})
.for_each(|(vertex, weights, animated)| {
let vpos = vertex.position();
let vnor = vertex.normal();
let (mut position, mut normal, total_weight): (Vec4, Vec3, f32) = weights.iter()
.filter_map(|weight| {
let vertex_group_id = unsafe{ vertex_groups.index.get_unchecked(weight.def_nr as usize) };
let mat = vertex_group_id.map(|id| unsafe{ matrices.get_unchecked(id) });
mat.map(|mat| (weight, mat))
})
.fold((zero(), zero(), 0.), |(position, normal, total_weight), (weight, mat)|{
let cpos = mat.vertices.fast_mul(vpos);
let cnor = mat.normals.fast_mul(vnor);
(position + (cpos - vpos) * weight.weight,
normal + (cnor - vnor) * weight.weight,
total_weight + weight.weight)
});
if total_weight > 0.{
let weight_factor = animated.default_weight() / total_weight;
position *= weight_factor;
position += vpos;
*animated.position_mut() = armature_cache.postmat.fast_mul(&position);
normal *= weight_factor;
normal += vnor;
*animated.normal_mut() = armature_cache.postmat3.fast_mul(&normal);
}
});
armature_cache.changed = false;
animated_geom.changed = true;
}
}
#[cfg(any(feature="gl", feature="gles", feature="webgl"))]
pub struct SkeletonGeometryUploader<B>{
skeletons_rendering: Property<'static, bool>,
marker_buff: PhantomData<B>
}
#[cfg(any(feature="gl", feature="gles", feature="webgl"))]
impl<B> SkeletonGeometryUploader<B>{
pub fn new(skeletons_rendering: Property<'static, bool>) -> SkeletonGeometryUploader<B>{
SkeletonGeometryUploader{
skeletons_rendering,
marker_buff: PhantomData,
}
}
}
#[cfg(any(feature="gl", feature="gles", feature="webgl"))]
impl<'a, B> SystemThreadLocal<'a> for SkeletonGeometryUploader<B>
where B: 'static + Clone +
super::renderer::memory::BufferExt<u8> +
glin::buffer::Cast<glin::IndexT> +
glin::buffer::Cast<Vertex3D>,
<B as glin::buffer::Cast<glin::IndexT>>::CastTo: 'static +
glin::BufferRangeMut<glin::IndexT> +
Clone,
<B as glin::buffer::Cast<Vertex3D>>::CastTo: 'static +
glin::BufferRangeMut<Vertex3D> +
Clone,
super::renderer::allocator::Allocator<B>: super::renderer::allocator::InternalCreation<B> +
super::renderer::allocator::Creation<B> +
super::renderer::allocator::Updater,
Allocator<Vertex3D,B>: super::renderer::memory::AllocatorFlags
{
fn run(&mut self, entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
if *self.skeletons_rendering{
let skeletons = entities
.iter_for::<(Read<Skeleton>, Read<GeometryRef>, Read<GpuGeometryRef>, Read<Visible>)>()
.filter(|(skeleton,_, _,visible)| visible.is_visible() && skeleton.changed);
let mut allocator = resources.get_mut::<Allocator<Vertex3D, B>>().unwrap();
let gl = resources.get::<gl::Renderer>().unwrap();
for (_, geometryref, gpugeometryref, _) in skeletons {
let geometry = entities.component_for::<Geometry<Vertex3D>>(geometryref).unwrap();
let gpu = entities.component_for_mut::<VertexBuffer>(gpugeometryref).unwrap();
allocator.update_vertex_buffer_range(&*gl, &gpu, &geometry.vertices()).unwrap();
}
}
}
}