Просмотр исходного кода

Add global.physics_config resource

Daniele Bartolini 12 лет назад
Родитель
Сommit
e9c4e845eb

+ 12 - 9
engine/Device.cpp

@@ -100,8 +100,6 @@ Device::Device()
 	, m_resource_bundle(NULL)
 
 	, m_world_manager(NULL)
-
-	, m_renderer_init_request(false)
 {
 	// Bundle dir is current dir by default.
 	string::strncpy(m_bundle_dir, os::get_cwd(), MAX_PATH_LENGTH);
@@ -186,6 +184,9 @@ void Device::init()
 	Log::d("Crown Engine initialized.");
 	Log::d("Initializing Game...");
 
+	m_physics_config = m_resource_manager->load(PHYSICS_CONFIG_EXTENSION, "global");
+	m_resource_manager->flush();
+
 	m_is_init = true;
 	start();
 
@@ -213,13 +214,15 @@ void Device::shutdown()
 	// Shutdowns the game
 	m_lua_environment->call_global("shutdown", 0);
 
+	m_resource_manager->unload(m_physics_config);
+
 	Log::d("Releasing audio...");
 	audio_system::shutdown();
 
-	Log::d("Releasing Physics...");
+	Log::d("Releasing physics...");
 	physics_system::shutdown();
 
-	Log::d("Releasing LuaEnvironment...");
+	Log::d("Releasing lua environment...");
 	if (m_lua_environment)
 	{
 		m_lua_environment->shutdown();
@@ -227,22 +230,22 @@ void Device::shutdown()
 		CE_DELETE(m_allocator, m_lua_environment);
 	}
 
-	Log::d("Releasing Input Devices...");
+	Log::d("Releasing input devices...");
 	CE_DELETE(m_allocator, m_touch);
 	CE_DELETE(m_allocator, m_mouse);
 	CE_DELETE(m_allocator, m_keyboard);
 
-	Log::d("Releasing Renderer...");
+	Log::d("Releasing renderer...");
 	if (m_renderer)
 	{
 		m_renderer->shutdown();
 		CE_DELETE(m_allocator, m_renderer);
 	}
 
-	Log::d("Releasing WorldManager...");
+	Log::d("Releasing world manager...");
 	CE_DELETE(m_allocator, m_world_manager);
 
-	Log::d("Releasing ResourceManager...");
+	Log::d("Releasing resource manager...");
 	if (m_resource_manager)
 	{
 		CE_DELETE(m_allocator, m_resource_manager);
@@ -253,7 +256,7 @@ void Device::shutdown()
 		Bundle::destroy(m_allocator, m_resource_bundle);
 	}
 
-	Log::d("Releasing Filesystem...");
+	Log::d("Releasing filesystem...");
 	if (m_filesystem)
 	{
 		CE_DELETE(m_allocator, m_filesystem);

+ 2 - 2
engine/Device.h

@@ -193,10 +193,10 @@ protected:
 	ConsoleServer*			m_console;
 	ResourceManager*		m_resource_manager;
 	Bundle*					m_resource_bundle;
-
 	WorldManager*			m_world_manager;
 
-	bool 					m_renderer_init_request;
+	// Configuration resources
+	ResourceId				m_physics_config;
 
 private:
 

+ 5 - 0
engine/compilers/BundleCompiler.cpp

@@ -44,6 +44,7 @@ namespace texture_resource { extern void compile(Filesystem&, const char*, File*
 namespace package_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace lua_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace physics_resource { extern void compile(Filesystem&, const char*, File*); }
+namespace physics_config_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace unit_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace sound_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace sprite_resource { extern void compile(Filesystem&, const char*, File*); }
@@ -166,6 +167,10 @@ bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir, con
 			{
 				gui_resource::compile(root_fs, filename, out_file);
 			}
+			else if (resource_type_hash == PHYSICS_CONFIG_TYPE)
+			{
+				physics_config_resource::compile(root_fs, filename, out_file);
+			}
 			else
 			{
 				Log::e("Oops, unknown resource type!");

+ 108 - 167
engine/physics/Actor.cpp

@@ -34,102 +34,73 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "SceneGraph.h"
 #include "PxPhysicsAPI.h"
 
-using physx::PxRigidDynamicFlag;
-using physx::PxMat44;
-using physx::PxTransform;
+#include "Device.h"
+#include "ResourceManager.h"
+
+
 using physx::PxActorFlag;
-using physx::PxVec3;
+using physx::PxActorType;
+using physx::PxBoxGeometry;
+using physx::PxD6Axis;
+using physx::PxD6Joint;
+using physx::PxD6JointCreate;
+using physx::PxD6Motion;
+using physx::PxFilterData;
+using physx::PxForceMode;
+using physx::PxMat44;
+using physx::PxPlaneGeometry;
 using physx::PxReal;
 using physx::PxRigidActor;
 using physx::PxRigidBody;
+using physx::PxRigidBodyExt;
 using physx::PxRigidDynamic;
+using physx::PxRigidDynamicFlag;
 using physx::PxRigidStatic;
-using physx::PxPlaneGeometry;
-using physx::PxSphereGeometry;
-using physx::PxBoxGeometry;
-using physx::PxRigidBodyExt;
 using physx::PxShape;
 using physx::PxShapeFlag;
+using physx::PxSphereGeometry;
+using physx::PxTransform;
 using physx::PxU32;
-using physx::PxFilterData;
-using physx::PxForceMode;
-
-using physx::PxD6Joint;
-using physx::PxD6JointCreate;
-using physx::PxD6Axis;
-using physx::PxD6Motion;
-
+using physx::PxVec3;
 
 namespace crown
 {
 
 //-----------------------------------------------------------------------------
-Actor::Actor(const PhysicsResource* res, uint32_t index, PxPhysics* physics, PxScene* scene, SceneGraph& sg, int32_t node, const Vector3& pos, const Quaternion& rot)
+Actor::Actor(const PhysicsResource* res, const PhysicsConfigResource* config, uint32_t index, PxPhysics* physics, PxScene* scene, SceneGraph& sg, int32_t node, const Vector3& pos, const Quaternion& rot)
 	: m_resource(res)
+	, m_config(config)
 	, m_index(index)
 	, m_scene(scene)
 	, m_scene_graph(sg)
 	, m_node(node)
 {
-	const PhysicsActor& a = m_resource->actor(m_index);
+	const PhysicsActor& actor = m_resource->actor(m_index);
+	const PhysicsActor2& actor_class = config->actor(actor.actor_class);
 
-	// Creates actor
-	Matrix4x4 m = sg.world_pose(node);
-	PxMat44 pose((PxReal*)(m.to_float_ptr()));
+	const PxMat44 pose((PxReal*) (sg.world_pose(node).to_float_ptr()));
 
-	switch (a.type)
+	if (actor_class.flags & PhysicsActor2::DYNAMIC)
 	{
-		case ActorType::STATIC:
+		m_actor = physics->createRigidDynamic(PxTransform(pose));
+		if (actor_class.flags & PhysicsActor2::KINEMATIC)
 		{
-			m_actor = physics->createRigidStatic(PxTransform(pose));
-			break;
+			static_cast<PxRigidDynamic*>(m_actor)->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, true);
 		}
-		case ActorType::DYNAMIC_PHYSICAL:
-		case ActorType::DYNAMIC_KINEMATIC:
-		{
-			m_actor = physics->createRigidDynamic(PxTransform(pose));
-
-			if (a.type == ActorType::DYNAMIC_KINEMATIC)
-			{
-				static_cast<PxRigidDynamic*>(m_actor)->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, true);
-			}
-			//PxRigidBodyExt::setMassAndUpdateInertia(*static_cast<PxRigidDynamic*>(m_actor), 500.0f);
 
-			PxD6Joint* joint = PxD6JointCreate(*physics, m_actor, PxTransform(pose), NULL, PxTransform(pose));
-			joint->setMotion(PxD6Axis::eX, PxD6Motion::eFREE);
-			joint->setMotion(PxD6Axis::eY, PxD6Motion::eFREE);
-			//joint->setMotion(PxD6Axis::eZ, PxD6Motion::eFREE);
-			//joint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE);
-			joint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE);
-
-			break;
-		}
-		default:
-		{
-			CE_FATAL("Oops, unknown actor type");
-			break;
-		}
+		PxD6Joint* joint = PxD6JointCreate(*physics, m_actor, PxTransform(pose), NULL, PxTransform(pose));
+		joint->setMotion(PxD6Axis::eX, PxD6Motion::eFREE);
+		joint->setMotion(PxD6Axis::eY, PxD6Motion::eFREE);
+		joint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE);
 	}
-
-	m_actor->userData = this;
-
-	// Creates material
-	m_mat = physics->createMaterial(a.static_friction, a.dynamic_friction, a.restitution);
-
-	// Creates shapes
-	uint32_t shape_index = m_resource->shape_index(m_index);
-	for (uint32_t i = 0; i < a.num_shapes; i++)
+	else
 	{
-		const PhysicsShape& shape = m_resource->shape(shape_index);
-		Vector3 pos = sg.world_position(node);
-
-		create_shape(pos, shape);
-
-		shape_index++;
+		m_actor = physics->createRigidStatic(PxTransform(pose));
 	}
 
-	m_group = a.group;
-	m_mask = a.mask;
+	m_actor->userData = this;
+
+	create_shapes(res, config, physics);
 
 	// FIXME collisions works only if enable_collision() is called here first
 	// collision enabled by default
@@ -150,39 +121,56 @@ Actor::~Actor()
 }
 
 //-----------------------------------------------------------------------------
-void Actor::create_shape(const Vector3& position, const PhysicsShape& s)
+void Actor::create_shapes(const PhysicsResource* res, const PhysicsConfigResource* config, PxPhysics* physics)
 {
-	PxShape* shape;
-
-	switch(s.type)
+	const PhysicsActor& actor = m_resource->actor(m_index);
+	uint32_t shape_index = m_resource->shape_index(m_index);
+	for (uint32_t i = 0; i < actor.num_shapes; i++)
 	{
-		case PhysicsShapeType::SPHERE:
-		{
-			shape = m_actor->createShape(PxSphereGeometry(s.data_0), *m_mat);
-			break;
-		}
-		case PhysicsShapeType::BOX:
-		{
-			shape = m_actor->createShape(PxBoxGeometry(s.data_0, s.data_1, s.data_2), *m_mat);
-			break;
-		}
-		case PhysicsShapeType::PLANE:
+		const PhysicsShape& shape = m_resource->shape(shape_index);
+		const PhysicsShape2& shape_class = config->shape(shape.shape_class);
+		const PhysicsMaterial& material = config->material(shape.material);
+
+		PxMaterial* mat = physics->createMaterial(material.static_friction, material.dynamic_friction, material.restitution);
+
+		PxShape* px_shape = NULL;
+		switch(shape.type)
 		{
-			// FIXME
-			shape = m_actor->createShape(PxPlaneGeometry(), *m_mat);
-			break;
+			case PhysicsShapeType::SPHERE:
+			{
+				px_shape = m_actor->createShape(PxSphereGeometry(shape.data_0), *mat);
+				break;
+			}
+			case PhysicsShapeType::BOX:
+			{
+				px_shape = m_actor->createShape(PxBoxGeometry(shape.data_0, shape.data_1, shape.data_2), *mat);
+				break;
+			}
+			case PhysicsShapeType::PLANE:
+			{
+				// FIXME
+				px_shape = m_actor->createShape(PxPlaneGeometry(), *mat);
+				break;
+			}
+			default:
+			{
+				CE_FATAL("Oops, unknown shape type");
+			}
 		}
-		default:
+
+		if (shape_class.trigger)
 		{
-			CE_FATAL("Oops, unknown shape type");
+			px_shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
+			px_shape->setFlag(PxShapeFlag::eTRIGGER_SHAPE, true);		
 		}
-	}
 
-	if (s.trigger)
-	{
-		shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
-		shape->setFlag(PxShapeFlag::eTRIGGER_SHAPE, true);		
+		shape_index++;
 	}
+
+	// PxFilterData filter;
+	// filter.word0 = (PxU32) m_group;
+	// filter.word1 = (PxU32) m_mask;
+	// shape->SetSimulationFilterData()
 }
 
 //-----------------------------------------------------------------------------
@@ -200,43 +188,43 @@ void Actor::disable_gravity()
 //-----------------------------------------------------------------------------
 void Actor::enable_collision()
 {
-	PxFilterData filter_data;
-	filter_data.word0 = (PxU32) m_group;
-	filter_data.word1 = (PxU32) m_mask;
+	// PxFilterData filter_data;
+	// filter_data.word0 = (PxU32) m_group;
+	// filter_data.word1 = (PxU32) m_mask;
 
-	const PxU32 num_shapes = m_actor->getNbShapes();
+	// const PxU32 num_shapes = m_actor->getNbShapes();
 
-	PxShape** shapes = (PxShape**) default_allocator().allocate((sizeof(PxShape*) * num_shapes));
-	m_actor->getShapes(shapes, num_shapes);
+	// PxShape** shapes = (PxShape**) default_allocator().allocate((sizeof(PxShape*) * num_shapes));
+	// m_actor->getShapes(shapes, num_shapes);
 
-	for(PxU32 i = 0; i < num_shapes; i++)
-	{
-		PxShape* shape = shapes[i];
-		shape->setSimulationFilterData(filter_data);
-	}
+	// for(PxU32 i = 0; i < num_shapes; i++)
+	// {
+	// 	PxShape* shape = shapes[i];
+	// 	shape->setSimulationFilterData(filter_data);
+	// }
 
-	default_allocator().deallocate(shapes);
+	// default_allocator().deallocate(shapes);
 }
 
 //-----------------------------------------------------------------------------
 void Actor::disable_collision()
 {
-	PxFilterData filter_data;
-	filter_data.word0 = (PxU32) CollisionGroup::GROUP_0;
-	filter_data.word1 = (PxU32) CollisionGroup::GROUP_0;
+	// PxFilterData filter_data;
+	// filter_data.word0 = (PxU32) CollisionGroup::GROUP_0;
+	// filter_data.word1 = (PxU32) CollisionGroup::GROUP_0;
 
-	const PxU32 num_shapes = m_actor->getNbShapes();
+	// const PxU32 num_shapes = m_actor->getNbShapes();
 
-	PxShape** shapes = (PxShape**) default_allocator().allocate((sizeof(PxShape*) * num_shapes));
-	m_actor->getShapes(shapes, num_shapes);
+	// PxShape** shapes = (PxShape**) default_allocator().allocate((sizeof(PxShape*) * num_shapes));
+	// m_actor->getShapes(shapes, num_shapes);
 
-	for(PxU32 i = 0; i < num_shapes; i++)
-	{
-		PxShape* shape = shapes[i];
-		shape->setSimulationFilterData(filter_data);
-	}
+	// for(PxU32 i = 0; i < num_shapes; i++)
+	// {
+	// 	PxShape* shape = shapes[i];
+	// 	shape->setSimulationFilterData(filter_data);
+	// }
 
-	default_allocator().deallocate(shapes);	
+	// default_allocator().deallocate(shapes);	
 }
 
 //-----------------------------------------------------------------------------
@@ -254,33 +242,20 @@ void Actor::clear_kinematic()
 //-----------------------------------------------------------------------------
 bool Actor::is_static() const
 {
-	const PhysicsActor& a = m_resource->actor(m_index);
-
-	return a.type == ActorType::STATIC;
+	return m_actor->getType() & PxActorType::eRIGID_STATIC;
 }
 
 //-----------------------------------------------------------------------------
 bool Actor::is_dynamic() const
 {
-	const PhysicsActor& a = m_resource->actor(m_index);
-
-	return a.type == ActorType::DYNAMIC_PHYSICAL || a.type == ActorType::DYNAMIC_KINEMATIC;
+	return m_actor->getType() & PxActorType::eRIGID_DYNAMIC;
 }
 
 //-----------------------------------------------------------------------------
 bool Actor::is_kinematic() const
 {
-	const PhysicsActor& a = m_resource->actor(m_index);
-
-	return a.type == ActorType::DYNAMIC_KINEMATIC;
-}
-
-//-----------------------------------------------------------------------------
-bool Actor::is_physical() const
-{
-	const PhysicsActor& a = m_resource->actor(m_index);
-
-	return a.type == ActorType::DYNAMIC_PHYSICAL;
+	if (!is_dynamic()) return false;
+	return static_cast<PxRigidDynamic*>(m_actor)->getRigidDynamicFlags() & PxRigidDynamicFlag::eKINEMATIC;
 }
 
 //-----------------------------------------------------------------------------
@@ -393,44 +368,10 @@ StringId32 Actor::name()
 	return a.name;
 }
 
-//-----------------------------------------------------------------------------
-void Actor::update_pose()
-{
-	// Read world pose
-	Matrix4x4 wp = m_scene_graph.world_pose(m_node);
-	const PxMat44 pose((PxReal*) (wp.to_float_ptr()));
-	const PxTransform world_transform(pose);
-
-	const PhysicsActor& a = m_resource->actor(m_index);
-
-	switch (a.type)
-	{
-		case ActorType::STATIC:
-		{
-			// m_actor->setGlobalPose(world_transform);
-		}
-		case ActorType::DYNAMIC_PHYSICAL:
-		{
-			break;
-		}
-		case ActorType::DYNAMIC_KINEMATIC:
-		{
-			static_cast<PxRigidDynamic*>(m_actor)->setKinematicTarget(world_transform);
-			break;
-		}
-		default: break;
-	}
-}
-
 //-----------------------------------------------------------------------------
 void Actor::update(const Matrix4x4& pose)
 {
-	const PhysicsActor& a = m_resource->actor(m_index);
-
-	if (a.type == ActorType::DYNAMIC_PHYSICAL)
-	{
-		m_scene_graph.set_world_pose(m_node, pose);
-	}
+	m_scene_graph.set_world_pose(m_node, pose);
 }
 
 } // namespace crown

+ 4 - 7
engine/physics/Actor.h

@@ -46,15 +46,15 @@ namespace crown
 {
 
 struct PhysicsResource;
+struct PhysicsConfigResource;
 struct Quaternion;
 struct Matrix4x4;
 struct Unit;
-struct PhysicsShape;
 class SceneGraph;
 
 struct Actor
 {
-						Actor(const PhysicsResource* res, uint32_t index, PxPhysics* physics, PxScene* scene, SceneGraph& sg, int32_t node, const Vector3& pos, const Quaternion& rot);
+						Actor(const PhysicsResource* res, const PhysicsConfigResource* config, uint32_t index, PxPhysics* physics, PxScene* scene, SceneGraph& sg, int32_t node, const Vector3& pos, const Quaternion& rot);
 						~Actor();
 
 	void				enable_gravity();
@@ -68,9 +68,7 @@ struct Actor
 
 	bool				is_static() const;
 	bool				is_dynamic() const;
-
 	bool				is_kinematic() const;
-	bool				is_physical() const;
 
 	float				linear_damping() const;
 	void				set_linear_damping(float rate);
@@ -93,23 +91,22 @@ struct Actor
 
 	StringId32			name();
 
-	void				update_pose();
 	void				update(const Matrix4x4& pose);
 
 private:
 
-	void				create_shape(const Vector3& position, const PhysicsShape& s);
+	void				create_shapes(const PhysicsResource* res, const PhysicsConfigResource* config, PxPhysics* physics);
 	
 public:
 
 	const PhysicsResource*	m_resource;
+	const PhysicsConfigResource* m_config;
 	uint32_t				m_index;
 
 	PxScene*				m_scene;
 	SceneGraph&				m_scene_graph;
 	int32_t					m_node;
 	PxRigidActor* 			m_actor;
-	PxMaterial* 			m_mat;
 	uint32_t				m_group;
 	uint32_t				m_mask;
 };

+ 7 - 13
engine/physics/PhysicsWorld.cpp

@@ -38,6 +38,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Hash.h"
 #include "StringUtils.h"
 #include "Actor.h"
+#include "ResourceManager.h"
 
 #include "PxPhysicsAPI.h"
 
@@ -245,7 +246,8 @@ PhysicsWorld::~PhysicsWorld()
 //-----------------------------------------------------------------------------
 ActorId	PhysicsWorld::create_actor(const PhysicsResource* res, const uint32_t index, SceneGraph& sg, int32_t node)
 {
-	Actor* actor = CE_NEW(m_actors_pool, Actor)(res, index, physics_system::s_physics, m_scene, sg, node, Vector3::ZERO, Quaternion::IDENTITY);
+	PhysicsConfigResource* config = (PhysicsConfigResource*) device()->resource_manager()->lookup("physics_config", "global");
+	Actor* actor = CE_NEW(m_actors_pool, Actor)(res, config, index, physics_system::s_physics, m_scene, sg, node, Vector3::ZERO, Quaternion::IDENTITY);
 	return m_actors.create(actor);
 }
 
@@ -367,16 +369,9 @@ void PhysicsWorld::clear_kinematic(ActorId id)
 	actor->clear_kinematic();
 }
 
-
 //-----------------------------------------------------------------------------
 void PhysicsWorld::update(float dt)
 {
-	// Update world pose of the actors
-	for (uint32_t i = 0; i < m_actors.size(); i++)
-	{
-		m_actors[i]->update_pose();
-	}
-
 	// Run with fixed timestep
 	m_scene->simulate(1.0 / 60.0);
 
@@ -389,15 +384,14 @@ void PhysicsWorld::update(float dt)
 	// Update each actor with its new transform
 	for (PxU32 i = 0; i < num_active_transforms; i++)
 	{
+		// Actors with userData == NULL are controllers
+		if (active_transforms[i].userData == NULL) continue;
+
 		const PxTransform tr = active_transforms[i].actor2World;
 		const Vector3 pos(tr.p.x, tr.p.y, tr.p.z);
 		const Quaternion rot(tr.q.x, tr.q.y, tr.q.z, tr.q.w);
 
-		Actor* actor = static_cast<Actor*>(active_transforms[i].userData);
-		if (actor != NULL)
-		{
-			actor->update(Matrix4x4(rot, pos));
-		}
+		static_cast<Actor*>(active_transforms[i].userData)->update(Matrix4x4(rot, pos));
 	}
 
 	// Update controllers

+ 424 - 211
engine/resource/PhysicsResource.cpp

@@ -24,6 +24,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
+#include <algorithm>
 #include "Allocator.h"
 #include "Filesystem.h"
 #include "Hash.h"
@@ -37,55 +38,6 @@ namespace crown
 namespace physics_resource
 {
 
-//-----------------------------------------------------------------------------
-static uint32_t actor_type_to_enum(const char* type)
-{
-	if (string::strcmp("static", type) == 0) return PhysicsActorType::STATIC;
-	else if (string::strcmp("dynamic_physical", type) == 0) return PhysicsActorType::DYNAMIC_PHYSICAL;
-	else if (string::strcmp("dynamic_kinematic", type) == 0) return PhysicsActorType::DYNAMIC_KINEMATIC;
-
-	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;
-	if (string::strcmp("GROUP_1", group) == 0) 	return PhysicsActorGroup::GROUP_1;
-	if (string::strcmp("GROUP_2", group) == 0) 	return PhysicsActorGroup::GROUP_2;
-	if (string::strcmp("GROUP_3", group) == 0) 	return PhysicsActorGroup::GROUP_3;
-	if (string::strcmp("GROUP_4", group) == 0) 	return PhysicsActorGroup::GROUP_4;
-	if (string::strcmp("GROUP_5", group) == 0) 	return PhysicsActorGroup::GROUP_5;
-	if (string::strcmp("GROUP_6", group) == 0) 	return PhysicsActorGroup::GROUP_6;
-	if (string::strcmp("GROUP_7", group) == 0) 	return PhysicsActorGroup::GROUP_7;
-	if (string::strcmp("GROUP_8", group) == 0) 	return PhysicsActorGroup::GROUP_8;
-	if (string::strcmp("GROUP_9", group) == 0) 	return PhysicsActorGroup::GROUP_9;
-	if (string::strcmp("GROUP_10", group) == 0) return PhysicsActorGroup::GROUP_10;
-	if (string::strcmp("GROUP_11", group) == 0) return PhysicsActorGroup::GROUP_11;
-	if (string::strcmp("GROUP_12", group) == 0) return PhysicsActorGroup::GROUP_12;
-	if (string::strcmp("GROUP_13", group) == 0) return PhysicsActorGroup::GROUP_13;
-	if (string::strcmp("GROUP_14", group) == 0) return PhysicsActorGroup::GROUP_14;
-	if (string::strcmp("GROUP_15", group) == 0) return PhysicsActorGroup::GROUP_15;
-	if (string::strcmp("GROUP_16", group) == 0) return PhysicsActorGroup::GROUP_16;
-	if (string::strcmp("GROUP_17", group) == 0) return PhysicsActorGroup::GROUP_17;
-	if (string::strcmp("GROUP_18", group) == 0) return PhysicsActorGroup::GROUP_18;
-	if (string::strcmp("GROUP_19", group) == 0) return PhysicsActorGroup::GROUP_19;
-	if (string::strcmp("GROUP_20", group) == 0) return PhysicsActorGroup::GROUP_20;
-	if (string::strcmp("GROUP_21", group) == 0) return PhysicsActorGroup::GROUP_21;
-	if (string::strcmp("GROUP_22", group) == 0) return PhysicsActorGroup::GROUP_22;
-	if (string::strcmp("GROUP_23", group) == 0) return PhysicsActorGroup::GROUP_23;
-	if (string::strcmp("GROUP_24", group) == 0) return PhysicsActorGroup::GROUP_24;
-	if (string::strcmp("GROUP_25", group) == 0) return PhysicsActorGroup::GROUP_25;
-	if (string::strcmp("GROUP_26", group) == 0) return PhysicsActorGroup::GROUP_26;
-	if (string::strcmp("GROUP_27", group) == 0) return PhysicsActorGroup::GROUP_27;
-	if (string::strcmp("GROUP_28", group) == 0) return PhysicsActorGroup::GROUP_28;
-	if (string::strcmp("GROUP_29", group) == 0) return PhysicsActorGroup::GROUP_29;
-	if (string::strcmp("GROUP_30", group) == 0) return PhysicsActorGroup::GROUP_30;
-	if (string::strcmp("GROUP_31", group) == 0) return PhysicsActorGroup::GROUP_31;
-
-	CE_FATAL("Bad actor group");
-}
-
 //-----------------------------------------------------------------------------
 static uint32_t shape_type_to_enum(const char* type)
 {
@@ -95,6 +47,7 @@ static uint32_t shape_type_to_enum(const char* type)
 	else if (string::strcmp("plane", type) == 0) 	return PhysicsShapeType::PLANE;
 
 	CE_FATAL("Bad shape type");
+	return 0;
 }
 
 //-----------------------------------------------------------------------------
@@ -105,171 +58,154 @@ static uint32_t joint_type_to_enum(const char* type)
 	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;	
+	else if (string::strcmp("d6", type) == 0) 			return PhysicsJointType::D6;
 
 	CE_FATAL("Bad joint type");
+	return 0;
 }
 
 //-----------------------------------------------------------------------------
 void parse_controller(JSONElement e, PhysicsController& controller)
 {
-	JSONElement name = e.key("name");
-	JSONElement height = e.key("height");
-	JSONElement radius = e.key("radius");
-	JSONElement slope_limit = e.key("slope_limit");
-	JSONElement step_offset = e.key("step_offset");
-	JSONElement contact_offset = e.key("contact_offset");
-
-	DynamicString contr_name;
-	name.string_value(contr_name);
-	controller.name = hash::murmur2_32(contr_name.c_str(), contr_name.length());
+	JSONElement name 				= e.key("name");
+	JSONElement height 				= e.key("height");
+	JSONElement radius 				= e.key("radius");
+	JSONElement slope_limit 		= e.key("slope_limit");
+	JSONElement step_offset 		= e.key("step_offset");
+	JSONElement contact_offset 		= e.key("contact_offset");
+	JSONElement collision_filter 	= e.key("collision_filter");
+
+	controller.name = name.string_id_value();
 	controller.height = height.float_value();
 	controller.radius = radius.float_value();
 	controller.slope_limit = slope_limit.float_value();
 	controller.step_offset = step_offset.float_value();
 	controller.contact_offset = contact_offset.float_value();
+	controller.collision_filter = collision_filter.string_id_value();
 }
 
 //-----------------------------------------------------------------------------
-void parse_shape(JSONElement e, PhysicsShape& shape)
+void parse_shapes(JSONElement e, List<PhysicsShape>& shapes)
 {
-	JSONElement name = e.key("name");
-	JSONElement type = e.key("type");
-	JSONElement trigger = e.key("trigger");
+	Vector<DynamicString> keys(default_allocator());
+	e.key_value(keys);
 
-	DynamicString shape_name;
-	DynamicString shape_type;
-	name.string_value(shape_name);
-	type.string_value(shape_type);
+	for (uint32_t k = 0; k < keys.size(); k++)
+	{
+		JSONElement shape 		= e.key(keys[k].c_str());
+		JSONElement clasz		= shape.key("class");
+		JSONElement type		= shape.key("type");
+		JSONElement material	= shape.key("material");
 
-	shape.name = hash::murmur2_32(shape_name.c_str(), shape_name.length());
-	shape.type = shape_type_to_enum(shape_type.c_str());
-	shape.trigger = trigger.bool_value();
+		PhysicsShape ps;
+		ps.name = keys[k].to_string_id();
+		ps.shape_class = clasz.string_id_value();
+		ps.material = material.string_id_value();
+		DynamicString stype; type.string_value(stype);
+		ps.type = shape_type_to_enum(stype.c_str());
 
-	switch (shape.type)
-	{
-		case PhysicsShapeType::SPHERE:
+		switch (ps.type)
 		{
-			JSONElement radius = e.key("radius");
-			shape.data_0 = radius.float_value();
-			break;
-		}
-		case PhysicsShapeType::CAPSULE:
-		{
-			// TODO
-			break;
-		}
-		case PhysicsShapeType::BOX:
-		{
-			JSONElement half_x = e.key("half_x");
-			JSONElement half_y = e.key("half_y");
-			JSONElement half_z = e.key("half_z");
+			case PhysicsShapeType::SPHERE:
+			{
+				JSONElement radius = shape.key("radius");
+				ps.data_0 = radius.float_value();
+				break;
+			}
+			case PhysicsShapeType::CAPSULE:
+			{
+				// TODO
+				break;
+			}
+			case PhysicsShapeType::BOX:
+			{
+				JSONElement half_x = shape.key("half_x");
+				JSONElement half_y = shape.key("half_y");
+				JSONElement half_z = shape.key("half_z");
 
-			shape.data_0 = half_x.float_value();
-			shape.data_1 = half_y.float_value();
-			shape.data_2 = half_z.float_value();
+				ps.data_0 = half_x.float_value();
+				ps.data_1 = half_y.float_value();
+				ps.data_2 = half_z.float_value();
 
-			break;
-		}
-		case PhysicsShapeType::PLANE:
-		{
-			// TODO
-			break;
+				break;
+			}
+			case PhysicsShapeType::PLANE:
+			{
+				// TODO
+				break;
+			}
 		}
+
+		shapes.push_back(ps);
 	}
 }
 
 //-----------------------------------------------------------------------------
-void parse_actor(JSONElement e, PhysicsActor& actor, List<PhysicsShape>& actor_shapes)
+void parse_actors(JSONElement e, List<PhysicsActor>& actors, List<PhysicsShape>& actor_shapes, List<uint32_t>& shape_indices)
 {
-	JSONElement name = e.key("name");
-	JSONElement node = e.key("node");
-	JSONElement type = e.key("type");
-	JSONElement material = e.key("material");
-	JSONElement group = e.key("group");
-	JSONElement mask = e.key("mask");
-	JSONElement shapes = e.key("shapes");
-
-	DynamicString actor_name;
-	DynamicString actor_node;
-	DynamicString actor_type;
-	List<float> actor_material(default_allocator());
-	DynamicString actor_group;
-	Vector<DynamicString> actor_mask(default_allocator());
-	name.string_value(actor_name);
-	node.string_value(actor_node);
-	type.string_value(actor_type);
-	material.array_value(actor_material);
-	group.string_value(actor_group);
-	mask.array_value(actor_mask);
-
-	memset(&actor, 0, sizeof(PhysicsActor));
-	actor.name = hash::murmur2_32(actor_name.c_str(), actor_name.length());
-	actor.node = hash::murmur2_32(actor_node.c_str(), actor_node.length());
-	actor.type = actor_type_to_enum(actor_type.c_str());
-	actor.static_friction = actor_material[0];
-	actor.dynamic_friction = actor_material[1];
-	actor.restitution = actor_material[2];
-	actor.group = actor_group_to_enum(actor_group.c_str());
-	for (uint32_t i = 0; i < actor_mask.size(); i++)
+	Vector<DynamicString> keys(default_allocator());
+	e.key_value(keys);
+
+	for (uint32_t k = 0; k < keys.size(); k++)
 	{
-		actor.mask |= actor_group_to_enum(actor_mask[i].c_str());
-	}
+		JSONElement actor 	= e.key(keys[k].c_str());
+		JSONElement node 	= actor.key("node");
+		JSONElement clasz	= actor.key("class");
+		JSONElement shapes	= actor.key("shapes");
 
-	actor.num_shapes = shapes.size();
+		PhysicsActor pa;
+		pa.name = keys[k].to_string_id();
+		pa.node = node.string_id_value();
+		pa.actor_class = clasz.string_id_value();
+		pa.num_shapes = shapes.size();
 
-	for (uint32_t i = 0; i < actor.num_shapes; i++)
-	{
-		PhysicsShape ps;
-		parse_shape(shapes[i], ps);
-		actor_shapes.push_back(ps);
+		actors.push_back(pa);
+		shape_indices.push_back(shape_indices.size());
+
+		parse_shapes(shapes, actor_shapes);
 	}
 }
 
 //-----------------------------------------------------------------------------
-void parse_joint(JSONElement e, PhysicsJoint& joint)
+void parse_joints(JSONElement e, List<PhysicsJoint>& joints)
 {
-	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 anchor_0 = e.key("anchor_0");
-	JSONElement anchor_1 = e.key("anchor_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;
-	List<float> joint_anchor_0(default_allocator());
-	List<float> joint_anchor_1(default_allocator());
-	
-	name.string_value(joint_name);
-	type.string_value(joint_type);
-	actor_0.string_value(joint_actor_0);
-	actor_1.string_value(joint_actor_1);
-	anchor_0.array_value(joint_anchor_0);
-	anchor_1.array_value(joint_anchor_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.anchor_0 = Vector3(joint_anchor_0.begin());
-	joint.anchor_1 = Vector3(joint_anchor_1.begin());
-	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();
+	Vector<DynamicString> keys(default_allocator());
+	e.key_value(keys);
+
+	for (uint32_t k = 0; k < keys.size(); k++)
+	{
+		JSONElement joint			= e.key(keys[k].c_str());
+		JSONElement type 			= joint.key("type");
+		JSONElement actor_0 		= joint.key("actor_0");
+		JSONElement actor_1 		= joint.key("actor_1");
+		JSONElement anchor_0 		= joint.key("anchor_0");
+		JSONElement anchor_1 		= joint.key("anchor_1");
+		JSONElement restitution 	= joint.key_or_nil("restitution");
+		JSONElement spring 			= joint.key_or_nil("spring");
+		JSONElement damping 		= joint.key_or_nil("damping");
+		JSONElement distance 		= joint.key_or_nil("distance");
+		JSONElement breakable 		= joint.key_or_nil("breakable");
+		JSONElement break_force 	= joint.key_or_nil("break_force");
+		JSONElement break_torque	= joint.key_or_nil("break_torque");
+
+		PhysicsJoint pj;
+		pj.name = keys[k].to_string_id();
+		DynamicString jtype; type.string_value(jtype);
+		pj.type = joint_type_to_enum(jtype.c_str());
+		pj.actor_0 = actor_0.string_id_value();
+		pj.actor_1 = actor_1.string_id_value();
+		pj.anchor_0 = Vector3(anchor_0[0].float_value(), anchor_0[1].float_value(), anchor_0[2].float_value());
+		pj.anchor_1 = Vector3(anchor_1[0].float_value(), anchor_1[1].float_value(), anchor_1[2].float_value());
+		pj.restitution = restitution.is_nil() 	? 0.5 : restitution.float_value();
+		pj.spring = spring.is_nil() 			? 100.0 : spring.float_value();
+		pj.damping = damping.is_nil() 			? 0.0 : damping.float_value();
+		pj.distance = distance.is_nil() 		? 1.0 : distance.float_value();
+		pj.breakable = breakable.is_nil() 		? false : breakable.bool_value();
+		pj.break_force = break_force.is_nil() 	? 3000.0 : break_force.float_value();
+		pj.break_torque = break_torque.is_nil() ? 1000.0 : break_torque.float_value();
+
+		joints.push_back(pj);
+	}
 }
 
 //-----------------------------------------------------------------------------
@@ -297,42 +233,13 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 		m_has_controller = true;
 	}
 
-	// Read actors
 	List<PhysicsActor> m_actors(default_allocator());
 	List<uint32_t> m_shapes_indices(default_allocator());
 	List<PhysicsShape> m_shapes(default_allocator());
-	JSONElement actors = root.key_or_nil("actors");
-	if (!actors.is_nil())
-	{
-		for (uint32_t i = 0; i < actors.size(); i++)
-		{
-			if (m_shapes.size() == 0)
-			{
-				m_shapes_indices.push_back(0);
-			}
-			else
-			{
-				m_shapes_indices.push_back(m_shapes.size());
-			}
-
-			PhysicsActor a;
-			parse_actor(actors[i], a, m_shapes);
-			m_actors.push_back(a);
-		}
-	}
-
-	// 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);
-		}
-	}
+
+	if (root.has_key("actors")) parse_actors(root.key("actors"), m_actors, m_shapes, m_shapes_indices);
+	if (root.has_key("joints")) parse_joints(root.key("joints"), m_joints);
 
 	fs.close(file);
 	default_allocator().deallocate(buf);
@@ -379,6 +286,312 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 		out_file->write((char*) m_joints.begin(), sizeof(PhysicsJoint) * m_joints.size());
 	}
 }
-
 } // namespace physics_resource
+
+namespace physics_config_resource
+{
+	struct ObjectName
+	{
+		StringId32 name;
+		uint32_t index;
+
+		bool operator()(const ObjectName& a, const ObjectName& b)
+		{
+			return a.name < b.name;
+		}
+	};
+
+	struct NameToMask
+	{
+		StringId32 name;
+		uint32_t mask;
+	};
+
+	uint32_t collides_with_to_mask(Vector<DynamicString>& collides_with, List<NameToMask>& name_to_mask)
+	{
+		uint32_t mask = 0;
+
+		for (uint32_t i = 0; i < collides_with.size(); i++)
+		{
+			StringId32 cur_name = collides_with[i].to_string_id();
+			for (uint32_t j = 0; j < name_to_mask.size(); j++)
+			{
+				if (cur_name == name_to_mask[j].name) mask |= name_to_mask[j].mask;
+			}
+		}
+
+		return mask;
+	}
+
+	uint32_t collision_filter_to_mask(const char* filter, List<NameToMask> name_to_mask)
+	{
+		StringId32 filter_hash = hash::murmur2_32(filter, string::strlen(filter));
+		for (uint32_t i = 0; i < name_to_mask.size(); i++)
+		{
+			if (name_to_mask[i].name == filter_hash) return name_to_mask[i].mask;
+		}
+
+		CE_ASSERT(false, "Collision filter '%s' not found", filter);
+		return 0;
+	}
+
+	void parse_materials(JSONElement e, List<ObjectName>& names, List<PhysicsMaterial>& objects)
+	{
+		Vector<DynamicString> keys(default_allocator());
+		e.key_value(keys);
+
+		for (uint32_t i = 0; i < keys.size(); i++)
+		{
+			JSONElement material 			= e.key(keys[i].c_str());
+			JSONElement static_friction 	= material.key("static_friction");
+			JSONElement dynamic_friction	= material.key("dynamic_friction");
+			JSONElement restitution			= material.key("restitution");
+
+			// Read material name
+			ObjectName mat_name;
+			mat_name.name = keys[i].to_string_id();
+			mat_name.index = i;
+
+			// Read material object
+			PhysicsMaterial mat;
+			mat.static_friction = static_friction.float_value();
+			mat.dynamic_friction = dynamic_friction.float_value();
+			mat.restitution = restitution.float_value();
+
+			names.push_back(mat_name);
+			objects.push_back(mat);
+		}
+	}
+
+	void parse_shapes(JSONElement e, List<NameToMask>& name_to_mask, List<ObjectName>& names, List<PhysicsShape2>& objects)
+	{
+		Vector<DynamicString> keys(default_allocator());
+		e.key_value(keys);
+
+		for (uint32_t i = 0; i < keys.size(); i++)
+		{
+			JSONElement shape				= e.key(keys[i].c_str());
+			JSONElement collision_filter 	= shape.key("collision_filter");
+			JSONElement trigger				= shape.key("trigger");
+
+			// Read shape name
+			ObjectName shape_name;
+			shape_name.name = keys[i].to_string_id();
+			shape_name.index = i;
+
+			// Read shape object
+			PhysicsShape2 ps2;
+			ps2.trigger = trigger.bool_value();
+			DynamicString cfilter; collision_filter.string_value(cfilter);
+			ps2.collision_filter = collision_filter_to_mask(cfilter.c_str(), name_to_mask);
+
+			names.push_back(shape_name);
+			objects.push_back(ps2);
+		}
+	}
+
+	void parse_actors(JSONElement e, List<ObjectName>& names, List<PhysicsActor2>& objects)
+	{
+		Vector<DynamicString> keys(default_allocator());
+		e.key_value(keys);
+
+		for (uint32_t i = 0; i < keys.size(); i++)
+		{
+			JSONElement actor			= e.key(keys[i].c_str());
+			JSONElement linear_damping	= actor.key_or_nil("linear_damping");
+			JSONElement angular_damping	= actor.key_or_nil("angular_damping");
+			JSONElement dynamic			= actor.key_or_nil("dynamic");
+			JSONElement kinematic		= actor.key_or_nil("kinematic");
+			JSONElement disable_gravity	= actor.key_or_nil("disable_gravity");
+
+			// Read actor name
+			ObjectName actor_name;
+			actor_name.name = keys[i].to_string_id();
+			actor_name.index = i;
+
+			// Read actor object
+			PhysicsActor2 pa2;
+			//actor.collision_filter = coll_filter.to_string_id();
+			pa2.linear_damping = linear_damping.is_nil() ? 0.0 : linear_damping.float_value();
+			pa2.angular_damping = angular_damping.is_nil() ? 0.05 : angular_damping.float_value();
+			pa2.flags = 0;
+			if (!dynamic.is_nil())
+			{
+				pa2.flags |= dynamic.bool_value() ? : 0;
+			}
+			if (!kinematic.is_nil())
+			{
+				pa2.flags |= kinematic.bool_value() ? PhysicsActor2::KINEMATIC : 0;
+			}
+			if (!disable_gravity.is_nil())
+			{
+				pa2.flags |= disable_gravity.bool_value() ? PhysicsActor2::DISABLE_GRAVITY : 0;
+			}
+
+			names.push_back(actor_name);
+			objects.push_back(pa2);
+		}
+	}
+
+	void parse_collision_filters(JSONElement e, List<ObjectName>& names, List<PhysicsCollisionFilter>& objects, List<NameToMask>& name_to_mask)
+	{
+		Vector<DynamicString> keys(default_allocator());
+		e.key_value(keys);
+
+		// Assign a unique mask to each collision filter
+		for (uint32_t i = 0; i < keys.size(); i++)
+		{
+			NameToMask ntm;
+			ntm.name = keys[i].to_string_id();
+			ntm.mask = 1 << i;
+			name_to_mask.push_back(ntm);
+		}
+
+		for (uint32_t i = 0; i < keys.size(); i++)
+		{
+			JSONElement filter			= e.key(keys[i].c_str());
+			JSONElement collides_with	= filter.key("collides_with");
+
+			// Read filter name
+			ObjectName filter_name;
+			filter_name.name = keys[i].to_string_id();
+			filter_name.index = i;
+
+			// Build mask
+			Vector<DynamicString> collides_with_vector(default_allocator());
+			collides_with.array_value(collides_with_vector);
+
+			PhysicsCollisionFilter pcf;
+			pcf.mask = collides_with_to_mask(collides_with_vector, name_to_mask);
+
+			printf("FILTER: %s, mask = %X\n", keys[i].c_str(), pcf.mask);
+
+			names.push_back(filter_name);
+			objects.push_back(pcf);
+		}		
+	}
+
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
+	{
+		File* file = fs.open(resource_path, FOM_READ);
+		char* buf = (char*)default_allocator().allocate(file->size());
+		file->read(buf, file->size());
+
+		JSONParser json(buf);
+		JSONElement root = json.root();
+
+		List<ObjectName> material_names(default_allocator());
+		List<PhysicsMaterial> material_objects(default_allocator());
+		List<ObjectName> shape_names(default_allocator());
+		List<PhysicsShape2> shape_objects(default_allocator());
+		List<ObjectName> actor_names(default_allocator());
+		List<PhysicsActor2> actor_objects(default_allocator());
+		List<ObjectName> filter_names(default_allocator());
+		List<PhysicsCollisionFilter> filter_objects(default_allocator());
+		List<NameToMask> name_to_mask(default_allocator());
+
+		// Parse materials
+		if (root.has_key("collision_filters")) parse_collision_filters(root.key("collision_filters"), filter_names, filter_objects, name_to_mask);
+		if (root.has_key("materials")) parse_materials(root.key("materials"), material_names, material_objects);
+		if (root.has_key("shapes")) parse_shapes(root.key("shapes"), name_to_mask, shape_names, shape_objects);
+		if (root.has_key("actors")) parse_actors(root.key("actors"), actor_names, actor_objects);
+
+		default_allocator().deallocate(buf);
+		fs.close(file);
+
+		// Sort objects by name
+		std::sort(material_names.begin(), material_names.end(), ObjectName());
+		std::sort(shape_names.begin(), shape_names.end(), ObjectName());
+		std::sort(actor_names.begin(), actor_names.end(), ObjectName());
+		std::sort(filter_names.begin(), filter_names.end(), ObjectName());
+
+		// Setup struct for writing
+		PhysicsConfigHeader header;
+		header.num_materials = material_names.size();
+		header.num_shapes = shape_names.size();
+		header.num_actors = actor_names.size();
+		header.num_filters = filter_names.size();
+
+		uint32_t offt = sizeof(PhysicsConfigHeader);
+		header.materials_offset = offt;
+		offt += sizeof(StringId32) * header.num_materials;
+		offt += sizeof(PhysicsMaterial) * header.num_materials;
+
+		header.shapes_offset = offt;
+		offt += sizeof(StringId32) * header.num_shapes;
+		offt += sizeof(PhysicsShape2) * header.num_shapes;
+
+		header.actors_offset = offt;
+		offt += sizeof(StringId32) * header.num_actors;
+		offt += sizeof(PhysicsActor2) * header.num_actors;
+
+		header.filters_offset = offt;
+		offt += sizeof(StringId32) * header.num_filters;
+		offt += sizeof(PhysicsCollisionFilter) * header.num_filters;
+
+		// Write all
+		out_file->write((char*) &header, sizeof(PhysicsConfigHeader));
+
+		if (header.num_materials)
+		{
+			// Write material names
+			for (uint32_t i = 0; i < material_names.size(); i++)
+			{
+				out_file->write((char*) &material_names[i].name, sizeof(StringId32));
+			}
+
+			// Write material objects
+			for (uint32_t i = 0; i < material_names.size(); i++)
+			{
+				out_file->write((char*) &material_objects[material_names[i].index], sizeof(PhysicsMaterial));
+			}
+		}
+
+		if (header.num_shapes)
+		{
+			// Write shape names
+			for (uint32_t i = 0; i < shape_names.size(); i++)
+			{
+				out_file->write((char*) &shape_names[i].name, sizeof(StringId32));
+			}
+
+			// Write material objects
+			for (uint32_t i = 0; i < shape_names.size(); i++)
+			{
+				out_file->write((char*) &shape_objects[shape_names[i].index], sizeof(PhysicsShape2));
+			}
+		}
+
+		if (header.num_actors)
+		{
+			// Write shape names
+			for (uint32_t i = 0; i < actor_names.size(); i++)
+			{
+				out_file->write((char*) &actor_names[i].name, sizeof(StringId32));
+			}
+
+			// Write material objects
+			for (uint32_t i = 0; i < actor_names.size(); i++)
+			{
+				out_file->write((char*) &actor_objects[actor_names[i].index], sizeof(PhysicsActor2));
+			}
+		}
+
+		if (header.num_filters)
+		{
+			// Write shape names
+			for (uint32_t i = 0; i < filter_names.size(); i++)
+			{
+				out_file->write((char*) &filter_names[i].name, sizeof(StringId32));
+			}
+
+			// Write material objects
+			for (uint32_t i = 0; i < filter_names.size(); i++)
+			{
+				out_file->write((char*) &filter_objects[filter_names[i].index], sizeof(PhysicsCollisionFilter));
+			}
+		}
+	}
+
+} // namespace physics_config_resource
 } // namespace crown

+ 180 - 69
engine/resource/PhysicsResource.h

@@ -26,6 +26,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
+#include <algorithm>
 #include "Types.h"
 #include "Allocator.h"
 #include "File.h"
@@ -56,76 +57,21 @@ struct PhysicsHeader
 struct PhysicsController
 {
 	StringId32 name;
-	float height;			// Height of the capsule
-	float radius;			// Radius of the capsule
-	float slope_limit;		// The maximum slope which the character can walk up in radians.
-	float step_offset;		// Maximum height of an obstacle which the character can climb.
-	float contact_offset;	// Skin around the object within which contacts will be generated. Use it to avoid numerical precision issues.
-};
-
-//-----------------------------------------------------------------------------
-struct PhysicsActorType
-{
-	enum Enum
-	{
-		STATIC,
-		DYNAMIC_PHYSICAL,
-		DYNAMIC_KINEMATIC
-	};
-};
-
-//-----------------------------------------------------------------------------
-struct PhysicsActorGroup
-{
-	enum Enum
-	{
-		GROUP_0		= (1<<0),
-		GROUP_1		= (1<<1),
-		GROUP_2		= (1<<2),
-		GROUP_3		= (1<<3),
-		GROUP_4		= (1<<4),
-		GROUP_5		= (1<<5),
-		GROUP_6		= (1<<6),
-		GROUP_7		= (1<<7),
-		GROUP_8		= (1<<8),
-		GROUP_9		= (1<<9),
-		GROUP_10	= (1<<10),
-		GROUP_11	= (1<<11),
-		GROUP_12	= (1<<12),
-		GROUP_13	= (1<<13),
-		GROUP_14	= (1<<14),
-		GROUP_15	= (1<<15),
-		GROUP_16	= (1<<16),
-		GROUP_17	= (1<<17),
-		GROUP_18	= (1<<18),
-		GROUP_19	= (1<<19),
-		GROUP_20	= (1<<20),
-		GROUP_21	= (1<<21),
-		GROUP_22	= (1<<22),
-		GROUP_23	= (1<<23),
-		GROUP_24	= (1<<24),
-		GROUP_25	= (1<<25),
-		GROUP_26	= (1<<26),
-		GROUP_27	= (1<<27),
-		GROUP_28	= (1<<28),
-		GROUP_29	= (1<<29),
-		GROUP_30	= (1<<30),
-		GROUP_31	= (1<<31)
-	};
+	float height;				// Height of the capsule
+	float radius;				// Radius of the capsule
+	float slope_limit;			// The maximum slope which the character can walk up in radians.
+	float step_offset;			// Maximum height of an obstacle which the character can climb.
+	float contact_offset;		// Skin around the object within which contacts will be generated. Use it to avoid numerical precision issues.
+	StringId32 collision_filter;// Collision filter from global.physics_config
 };
 
 //-----------------------------------------------------------------------------
 struct PhysicsActor
 {
-	StringId32 name;
-	StringId32 node;
-	uint32_t type;
-	uint32_t group;
-	uint32_t mask;
-	float static_friction;
-	float dynamic_friction;
-	float restitution;
-	uint32_t num_shapes;
+	StringId32 name;			// Name of the actor
+	StringId32 node;			// Node from .unit file
+	StringId32 actor_class;		// Actor from global.physics
+	uint32_t num_shapes;		// Number of shapes
 };
 
 //-----------------------------------------------------------------------------
@@ -143,10 +89,10 @@ struct PhysicsShapeType
 //-----------------------------------------------------------------------------
 struct PhysicsShape
 {
-	StringId32 name;
-	uint32_t type;
-	bool trigger;
-
+	StringId32 name;			// Name of the shape
+	StringId32 shape_class;		// Shape class from global.physics_config
+	StringId32 type;			// Type of the shape
+	StringId32 material;		// Material from global.physics_config
 	float data_0;
 	float data_1;
 	float data_2;
@@ -305,4 +251,169 @@ private:
 	PhysicsResource();
 };
 
+struct PhysicsConfigHeader
+{
+	uint32_t num_materials;
+	uint32_t materials_offset;
+	uint32_t num_shapes;
+	uint32_t shapes_offset;
+	uint32_t num_actors;
+	uint32_t actors_offset;
+	uint32_t num_filters;
+	uint32_t filters_offset;
+};
+
+struct PhysicsMaterial
+{
+	float static_friction;
+	float dynamic_friction;
+	float restitution;
+	// uint8_t restitution_combine_mode;
+	// uint8_t friction_combine_mode;
+};
+
+struct PhysicsCollisionFilter
+{
+	uint32_t me;
+	uint32_t mask;
+};
+
+struct PhysicsShape2
+{
+	uint32_t collision_filter;
+	bool trigger;
+};
+
+struct PhysicsActor2
+{
+	enum
+	{
+		DYNAMIC			= (1 << 0),
+		KINEMATIC		= (1 << 1),
+		DISABLE_GRAVITY	= (1 << 2)
+	};
+
+	uint32_t collision_filter;
+	float linear_damping;
+	float angular_damping;
+	uint8_t flags;
+};
+
+//-----------------------------------------------------------------------------
+struct PhysicsConfigResource
+{
+	//-----------------------------------------------------------------------------
+	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+		File* file = bundle.open(id);
+		const size_t file_size = file->size();
+
+		void* res = allocator.allocate(file_size);
+		file->read(res, file_size);
+
+		bundle.close(file);
+
+		return res;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void online(void* resource)
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	static void unload(Allocator& allocator, void* resource)
+	{
+		CE_ASSERT_NOT_NULL(resource);
+		allocator.deallocate(resource);
+	}
+
+	//-----------------------------------------------------------------------------
+	static void offline(void* resource)
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t num_materials() const
+	{
+		return ((PhysicsConfigHeader*) this)->num_materials;
+	}
+
+	/// Returns the material with the given @a name
+	PhysicsMaterial material(StringId32 name) const
+	{
+		const PhysicsConfigHeader* h = (PhysicsConfigHeader*) this;
+		StringId32* begin = (StringId32*) (((char*) this) + h->materials_offset);
+		StringId32* end = begin + num_materials();
+		StringId32* id = std::find(begin, end, name);
+		CE_ASSERT(id != end, "Material not found");
+		return material_by_index(id - begin);
+	}
+
+	PhysicsMaterial material_by_index(uint32_t i) const
+	{
+		CE_ASSERT(i < num_materials(), "Index out of bounds");
+		const PhysicsConfigHeader* h = (PhysicsConfigHeader*) this;
+		const PhysicsMaterial* base = (PhysicsMaterial*) (((char*) this) + h->materials_offset + sizeof(StringId32) * num_materials());
+		return base[i];
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t num_shapes() const
+	{
+		return ((PhysicsConfigHeader*) this)->num_shapes;
+	}
+
+	//-----------------------------------------------------------------------------
+	PhysicsShape2 shape(StringId32 name) const
+	{
+		const PhysicsConfigHeader* h = (PhysicsConfigHeader*) this;
+		StringId32* begin = (StringId32*) (((char*) this) + h->shapes_offset);
+		StringId32* end = begin + num_shapes();
+		StringId32* id = std::find(begin, end, name);
+		CE_ASSERT(id != end, "Shape not found");
+		return shape_by_index(id - begin);
+	}
+
+	//-----------------------------------------------------------------------------
+	PhysicsShape2 shape_by_index(uint32_t i) const
+	{
+		CE_ASSERT(i < num_shapes(), "Index out of bounds");
+		const PhysicsConfigHeader* h = (PhysicsConfigHeader*) this;
+		const PhysicsShape2* base = (PhysicsShape2*) (((char*) this) + h->shapes_offset + sizeof(StringId32) * num_shapes());
+		return base[i];
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t num_actors() const
+	{
+		return ((PhysicsConfigHeader*) this)->num_actors;
+	}
+
+	/// Returns the actor with the given @a name
+	PhysicsActor2 actor(StringId32 name) const
+	{
+		const PhysicsConfigHeader* h = (PhysicsConfigHeader*) this;
+		StringId32* begin = (StringId32*) (((char*) this) + h->actors_offset);
+		StringId32* end = begin + num_actors();
+		StringId32* id = std::find(begin, end, name);
+		CE_ASSERT(id != end, "Actor not found");
+		return actor_by_index(id - begin);
+	}
+
+	//-----------------------------------------------------------------------------
+	PhysicsActor2 actor_by_index(uint32_t i) const
+	{
+		CE_ASSERT(i < num_actors(), "Index out of bounds");
+		const PhysicsConfigHeader* h = (PhysicsConfigHeader*) this;
+		const PhysicsActor2* base = (PhysicsActor2*) (((char*) this) + h->actors_offset + sizeof(StringId32) * num_actors());
+		return base[i];
+	}
+
+private:
+
+	// Disable construction
+	PhysicsConfigResource();
+};
+
 } // namespace crown

+ 26 - 24
engine/resource/Resource.h

@@ -34,31 +34,33 @@ namespace crown
 {
 
 /// Hashed values for supported resource types
-const char* const TEXTURE_EXTENSION			= "texture";
-const char* const MESH_EXTENSION			= "mesh";
-const char* const LUA_EXTENSION				= "lua";
-const char* const TEXT_EXTENSION			= "text";
-const char* const MATERIAL_EXTENSION		= "material";
-const char* const SOUND_EXTENSION			= "sound";
-const char* const SPRITE_EXTENSION			= "sprite";
-const char* const CONFIG_EXTENSION			= "config";
-const char* const PACKAGE_EXTENSION			= "package";
-const char* const UNIT_EXTENSION			= "unit";
-const char* const PHYSICS_EXTENSION			= "physics";
-const char* const GUI_EXTENSION				= "gui";
+#define TEXTURE_EXTENSION			"texture"
+#define MESH_EXTENSION				"mesh"
+#define LUA_EXTENSION				"lua"
+#define TEXT_EXTENSION				"text"
+#define MATERIAL_EXTENSION			"material"
+#define SOUND_EXTENSION				"sound"
+#define SPRITE_EXTENSION			"sprite"
+#define CONFIG_EXTENSION			"config"
+#define PACKAGE_EXTENSION			"package"
+#define UNIT_EXTENSION				"unit"
+#define PHYSICS_EXTENSION			"physics"
+#define GUI_EXTENSION				"gui"
+#define PHYSICS_CONFIG_EXTENSION	"physics_config"
 
-const uint32_t TEXTURE_TYPE					= 0x0DEED4F7;
-const uint32_t MESH_TYPE					= 0x742FBC9A;
-const uint32_t LUA_TYPE						= 0xD96E7C37;
-const uint32_t TEXT_TYPE					= 0x045CC650;
-const uint32_t MATERIAL_TYPE				= 0x46807A92;
-const uint32_t SOUND_TYPE					= 0xD196AB6E;
-const uint32_t SPRITE_TYPE					= 0x5DD272E5;
-const uint32_t CONFIG_TYPE					= 0x17DEA5E1;
-const uint32_t PACKAGE_TYPE					= 0xC0A2212C;
-const uint32_t UNIT_TYPE					= 0x516224CF;
-const uint32_t PHYSICS_TYPE					= 0xFA32C012;
-const uint32_t GUI_TYPE						= 0x2C56149A;
+#define TEXTURE_TYPE				0x0DEED4F7
+#define MESH_TYPE					0x742FBC9A
+#define LUA_TYPE					0xD96E7C37
+#define TEXT_TYPE					0x045CC650
+#define MATERIAL_TYPE				0x46807A92
+#define SOUND_TYPE					0xD196AB6E
+#define SPRITE_TYPE					0x5DD272E5
+#define CONFIG_TYPE					0x17DEA5E1
+#define PACKAGE_TYPE				0xC0A2212C
+#define UNIT_TYPE					0x516224CF
+#define PHYSICS_TYPE				0xFA32C012
+#define GUI_TYPE					0x2C56149A
+#define PHYSICS_CONFIG_TYPE			0x514F14A1
 
 /// ResourceId uniquely identifies a resource by its name and type.
 /// In order to speed up the lookup by the manager, it also keeps

+ 2 - 1
engine/resource/ResourceRegistry.cpp

@@ -50,7 +50,8 @@ static const ResourceCallback RESOURCE_CALLBACK_REGISTRY[] =
 	{ PACKAGE_TYPE, PackageResource::load, PackageResource::unload, PackageResource::online, PackageResource::offline },
 	{ PHYSICS_TYPE, PhysicsResource::load, PhysicsResource::unload, PhysicsResource::online, PhysicsResource::offline },
 	{ MATERIAL_TYPE, MaterialResource::load, MaterialResource::unload, MaterialResource::online, MaterialResource::offline },
-	{ GUI_TYPE, GuiResource::load, GuiResource::unload, GuiResource::online, GuiResource::offline },	
+	{ GUI_TYPE, GuiResource::load, GuiResource::unload, GuiResource::online, GuiResource::offline },
+	{ PHYSICS_CONFIG_TYPE, PhysicsConfigResource::load, PhysicsConfigResource::unload, PhysicsConfigResource::online, PhysicsConfigResource::offline },
 	{ 0, NULL, NULL, NULL, NULL }
 };