Procházet zdrojové kódy

add joint, need FIX

mikymod před 12 roky
rodič
revize
205c242acc

+ 2 - 0
engine/CMakeLists.txt

@@ -395,6 +395,7 @@ set (PHYSICS_SRC
 	physics/Controller.cpp
 	physics/PhysicsWorld.cpp
 	physics/Trigger.cpp
+	physics/Joint.cpp
 )
 
 set (PHYSICS_HEADERS
@@ -403,6 +404,7 @@ set (PHYSICS_HEADERS
 	physics/PhysicsTypes.h
 	physics/PhysicsWorld.h
 	physics/Trigger.h
+	physics/Joint.h
 	physics/PhysicsCallback.h
 )
 

+ 7 - 0
engine/physics/Actor.cpp

@@ -388,6 +388,13 @@ void Actor::wake_up()
 	((PxRigidDynamic*)m_actor)->wakeUp();
 }
 
+//-----------------------------------------------------------------------------
+StringId32 Actor::name()
+{
+	const PhysicsActor& a = m_resource->actor(m_index);
+	return a.name;
+}
+
 //-----------------------------------------------------------------------------
 void Actor::update_pose()
 {

+ 2 - 0
engine/physics/Actor.h

@@ -90,6 +90,8 @@ struct Actor
 	bool				is_sleeping();
 	void				wake_up();
 
+	StringId32			name();
+
 	void				update_pose();
 	void				update(const Matrix4x4& pose);
 

+ 171 - 0
engine/physics/Joint.cpp

@@ -0,0 +1,171 @@
+/*
+Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "Joint.h"
+#include "Actor.h"
+#include "Vector3.h"
+#include "PhysicsResource.h"
+#include "SceneGraph.h"
+#include "MathUtils.h"
+
+#include "PxVec3.h"
+#include "PxMat44.h"
+#include "PxRigidActor.h"
+#include "PxRigidDynamic.h"
+#include "PxRigidStatic.h"
+#include "PxBoxGeometry.h"
+
+#include "PxFixedJoint.h"
+#include "PxSphericalJoint.h"
+#include "PxRevoluteJoint.h"
+#include "PxPrismaticJoint.h"
+#include "PxDistanceJoint.h"
+#include "PxJointLimit.h"
+
+using physx::PxPhysics;
+using physx::PxScene;
+
+using physx::PxTransform;
+using physx::PxVec3;
+using physx::PxMat44;
+using physx::PxRigidActor;
+using physx::PxBoxGeometry;
+using physx::PxReal;
+using physx::PxPi;
+using physx::PxConstraintFlag;
+
+using physx::PxJoint;
+using physx::PxFixedJoint;
+using physx::PxFixedJointCreate;
+using physx::PxJointLimitPair;
+
+using physx::PxSphericalJoint;
+using physx::PxSphericalJointCreate;
+using physx::PxSphericalJointFlag;
+using physx::PxJointLimitCone;
+
+using physx::PxRevoluteJoint;
+using physx::PxRevoluteJointCreate;
+using physx::PxRevoluteJointFlag;
+
+using physx::PxPrismaticJoint;
+using physx::PxPrismaticJointCreate;
+using physx::PxPrismaticJointFlag;
+
+using physx::PxDistanceJoint;
+using physx::PxDistanceJointCreate;
+using physx::PxDistanceJointFlag;
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+Joint::Joint(PxPhysics* physics, const PhysicsResource* pr, const uint32_t index, const Actor& a1, const Actor& a2)
+	: m_resource(pr)
+	, m_index(index)
+{
+	const PhysicsJoint& joint = m_resource->joint(m_index);
+
+	Matrix4x4 m1 = a1.m_scene_graph.world_pose(a1.m_node);
+	PxMat44 pose1((PxReal*)(m1.to_float_ptr()));
+
+	Matrix4x4 m2 = a2.m_scene_graph.world_pose(a2.m_node);
+	PxMat44 pose2((PxReal*)(m2.to_float_ptr()));
+
+	switch(joint.type)
+	{
+		case JointType::FIXED:
+		{
+			m_joint = PxFixedJointCreate(*physics, a1.m_actor, PxTransform(pose1), a2.m_actor, PxTransform(pose2));
+
+			break;
+		}
+		case JointType::SPHERICAL:
+		{
+			PxJointLimitCone limit_cone(math::deg_to_rad(10.0), math::deg_to_rad(90.0), 0.01f);
+			limit_cone.restitution = joint.restitution;
+			limit_cone.spring = joint.spring;
+			limit_cone.damping = joint.damping;
+			limit_cone.contactDistance = joint.distance;
+
+			m_joint = PxSphericalJointCreate(*physics, a1.m_actor, PxTransform(pose1), a2.m_actor, PxTransform(pose2));	
+			static_cast<PxSphericalJoint*>(m_joint)->setLimitCone(limit_cone);
+			static_cast<PxSphericalJoint*>(m_joint)->setSphericalJointFlag(PxSphericalJointFlag::eLIMIT_ENABLED, true);
+
+			break;
+		}
+		case JointType::REVOLUTE:
+		{
+			PxJointLimitPair limit_pair(-math::deg_to_rad(45.0), math::deg_to_rad(45.0), 0.01f);
+			limit_pair.spring = joint.spring;
+			limit_pair.damping = joint.damping;
+
+			m_joint = PxRevoluteJointCreate(*physics, a1.m_actor, PxTransform(pose1), a2.m_actor, PxTransform(pose2));
+			static_cast<PxRevoluteJoint*>(m_joint)->setLimit(limit_pair);
+			static_cast<PxRevoluteJoint*>(m_joint)->setRevoluteJointFlag(PxRevoluteJointFlag::eLIMIT_ENABLED, true);
+			static_cast<PxRevoluteJoint*>(m_joint)->setDriveVelocity(10.0f);
+			static_cast<PxRevoluteJoint*>(m_joint)->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_ENABLED, true);
+
+			break;
+		}
+		case JointType::PRISMATIC:
+		{
+			PxJointLimitPair limit_pair(math::deg_to_rad(20.0), math::deg_to_rad(45.0), 0.01f);
+			limit_pair.spring = joint.spring;
+			limit_pair.damping = joint.damping;
+
+			m_joint = PxPrismaticJointCreate(*physics, a1.m_actor, PxTransform(pose1), a2.m_actor, PxTransform(pose2));
+			static_cast<PxPrismaticJoint*>(m_joint)->setLimit(limit_pair);
+			static_cast<PxPrismaticJoint*>(m_joint)->setPrismaticJointFlag(PxPrismaticJointFlag::eLIMIT_ENABLED, true);
+
+			break;
+		}
+		case JointType::DISTANCE:
+		{
+			m_joint = PxDistanceJointCreate(*physics, a1.m_actor, PxTransform(pose1), a2.m_actor, PxTransform(pose2));
+			static_cast<PxDistanceJoint*>(m_joint)->setMaxDistance(10.0f);
+			static_cast<PxDistanceJoint*>(m_joint)->setDistanceJointFlag(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED, true);
+
+			break;
+		}
+		case JointType::D6:
+		{
+			// Must be implemented
+
+			break;
+		}
+	}
+
+	if (joint.breakable) m_joint->setBreakForce(joint.break_force, joint.break_torque);
+}
+
+//-----------------------------------------------------------------------------
+Joint::~Joint()
+{
+
+}
+
+} // namespace crown

+ 64 - 0
engine/physics/Joint.h

@@ -0,0 +1,64 @@
+/*
+Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#pragma once
+
+#include "Types.h"
+
+#include "PxPhysics.h"
+#include "PxScene.h"
+#include "PxJoint.h"
+#include "PxMaterial.h"
+
+using physx::PxPhysics;
+using physx::PxJoint;
+using physx::PxScene;
+using physx::PxMaterial;
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+struct Actor;
+struct PhysicsResource;
+
+//-----------------------------------------------------------------------------
+struct Joint
+{
+	Joint(PxPhysics* physics, const PhysicsResource* pr, const uint32_t index, const Actor& a1, const Actor& a2);
+	~Joint();
+
+public:
+
+	const PhysicsResource* m_resource;
+	const uint32_t m_index;
+
+	PxJoint* 			m_joint;
+	PxMaterial* 		m_mat;
+
+};
+
+} // namespace crown

+ 8 - 8
engine/physics/PhysicsCallback.h

@@ -56,31 +56,31 @@ public:
 	//-----------------------------------------------------------------------------
 	void onConstraintBreak(PxConstraintInfo* /*constraints*/, PxU32 /*count*/)
 	{
-		Log::i("COSTRAINTBREAK");
+		// Log::i("COSTRAINTBREAK");
 	}
 
 	//-----------------------------------------------------------------------------
 	void onContact(const PxContactPairHeader& /*pairHeader*/, const PxContactPair* /*pairs*/, PxU32 /*nbPairs*/)
 	{
-		Log::i("CONTACT");
+		// Log::i("CONTACT");
 	}
 
 	//-----------------------------------------------------------------------------
 	void onTrigger(PxTriggerPair* /*pairs*/, PxU32 /*count*/)
 	{
-		Log::i("TRIGGER");
+		// Log::i("TRIGGER");
 	}
 
 	//-----------------------------------------------------------------------------
 	void onWake(PxActor** /*actors*/, PxU32 /*count*/)
 	{
-		Log::i("WAKE");
+		// Log::i("WAKE");
 	}
 
 	//-----------------------------------------------------------------------------
 	void onSleep(PxActor** /*actors*/, PxU32 /*count*/)
 	{
-		Log::i("SLEEP");
+		// Log::i("SLEEP");
 	}
 };
 
@@ -90,19 +90,19 @@ class PhysicsControllerCallback : public PxUserControllerHitReport
 	//-----------------------------------------------------------------------------
 	void onShapeHit(const PxControllerShapeHit& hit)
 	{
-		Log::i("SHAPE HIT");
+		// Log::i("SHAPE HIT");
 	}
 
 	//-----------------------------------------------------------------------------
 	void onControllerHit(const PxControllersHit& hit)
 	{
-		Log::i("CONTROLLER HIT");
+		// Log::i("CONTROLLER HIT");
 	}
 
 	//-----------------------------------------------------------------------------
 	void onObstacleHit(const PxControllerObstacleHit& hit)
 	{
-		Log::i("OBSTACLE HIT");
+		// Log::i("OBSTACLE HIT");
 	}
 };
 

+ 15 - 0
engine/physics/PhysicsTypes.h

@@ -32,6 +32,7 @@ namespace crown
 typedef Id ActorId;
 typedef Id ControllerId;
 typedef Id TriggerId;
+typedef Id JointId;
 
 //-----------------------------------------------------------------------------
 struct ActorType
@@ -55,6 +56,20 @@ struct ShapeType
 	};
 };
 
+//-----------------------------------------------------------------------------
+struct JointType
+{
+	enum Enum
+	{
+		FIXED,
+		SPHERICAL,
+		REVOLUTE,
+		PRISMATIC,
+		DISTANCE,
+		D6
+	};
+};
+
 //-----------------------------------------------------------------------------
 struct CollisionGroup
 {

+ 51 - 1
engine/physics/PhysicsWorld.cpp

@@ -32,8 +32,11 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "SceneGraph.h"
 #include "Controller.h"
 #include "Trigger.h"
+#include "Joint.h"
 #include "PhysicsCallback.h"
 #include "ProxyAllocator.h"
+#include "Hash.h"
+#include "StringUtils.h"
 
 #include "PxPhysicsAPI.h"
 
@@ -58,6 +61,7 @@ using physx::PxFilterObjectIsTrigger;
 using physx::PxPairFlag;
 using physx::PxFilterFlag;
 using physx::PxSceneLimits;
+using physx::PxVisualizationParameter;
 
 namespace crown
 {
@@ -197,6 +201,7 @@ PhysicsWorld::PhysicsWorld()
 	, m_actors_pool(default_allocator(), MAX_ACTORS, sizeof(Actor), CE_ALIGNOF(Actor))
 	, m_controllers_pool(default_allocator(), MAX_CONTROLLERS, sizeof(Controller), CE_ALIGNOF(Controller))
 	, m_triggers_pool(default_allocator(), MAX_TRIGGERS, sizeof(Trigger), CE_ALIGNOF(Trigger))
+	, m_joints_pool(default_allocator(), MAX_JOINTS, sizeof(Joint), CE_ALIGNOF(Joint))
 {
 	// Create the scene
 	PxSceneLimits scene_limits;
@@ -220,7 +225,7 @@ PhysicsWorld::PhysicsWorld()
 
 	CE_ASSERT(scene_desc.isValid(), "Scene is not valid");
 	m_scene = physics_system::s_physics->createScene(scene_desc);
-
+	
 	// Create controller manager
 	m_controller_manager = PxCreateControllerManager(*physics_system::s_foundation);
 	CE_ASSERT(m_controller_manager != NULL, "Failed to create PhysX controller manager");
@@ -282,6 +287,36 @@ void PhysicsWorld::destroy_trigger(TriggerId id)
 	m_triggers.destroy(id);
 }
 
+//-----------------------------------------------------------------------------
+JointId	PhysicsWorld::create_joint(const PhysicsResource* pr, const uint32_t index, const Actor& a1, const Actor& a2)
+{
+	Joint* joint = CE_NEW(m_joints_pool, Joint)(physics_system::s_physics, pr, index, a1, a2);
+	return m_joints.create(joint);
+}
+
+//-----------------------------------------------------------------------------
+void PhysicsWorld::destroy_joint(JointId id)
+{
+	CE_ASSERT(m_joints.has(id), "Joint does not exist");
+
+	CE_DELETE(m_joints_pool, m_joints.lookup(id));
+	m_joints.destroy(id);
+}
+
+//-----------------------------------------------------------------------------
+Actor* PhysicsWorld::lookup_actor(StringId32 name)
+{
+	for (uint32_t i = 0; i < m_actors.size(); i++)
+	{
+		Actor* actor = m_actors[i];
+
+		if (actor->name() == name)
+		{
+			return actor;
+		}
+	}
+}
+
 //-----------------------------------------------------------------------------
 Actor* PhysicsWorld::lookup_actor(ActorId id)
 {
@@ -315,6 +350,21 @@ void PhysicsWorld::set_gravity(const Vector3& g)
 	m_scene->setGravity(PxVec3(g.x, g.y, g.z));
 }
 
+//-----------------------------------------------------------------------------
+void PhysicsWorld::set_kinematic(ActorId id)
+{
+	Actor* actor = lookup_actor(id);
+	actor->set_kinematic();
+}
+
+//-----------------------------------------------------------------------------
+void PhysicsWorld::clear_kinematic(ActorId id)
+{
+	Actor* actor = lookup_actor(id);
+	actor->clear_kinematic();
+}
+
+
 //-----------------------------------------------------------------------------
 void PhysicsWorld::update(float dt)
 {

+ 12 - 0
engine/physics/PhysicsWorld.h

@@ -45,6 +45,7 @@ using physx::PxActor;
 #define MAX_ACTORS 1024
 #define MAX_CONTROLLERS 1024
 #define MAX_TRIGGERS 1024
+#define MAX_JOINTS 512
 
 namespace crown
 {
@@ -67,6 +68,7 @@ struct Controller;
 struct Vector3;
 struct Actor;
 struct Trigger;
+struct Joint;
 struct Quaternion;
 class SceneGraph;
 
@@ -87,6 +89,10 @@ public:
 	TriggerId					create_trigger(const Vector3& half_extents, const Vector3& pos, const Quaternion& rot);
 	void						destroy_trigger(TriggerId id);
 
+	JointId						create_joint(const PhysicsResource* pr, const uint32_t index, const Actor& a1, const Actor& a2);
+	void						destroy_joint(JointId id);
+
+	Actor*						lookup_actor(StringId32 name);
 	Actor*						lookup_actor(ActorId id);
 	Controller*					lookup_controller(ControllerId id);
 	Trigger*					lookup_trigger(TriggerId id);
@@ -94,6 +100,9 @@ public:
 	Vector3						gravity() const;
 	void						set_gravity(const Vector3& g);
 
+	void						set_kinematic(ActorId id);
+	void						clear_kinematic(ActorId id);
+
 	void						update(float dt);
 
 public:
@@ -112,6 +121,9 @@ public:
 
 	PoolAllocator				m_triggers_pool;
 	IdArray<MAX_TRIGGERS, Trigger*> m_triggers;
+
+	PoolAllocator				m_joints_pool;
+	IdArray<MAX_JOINTS, Joint*> m_joints;
 };
 
 } // namespace crown

+ 75 - 1
engine/resource/PhysicsResource.cpp

@@ -37,6 +37,7 @@ namespace crown
 namespace physics_resource
 {
 
+//-----------------------------------------------------------------------------
 static uint32_t actor_type_to_enum(const char* type)
 {
 	if (string::strcmp("static", type) == 0) return PhysicsActorType::STATIC;
@@ -46,6 +47,7 @@ static uint32_t actor_type_to_enum(const char* type)
 	CE_FATAL("Bad actor type");
 }
 
+//-----------------------------------------------------------------------------
 static uint32_t actor_group_to_enum(const char* group)
 {
 	if (string::strcmp("GROUP_0", group) == 0) 	return PhysicsActorGroup::GROUP_0;
@@ -84,6 +86,7 @@ static uint32_t actor_group_to_enum(const char* group)
 	CE_FATAL("Bad actor group");
 }
 
+//-----------------------------------------------------------------------------
 static uint32_t shape_type_to_enum(const char* type)
 {
 	if (string::strcmp("sphere", type) == 0) 		return PhysicsShapeType::SPHERE;
@@ -94,6 +97,19 @@ static uint32_t shape_type_to_enum(const char* type)
 	CE_FATAL("Bad shape type");
 }
 
+//-----------------------------------------------------------------------------
+static uint32_t joint_type_to_enum(const char* type)
+{
+	if (string::strcmp("fixed", type) == 0) 			return PhysicsJointType::FIXED;
+	else if (string::strcmp("spherical", type) == 0) 	return PhysicsJointType::SPHERICAL;
+	else if (string::strcmp("revolute", type) == 0) 	return PhysicsJointType::REVOLUTE;
+	else if (string::strcmp("prismatic", type) == 0) 	return PhysicsJointType::PRISMATIC;
+	else if (string::strcmp("distance", type) == 0) 	return PhysicsJointType::DISTANCE;
+	else if (string::strcmp("d6", type) == 0) 			return PhysicsJointType::D6;	
+
+	CE_FATAL("Bad joint type");
+}
+
 //-----------------------------------------------------------------------------
 void parse_controller(JSONElement e, PhysicsController& controller)
 {
@@ -208,6 +224,44 @@ void parse_actor(JSONElement e, PhysicsActor& actor, List<PhysicsShape>& actor_s
 	}
 }
 
+//-----------------------------------------------------------------------------
+void parse_joint(JSONElement e, PhysicsJoint& joint)
+{
+	JSONElement name = e.key("name");
+	JSONElement type = e.key("type");
+	JSONElement actor_0 = e.key("actor_0");
+	JSONElement actor_1 = e.key("actor_1");
+	JSONElement restitution = e.key("restitution");
+	JSONElement spring = e.key("spring");
+	JSONElement damping = e.key("damping");
+	JSONElement distance = e.key("distance");
+	JSONElement breakable = e.key("breakable");
+	JSONElement break_force = e.key("break_force");
+	JSONElement break_torque = e.key("break_torque");
+
+	DynamicString joint_name;
+	DynamicString joint_type;
+	DynamicString joint_actor_0;
+	DynamicString joint_actor_1;
+	
+	name.string_value(joint_name);
+	type.string_value(joint_type);
+	actor_0.string_value(joint_actor_0);
+	actor_1.string_value(joint_actor_1);
+
+	joint.name = hash::murmur2_32(joint_name.c_str(), joint_name.length());
+	joint.type = joint_type_to_enum(joint_type.c_str());
+	joint.actor_0 = hash::murmur2_32(joint_actor_0.c_str(), joint_actor_0.length());
+	joint.actor_1 = hash::murmur2_32(joint_actor_1.c_str(), joint_actor_1.length());
+	joint.restitution = restitution.float_value();
+	joint.spring = spring.float_value();
+	joint.damping = damping.float_value();
+	joint.distance = distance.float_value();
+	joint.breakable = breakable.bool_value();
+	joint.break_force = break_force.float_value();
+	joint.break_torque = break_torque.float_value();
+}
+
 //-----------------------------------------------------------------------------
 void compile(Filesystem& fs, const char* resource_path, File* out_file)
 {
@@ -257,6 +311,19 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 		}
 	}
 
+	// Read joints
+	List<PhysicsJoint> m_joints(default_allocator());
+	JSONElement joints = root.key_or_nil("joints");
+	if (!joints.is_nil())
+	{
+		for (uint32_t i = 0; i < joints.size(); i++)
+		{
+			PhysicsJoint j;
+			parse_joint(joints[i], j);
+			m_joints.push_back(j);
+		}
+	}
+
 	fs.close(file);
 	default_allocator().deallocate(buf);
 
@@ -266,12 +333,14 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	h.num_actors = m_actors.size();
 	h.num_shapes_indices = m_shapes_indices.size();
 	h.num_shapes = m_shapes.size();
+	h.num_joints = m_joints.size();
 
 	uint32_t offt = sizeof(PhysicsHeader);
 	h.controller_offset = offt; offt += sizeof(PhysicsController) * h.num_controllers;
 	h.actors_offset = offt; offt += sizeof(PhysicsActor) * h.num_actors;
 	h.shapes_indices_offset = offt; offt += sizeof(uint32_t) * h.num_shapes_indices;
-	h.shapes_offset = offt;
+	h.shapes_offset = offt; offt += sizeof(PhysicsShape) * h.num_shapes;
+	h.joints_offset = offt;
 
 	out_file->write((char*) &h, sizeof(PhysicsHeader));
 
@@ -294,6 +363,11 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	{
 		out_file->write((char*) m_shapes.begin(), sizeof(PhysicsShape) * m_shapes.size());
 	}
+
+	if (m_joints.size())
+	{
+		out_file->write((char*) m_joints.begin(), sizeof(PhysicsJoint) * m_joints.size());
+	}
 }
 
 } // namespace physics_resource

+ 50 - 0
engine/resource/PhysicsResource.h

@@ -47,6 +47,8 @@ struct PhysicsHeader
 	uint32_t shapes_indices_offset;
 	uint32_t num_shapes;
 	uint32_t shapes_offset;
+	uint32_t num_joints;
+	uint32_t joints_offset;
 };
 
 //-----------------------------------------------------------------------------
@@ -149,6 +151,38 @@ struct PhysicsShape
 	float data_3;
 };
 
+//-----------------------------------------------------------------------------
+struct PhysicsJointType
+{
+	enum Enum
+	{
+		FIXED,
+		SPHERICAL,
+		REVOLUTE,
+		PRISMATIC,
+		DISTANCE,
+		D6
+	};
+};
+
+//-----------------------------------------------------------------------------
+struct PhysicsJoint
+{
+	StringId32 name;
+	uint32_t type;
+	StringId32 actor_0;
+	StringId32 actor_1;
+
+	float restitution;
+	float spring;
+	float damping;
+	float distance;
+
+	bool  breakable;
+	float break_force;
+	float break_torque;
+};
+
 //-----------------------------------------------------------------------------
 struct PhysicsResource
 {
@@ -245,6 +279,22 @@ struct PhysicsResource
 		return shape[i];
 	}
 
+	//-----------------------------------------------------------------------------
+	uint32_t num_joints() const
+	{
+		return ((PhysicsHeader*) this)->num_joints;
+	}
+
+	//-----------------------------------------------------------------------------
+	PhysicsJoint joint(uint32_t i) const
+	{
+		CE_ASSERT(i < num_joints(), "Index out of bounds");
+
+		const PhysicsHeader* ph = (PhysicsHeader*) this;
+		PhysicsJoint* joint = (PhysicsJoint*) (((char*) this) + ph->joints_offset);
+		return joint[i];		
+	}
+
 private:
 
 	// Disable construction

+ 38 - 0
engine/world/Unit.cpp

@@ -211,6 +211,17 @@ void Unit::create_physics_objects()
 			ActorId id = m_world.physics_world()->create_actor(pr, i, m_scene_graph, m_scene_graph.node(actor.node));
 			add_actor(actor.name, id);
 		}
+
+		// Create joints if any
+		for (uint32_t i = 0; i < pr->num_joints(); i++)
+		{
+			const PhysicsJoint& joint = pr->joint(i);
+
+			Actor* a1 = actor_by_index(joint.actor_0);
+			Actor* a2 = actor_by_index(joint.actor_1);
+
+			JointId id = m_world.physics_world()->create_joint(pr, i, *a1, *a2);
+		}
 	}
 }
 
@@ -368,6 +379,23 @@ Id Unit::find_component(uint32_t index, uint32_t size, Component* array)
 	return comp;
 }
 
+//-----------------------------------------------------------------------------
+Id Unit::find_component_by_index(StringId32 name, uint32_t size, Component* array)
+{
+	Id comp;
+	comp.id = INVALID_ID;
+
+	for (uint32_t i = 0; i < size; i++)
+	{
+		if (name == array[i].name)
+		{
+			comp = array[i].component;
+		}
+	}
+
+	return comp;
+}
+
 //-----------------------------------------------------------------------------
 void Unit::add_camera(StringId32 name, CameraId camera)
 {
@@ -495,6 +523,16 @@ Actor* Unit::actor(uint32_t i)
 	return m_world.physics_world()->lookup_actor(actor);
 }	
 
+//-----------------------------------------------------------------------------
+Actor* Unit::actor_by_index(StringId32 name)
+{
+	ActorId actor = find_component_by_index(name, m_num_actors, m_actors);
+
+	// CE_ASSERT(actor.id != INVALID_ID, "Unit does not have actor with name '%d'", name);
+
+	return m_world.physics_world()->lookup_actor(actor);
+}
+
 //-----------------------------------------------------------------------------
 Controller* Unit::controller()
 {

+ 2 - 0
engine/world/Unit.h

@@ -113,6 +113,7 @@ struct Unit
 	void				add_component(StringId32 name, Id component, uint32_t& size, Component* array);
 	Id					find_component(const char* name, uint32_t size, Component* array);
 	Id					find_component(uint32_t index, uint32_t size, Component* array);
+	Id 					find_component_by_index(StringId32 name, uint32_t size, Component* array);
 
 	void				add_camera(StringId32 name, CameraId camera);
 	void				add_mesh(StringId32 name, MeshId mesh);
@@ -132,6 +133,7 @@ struct Unit
 
 	Actor*				actor(const char* name);
 	Actor*				actor(uint32_t i);
+	Actor*				actor_by_index(StringId32 name);
 
 	Material*			material(const char* name);
 	Material*			material(uint32_t i);