1656 lines
65 KiB
Ada
1656 lines
65 KiB
Ada
with
|
|
gel.Forge,
|
|
gel.Conversions,
|
|
physics.Model,
|
|
|
|
openGL.Model.any,
|
|
opengl.Palette,
|
|
opengl.Program .lit.colored_textured_skinned,
|
|
opengl.Geometry.lit_colored_textured_skinned,
|
|
|
|
collada.Document,
|
|
collada.Library,
|
|
collada.Library.controllers,
|
|
collada.Library.animations,
|
|
|
|
ada.Strings.unbounded,
|
|
ada.Strings.Maps;
|
|
|
|
package body gel.Rig
|
|
is
|
|
use linear_Algebra_3D;
|
|
|
|
|
|
-----------
|
|
--- Utility
|
|
--
|
|
|
|
function "+" (From : in ada.strings.unbounded.unbounded_String) return String
|
|
renames ada.strings.unbounded.to_String;
|
|
|
|
function "+" (From : in String) return ada.strings.unbounded.unbounded_String
|
|
renames ada.strings.unbounded.to_unbounded_String;
|
|
|
|
|
|
|
|
function to_gel_joint_Id (Parent, Child : in bone_Id) return gel_joint_Id
|
|
is
|
|
use ada.Strings.unbounded;
|
|
begin
|
|
return Parent & "_to_" & Child;
|
|
end to_gel_joint_Id;
|
|
|
|
|
|
|
|
function to_Math (From : in collada.Matrix_4x4) return math.Matrix_4x4
|
|
is
|
|
begin
|
|
return [1 => [From (1, 1), From (1, 2), From (1, 3), From (1, 4)],
|
|
2 => [From (2, 1), From (2, 2), From (2, 3), From (2, 4)],
|
|
3 => [From (3, 1), From (3, 2), From (3, 3), From (3, 4)],
|
|
4 => [From (4, 1), From (4, 2), From (4, 3), From (4, 4)]];
|
|
end to_Math;
|
|
pragma Unreferenced (to_Math);
|
|
|
|
|
|
|
|
function to_Details (Length : Real := Unspecified;
|
|
width_Factor,
|
|
depth_Factor : Real := 0.1;
|
|
|
|
pitch_Limits,
|
|
yaw_Limits,
|
|
roll_Limits : gel.Sprite.DoF_Limits := (to_Radians (-15.0),
|
|
to_Radians ( 15.0))) return bone_Details
|
|
is
|
|
begin
|
|
return (Length, width_Factor, depth_Factor,
|
|
pitch_Limits, yaw_Limits, roll_Limits);
|
|
end to_Details;
|
|
|
|
|
|
---------
|
|
--- Forge
|
|
--
|
|
|
|
package body Forge
|
|
is
|
|
|
|
function new_Rig (in_World : in gel.World.view;
|
|
Model : in openGL.Model.view;
|
|
Mass : in Real := 0.0;
|
|
is_Kinematic : in Boolean := False) return Rig.view
|
|
is
|
|
Self : constant Rig.view := new Rig.item;
|
|
begin
|
|
Self.define (in_World, Model, Mass, is_Kinematic);
|
|
|
|
return Self;
|
|
end new_Rig;
|
|
|
|
|
|
|
|
function new_Rig (bone_Sprites : in bone_id_Map_of_sprite;
|
|
joint_inv_bind_Matrices : in inverse_bind_matrix_Vector;
|
|
joint_site_Offets : in joint_Id_Map_of_bone_site_offset;
|
|
Model : in openGL.Model.view) return Rig.view
|
|
is
|
|
the_Box : constant Rig.View := new Rig.item;
|
|
begin
|
|
the_Box.bone_Sprites := bone_Sprites;
|
|
the_Box.joint_inv_bind_Matrices := joint_inv_bind_Matrices;
|
|
the_Box.phys_joint_site_Offets := joint_site_Offets;
|
|
the_Box.Model := Model;
|
|
|
|
return the_Box;
|
|
end new_Rig;
|
|
|
|
end Forge;
|
|
|
|
|
|
---------------------------
|
|
--- Skin program parameters
|
|
--
|
|
|
|
overriding
|
|
procedure enable (Self : in out skin_program_Parameters)
|
|
is
|
|
use joint_id_Maps_of_slot;
|
|
|
|
subtype Program_view is openGL.Program.lit.colored_textured_skinned.view;
|
|
|
|
Cursor : joint_id_Maps_of_slot.Cursor := Self.joint_Map_of_slot.First;
|
|
Slot : Integer;
|
|
|
|
begin
|
|
while has_Element (Cursor)
|
|
loop
|
|
Slot := Element (Cursor);
|
|
|
|
Program_view (Self.Program).bone_Transform_is (Which => Slot,
|
|
Now => Self.bone_Transforms.Element (Slot));
|
|
next (Cursor);
|
|
end loop;
|
|
end enable;
|
|
|
|
|
|
-------------
|
|
--- Animation
|
|
--
|
|
|
|
procedure define_global_Transform_for (Self : in out Item'Class; the_Joint : in collada.Library.visual_scenes.Node_view;
|
|
Slot : in out Positive)
|
|
is
|
|
use collada.Library;
|
|
|
|
which_Joint : constant scene_joint_Id := the_Joint.Id;
|
|
child_Joints : constant visual_scenes.Nodes := the_Joint.Children;
|
|
|
|
default_scene_Joint : scene_Joint;
|
|
the_global_Transform : constant Matrix_4x4 := Transpose (the_Joint.global_Transform); -- Transpose to convert to row-major.
|
|
|
|
begin
|
|
Self.joint_pose_Transforms.insert (which_Joint, the_global_Transform);
|
|
Self.collada_Joints .insert (which_Joint, the_Joint);
|
|
|
|
default_scene_Joint.Node := the_Joint;
|
|
Self.scene_Joints.insert (which_Joint, default_scene_Joint);
|
|
|
|
for i in child_Joints'Range
|
|
loop
|
|
Slot := Slot + 1;
|
|
define_global_Transform_for (Self, child_Joints (i), Slot); -- Recurse over children.
|
|
end loop;
|
|
end define_global_Transform_for;
|
|
|
|
|
|
|
|
procedure update_global_Transform_for (Self : in out Item'Class; the_Joint : in collada.Library.visual_scenes.Node_view)
|
|
is
|
|
use collada.Library,
|
|
ada.Strings.unbounded;
|
|
|
|
which_Joint : constant scene_joint_Id := the_Joint.Id;
|
|
child_Joints : constant visual_scenes.Nodes := the_Joint.Children;
|
|
|
|
the_global_Transform : constant Matrix_4x4 := math.Transpose (the_Joint.global_Transform); -- Transpose to convert to row-major.
|
|
joint_site_Offet : Vector_3;
|
|
|
|
begin
|
|
if which_Joint = Self.root_Joint.Name
|
|
then joint_site_Offet := [0.0, 0.0, 0.0];
|
|
else joint_site_Offet := Self.anim_joint_site_Offets (which_Joint);
|
|
end if;
|
|
|
|
|
|
Self.joint_pose_Transforms.replace (which_Joint, (the_global_Transform));
|
|
Self.scene_Joints (which_Joint).Transform := the_global_Transform;
|
|
|
|
declare
|
|
use type gel.Sprite.view;
|
|
|
|
the_bone_Id : constant bone_Id := which_Joint;
|
|
Site : Vector_3;
|
|
Rotation : Matrix_3x3;
|
|
|
|
begin
|
|
if Self.bone_Sprites (the_bone_Id) /= null
|
|
then
|
|
Site := get_Translation (the_global_Transform);
|
|
Site := Site - joint_site_Offet * (get_Rotation (the_global_Transform));
|
|
Site := Site * Inverse (Self.base_Sprite.Spin);
|
|
Site := Site + Self.overall_Site;
|
|
|
|
Rotation := Inverse (get_Rotation (the_global_Transform));
|
|
Rotation := Self.base_Sprite.Spin * Rotation;
|
|
|
|
Self.bone_Sprites (the_bone_Id).all.Site_is (Site);
|
|
|
|
if which_Joint /= Self.root_Joint.Name
|
|
then
|
|
Self.bone_Sprites (the_bone_Id).all.Spin_is (Rotation);
|
|
end if;
|
|
end if;
|
|
end;
|
|
|
|
for i in child_Joints'Range
|
|
loop
|
|
Self.update_global_Transform_for (child_Joints (i)); -- Recurse over children.
|
|
end loop;
|
|
end update_global_Transform_for;
|
|
|
|
|
|
|
|
procedure update_all_global_Transforms (Self : in out Item'Class)
|
|
is
|
|
begin
|
|
Self.update_global_Transform_for (Self.root_Joint); -- Re-determine all joint transforms, recursively.
|
|
end update_all_global_Transforms;
|
|
|
|
|
|
|
|
procedure set_rotation_Angle (Self : in out Item'Class; for_Joint : in scene_joint_Id;
|
|
Axis : in axis_Kind;
|
|
To : in Real)
|
|
is
|
|
begin
|
|
case Axis is
|
|
when x_Axis => Self.set_x_rotation_Angle (for_Joint, To);
|
|
when y_Axis => Self.set_y_rotation_Angle (for_Joint, To);
|
|
when z_Axis => Self.set_z_rotation_Angle (for_Joint, To);
|
|
end case;
|
|
end set_rotation_Angle;
|
|
|
|
|
|
|
|
procedure set_Location (Self : in out Item'Class; for_Joint : in scene_joint_Id;
|
|
To : in Vector_3)
|
|
is
|
|
begin
|
|
Self.scene_Joints (for_Joint).Node.set_Location (To);
|
|
end set_Location;
|
|
|
|
|
|
|
|
procedure set_Location_x (Self : in out Item'Class; for_Joint : in scene_joint_Id;
|
|
To : in Real)
|
|
is
|
|
begin
|
|
Self.scene_Joints (for_Joint).Node.set_Location_x (To);
|
|
end set_Location_x;
|
|
|
|
|
|
procedure set_Location_y (Self : in out Item'Class; for_Joint : in scene_joint_Id;
|
|
To : in Real)
|
|
is
|
|
begin
|
|
Self.scene_Joints (for_Joint).Node.set_Location_y (To);
|
|
end set_Location_y;
|
|
|
|
|
|
procedure set_Location_z (Self : in out Item'Class; for_Joint : in scene_joint_Id;
|
|
To : in Real)
|
|
is
|
|
begin
|
|
Self.scene_Joints (for_Joint).Node.set_Location_z (To);
|
|
end set_location_z;
|
|
|
|
|
|
|
|
procedure set_Transform (Self : in out Item'Class; for_Joint : in scene_joint_Id;
|
|
To : in Matrix_4x4)
|
|
is
|
|
begin
|
|
Self.scene_Joints (for_Joint).Node.set_Transform (To);
|
|
end set_Transform;
|
|
|
|
|
|
|
|
procedure set_x_rotation_Angle (Self : in out Item'Class; for_Joint : in scene_joint_Id;
|
|
To : in Real)
|
|
is
|
|
begin
|
|
Self.scene_Joints (for_Joint).Node.set_x_rotation_Angle (To);
|
|
end set_x_rotation_Angle;
|
|
|
|
|
|
|
|
procedure set_y_rotation_Angle (Self : in out Item'Class; for_Joint : in scene_joint_Id;
|
|
To : in Real)
|
|
is
|
|
begin
|
|
Self.scene_Joints (for_Joint).Node.set_y_rotation_Angle (To);
|
|
end set_y_rotation_Angle;
|
|
|
|
|
|
|
|
procedure set_z_rotation_Angle (Self : in out Item'Class; for_Joint : in scene_joint_Id;
|
|
To : in Real)
|
|
is
|
|
begin
|
|
Self.scene_Joints (for_Joint).Node.set_z_rotation_Angle (To);
|
|
end set_z_rotation_Angle;
|
|
|
|
|
|
----------
|
|
--- Define
|
|
--
|
|
|
|
procedure define (Self : in out Item; in_World : in gel .World.view;
|
|
Model : in openGL.Model.view;
|
|
Mass : in Real := 0.0;
|
|
is_Kinematic : in Boolean := False;
|
|
bone_Details : in bone_id_Map_of_details := bone_id_Maps_of_details.empty_Map)
|
|
is
|
|
use collada.Document,
|
|
collada.Library,
|
|
collada.Library.visual_Scenes,
|
|
|
|
ada.Strings.unbounded,
|
|
ada.Strings;
|
|
|
|
type any_Model_view is access all openGL.Model.any.item;
|
|
|
|
the_Model : constant any_Model_view := any_Model_view (Model);
|
|
the_Document : constant collada.Document.item := to_Document (openGL.to_String (the_Model.model_Name));
|
|
|
|
|
|
function get_root_Joint return visual_Scenes.Node_view
|
|
is
|
|
begin
|
|
if the_Document.Libraries.visual_Scenes.skeletal_Root = ""
|
|
then
|
|
return the_Document.Libraries.visual_Scenes.Contents (1).root_Node;
|
|
else
|
|
return the_Document.Libraries.visual_Scenes.Contents (1).root_Node.Child (1);
|
|
end if;
|
|
end get_root_Joint;
|
|
|
|
|
|
the_root_Joint : constant visual_scenes.Node_view := get_root_Joint;
|
|
prior_bone_Length : Real := 1.0;
|
|
|
|
|
|
package joint_id_Maps_of_vector_3 is new ada.Containers.hashed_Maps (Key_type => scene_joint_Id,
|
|
Element_type => Vector_3,
|
|
Hash => ada.Strings.unbounded.Hash,
|
|
equivalent_Keys => ada.Strings.unbounded."=",
|
|
"=" => "=");
|
|
subtype joint_id_Map_of_vector_3 is joint_id_Maps_of_vector_3.Map;
|
|
|
|
|
|
joint_Sites : joint_id_Map_of_vector_3;
|
|
|
|
procedure set_Site_for (the_Joint : in visual_Scenes.Node_view)
|
|
is
|
|
which_Joint : constant scene_joint_Id := the_Joint.Id;
|
|
child_Joints : constant visual_Scenes.Nodes := the_Joint.Children;
|
|
|
|
begin
|
|
if which_Joint = Self.root_Joint.Name
|
|
then
|
|
joint_Sites.insert (which_Joint,
|
|
[0.0, 0.0, 0.0]);
|
|
else
|
|
joint_Sites.insert (which_Joint,
|
|
get_Translation (Self.joint_bind_Matrix (which_Joint)));
|
|
end if;
|
|
|
|
for i in child_Joints'Range
|
|
loop
|
|
set_Site_for (child_Joints (i)); -- Recurse over children.
|
|
end loop;
|
|
end set_Site_for;
|
|
|
|
|
|
procedure create_Bone (the_Bone : in bone_Id;
|
|
start_Joint : in scene_joint_Id;
|
|
end_Point : in Vector_3;
|
|
Scale : in Vector_3;
|
|
Mass : in Real)
|
|
is
|
|
pragma Unreferenced (Mass);
|
|
use opengl.Palette;
|
|
|
|
new_Sprite : gel.Sprite.view;
|
|
the_bone_Site : constant Vector_3 := midPoint (joint_Sites (start_Joint),
|
|
end_Point);
|
|
begin
|
|
if the_Bone = Self.root_Joint.Name
|
|
then
|
|
declare
|
|
use standard.physics.Model;
|
|
|
|
Size : constant Vector_3 := [0.1, 0.1, 0.1];
|
|
|
|
physics_Model : constant standard.physics.Model.View
|
|
:= standard.physics.Model.Forge.new_physics_Model (shape_Info => (Kind => Cube,
|
|
half_Extents => Size / 2.0),
|
|
Mass => 1.0);
|
|
begin
|
|
new_Sprite := gel.Sprite.Forge.new_Sprite (Name => "Skin Sprite",
|
|
World => gel.sprite.World_view (in_World),
|
|
graphics_Model => Model,
|
|
physics_Model => physics_Model,
|
|
is_Kinematic => is_Kinematic);
|
|
end;
|
|
|
|
new_Sprite.Site_is ([0.0, 0.0, 0.0]);
|
|
new_Sprite.Spin_is (Identity_3x3);
|
|
|
|
Self.bone_pose_Transforms.insert (the_Bone, Identity_4x4);
|
|
Self.skin_Sprite := new_Sprite;
|
|
|
|
else
|
|
new_Sprite := gel.Forge.new_box_Sprite (in_World => in_World.all'Access,
|
|
Mass => 1.0,
|
|
Size => Scale,
|
|
Colors => [1 => Black,
|
|
3 => Green,
|
|
4 => Blue,
|
|
others => Red],
|
|
is_Kinematic => is_Kinematic);
|
|
new_Sprite.Site_is (the_bone_Site);
|
|
new_Sprite.Spin_is (Inverse (get_Rotation (Self.joint_bind_Matrix (start_Joint))));
|
|
|
|
new_Sprite.is_Visible (False);
|
|
|
|
Self.anim_joint_site_Offets.insert (the_Bone, Inverse (get_Rotation (Self.joint_inv_bind_Matrix (start_Joint)))
|
|
* (joint_Sites (start_Joint) - the_bone_Site));
|
|
|
|
Self.phys_joint_site_Offets.insert (the_Bone, joint_Sites (start_Joint) - the_bone_Site);
|
|
|
|
|
|
Self.bone_pose_Transforms .insert (the_Bone, to_transform_Matrix (Rotation => get_Rotation (Self.joint_pose_Transforms (start_Joint)),
|
|
Translation => the_bone_Site));
|
|
end if;
|
|
|
|
Self.bone_Sprites.insert (the_Bone, new_Sprite);
|
|
|
|
declare
|
|
new_Sprite : constant gel.Sprite.view := gel.Forge.new_box_Sprite (in_World => in_World,
|
|
Mass => 0.0,
|
|
Size => [0.02, 0.02, 0.02],
|
|
Colors => [others => Yellow],
|
|
is_Kinematic => True);
|
|
begin
|
|
Self.joint_Sprites.insert (the_Bone, new_Sprite);
|
|
end;
|
|
end create_Bone;
|
|
|
|
|
|
procedure create_Bone_for (the_Joint : in visual_Scenes.Node_view; Parent : in bone_Id)
|
|
is
|
|
use bone_id_Maps_of_details;
|
|
|
|
which_Joint : constant scene_joint_Id := the_Joint.Id;
|
|
child_Joints : constant visual_Scenes.Nodes := the_Joint.Children;
|
|
|
|
the_bone_Details : Rig.bone_Details;
|
|
|
|
bone_Length : Real;
|
|
end_Point : Vector_3;
|
|
|
|
new_Joint : gel.Joint.view;
|
|
|
|
|
|
function guessed_bone_Length return Real
|
|
is
|
|
begin
|
|
if child_Joints'Length = 0
|
|
then
|
|
return prior_bone_Length;
|
|
|
|
else
|
|
if which_Joint = Self.root_Joint.Name
|
|
then
|
|
return Distance (joint_Sites.Element (which_Joint),
|
|
joint_Sites.Element (child_Joints (child_Joints'First).Id));
|
|
else
|
|
return Distance (joint_Sites.Element (which_Joint),
|
|
joint_Sites.Element (child_Joints (child_Joints'Last).Id));
|
|
end if;
|
|
end if;
|
|
end guessed_bone_Length;
|
|
|
|
|
|
begin
|
|
if bone_Details.contains (which_Joint)
|
|
then
|
|
the_bone_Details := bone_Details.Element (which_Joint);
|
|
|
|
if the_bone_Details.Length = Unspecified
|
|
then bone_Length := guessed_bone_Length;
|
|
else bone_Length := the_bone_Details.Length;
|
|
end if;
|
|
else
|
|
bone_Length := guessed_bone_Length;
|
|
end if;
|
|
|
|
end_Point := joint_Sites.Element (which_Joint)
|
|
+ [0.0, bone_Length, 0.0] * get_Rotation (Self.joint_bind_Matrix (which_Joint));
|
|
prior_bone_Length := bone_Length;
|
|
|
|
Self.joint_Parent.insert (which_Joint, Parent);
|
|
|
|
create_Bone (which_Joint,
|
|
which_Joint,
|
|
end_Point,
|
|
[the_bone_Details.width_Factor * bone_Length,
|
|
bone_Length * 0.90,
|
|
the_bone_Details.depth_Factor * bone_Length],
|
|
1.0);
|
|
|
|
if Parent /= (+"")
|
|
then
|
|
Self.Sprite (Parent).attach_via_ball_Socket (Self.bone_Sprites (which_Joint),
|
|
|
|
pivot_Axis => x_Rotation_from (0.0),
|
|
pivot_Anchor => joint_Sites.Element (which_Joint),
|
|
|
|
pitch_Limits => the_bone_Details.pitch_Limits,
|
|
yaw_Limits => the_bone_Details. yaw_Limits,
|
|
roll_Limits => the_bone_Details. roll_Limits,
|
|
|
|
new_Joint => new_Joint);
|
|
|
|
Self.Joints.insert (to_gel_joint_Id (Parent, which_Joint),
|
|
new_Joint);
|
|
end if;
|
|
|
|
for i in child_Joints'Range
|
|
loop
|
|
create_Bone_for (child_Joints (i), -- Recurse over children.
|
|
parent => which_Joint);
|
|
end loop;
|
|
end create_Bone_for;
|
|
|
|
|
|
use collada.Library.Controllers;
|
|
|
|
global_transform_Slot : Positive := 1;
|
|
|
|
begin
|
|
Self.root_Joint := the_root_Joint; -- Remember our root joint.
|
|
Self.Model := Model.all'unchecked_Access; -- Remember our model.
|
|
|
|
--- Parse Controllers.
|
|
--
|
|
|
|
-- Set the bind shape matrix.
|
|
--
|
|
Self.bind_shape_Matrix := Transpose (bind_shape_Matrix_of (the_Document.Libraries.Controllers.Contents (1).Skin));
|
|
|
|
|
|
-- Set the joint slots.
|
|
--
|
|
declare
|
|
the_Skin : constant Controllers.Skin := the_Document.Libraries.Controllers.Contents (1).Skin;
|
|
the_joint_Names : constant collada.Text_array := joint_Names_of (the_Skin);
|
|
begin
|
|
for i in 1 .. Integer (the_joint_Names'Length)
|
|
loop
|
|
Self.program_Parameters.joint_Map_of_slot.insert (the_joint_Names (i),
|
|
i);
|
|
end loop;
|
|
end;
|
|
|
|
-- Set the inverse bind matrices for all joints.
|
|
--
|
|
declare
|
|
the_Skin : constant Controllers.Skin := the_Document.Libraries.Controllers.Contents (1).Skin;
|
|
the_bind_Poses : constant collada.Matrix_4x4_array := bind_Poses_of (the_Skin);
|
|
begin
|
|
for i in 1 .. Integer (the_bind_Poses'Length)
|
|
loop
|
|
Self.joint_inv_bind_Matrices .append (Transpose (the_bind_Poses (i))); -- Transpose corrects for collada column vectors.
|
|
Self.program_Parameters.bone_Transforms.append (Identity_4x4);
|
|
end loop;
|
|
end;
|
|
|
|
|
|
--- Parse Visual Scene.
|
|
--
|
|
Self.define_global_Transform_for (the_root_Joint, -- Determine all joint transforms, recursively.
|
|
Slot => global_transform_Slot);
|
|
set_Site_for (the_root_Joint);
|
|
create_Bone_for (the_root_Joint, Parent => +""); -- Create all other bones, recursively.
|
|
|
|
|
|
--- Parse the Collada animations file.
|
|
--
|
|
declare
|
|
use collada.Library.Animations;
|
|
the_Animations : constant access Animation_array := the_Document.Libraries.Animations.Contents;
|
|
|
|
begin
|
|
if the_Animations /= null
|
|
then
|
|
for Each in the_Animations'Range
|
|
loop
|
|
declare
|
|
the_Animation : constant animations.Animation := the_Animations (Each);
|
|
the_Inputs : access collada.float_Array := Inputs_of (the_Animation);
|
|
|
|
|
|
procedure common_setup (Channel : in channel_Id;
|
|
scene_Joint : in scene_Joint_Id;
|
|
Sid : in String)
|
|
is
|
|
default_scene_Joint : rig.scene_Joint;
|
|
default_Channel : animation_Channel;
|
|
begin
|
|
Self.Channels.insert (Channel, default_Channel);
|
|
|
|
Self.Channels (Channel).Target := Self.scene_Joints (scene_Joint).Node.fetch_Transform (Sid);
|
|
Self.Channels (Channel).target_Joint := scene_Joint;
|
|
|
|
Self.Channels (Channel).Times := Inputs_of (the_Animation);
|
|
Self.Channels (Channel).Values := Outputs_of (the_Animation);
|
|
end common_setup;
|
|
|
|
|
|
procedure setup_Rotation (Channel : in channel_Id;
|
|
scene_Joint : in scene_Joint_Id;
|
|
Sid : in String)
|
|
is
|
|
begin
|
|
common_setup (Channel, scene_Joint, Sid);
|
|
|
|
-- For angle interpolation during 'rotation' animation.
|
|
--
|
|
Self.Channels (Channel).initial_Angle := Self.Channels (Channel).Values (1);
|
|
Self.Channels (Channel).current_Angle := Self.Channels (Channel).initial_Angle;
|
|
end setup_Rotation;
|
|
pragma Unreferenced (setup_Rotation);
|
|
|
|
|
|
procedure setup_Location (Channel : in channel_Id;
|
|
scene_Joint : in scene_Joint_Id;
|
|
Sid : in String)
|
|
is
|
|
begin
|
|
common_setup (Channel, scene_Joint, Sid);
|
|
|
|
-- For location interpolation during 'translation' animation.
|
|
--
|
|
Self.Channels (Channel).current_Site := [Self.Channels (Channel).Values (1),
|
|
Self.Channels (Channel).Values (2),
|
|
Self.Channels (Channel).Values (3)];
|
|
Self.Channels (Channel).initial_Site := Self.Channels (Channel).current_Site;
|
|
end setup_Location;
|
|
pragma Unreferenced (setup_Location);
|
|
|
|
|
|
procedure setup_Location_x (Channel : in channel_Id;
|
|
scene_Joint : in scene_Joint_Id;
|
|
Sid : in String)
|
|
is
|
|
begin
|
|
common_setup (Channel, scene_Joint, Sid);
|
|
|
|
-- For matrix interpolation during 'full_transform' animation.
|
|
--
|
|
Self.Channels (Channel).Transforms := new Transforms (1 .. Self.Channels (Channel).Values'Length);
|
|
|
|
for i in Self.Channels (Channel).Transforms'Range
|
|
loop
|
|
declare
|
|
the_X_Value : constant Real := Self.Channels (Channel).Values (i);
|
|
begin
|
|
Self.Channels (Channel).Transforms (i) := (Rotation => to_Quaternion (Identity_3x3),
|
|
Translation => [the_X_Value, 0.0, 0.0]);
|
|
end;
|
|
end loop;
|
|
|
|
Self.Channels (Channel).initial_Transform := Self.Channels (Channel).Transforms (1);
|
|
Self.Channels (Channel).current_Transform := Self.Channels (Channel).initial_Transform;
|
|
|
|
Self.Channels (Channel).current_Site := Self.Channels (Channel).initial_Transform.Translation;
|
|
Self.Channels (Channel).initial_Site := Self.Channels (Channel).current_Site;
|
|
end setup_Location_x;
|
|
|
|
|
|
procedure setup_Location_y (Channel : in channel_Id;
|
|
scene_Joint : in scene_Joint_Id;
|
|
Sid : in String)
|
|
is
|
|
begin
|
|
common_setup (Channel, scene_Joint, Sid);
|
|
|
|
-- For matrix interpolation during 'full_transform' animation.
|
|
--
|
|
Self.Channels (Channel).Transforms := new Transforms (1 .. Self.Channels (Channel).Values'Length);
|
|
|
|
for i in Self.Channels (Channel).Transforms'Range
|
|
loop
|
|
declare
|
|
the_Y_Value : constant Real := Self.Channels (Channel).Values (i);
|
|
begin
|
|
Self.Channels (Channel).Transforms (i) := (rotation => to_Quaternion (Identity_3x3),
|
|
translation => [0.0, the_Y_Value, 0.0]);
|
|
end;
|
|
end loop;
|
|
|
|
Self.Channels (Channel).initial_Transform := Self.Channels (Channel).Transforms (1);
|
|
Self.Channels (Channel).current_Transform := Self.Channels (Channel).initial_Transform;
|
|
|
|
Self.Channels (Channel).current_Site := Self.Channels (Channel).initial_Transform.Translation;
|
|
Self.Channels (Channel).initial_Site := Self.Channels (Channel).current_Site;
|
|
end setup_Location_y;
|
|
|
|
|
|
procedure setup_Location_z (Channel : in channel_Id;
|
|
scene_Joint : in scene_Joint_Id;
|
|
Sid : in String)
|
|
is
|
|
begin
|
|
common_setup (Channel, scene_Joint, Sid);
|
|
|
|
-- For matrix interpolation during 'full_transform' animation.
|
|
--
|
|
Self.Channels (Channel).Transforms := new Transforms (1 .. Self.Channels (Channel).Values'Length);
|
|
|
|
for i in Self.Channels (Channel).Transforms'Range
|
|
loop
|
|
declare
|
|
the_Z_Value : constant Real := Self.Channels (Channel).Values (i);
|
|
begin
|
|
Self.Channels (Channel).Transforms (i) := (rotation => to_Quaternion (Identity_3x3),
|
|
translation => [0.0, 0.0, the_Z_Value]);
|
|
end;
|
|
end loop;
|
|
|
|
Self.Channels (Channel).initial_Transform := Self.Channels (Channel).Transforms (1);
|
|
Self.Channels (Channel).current_Transform := Self.Channels (Channel).initial_Transform;
|
|
|
|
Self.Channels (Channel).current_Site := Self.Channels (Channel).initial_Transform.Translation;
|
|
Self.Channels (Channel).initial_Site := Self.Channels (Channel).current_Site;
|
|
end setup_Location_z;
|
|
|
|
|
|
procedure setup_full_Transform (Channel : in channel_Id;
|
|
scene_Joint : in scene_Joint_Id;
|
|
Sid : in String)
|
|
is
|
|
begin
|
|
common_setup (Channel, scene_Joint, Sid);
|
|
|
|
-- For matrix interpolation during 'full_transform' animation.
|
|
--
|
|
Self.Channels (Channel).Transforms := new Transforms (1 .. Collada.matrix_Count (Self.Channels (Channel).Values.all));
|
|
|
|
for i in Self.Channels (Channel).Transforms'Range
|
|
loop
|
|
declare
|
|
the_Matrix : constant math.Matrix_4x4 := Transpose (Collada.get_Matrix (Self.Channels (Channel).Values.all,
|
|
which => i));
|
|
begin
|
|
Self.Channels (Channel).Transforms (i) := (Rotation => to_Quaternion (get_Rotation (the_Matrix)),
|
|
Translation => get_Translation (the_Matrix));
|
|
end;
|
|
end loop;
|
|
|
|
Self.Channels (Channel).initial_Transform := Self.Channels (Channel).Transforms (1);
|
|
Self.Channels (Channel).current_Transform := Self.Channels (Channel).initial_Transform;
|
|
|
|
Self.Channels (Channel).current_Site := Self.Channels (Channel).initial_Transform.Translation;
|
|
Self.Channels (Channel).initial_Site := Self.Channels (Channel).current_Site;
|
|
end setup_full_Transform;
|
|
|
|
|
|
function Index (Source : in unbounded_String;
|
|
Pattern : in String;
|
|
Going : in Direction := Forward;
|
|
Mapping : in Maps.character_Mapping := ada.Strings.Maps.Identity) return Natural
|
|
renames ada.Strings.unbounded.Index;
|
|
|
|
begin
|
|
if Index (the_Animation.Channel.Target, "hips/transform") /= 0 then
|
|
setup_full_Transform (+"hips", +"hips", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "thigh_L/transform") /= 0 then
|
|
setup_full_Transform (+"thigh_L", +"thigh_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "shin_L/transform") /= 0 then
|
|
setup_full_Transform (+"shin_L", +"shin_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "foot_L/transform") /= 0 then
|
|
setup_full_Transform (+"foot_L", +"foot_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "toe_L/transform") /= 0 then
|
|
setup_full_Transform (+"toe_L", +"toe_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "thigh_R/transform") /= 0 then
|
|
setup_full_Transform (+"thigh_R", +"thigh_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "shin_R/transform") /= 0 then
|
|
setup_full_Transform (+"shin_R", +"shin_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "foot_R/transform") /= 0 then
|
|
setup_full_Transform (+"foot_R", +"foot_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "toe_R/transform") /= 0 then
|
|
setup_full_Transform (+"toe_R", +"toe_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "spine/transform") /= 0 then
|
|
setup_full_Transform (+"spine", +"spine", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "chest/transform") /= 0 then
|
|
setup_full_Transform (+"chest", +"chest", "transform");
|
|
|
|
|
|
elsif Index (the_Animation.Channel.Target, "clavicle_R/transform") /= 0 then
|
|
setup_full_Transform (+"clavicle_R", +"clavicle_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "upper_arm_R/transform") /= 0 then
|
|
setup_full_Transform (+"upper_arm_R", +"upper_arm_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "forearm_R/transform") /= 0 then
|
|
setup_full_Transform (+"forearm_R", +"forearm_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "hand_R/transform") /= 0 then
|
|
setup_full_Transform (+"hand_R", +"hand_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "thumb_02_R/transform") /= 0 then
|
|
setup_full_Transform (+"thumb_02_R", +"thumb_02_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "thumb_03_R/transform") /= 0 then
|
|
setup_full_Transform (+"thumb_03_R", +"thumb_03_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "f_ring_01_R/transform") /= 0 then
|
|
setup_full_Transform (+"f_ring_01_R", +"f_ring_01_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "f_index_01_R/transform") /= 0 then
|
|
setup_full_Transform (+"f_index_01_R", +"f_index_01_R", "transform");
|
|
|
|
|
|
elsif Index (the_Animation.Channel.Target, "clavicle_L/transform") /= 0 then
|
|
setup_full_Transform (+"clavicle_L", +"clavicle_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "upper_arm_L/transform") /= 0 then
|
|
setup_full_Transform (+"upper_arm_L", +"upper_arm_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "forearm_L/transform") /= 0 then
|
|
setup_full_Transform (+"forearm_L", +"forearm_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "hand_L/transform") /= 0 then
|
|
setup_full_Transform (+"hand_L", +"hand_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "thumb_02_L/transform") /= 0 then
|
|
setup_full_Transform (+"thumb_02_L", +"thumb_02_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "thumb_03_L/transform") /= 0 then
|
|
setup_full_Transform (+"thumb_03_L", +"thumb_03_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "f_ring_01_L/transform") /= 0 then
|
|
setup_full_Transform (+"f_ring_01_L", +"f_ring_01_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "f_index_01_L/transform") /= 0 then
|
|
setup_full_Transform (+"f_index_01_L", +"f_index_01_L", "transform");
|
|
|
|
|
|
elsif Index (the_Animation.Channel.Target, "neck/transform") /= 0 then
|
|
setup_full_Transform (+"neck", +"neck", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "head/transform") /= 0 then
|
|
setup_full_Transform (+"head", +"head", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "jaw/transform") /= 0 then
|
|
setup_full_Transform (+"jaw", +"jaw", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "eye_R/transform") /= 0 then
|
|
setup_full_Transform (+"eye_R", +"eye_R", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "eye_L/transform") /= 0 then
|
|
setup_full_Transform (+"eye_L", +"eye_L", "transform");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "stride_bone/location.X") /= 0 then
|
|
-- setup_Location_x (+"stride_bone_x", +"stride_bone", "x");
|
|
setup_Location_x (+"stride_bone_x", +"human", "x");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "stride_bone/location.Y") /= 0 then
|
|
-- setup_Location_y (+"stride_bone_y", +"stride_bone", "y");
|
|
setup_Location_y (+"stride_bone_y", +"human", "y");
|
|
|
|
elsif Index (the_Animation.Channel.Target, "stride_bone/location.Z") /= 0 then
|
|
-- setup_Location_z (+"stride_bone_z", +"stride_bone", "z");
|
|
setup_Location_z (+"stride_bone_z", +"human", "z");
|
|
|
|
else
|
|
raise constraint_Error with +the_Animation.Channel.Target & " not handled";
|
|
end if;
|
|
end;
|
|
end loop;
|
|
end if;
|
|
|
|
end;
|
|
|
|
end define;
|
|
|
|
|
|
|
|
procedure enable_Graphics (Self : in out Item)
|
|
is
|
|
begin
|
|
Self .program_Parameters.Program_is (opengl.Program.view (opengl.Geometry.lit_colored_textured_skinned.Program));
|
|
Self.skin_Sprite.program_Parameters_are (Self.program_Parameters'unchecked_Access);
|
|
end enable_Graphics;
|
|
|
|
|
|
|
|
function Joints (Self : in Item) return gel_joint_id_Map_of_gel_Joint
|
|
is
|
|
begin
|
|
return Self.Joints;
|
|
end Joints;
|
|
|
|
|
|
|
|
function joint_inv_bind_Matrices (Self : in Item'Class) return inverse_bind_matrix_Vector
|
|
is
|
|
begin
|
|
return Self.joint_inv_bind_Matrices;
|
|
end joint_inv_bind_Matrices;
|
|
|
|
|
|
|
|
procedure joint_inv_bind_Matrices_are (Self : in out Item'Class; Now : in inverse_bind_matrix_Vector)
|
|
is
|
|
begin
|
|
Self.joint_inv_bind_Matrices := Now;
|
|
end joint_inv_bind_Matrices_are;
|
|
|
|
|
|
|
|
function joint_site_Offets (Self : in Item'Class) return joint_Id_Map_of_bone_site_offset
|
|
is
|
|
begin
|
|
return Self.phys_joint_site_Offets;
|
|
end joint_site_Offets;
|
|
|
|
|
|
--------------
|
|
--- Attributes
|
|
--
|
|
|
|
procedure Site_is (Self :in out Item; Now : in Vector_3)
|
|
is
|
|
begin
|
|
Self.base_Sprite.move (to_Site => Now);
|
|
Self.overall_Site := Now;
|
|
end Site_is;
|
|
|
|
|
|
|
|
procedure Spin_is (Self :in out Item; Now : in Matrix_3x3)
|
|
is
|
|
begin
|
|
Self.base_Sprite.rotate (to_Spin => Now);
|
|
end Spin_is;
|
|
|
|
|
|
|
|
function Sprite (Self : in Item'Class; Bone : in bone_Id) return gel.Sprite.view
|
|
is
|
|
begin
|
|
return Self.bone_Sprites (Bone);
|
|
end Sprite;
|
|
|
|
|
|
|
|
function base_Sprite (Self : in Item'Class) return gel.Sprite.view
|
|
is
|
|
begin
|
|
return Self.bone_Sprites.Element (Self.root_Joint.Name);
|
|
end base_Sprite;
|
|
|
|
|
|
|
|
function skin_Sprite (Self : in Item'Class) return gel.Sprite.view
|
|
is
|
|
begin
|
|
return Self.skin_Sprite;
|
|
end skin_Sprite;
|
|
|
|
|
|
|
|
function bone_Sprites (Self : in Item) return bone_id_Map_of_sprite
|
|
is
|
|
begin
|
|
return Self.bone_Sprites;
|
|
end bone_Sprites;
|
|
|
|
|
|
|
|
procedure set_GL_program_Parameters (Self : in out Item'Class; for_Bone : in controller_joint_Id;
|
|
To : in Matrix_4x4)
|
|
is
|
|
use gel.Conversions;
|
|
bone_Slot : constant Positive := Self.program_Parameters.joint_Map_of_slot.Element (for_Bone);
|
|
begin
|
|
Self.program_Parameters.bone_Transforms.replace_Element (bone_Slot,
|
|
to_GL (To));
|
|
end set_GL_program_Parameters;
|
|
|
|
|
|
|
|
procedure animation_Transforms_are (Self : in out Item'Class; Now : in bone_id_Map_of_transform)
|
|
is
|
|
begin
|
|
Self.animation_Transforms := Now;
|
|
end animation_Transforms_are;
|
|
|
|
|
|
|
|
procedure motion_Mode_is (Self : in out Item; Now : in motion_Mode)
|
|
is
|
|
begin
|
|
Self.Mode := Now;
|
|
end motion_Mode_is;
|
|
|
|
|
|
--------------
|
|
--- Operations
|
|
--
|
|
|
|
procedure evolve (Self : in out Item'Class; world_Age : in Duration)
|
|
is
|
|
|
|
function get_root_Transform return Matrix_4x4
|
|
is
|
|
begin
|
|
case Self.Mode
|
|
is
|
|
when Dynamics =>
|
|
return Self.base_Sprite.Transform;
|
|
|
|
when Animation =>
|
|
declare
|
|
the_Transform : Matrix_4x4;
|
|
begin
|
|
set_Rotation (the_Transform, x_Rotation_from (to_Radians (0.0)));
|
|
set_Translation (the_Transform, -get_Translation (Inverse (Self.joint_pose_Transforms (Self.root_Joint.Name))));
|
|
|
|
return the_Transform;
|
|
end;
|
|
end case;
|
|
end get_root_Transform;
|
|
|
|
|
|
root_Transform : constant Matrix_4x4 := get_root_Transform;
|
|
inv_root_Transform : constant Matrix_4x4 := Inverse (root_Transform);
|
|
|
|
|
|
function joint_Transform_for (the_collada_Joint : in controller_joint_Id) return Matrix_4x4
|
|
is
|
|
begin
|
|
case Self.Mode
|
|
is
|
|
when Dynamics =>
|
|
declare
|
|
the_bone_Transform : constant Matrix_4x4 := Self.Sprite (the_collada_Joint).Transform;
|
|
the_joint_site_Offset : Vector_3 := Self.phys_joint_site_Offets (the_collada_Joint);
|
|
the_joint_Transform : Matrix_4x4;
|
|
begin
|
|
the_joint_site_Offset := the_joint_site_Offset
|
|
* get_Rotation (Self.joint_inv_bind_Matrix (the_collada_Joint))
|
|
* get_Rotation (the_bone_Transform);
|
|
|
|
set_Translation (the_joint_Transform, get_Translation (the_bone_Transform) + the_joint_site_Offset);
|
|
set_Rotation (the_joint_Transform, get_Rotation (the_bone_Transform));
|
|
|
|
Self.joint_Sprites (the_collada_Joint).all.Site_is (get_Translation (the_joint_Transform));
|
|
|
|
return the_joint_Transform;
|
|
end;
|
|
|
|
when Animation =>
|
|
Self.joint_Sprites (the_collada_Joint).all.Site_is ( get_Translation (Self.scene_Joints (the_collada_Joint).Transform));
|
|
Self.joint_Sprites (the_collada_Joint).all.Spin_is (Inverse (get_Rotation (Self.scene_Joints (the_collada_Joint).Transform)));
|
|
|
|
return Self.scene_Joints (the_collada_Joint).Transform;
|
|
end case;
|
|
end joint_Transform_for;
|
|
|
|
|
|
procedure set_Transform_for (the_Bone : in controller_joint_Id)
|
|
is
|
|
the_Slot : constant Positive := Self.program_Parameters.joint_Map_of_slot (the_Bone);
|
|
begin
|
|
Self.set_GL_program_Parameters (for_Bone => the_Bone,
|
|
To => Self.bind_shape_Matrix
|
|
* Self.joint_inv_bind_Matrices.Element (the_Slot)
|
|
* joint_Transform_for (the_Bone)
|
|
* inv_root_Transform);
|
|
end set_Transform_for;
|
|
|
|
|
|
procedure set_proxy_Transform_for (the_Bone : in controller_joint_Id; the_Proxy : in controller_joint_Id)
|
|
is
|
|
the_Slot : constant Positive := Self.program_Parameters.joint_Map_of_slot (the_Proxy);
|
|
begin
|
|
Self.set_GL_program_Parameters (for_bone => the_Bone,
|
|
to => Self.bind_shape_Matrix
|
|
* Self.joint_inv_bind_Matrices .Element (the_Slot)
|
|
* joint_Transform_for (the_Proxy)
|
|
* inv_root_Transform);
|
|
end set_proxy_Transform_for;
|
|
pragma Unreferenced (set_proxy_Transform_for);
|
|
|
|
|
|
use joint_Id_Maps_of_bone_site_offset;
|
|
|
|
Cursor : joint_Id_Maps_of_bone_site_offset.Cursor := Self.phys_joint_site_Offets.First;
|
|
|
|
begin
|
|
if Self.Mode = Animation
|
|
then
|
|
Self.animate (world_Age);
|
|
end if;
|
|
|
|
while has_Element (Cursor)
|
|
loop
|
|
if Self.program_Parameters.joint_Map_of_slot.Contains (Key (Cursor))
|
|
then
|
|
set_Transform_for (Key (Cursor)); -- Updates gl skin program params.
|
|
end if;
|
|
|
|
next (Cursor);
|
|
end loop;
|
|
end evolve;
|
|
|
|
|
|
|
|
procedure assume_Pose (Self : in out Item)
|
|
is
|
|
use bone_id_Maps_of_transform;
|
|
|
|
the_Bone : gel.Sprite.view;
|
|
Cursor : bone_id_Maps_of_transform.Cursor := Self.bone_pose_Transforms.First;
|
|
|
|
begin
|
|
while has_Element (Cursor)
|
|
loop
|
|
the_Bone := Self.bone_Sprites (Key (Cursor));
|
|
the_Bone.Transform_is (Element (Cursor));
|
|
|
|
next (Cursor);
|
|
end loop;
|
|
end assume_Pose;
|
|
|
|
|
|
|
|
function Parent_of (Self : in Item; the_Bone : in bone_Id) return bone_Id
|
|
is
|
|
begin
|
|
if Self.joint_Parent.Contains (the_Bone)
|
|
then
|
|
return Self.joint_Parent.Element (the_Bone);
|
|
else
|
|
return null_Id;
|
|
end if;
|
|
end Parent_of;
|
|
|
|
|
|
|
|
function joint_site_Offet (Self : in Item; for_Bone : in bone_Id) return math.Vector_3
|
|
is
|
|
begin
|
|
return Self.phys_joint_site_Offets.Element (for_Bone);
|
|
end joint_site_Offet;
|
|
|
|
|
|
|
|
function joint_inv_bind_Matrix (Self : in Item; for_Bone : in bone_Id) return math.Matrix_4x4
|
|
is
|
|
use ada.Strings.unbounded;
|
|
begin
|
|
if for_Bone = Self.root_Joint.Name
|
|
then
|
|
return math.Identity_4x4;
|
|
else
|
|
return Self.joint_inv_bind_Matrices.Element (Self.program_Parameters.joint_Map_of_slot.Element (for_Bone));
|
|
end if;
|
|
end joint_inv_bind_Matrix;
|
|
|
|
|
|
|
|
function joint_bind_Matrix (Self : in Item; for_Bone : in bone_Id) return Matrix_4x4
|
|
is
|
|
begin
|
|
return Inverse (Self.joint_inv_bind_Matrix (for_Bone));
|
|
end joint_bind_Matrix;
|
|
|
|
|
|
-------------
|
|
--- Animation
|
|
--
|
|
|
|
procedure animate (Self : in out Item; world_Age : in Duration)
|
|
is
|
|
Now : Duration;
|
|
Elapsed : Duration;
|
|
|
|
|
|
procedure update_rotation_Animation (for_Channel : in channel_Id;
|
|
for_Joint : in scene_joint_Id;
|
|
for_Axis : in axis_Kind)
|
|
is
|
|
the_Channel : animation_Channel renames Self.Channels (for_Channel);
|
|
Cursor : math.Index renames the_Channel.Cursor;
|
|
|
|
function Reduced (Angle : in Real) return Real -- TODO: Use Degrees type.
|
|
is
|
|
begin
|
|
if Angle > 180.0 then return -360.0 + Angle;
|
|
elsif Angle < -180.0 then return 360.0 + Angle;
|
|
else return Angle;
|
|
end if;
|
|
end Reduced;
|
|
|
|
begin
|
|
if Cursor < the_Channel.Times'Last
|
|
then
|
|
if Cursor = 0
|
|
or else Elapsed > Duration (the_Channel.Times (Cursor))
|
|
then
|
|
Cursor := Cursor + 1;
|
|
|
|
if Cursor = 1
|
|
then
|
|
if the_Channel.Times (Cursor) = 0.0
|
|
then
|
|
the_Channel.interp_Delta := Reduced (the_Channel.Values (Cursor) - the_Channel.current_Angle);
|
|
else
|
|
the_Channel.interp_Delta := Reduced (the_Channel.Values (Cursor) - the_Channel.current_Angle)
|
|
/ (the_Channel.Times (Cursor));
|
|
end if;
|
|
|
|
else
|
|
the_Channel.interp_Delta := Reduced (the_Channel.Values (Cursor) - the_Channel.current_Angle)
|
|
/ (the_Channel.Times (Cursor) - the_Channel.Times (Cursor - 1));
|
|
end if;
|
|
|
|
the_Channel.interp_Delta := the_Channel.interp_Delta / 60.0; -- 60.0 is frames/sec.
|
|
end if;
|
|
end if;
|
|
|
|
if Elapsed < Duration (the_Channel.Times (the_Channel.Times'Last))
|
|
then
|
|
the_Channel.current_Angle := Reduced ( the_Channel.current_Angle
|
|
+ the_Channel.interp_Delta);
|
|
|
|
Self.set_rotation_Angle (for_Joint,
|
|
for_Axis,
|
|
To => to_Radians (Degrees (the_Channel.current_Angle)));
|
|
end if;
|
|
end update_rotation_Animation;
|
|
pragma Unreferenced (update_rotation_Animation);
|
|
|
|
|
|
|
|
procedure update_location_Animation (for_Channel : in channel_Id;
|
|
for_Joint : in scene_joint_Id)
|
|
is
|
|
pragma Unreferenced (for_Joint);
|
|
the_Channel : animation_Channel renames Self.Channels (for_Channel);
|
|
Cursor : Index renames the_Channel.Cursor;
|
|
Elapsed : constant Duration := Now - Self.start_Time;
|
|
|
|
function site_X return Real is begin return the_Channel.Values ((Cursor - 1) * 3 + 1); end site_X;
|
|
function site_Y return Real is begin return the_Channel.Values ((Cursor - 1) * 3 + 2); end site_Y;
|
|
function site_Z return Real is begin return the_Channel.Values ((Cursor - 1) * 3 + 3); end site_Z;
|
|
|
|
begin
|
|
if Cursor < the_Channel.Times'Last
|
|
then
|
|
if Cursor = 0
|
|
or else Elapsed > Duration (the_Channel.Times (Cursor))
|
|
then
|
|
Cursor := Cursor + 1;
|
|
|
|
if Cursor = 1
|
|
then
|
|
if the_Channel.Times (Cursor) = 0.0
|
|
then
|
|
the_Channel.site_interp_Delta (1) := site_X - the_Channel.current_Site (1);
|
|
the_Channel.site_interp_Delta (2) := site_Y - the_Channel.current_Site (2);
|
|
the_Channel.site_interp_Delta (3) := site_Z - the_Channel.current_Site (3);
|
|
else
|
|
the_Channel.site_interp_Delta (1) := (site_X - the_Channel.current_Site (1))
|
|
/ (the_Channel.Times (Cursor));
|
|
the_Channel.site_interp_Delta (2) := (site_Y - the_Channel.current_Site (2))
|
|
/ (the_Channel.Times (Cursor));
|
|
the_Channel.site_interp_Delta (3) := (site_Z - the_Channel.current_Site (3))
|
|
/ (the_Channel.Times (Cursor));
|
|
end if;
|
|
|
|
else
|
|
the_Channel.site_interp_Delta (1) := (site_X - the_Channel.current_Site (1))
|
|
/ (the_Channel.Times (Cursor) - the_Channel.Times (Cursor - 1));
|
|
the_Channel.site_interp_Delta (2) := (site_Y - the_Channel.current_Site (2))
|
|
/ (the_Channel.Times (Cursor) - the_Channel.Times (Cursor - 1));
|
|
the_Channel.site_interp_Delta (3) := (site_Z - the_Channel.current_Site (3))
|
|
/ (the_Channel.Times (Cursor) - the_Channel.Times (Cursor - 1));
|
|
end if;
|
|
|
|
the_Channel.site_interp_Delta (1) := the_Channel.site_interp_Delta (1) / 60.0; -- 60.0 is frames/sec.
|
|
the_Channel.site_interp_Delta (2) := the_Channel.site_interp_Delta (2) / 60.0; --
|
|
the_Channel.site_interp_Delta (3) := the_Channel.site_interp_Delta (3) / 60.0; --
|
|
end if;
|
|
|
|
Self.set_Location (the_Channel.target_Joint, to => the_Channel.current_Site);
|
|
|
|
the_Channel.current_Site (1) := the_Channel.current_Site (1) + the_Channel.site_interp_Delta (1);
|
|
the_Channel.current_Site (2) := the_Channel.current_Site (2) + the_Channel.site_interp_Delta (2);
|
|
the_Channel.current_Site (3) := the_Channel.current_Site (3) + the_Channel.site_interp_Delta (3);
|
|
|
|
end if;
|
|
end update_location_Animation;
|
|
pragma Unreferenced (update_location_Animation);
|
|
|
|
|
|
|
|
procedure update_location_X_Animation (for_Channel : in channel_Id;
|
|
for_Joint : in scene_joint_Id)
|
|
is
|
|
pragma Unreferenced (for_Joint);
|
|
the_Channel : animation_Channel renames Self.Channels (for_Channel);
|
|
Cursor : Index renames the_Channel.Cursor;
|
|
Elapsed : constant Duration := Now - Self.start_Time;
|
|
|
|
function site_X return Real is begin return the_Channel.Values (Cursor); end site_X;
|
|
|
|
begin
|
|
if Cursor < the_Channel.Times'Last
|
|
then
|
|
if Cursor = 0
|
|
or else Elapsed > Duration (the_Channel.Times (Cursor))
|
|
then
|
|
Cursor := Cursor + 1;
|
|
|
|
if Cursor = 1
|
|
then
|
|
if the_Channel.Times (Cursor) = 0.0
|
|
then
|
|
the_Channel.site_interp_Delta (1) := site_X - the_Channel.current_Site (1);
|
|
else
|
|
the_Channel.site_interp_Delta (1) := (site_X - the_Channel.current_Site (1))
|
|
/ (the_Channel.Times (Cursor));
|
|
end if;
|
|
|
|
else
|
|
the_Channel.site_interp_Delta (1) := (site_X - the_Channel.current_Site (1))
|
|
/ (the_Channel.Times (Cursor) - the_Channel.Times (Cursor - 1));
|
|
end if;
|
|
|
|
the_Channel.site_interp_Delta (1) := the_Channel.site_interp_Delta (1) / 60.0; -- 60.0 is frames/sec.
|
|
end if;
|
|
|
|
Self.set_Location_x (the_Channel.target_Joint, To => the_Channel.current_Site (1));
|
|
|
|
the_Channel.current_Site (1) := the_Channel.current_Site (1) + the_Channel.site_interp_Delta (1);
|
|
end if;
|
|
end update_location_X_Animation;
|
|
|
|
|
|
|
|
procedure update_location_Y_Animation (for_Channel : in channel_Id;
|
|
for_Joint : in scene_joint_Id)
|
|
is
|
|
pragma Unreferenced (for_Joint);
|
|
the_Channel : animation_Channel renames Self.Channels (for_Channel);
|
|
Cursor : Index renames the_Channel.Cursor;
|
|
Elapsed : constant Duration := Now - Self.start_Time;
|
|
|
|
function site_Y return math.Real is begin return the_Channel.Values (Cursor); end site_Y;
|
|
|
|
begin
|
|
if Cursor < the_Channel.Times'Last
|
|
then
|
|
if Cursor = 0
|
|
or else Elapsed > Duration (the_Channel.Times (Cursor))
|
|
then
|
|
Cursor := Cursor + 1;
|
|
|
|
if Cursor = 1
|
|
then
|
|
if the_Channel.Times (Cursor) = 0.0
|
|
then
|
|
the_Channel.site_interp_Delta (2) := site_Y - the_Channel.current_Site (2);
|
|
else
|
|
the_Channel.site_interp_Delta (2) := (site_Y - the_Channel.current_Site (2))
|
|
/ (the_Channel.Times (Cursor));
|
|
end if;
|
|
else
|
|
the_Channel.site_interp_Delta (2) := (site_Y - the_Channel.current_Site (2))
|
|
/ (the_Channel.Times (Cursor) - the_Channel.Times (Cursor - 1));
|
|
end if;
|
|
|
|
the_Channel.site_interp_Delta (2) := the_Channel.site_interp_Delta (2) / 60.0; -- 60.0 is frames/sec
|
|
end if;
|
|
|
|
Self.set_Location_y (the_Channel.target_Joint, To => the_Channel.current_Site (2));
|
|
|
|
the_Channel.current_Site (2) := the_Channel.current_Site (2) + the_Channel.site_interp_Delta (2);
|
|
end if;
|
|
end update_location_Y_Animation;
|
|
|
|
|
|
|
|
procedure update_location_Z_Animation (for_Channel : in channel_Id;
|
|
for_Joint : in scene_joint_Id)
|
|
is
|
|
pragma Unreferenced (for_Joint);
|
|
the_Channel : animation_Channel renames Self.Channels (for_Channel);
|
|
Cursor : math.Index renames the_Channel.Cursor;
|
|
Elapsed : constant Duration := Now - Self.start_Time;
|
|
|
|
function site_Z return math.Real is begin return the_Channel.Values (Cursor); end site_Z;
|
|
|
|
begin
|
|
if Cursor < the_Channel.Times'Last
|
|
then
|
|
if Cursor = 0
|
|
or else Elapsed > Duration (the_Channel.Times (Cursor))
|
|
then
|
|
Cursor := Cursor + 1;
|
|
|
|
if Cursor = 1
|
|
then
|
|
if the_Channel.Times (Cursor) = 0.0
|
|
then
|
|
the_Channel.site_interp_Delta (3) := site_Z - the_Channel.current_Site (3);
|
|
else
|
|
the_Channel.site_interp_Delta (3) := (site_Z - the_Channel.current_Site (3))
|
|
/ (the_Channel.Times (Cursor));
|
|
end if;
|
|
|
|
else
|
|
the_Channel.site_interp_Delta (3) := (site_Z - the_Channel.current_Site (3))
|
|
/ (the_Channel.Times (Cursor) - the_Channel.Times (Cursor - 1));
|
|
end if;
|
|
|
|
the_Channel.site_interp_Delta (3) := the_Channel.site_interp_Delta (3) / 60.0; -- 60.0 is frames/sec
|
|
end if;
|
|
|
|
Self.set_Location_z (the_Channel.target_Joint, To => the_Channel.current_Site (3));
|
|
|
|
the_Channel.current_Site (3) := the_Channel.current_Site (3) + the_Channel.site_interp_Delta (3);
|
|
end if;
|
|
end update_location_Z_Animation;
|
|
|
|
|
|
|
|
procedure update_full_transform_Animation (for_Channel : in channel_Id;
|
|
for_Joint : in scene_joint_Id)
|
|
is
|
|
pragma Unreferenced (for_Joint);
|
|
the_Channel : animation_Channel renames Self.Channels (for_Channel);
|
|
Cursor : Index renames the_Channel.Cursor;
|
|
Cursor_updated : Boolean := False;
|
|
new_Transform : Matrix_4x4 := Identity_4x4;
|
|
|
|
begin
|
|
if Cursor = the_Channel.Times'Last
|
|
then
|
|
Cursor := 0;
|
|
Self.start_Time := Now;
|
|
end if;
|
|
|
|
-- Rotation
|
|
--
|
|
declare
|
|
Initial : Transform;
|
|
begin
|
|
if Cursor < the_Channel.Times'Last
|
|
then
|
|
if Cursor = 0
|
|
or else Elapsed > Duration (the_Channel.Times (Cursor))
|
|
then
|
|
Cursor := Cursor + 1;
|
|
Cursor_updated := True;
|
|
|
|
if Cursor = 1
|
|
then
|
|
Initial := the_Channel.current_Transform;
|
|
|
|
if the_Channel.Times (Cursor) = 0.0
|
|
then
|
|
the_Channel.Transform_interp_Delta := 1.0 / 60.0;
|
|
else
|
|
the_Channel.Transform_interp_Delta := the_Channel.Times (Cursor);
|
|
end if;
|
|
|
|
else
|
|
Initial := the_Channel.Transforms (Cursor - 1);
|
|
the_Channel.Transform_interp_Delta := the_Channel.Times (Cursor) - the_Channel.Times (Cursor - 1);
|
|
end if;
|
|
|
|
the_Channel.current_Transform := the_Channel.Transforms (Cursor);
|
|
the_Channel.Transform_interp_Delta := 1.0 / (the_Channel.Transform_interp_Delta * 60.0); -- 60.0 is frames/sec.
|
|
the_Channel.slerp_Time := 0.0;
|
|
|
|
else
|
|
if Cursor > 1
|
|
then Initial := the_Channel.Transforms (Cursor - 1);
|
|
else Initial := the_Channel.Transforms (Cursor);
|
|
end if;
|
|
end if;
|
|
|
|
else
|
|
Initial := the_Channel.Transforms (1);
|
|
end if;
|
|
|
|
if Elapsed < Duration (the_Channel.Times (the_Channel.Times'Last))
|
|
then
|
|
set_Rotation (new_Transform, to_Matrix (Interpolated (Initial.Rotation,
|
|
the_Channel.current_Transform.Rotation,
|
|
Percent => to_Percentage (the_Channel.slerp_Time))));
|
|
the_Channel.slerp_Time := the_Channel.slerp_Time
|
|
+ the_Channel.Transform_interp_Delta;
|
|
end if;
|
|
end;
|
|
|
|
|
|
-- Location
|
|
--
|
|
declare
|
|
desired_Site : constant Vector_3 := the_Channel.Transforms (Cursor).Translation;
|
|
begin
|
|
if Cursor < the_Channel.Times'Last
|
|
then
|
|
if Cursor_updated
|
|
then
|
|
if Cursor = 1
|
|
then
|
|
if the_Channel.Times (Cursor) = 0.0
|
|
then
|
|
the_Channel.site_interp_Delta := desired_Site - the_Channel.current_Site;
|
|
else
|
|
the_Channel.site_interp_Delta := (desired_Site - the_Channel.current_Site)
|
|
/ (the_Channel.Times (Cursor));
|
|
end if;
|
|
|
|
else
|
|
the_Channel.site_interp_Delta := (desired_Site - the_Channel.current_Site)
|
|
/ (the_Channel.Times (Cursor) - the_Channel.Times (Cursor - 1));
|
|
end if;
|
|
|
|
the_Channel.site_interp_Delta := the_Channel.site_interp_Delta / 60.0; -- 60.0 is frames/sec.
|
|
end if;
|
|
|
|
the_Channel.current_Site := the_Channel.current_Site + the_Channel.site_interp_Delta;
|
|
|
|
set_Translation (new_Transform, To => the_Channel.current_Site);
|
|
end if;
|
|
end;
|
|
|
|
|
|
-- Scale
|
|
--
|
|
|
|
-- (TODO)
|
|
|
|
|
|
-- Store the new transform.
|
|
--
|
|
Self.set_Transform (the_Channel.target_Joint,
|
|
To => Transpose (new_Transform)); -- Transpose to convert to collada column vectors.
|
|
end update_full_transform_Animation;
|
|
|
|
|
|
begin
|
|
Now := world_Age;
|
|
|
|
if Self.start_Time = 0.0 then
|
|
Self.start_Time := Now;
|
|
end if;
|
|
|
|
Elapsed := Now - Self.start_Time;
|
|
|
|
declare
|
|
use channel_id_Maps_of_animation_Channel,
|
|
ada.Strings.Unbounded;
|
|
|
|
Cursor : channel_id_Maps_of_animation_Channel.Cursor := Self.Channels.First;
|
|
begin
|
|
while has_Element (Cursor)
|
|
loop
|
|
if Key (Cursor) = (+"stride_bone_x")
|
|
then
|
|
update_location_X_Animation (Key (Cursor),
|
|
Key (Cursor));
|
|
|
|
elsif Key (Cursor) = (+"stride_bone_y")
|
|
then
|
|
update_location_Y_Animation (Key (Cursor),
|
|
Key (Cursor));
|
|
|
|
elsif Key (Cursor) = (+"stride_bone_z")
|
|
then
|
|
update_location_Z_Animation (Key (Cursor),
|
|
Key (Cursor));
|
|
else
|
|
update_full_transform_Animation (Key (Cursor),
|
|
Key (Cursor));
|
|
end if;
|
|
|
|
next (Cursor);
|
|
end loop;
|
|
end;
|
|
|
|
Self.update_all_global_Transforms;
|
|
end animate;
|
|
|
|
|
|
|
|
procedure reset_Animation (Self : in out Item)
|
|
is
|
|
use channel_id_Maps_of_animation_Channel;
|
|
|
|
Cursor : channel_id_Maps_of_animation_Channel.Cursor := Self.Channels.First;
|
|
the_Channel : animation_Channel;
|
|
|
|
begin
|
|
Self.start_Time := 0.0;
|
|
|
|
while has_Element (Cursor)
|
|
loop
|
|
the_Channel := Element (Cursor);
|
|
|
|
the_Channel.Cursor := 0;
|
|
the_Channel.current_Angle := the_Channel.initial_Angle;
|
|
the_Channel.current_Site := the_Channel.initial_Site;
|
|
the_Channel.interp_Delta := 0.0;
|
|
|
|
Self.Channels.replace_Element (Cursor, the_Channel);
|
|
|
|
next (Cursor);
|
|
end loop;
|
|
end reset_Animation;
|
|
|
|
|
|
end gel.Rig;
|