use crate::skinning::{ DefaultWeight, GeometryWeights, ArmatureCache };
use rin_scene::{
components::Ty,
transformation::{Bone, BoneFlags, RotMode},
geometry::{VertexGroups, AnimatedGeometry},
physics::rigidbody::{RigidBody, RigidBodyShape},
light::shadow,
};
use rin_graphics::Node;
use rin_math::{Vec4, vec4, Vec3, vec3, vec2, Vec2, ToPnt, UnitQuat, Unit, Rad, Angle};
use rinecs::{Component, UniqueEntities};
use std::mem;
use super::Action;
#[cfg(gl)]
use rin_gl::VertexFormat;
use serde_derive::{Serialize, Deserialize};
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[cfg_attr(gl, derive(VertexFormat))]
#[repr(C)]
pub struct Vertex{
pub position: Vec4,
pub normal: Vec4,
pub texcoord: Vec2,
pub default_weight: f32,
pad: f32,
}
impl rinblender::Vertex4Ext for Vertex {
#[inline]
fn position(&self) -> &Vec4 {
&self.position
}
#[inline]
fn normal(&self) -> &Vec4{
&self.normal
}
#[inline]
fn texcoord(&self) -> &Vec2{
&self.texcoord
}
#[inline]
fn position_mut(&mut self) -> &mut Vec4{
&mut self.position
}
#[inline]
fn normal_mut(&mut self) -> &mut Vec4{
&mut self.normal
}
#[inline]
fn texcoord_mut(&mut self) -> &mut Vec2{
&mut self.texcoord
}
}
#[cfg(not(gl))]
impl crate::skinning::VertexFormat for Vertex{}
impl Default for Vertex{
fn default() -> Vertex{
Vertex{
position: vec4!(vec3!(0.), 1.),
normal: vec4!(Vec3::y(), 1.),
texcoord: vec2!(0.),
default_weight: 0.,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
}
}
}
impl rin_graphics::Vertex for Vertex{
type Position = Vec4;
fn position(&self) -> &Vec4 {
&self.position
}
fn position_mut(&mut self) -> &mut Vec4{
&mut self.position
}
}
impl rin_graphics::Normal for Vertex{
type Normal = Vec4;
fn normal(&self) -> &Vec4 {
&self.normal
}
fn normal_mut(&mut self) -> &mut Vec4{
&mut self.normal
}
}
impl DefaultWeight for Vertex{
fn default_weight(&self) -> f32{
self.default_weight
}
fn set_default_weight(&mut self, dw: f32){
self.default_weight = dw;
}
}
#[cfg(feature="meshopt")]
impl meshopt::DecodePosition for Vertex{
fn decode_position(&self) -> [f32;3]{
[self.position.x, self.position.y, self.position.z]
}
}
impl<'a> From<(&'a rinblender::Vertex, f32)> for Vertex{
fn from(v: (&'a rinblender::Vertex, f32)) -> Vertex{
let (v, default_weight) = v;
Vertex{
position: vec4!(v.position, 1.0),
normal: vec4!(v.normal, 1.0),
texcoord: v.texcoord,
default_weight,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
}
}
}
pub trait FromBlender<T> {
fn from_blender(blender: T) -> Self;
}
pub trait IntoBlender<T>{
fn into_blender(self) -> T;
}
impl<T, F: FromBlender<T>> IntoBlender<F> for T{
fn into_blender(self) -> F {
F::from_blender(self)
}
}
impl<'a> FromBlender<&'a rinblender::Transformations> for Node {
fn from_blender(trafo: &'a rinblender::Transformations) -> Node {
if let Some(parent_inv) = trafo.parent_inv {
Node::with_preparent(parent_inv, trafo.position, trafo.into_quat(), trafo.scale)
}else{
Node::new(trafo.position, trafo.into_quat(), trafo.scale)
}
}
}
impl<'a> FromBlender<&'a rinblender::Bone> for Node {
fn from_blender(bone: &'a rinblender::Bone) -> Node {
Node::from_blender(bone.transformations())
}
}
#[derive(Clone, Copy, Component, Debug, Serialize, Deserialize)]
pub struct Selectable(pub bool);
impl<'a> FromBlender<(&'a rinblender::Bone, &'a str, Option<rinecs::Ptr<'a, Bone>>)> for Bone {
fn from_blender(from: (&'a rinblender::Bone, &'a str, Option<rinecs::Ptr<'a, Bone>>)) -> Bone {
let (bone, prefix, parent) = from;
let node = Node::from_blender(bone.transformations());
let mut flags = BoneFlags::empty();
if bone.flags().contains(rinblender::bones::Flags::HINGE){
flags |= BoneFlags::NO_ROTATION_FROM_PARENT;
}
if bone.flags().contains(rinblender::bones::Flags::NO_SCALE) {
flags |= BoneFlags::NO_SCALE_FROM_PARENT;
}
let mut rest = node.clone();
rest.update_with_parent(parent.map(|p| &p.rest));
Bone{
rest,
original: node,
animated: Node::identity(),
rest_mat: bone.rest_mat().clone(),
inv_rest_mat: bone.inv_rest_mat().clone(),
animated_id: bone.animated_id(),
optimized_id: bone.animated_id(),
head: bone.head().to_pnt(),
tail: bone.tail().to_pnt(),
head_radius: bone.head_radius(),
tail_radius: bone.tail_radius(),
name: prefix.to_owned() + "_" + bone.name(),
rot_mode: bone.original_rot_mode().into_blender(),
has_changed: false,
flags,
used: false,
}
}
}
#[derive(Clone,Debug,Copy,PartialEq,Eq,Serialize, Deserialize)]
pub enum RotOrder{
XYZ,
XZY,
YXZ,
YZX,
ZXY,
ZYX,
}
impl Into<rinblender::RotOrder> for RotOrder{
fn into(self) -> rinblender::RotOrder{
unsafe{ mem::transmute(self) }
}
}
#[derive(Clone,Debug,Copy,PartialEq,Component,Serialize,Deserialize)]
pub enum Rotation {
Quat(UnitQuat),
Euler(RotOrder, Vec3<Rad<f32>>),
AxisAngle(Unit<Vec3>, Rad<f32>),
}
impl Rotation{
pub fn into_quat(self) -> UnitQuat {
match self{
Rotation::Quat(q) => q,
Rotation::Euler(rot_order, rot) =>
rinblender::utils::euler_to_quaternion(&rot, rot_order.into()),
Rotation::AxisAngle(axis, angle) =>
UnitQuat::from_axis_angle(&axis, angle.value()),
}
}
}
impl From<rinblender::Rotation> for Rotation {
fn from(rot: rinblender::Rotation) -> Rotation {
unsafe{ mem::transmute(rot) }
}
}
impl AsRef<rinblender::Rotation> for Rotation {
fn as_ref(&self) -> &rinblender::Rotation {
unsafe{ mem::transmute(self) }
}
}
#[derive(Clone,Component, Debug, Serialize, Deserialize, Default)]
pub struct SceneIndex{
pub skeletons: UniqueEntities,
pub poses: UniqueEntities,
pub models: UniqueEntities,
pub lights: UniqueEntities,
pub empties: UniqueEntities,
}
#[derive(Clone,Component, Debug, Serialize, Deserialize)]
pub struct ObjectId(pub rinblender::ObjectId);
#[derive(Clone, Copy)]
pub struct CharacterEntity{
pub character: rinecs::Entity,
pub skeleton: Option<rinecs::Entity>,
}
pub fn to_animated_geometry(model: rinblender::TriModel)
-> (AnimatedGeometry<Vertex>, GeometryWeights)
{
let mut dvert = vec![];
let mut dweight = vec![];
for v in model.original_vertices().iter(){
if model.mesh().dvert.len() > v.original_idx as usize{
let dw = model.mesh().dvert(v.original_idx as usize);
let start = dweight.len();
dweight.extend_from_slice(dw);
let end = dweight.len();
dvert.push(Some(rinblender::mesh::MDeformVert{
dw_start: start,
dw_end: end,
flag: 0,
}));
}else{
dvert.push(None);
}
}
let animated_geometry = AnimatedGeometry{
geom: model.animated_vertices().iter().map(|v| {
let default_group = model.default_group();
let default_group = default_group.map(|d| d.as_ref()).unwrap_or("");
let default_weight = if model.mesh().dvert.len() > v.original_idx as usize{
model.mesh()
.dvert(v.original_idx as usize)
.iter()
.find(|weight| model.vertex_groups().len() > weight.def_nr as usize &&
model.vertex_groups()[weight.def_nr as usize] == default_group)
.map(|weight| weight.weight)
.unwrap_or(1.0)
}else{
1.0
};
Vertex::from((v,default_weight))
}).collect(),
changed: true,
};
let weights = GeometryWeights{
dvert,
dweight,
deformflags: model.skeleton_deformflag(),
final_weights: Vec::new(),
final_dverts: Vec::new(),
gpu_weights: Vec::new(),
};
(animated_geometry, weights)
}
#[derive(Component, Debug)]
#[debug_as_string]
pub struct OriginalGeometryBuffer<V: 'static + std::fmt::Debug>(pub glin::SharedBuffer<V>);
impl<'a> FromBlender<&'a rinblender::BlenderObject> for Ty{
fn from_blender(ty: &'a rinblender::BlenderObject) -> Ty{
match *ty{
rinblender::BlenderObject::Armature(_) => Ty::Armature,
rinblender::BlenderObject::Model(_) => Ty::Model,
rinblender::BlenderObject::Light(_) => Ty::Light,
rinblender::BlenderObject::Empty(_) => Ty::Empty,
}
}
}
impl<'a> FromBlender<&'a rinblender::RigidBody> for RigidBody{
fn from_blender(rigid_body: &'a rinblender::RigidBody) -> RigidBody{
unsafe{ mem::transmute_copy(rigid_body) }
}
}
impl<'a> FromBlender<&'a rinblender::RigidBodyShape> for RigidBodyShape{
fn from_blender(shape: &'a rinblender::RigidBodyShape) -> RigidBodyShape{
unsafe{ mem::transmute_copy(shape) }
}
}
impl FromBlender<rinblender::RotMode> for RotMode{
fn from_blender(rotmode: rinblender::RotMode) -> RotMode{
unsafe{ mem::transmute(rotmode) }
}
}
impl<'a> FromBlender<&'a rinblender::Lamp> for shadow::Parameters{
fn from_blender(light: &'a rinblender::Lamp) -> shadow::Parameters{
let bias = if light.ty == rinblender::LightType::Directional{
light.shadow_bias * 0.001
}else{
light.shadow_bias * 0.00002
};
let far_clip = if light.ty == rinblender::LightType::Directional{
light.shadow_far_clip.unwrap()
}else if light.ty == rinblender::LightType::Spot{
light.strength.sqrt()
}else if light.ty == rinblender::LightType::Point{
light.strength.sqrt()
}else{
unreachable!()
};
let shadow_frustum_size = light.shadow_frustum_size
.unwrap_or(far_clip - light.shadow_near_clip);
shadow::Parameters{
map_size: light.shadow_bufsize,
near_clip: light.shadow_near_clip,
far_clip,
left: -shadow_frustum_size * 0.5,
right: shadow_frustum_size * 0.5,
bottom: -shadow_frustum_size * 0.5,
top: shadow_frustum_size * 0.5,
bias,
resolution: shadow::Resolution::_32,
depth_clamp: false,
}
}
}
impl<'a> FromBlender<&'a rinblender::Model> for VertexGroups {
fn from_blender(model: &'a rinblender::Model) -> VertexGroups {
VertexGroups{
vertex_groups: model.vertex_groups().to_vec(),
default_group: model.vertex_groups().iter()
.position(|group| group == model.default_group().map(|s| s.as_ref()).unwrap_or("")),
}
}
}
impl<'a> FromBlender<&'a rinblender::Skeleton> for ArmatureCache{
fn from_blender(skeleton: &'a rinblender::Skeleton) -> ArmatureCache{
let index = skeleton.animated_index().clone();
ArmatureCache{
index,
skinning_bones_index: vec![],
changed: false,
postmat: None,
postmat3: None,
premat: None,
premat3: None,
}
}
}
pub trait RotModeToOrder {
fn to_rot_order(self) -> RotOrder;
}
impl RotModeToOrder for RotMode{
fn to_rot_order(self) -> RotOrder{
match self{
RotMode::EulerXYZ => RotOrder::XYZ,
RotMode::EulerXZY => RotOrder::XZY,
RotMode::EulerYXZ => RotOrder::YXZ,
RotMode::EulerYZX => RotOrder::YZX,
RotMode::EulerZXY => RotOrder::ZXY,
RotMode::EulerZYX => RotOrder::ZYX,
_ => panic!("Not an euler rotation")
}
}
}
#[derive(Component)]
#[debug_as_string]
pub struct ShapeKey{
pub key: rinblender::TrimeshKey,
pub action: Option<Action>,
}
impl std::fmt::Debug for ShapeKey {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("ShapeKey")
.field("key", &self.key.name())
.field("action", &self.action)
.finish()
}
}