Explorar o código

world: instantiate animation skeleton

Part-of: #276
Daniele Bartolini hai 11 meses
pai
achega
079da0b624

+ 1 - 1
src/resource/unit_compiler.cpp

@@ -892,7 +892,7 @@ UnitCompiler::UnitCompiler(Allocator &a)
 	unit_compiler::register_component_compiler(*this, "collider",                &physics_resource_internal::compile_collider, 1.0f);
 	unit_compiler::register_component_compiler(*this, "actor",                   &physics_resource_internal::compile_actor,    2.0f);
 	unit_compiler::register_component_compiler(*this, "joint",                   &physics_resource_internal::compile_joint,    3.0f);
-	unit_compiler::register_component_compiler(*this, "animation_state_machine", &compile_animation_state_machine,             1.0f);
+	unit_compiler::register_component_compiler(*this, "animation_state_machine", &compile_animation_state_machine,             3.0f);
 }
 
 UnitCompiler::~UnitCompiler()

+ 85 - 3
src/world/animation_state_machine.cpp

@@ -6,6 +6,9 @@
 #include "core/containers/array.inl"
 #include "core/containers/hash_map.inl"
 #include "core/containers/types.h"
+#include "core/math/constants.h"
+#include "core/math/matrix4x4.inl"
+#include "core/math/vector3.inl"
 #include "core/memory/globals.h"
 #include "core/strings/string_id.inl"
 #include "resource/expression_language.h"
@@ -14,8 +17,10 @@
 #include "resource/state_machine_resource.h"
 #include "world/animation_state_machine.h"
 #include "world/event_stream.inl"
+#include "world/render_world.h"
 #include "world/types.h"
 #include "world/unit_manager.h"
+#include "world/world.h"
 
 namespace crown
 {
@@ -57,7 +62,28 @@ AnimationStateMachine::~AnimationStateMachine()
 	_marker = 0;
 }
 
-StateMachineInstance AnimationStateMachine::create(UnitId unit, const AnimationStateMachineDesc &desc)
+static void mesh_set_skeleton_recursively(UnitId unit, AnimationSkeletonInstance *skeleton, SceneGraph &scene_graph, RenderWorld &render_world)
+{
+	// Set skeleton in this unit and all its children.
+	UnitId child_id = unit;
+	MeshInstance mesh = render_world.mesh_instance(child_id);
+	if (is_valid(mesh)) {
+		render_world.mesh_set_skeleton(mesh, skeleton);
+	}
+
+	TransformInstance transform = scene_graph.instance(unit);
+	if (is_valid(transform)) {
+		TransformInstance cur_child = scene_graph.first_child(transform);
+		while (is_valid(cur_child)) {
+			child_id = scene_graph.owner(cur_child);
+			mesh_set_skeleton_recursively(child_id, skeleton, scene_graph, render_world);
+
+			cur_child = scene_graph.next_sibling(cur_child);
+		}
+	}
+}
+
+StateMachineInstance AnimationStateMachine::create(UnitId unit, const AnimationStateMachineDesc &desc, World &world)
 {
 	CE_ASSERT(!hash_map::has(_map, unit), "Unit already has a state machine component");
 
@@ -74,9 +100,58 @@ StateMachineInstance AnimationStateMachine::create(UnitId unit, const AnimationS
 	m.state_next    = NULL;
 	m.state_machine = smr;
 	m.variables     = (f32 *)default_allocator().allocate(sizeof(*m.variables)*smr->num_variables);
+	m.skeleton      = NULL;
 
 	memcpy(m.variables, state_machine::variables(smr), sizeof(*m.variables)*smr->num_variables);
 
+	if (smr->animation_type == RESOURCE_TYPE_MESH_ANIMATION) {
+		// Spawn the skeleton hierarchy.
+		const MeshSkeletonResource *skeleton_resource = (MeshSkeletonResource *)_resource_manager->get(RESOURCE_TYPE_MESH_SKELETON, smr->skeleton_name);
+		const BoneTransform *local_transforms = mesh_skeleton_resource::local_transforms(skeleton_resource);
+		const u32 *parents = mesh_skeleton_resource::parents(skeleton_resource);
+
+		u32 size = sizeof(AnimationSkeletonInstance)
+			+ sizeof(UnitId) * skeleton_resource->num_bones
+			+ sizeof(Matrix4x4) * skeleton_resource->num_bones
+			;
+		AnimationSkeletonInstance *skeleton = (AnimationSkeletonInstance *)default_allocator().allocate(size);
+		skeleton->num_bones = skeleton_resource->num_bones;
+		skeleton->offsets = mesh_skeleton_resource::binding_matrices(skeleton_resource);
+		skeleton->bone_lookup = (UnitId *)&skeleton[1];
+		skeleton->bones = (Matrix4x4 *)(skeleton->bone_lookup + skeleton_resource->num_bones);
+		m.skeleton = skeleton;
+
+		for (u32 i = 0; i < skeleton_resource->num_bones; ++i)
+			skeleton->bone_lookup[i] = _unit_manager->create();
+
+		SceneGraph &scene_graph = *world._scene_graph;
+		RenderWorld &render_world = *world._render_world;
+
+		for (u32 i = 0; i < skeleton_resource->num_bones; ++i) {
+			TransformInstance ti = scene_graph.create(skeleton->bone_lookup[i]
+				, local_transforms[i].position
+				, local_transforms[i].rotation
+				, local_transforms[i].scale
+				);
+			if (parents[i] != UINT16_MAX) {
+				TransformInstance parent_ti = scene_graph.instance(skeleton->bone_lookup[parents[i]]);
+				scene_graph.link(parent_ti
+					, ti
+					, local_transforms[i].position
+					, local_transforms[i].rotation
+					, local_transforms[i].scale
+					);
+			} else {
+				Vector3 scale = local_transforms[i].scale;
+				Matrix4x4 tr = from_quaternion_translation(local_transforms[i].rotation, local_transforms[i].position);
+				scene_graph.set_local_pose(ti, tr);
+				scene_graph.set_local_scale(ti, scale);
+			}
+		}
+
+		mesh_set_skeleton_recursively(unit, skeleton, scene_graph, render_world);
+	}
+
 	u32 last = array::size(_machines);
 	array::push_back(_machines, m);
 	hash_map::set(_map, unit, last);
@@ -90,6 +165,8 @@ void AnimationStateMachine::destroy(StateMachineInstance state_machine)
 	const UnitId u = _machines[state_machine.i].unit;
 	const UnitId last_u = _machines[last_i].unit;
 
+	// TODO: Get rid of these allocations ASAP!
+	default_allocator().deallocate(_machines[state_machine.i].skeleton);
 	default_allocator().deallocate(_machines[state_machine.i].variables);
 	_machines[state_machine.i] = _machines[last_i];
 
@@ -146,7 +223,7 @@ void AnimationStateMachine::trigger(StateMachineInstance state_machine, StringId
 		CE_FATAL("Unknown transition mode");
 }
 
-void AnimationStateMachine::update(float dt)
+void AnimationStateMachine::update(float dt, SceneGraph &scene_graph)
 {
 	f32 stack_data[32];
 	expression_language::Stack stack(stack_data, countof(stack_data));
@@ -208,7 +285,12 @@ void AnimationStateMachine::update(float dt)
 		}
 
 		if (mi.anim_type == RESOURCE_TYPE_MESH_ANIMATION) {
-			// TODO.
+			mesh_animation_player::evaluate(*_mesh_animation_player
+				, mi.anim_id
+				, mi.time
+				, scene_graph
+				, mi.skeleton->bone_lookup
+				);
 		} else if (mi.anim_type == RESOURCE_TYPE_SPRITE_ANIMATION) {
 			sprite_animation_player::evaluate(*_sprite_animation_player
 				, mi.anim_id

+ 4 - 2
src/world/animation_state_machine.h

@@ -11,6 +11,7 @@
 #include "world/event_stream.h"
 #include "world/mesh_animation_player.h"
 #include "world/sprite_animation_player.h"
+#include "world/scene_graph.h"
 #include "world/types.h"
 
 namespace crown
@@ -29,6 +30,7 @@ struct AnimationStateMachine
 		const State *state_next;
 		const StateMachineResource *state_machine;
 		f32 *variables;
+		AnimationSkeletonInstance *skeleton;
 	};
 
 	u32 _marker;
@@ -53,7 +55,7 @@ struct AnimationStateMachine
 	~AnimationStateMachine();
 
 	/// Creates a new state machine instance for the @a unit.
-	StateMachineInstance create(UnitId unit, const AnimationStateMachineDesc &desc);
+	StateMachineInstance create(UnitId unit, const AnimationStateMachineDesc &desc, World &world);
 
 	/// Destroys the @a state_machine.
 	void destroy(StateMachineInstance state_machine);
@@ -77,7 +79,7 @@ struct AnimationStateMachine
 	void trigger(StateMachineInstance state_machine, StringId32 event);
 
 	///
-	void update(float dt);
+	void update(float dt, SceneGraph &scene_graph);
 
 	///
 	void unit_destroyed_callback(UnitId unit);

+ 2 - 2
src/world/world.cpp

@@ -174,7 +174,7 @@ UnitId World::unit_by_name(StringId32 name)
 
 void World::update_animations(f32 dt)
 {
-	_animation_state_machine->update(dt);
+	_animation_state_machine->update(dt, *_scene_graph);
 }
 
 void World::update_scene(f32 dt)
@@ -696,7 +696,7 @@ void spawn_units(World &w, const UnitResource *ur, const Vector3 &pos, const Qua
 		} else if (component->type == STRING_ID_32("animation_state_machine", UINT32_C(0xe87992ac))) {
 			const AnimationStateMachineDesc *asmd = (const AnimationStateMachineDesc *)data;
 			for (u32 i = 0, n = component->num_instances; i < n; ++i, ++asmd) {
-				animation_state_machine->create(unit_lookup[unit_index[i]], *asmd);
+				animation_state_machine->create(unit_lookup[unit_index[i]], *asmd, w);
 			}
 		} else {
 			CE_FATAL("Unknown component type");