Daniele Bartolini 10 роки тому
батько
коміт
b94f3d89a5

+ 34 - 52
src/resource/level_resource.cpp

@@ -3,12 +3,14 @@
  * License: https://github.com/taylor001/crown/blob/master/LICENSE
  */
 
-#include "level_resource.h"
 #include "array.h"
-#include "memory.h"
-#include "json_parser.h"
-#include "filesystem.h"
 #include "compile_options.h"
+#include "filesystem.h"
+#include "level_resource.h"
+#include "map.h"
+#include "memory.h"
+#include "sjson.h"
+#include "unit_compiler.h"
 
 namespace crown
 {
@@ -17,64 +19,51 @@ namespace level_resource
 	void compile(const char* path, CompileOptions& opts)
 	{
 		Buffer buf = opts.read(path);
-		JSONParser json(buf);
-		JSONElement root = json.root();
+		TempAllocator4096 ta;
+		JsonObject object(ta);
+		sjson::parse(buf, object);
 
-		Array<LevelUnit> units(default_allocator());
 		Array<LevelSound> sounds(default_allocator());
-
 		{
-			JSONElement sounds_arr = root.key("sounds");
-			const uint32_t size = sounds_arr.size();
-			for (uint32_t i = 0; i < size; i++)
+			JsonArray sounds_json(ta);
+			sjson::parse_array(object["sounds"], sounds_json);
+
+			for (uint32_t i = 0, n = array::size(sounds_json); i < n; ++i)
 			{
-				JSONElement e = sounds_arr[i];
+				JsonObject sound(ta);
+				sjson::parse_object(sounds_json[i], sound);
+
 				LevelSound ls;
-				ls.name = e.key("name").to_resource_id();
-				ls.position = e.key("position").to_vector3();
-				ls.volume = e.key("volume").to_float();
-				ls.range = e.key("range").to_float();
-				ls.loop = e.key("loop").to_bool();
+				ls.name     = sjson::parse_resource_id(sound["name"]);
+				ls.position = sjson::parse_vector3    (sound["position"]);
+				ls.volume   = sjson::parse_float      (sound["volume"]);
+				ls.range    = sjson::parse_float      (sound["range"]);
+				ls.loop     = sjson::parse_float      (sound["loop"]);
+
 				array::push_back(sounds, ls);
 			}
 		}
 
+		UnitCompiler uc(opts);
+		Array<char> unit_buffer(default_allocator());
 		{
-			JSONElement units_arr = root.key("units");
-			const uint32_t size = units_arr.size();
-			for (uint32_t i = 0; i < size; i++)
-			{
-				JSONElement e = units_arr[i];
-				LevelUnit lu;
-				lu.name = e.key("name").to_resource_id();
-				lu.position = e.key("position").to_vector3();
-				lu.rotation = e.key("rotation").to_quaternion();
-				array::push_back(units, lu);
-			}
+			uc.compile_multiple_units(object["units"]);
+			unit_buffer = uc.get();
 		}
 
+		// Write
 		LevelResource lr;
-		lr.version = LEVEL_VERSION;
-		lr.num_units = array::size(units);
-		lr.num_sounds = array::size(sounds);
-
-		uint32_t offt = sizeof(LevelResource);
-		lr.units_offset = offt; offt += sizeof(LevelUnit) * lr.num_units;
-		lr.sounds_offset = offt;
+		lr.version       = LEVEL_VERSION;
+		lr.num_sounds    = array::size(sounds);
+		lr.units_offset  = sizeof(LevelResource);
+		lr.sounds_offset = lr.units_offset + array::size(unit_buffer);
 
 		opts.write(lr.version);
-		opts.write(lr.num_units);
 		opts.write(lr.units_offset);
 		opts.write(lr.num_sounds);
 		opts.write(lr.sounds_offset);
 
-		for (uint32_t i = 0; i < array::size(units); ++i)
-		{
-			opts.write(units[i].name);
-			opts.write(units[i].position);
-			opts.write(units[i].rotation);
-			opts.write(units[i]._pad);
-		}
+		opts.write(unit_buffer);
 
 		for (uint32_t i = 0; i < array::size(sounds); ++i)
 		{
@@ -103,16 +92,9 @@ namespace level_resource
 		allocator.deallocate(resource);
 	}
 
-	uint32_t num_units(const LevelResource* lr)
+	const UnitResource* get_units(const LevelResource* lr)
 	{
-		return lr->num_units;
-	}
-
-	const LevelUnit* get_unit(const LevelResource* lr, uint32_t i)
-	{
-		CE_ASSERT(i < num_units(lr), "Index out of bounds");
-		const LevelUnit* begin = (LevelUnit*)((char*)lr + lr->units_offset);
-		return &begin[i];
+		return (const UnitResource*)((char*)lr + lr->units_offset);
 	}
 
 	uint32_t num_sounds(const LevelResource* lr)

+ 1 - 11
src/resource/level_resource.h

@@ -18,20 +18,11 @@ namespace crown
 struct LevelResource
 {
 	uint32_t version;
-	uint32_t num_units;
 	uint32_t units_offset;
 	uint32_t num_sounds;
 	uint32_t sounds_offset;
 };
 
-struct LevelUnit
-{
-	StringId64 name;
-	Vector3 position;
-	Quaternion rotation;
-	uint32_t _pad;
-};
-
 struct LevelSound
 {
 	StringId64 name;
@@ -48,8 +39,7 @@ namespace level_resource
 	void* load(File& file, Allocator& a);
 	void unload(Allocator& allocator, void* resource);
 
-	uint32_t num_units(const LevelResource* lr);
-	const LevelUnit* get_unit(const LevelResource* lr, uint32_t i);
+	const UnitResource* get_units(const LevelResource* lr);
 	uint32_t num_sounds(const LevelResource* lr);
 	const LevelSound* get_sound(const LevelResource* lr, uint32_t i);
 } // namespace level_resource

+ 63 - 38
src/resource/material_resource.cpp

@@ -3,16 +3,16 @@
  * License: https://github.com/taylor001/crown/blob/master/LICENSE
  */
 
-#include "material_resource.h"
+#include "compile_options.h"
 #include "dynamic_string.h"
-#include "string_utils.h"
-#include "string_utils.h"
-#include "json_parser.h"
 #include "filesystem.h"
+#include "map.h"
+#include "material_resource.h"
 #include "reader_writer.h"
 #include "resource_manager.h"
+#include "sjson.h"
+#include "string_utils.h"
 #include "vector.h"
-#include "compile_options.h"
 #include <bgfx/bgfx.h>
 
 namespace crown
@@ -41,25 +41,34 @@ namespace material_resource
 		return offt;
 	}
 
-	static void parse_textures(JSONElement root, Array<TextureData>& textures, Array<char>& names, Array<char>& dynamic)
+	static void parse_textures(const char* json, Array<TextureData>& textures, Array<char>& names, Array<char>& dynamic)
 	{
-		using namespace vector;
+		TempAllocator4096 ta;
+		JsonObject object(ta);
+		sjson::parse(json, object);
 
-		Vector<DynamicString> keys(default_allocator());
-		root.key("textures").to_keys(keys);
+		const typename JsonObject::Node* begin = map::begin(object);
+		const typename JsonObject::Node* end = map::end(object);
 
-		for (uint32_t i = 0; i < size(keys); i++)
+		for (; begin != end; ++begin)
 		{
+			const FixedString key = begin->pair.first;
+			const char* value     = begin->pair.second;
+
+			const ResourceId texid = sjson::parse_resource_id(value);
+
 			TextureHandle th;
 			th.sampler_handle = 0;
 			th.texture_handle = 0;
 
-			ResourceId texid = root.key("textures").key(keys[i].c_str()).to_resource_id();
+			const uint32_t sampler_name_offset = array::size(names);
+			array::push(names, key.data(), key.length());
+			array::push_back(names, '\0');
 
 			TextureData td;
-			td.sampler_name_offset = array::size(names); array::push(names, keys[i].c_str(), keys[i].length()); array::push_back(names, '\0');
-			td.id = texid;
-			td.data_offset = reserve_dynamic_data(th, dynamic);
+			td.sampler_name_offset = sampler_name_offset;
+			td.id                  = texid;
+			td.data_offset         = reserve_dynamic_data(th, dynamic);
 
 			array::push_back(textures, td);
 		}
@@ -92,48 +101,61 @@ namespace material_resource
 		return UniformType::COUNT;
 	}
 
-	static void parse_uniforms(JSONElement root, Array<UniformData>& uniforms, Array<char>& names, Array<char>& dynamic)
+	static void parse_uniforms(const char* json, Array<UniformData>& uniforms, Array<char>& names, Array<char>& dynamic)
 	{
-		using namespace vector;
+		TempAllocator4096 ta;
+		JsonObject object(ta);
+		sjson::parse(json, object);
 
-		Vector<DynamicString> keys(default_allocator());
-		root.key("uniforms").to_keys(keys);
+		const typename JsonObject::Node* begin = map::begin(object);
+		const typename JsonObject::Node* end = map::end(object);
 
-		for (uint32_t i = 0; i < size(keys); i++)
+		for (; begin != end; ++begin)
 		{
+			const FixedString key = begin->pair.first;
+			const char* value     = begin->pair.second;
+
 			UniformHandle uh;
 			uh.uniform_handle = 0;
 
-			DynamicString type = root.key("uniforms").key(keys[i].c_str()).key("type").to_string();
+			JsonObject uniform(ta);
+			sjson::parse_object(value, uniform);
+
+			DynamicString type(ta);
+			sjson::parse_string(uniform["type"], type);
+
+			const uint32_t name_offset = array::size(names);
+			array::push(names, key.data(), key.length());
+			array::push_back(names, '\0');
 
 			UniformData ud;
-			ud.name_offset = array::size(names); array::push(names, keys[i].c_str(), keys[i].length()); array::push_back(names, '\0');
-			ud.type = string_to_uniform_type(type.c_str());
+			ud.name_offset = name_offset;
+			ud.type        = string_to_uniform_type(type.c_str());
 			ud.data_offset = reserve_dynamic_data(uh, dynamic);
 
 			switch (ud.type)
 			{
 				case UniformType::FLOAT:
 				{
-					float data = root.key("uniforms").key(keys[i].c_str()).key("value").to_float();
+					float data = sjson::parse_float(uniform["value"]);
 					reserve_dynamic_data(data, dynamic);
 					break;
 				}
 				case UniformType::VECTOR2:
 				{
-					Vector2 data = root.key("uniforms").key(keys[i].c_str()).key("value").to_vector2();
+					Vector2 data = sjson::parse_vector2(uniform["value"]);
 					reserve_dynamic_data(data, dynamic);
 					break;
 				}
 				case UniformType::VECTOR3:
 				{
-					Vector3 data = root.key("uniforms").key(keys[i].c_str()).key("value").to_vector3();
+					Vector3 data = sjson::parse_vector3(uniform["value"]);
 					reserve_dynamic_data(data, dynamic);
 					break;
 				}
 				case UniformType::VECTOR4:
 				{
-					Vector4 data = root.key("uniforms").key(keys[i].c_str()).key("value").to_vector4();
+					Vector4 data = sjson::parse_vector4(uniform["value"]);
 					reserve_dynamic_data(data, dynamic);
 					break;
 				}
@@ -147,27 +169,30 @@ namespace material_resource
 	void compile(const char* path, CompileOptions& opts)
 	{
 		Buffer buf = opts.read(path);
-		JSONParser json(buf);
-		JSONElement root = json.root();
+		TempAllocator4096 ta;
+		JsonObject object(ta);
+		sjson::parse(buf, object);
 
 		Array<TextureData> texdata(default_allocator());
 		Array<UniformData> unidata(default_allocator());
 		Array<char> names(default_allocator());
 		Array<char> dynblob(default_allocator());
 
-		StringId32 shader = root.key("shader").to_string_id();
-		parse_textures(root, texdata, names, dynblob);
-		parse_uniforms(root, unidata, names, dynblob);
+		DynamicString shader(ta);
+		sjson::parse_string(object["shader"], shader);
+
+		parse_textures(object["textures"], texdata, names, dynblob);
+		parse_uniforms(object["uniforms"], unidata, names, dynblob);
 
 		MaterialResource mr;
-		mr.version = MATERIAL_VERSION;
-		mr.shader = shader;
-		mr.num_textures = array::size(texdata);
+		mr.version             = MATERIAL_VERSION;
+		mr.shader              = shader.to_string_id();
+		mr.num_textures        = array::size(texdata);
 		mr.texture_data_offset = sizeof(mr);
-		mr.num_uniforms = array::size(unidata);
-		mr.uniform_data_offset = sizeof(mr) + sizeof(TextureData) * array::size(texdata);
-		mr.dynamic_data_size = array::size(dynblob);
-		mr.dynamic_data_offset = sizeof(mr) + sizeof(TextureData) * array::size(texdata) + sizeof(UniformData) * array::size(unidata);
+		mr.num_uniforms        = array::size(unidata);
+		mr.uniform_data_offset = mr.texture_data_offset + sizeof(TextureData)*array::size(texdata);
+		mr.dynamic_data_size   = array::size(dynblob);
+		mr.dynamic_data_offset = mr.uniform_data_offset + sizeof(UniformData)*array::size(unidata);
 
 		// Write
 		opts.write(mr.version);

Різницю між файлами не показано, бо вона завелика
+ 319 - 458
src/resource/physics_resource.cpp


+ 15 - 112
src/resource/physics_resource.h

@@ -11,118 +11,20 @@
 #include "math_types.h"
 #include "compiler_types.h"
 #include "string_id.h"
+#include "container_types.h"
 
 namespace crown
 {
 
-struct PhysicsResource
-{
-	uint32_t version;
-	uint32_t num_controllers;		// 0 or 1, ATM
-	uint32_t controller_offset;
-	uint32_t num_colliders;
-	uint32_t colliders_offset;
-	uint32_t num_actors;
-	uint32_t actors_offset;
-	uint32_t num_joints;
-	uint32_t joints_offset;
-};
-
-struct ControllerResource
-{
-	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.
-	StringId32 collision_filter;// Collision filter from global.physics_config
-};
-
-struct ActorFlags
-{
-	enum Enum
-	{
-		LOCK_TRANSLATION_X = (1 << 0),
-		LOCK_TRANSLATION_Y = (1 << 1),
-		LOCK_TRANSLATION_Z = (1 << 2),
-		LOCK_ROTATION_X = (1 << 3),
-		LOCK_ROTATION_Y = (1 << 4),
-		LOCK_ROTATION_Z = (1 << 5)
-	};
-};
-
-struct ActorResource
-{
-	StringId32 name;			// Name of the actor
-	StringId32 node;			// Node from .unit file
-	StringId32 actor_class;		// Actor from global.physics
-	float mass;					// Mass of the actor
-	uint32_t flags;
-};
-
-struct ShapeResource
-{
-	StringId32 name;			// Name of the shape
-	StringId32 shape_class;		// Shape class from global.physics_config
-	uint32_t type;				// Type of the shape
-	StringId32 material;		// Material from global.physics_config
-	Vector3 position;			// In actor space
-	Quaternion rotation;		// In actor space
-	float data_0;
-	float data_1;
-	float data_2;
-	float data_3;
-};
-
-struct JointResource
-{
-	StringId32 name;
-	uint32_t type;
-	StringId32 actor_0;
-	StringId32 actor_1;
-	Vector3 anchor_0;
-	Vector3 anchor_1;
-
-	bool breakable;
-	char _pad[3];
-	float break_force;
-	float break_torque;
-
-	// Revolute/Prismatic Joint Limits
-	float lower_limit;
-	float upper_limit;
-
-	// Spherical Joint Limits
-	float y_limit_angle;
-	float z_limit_angle;
-
-	// Distance Joint Limits
-	float max_distance;
-
-	// JointLimitPair/cone param
-	float contact_dist;
-
-	float restitution;
-	float spring;
-	float damping;
-	float distance;
-};
-
 namespace physics_resource
 {
-	void compile(const char* path, CompileOptions& opts);
-	void* load(File& file, Allocator& a);
-	void unload(Allocator& allocator, void* resource);
-
-	bool has_controller(const PhysicsResource* pr);
-	const ControllerResource* controller(const PhysicsResource* pr);
-	uint32_t num_colliders(const PhysicsResource* ar);
-	const ShapeResource* collider(const PhysicsResource* ar, uint32_t i);
-	uint32_t num_actors(const PhysicsResource* pr);
-	const ActorResource* actor(const PhysicsResource* pr, uint32_t i);
-	uint32_t num_joints(const PhysicsResource* pr);
-	const JointResource* joint(const PhysicsResource* pr, uint32_t i);
+	inline void compile(const char* /*path*/, CompileOptions& /*opts*/) {}
+	inline void* load(File& /*file*/, Allocator& /*a*/) { return NULL; }
+	inline void unload(Allocator& /*a*/, void* /*res*/) {}
+	Buffer compile_controller(const char* json, CompileOptions& opts);
+	Buffer compile_collider(const char* json, CompileOptions& opts);
+	Buffer compile_actor(const char* json, CompileOptions& opts);
+	Buffer compile_joint(const char* json, CompileOptions& opts);
 } // namespace physics_resource
 
 struct PhysicsConfigResource
@@ -140,22 +42,22 @@ struct PhysicsConfigResource
 
 struct PhysicsConfigMaterial
 {
+	StringId32 name;
 	float static_friction;
 	float dynamic_friction;
 	float restitution;
-	// uint8_t restitution_combine_mode;
-	// uint8_t friction_combine_mode;
 };
 
 struct PhysicsCollisionFilter
 {
+	StringId32 name;
 	uint32_t me;
 	uint32_t mask;
 };
 
 struct PhysicsConfigShape
 {
-	StringId32 collision_filter;
+	StringId32 name;
 	bool trigger;
 	char _pad[3];
 };
@@ -164,11 +66,12 @@ struct PhysicsConfigActor
 {
 	enum
 	{
-		DYNAMIC			= (1 << 0),
-		KINEMATIC		= (1 << 1),
-		DISABLE_GRAVITY	= (1 << 2)
+		DYNAMIC         = (1 << 0),
+		KINEMATIC       = (1 << 1),
+		DISABLE_GRAVITY = (1 << 2)
 	};
 
+	StringId32 name;
 	float linear_damping;
 	float angular_damping;
 	uint32_t flags;

+ 311 - 0
src/resource/unit_compiler.cpp

@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors.
+ * License: https://github.com/taylor001/crown/blob/master/LICENSE
+ */
+
+#include "unit_compiler.h"
+#include "unit_resource.h"
+#include "array.h"
+#include "sort_map.h"
+#include "compile_options.h"
+#include "math_utils.h"
+#include "world_types.h"
+#include "graphics_types.h"
+#include "physics_resource.h"
+#include "temp_allocator.h"
+#include "sjson.h"
+#include "map.h"
+
+namespace crown
+{
+
+struct ProjectionInfo
+{
+	const char* name;
+	ProjectionType::Enum type;
+};
+
+static const ProjectionInfo s_projection[] =
+{
+	{ "perspective",  ProjectionType::PERSPECTIVE  },
+	{ "orthographic", ProjectionType::ORTHOGRAPHIC }
+};
+CE_STATIC_ASSERT(CE_COUNTOF(s_projection) == ProjectionType::COUNT);
+
+struct LightInfo
+{
+	const char* name;
+	LightType::Enum type;
+};
+
+static const LightInfo s_light[] =
+{
+	{ "directional", LightType::DIRECTIONAL },
+	{ "omni",        LightType::OMNI        },
+	{ "spot",        LightType::SPOT        }
+};
+CE_STATIC_ASSERT(CE_COUNTOF(s_light) == LightType::COUNT);
+
+static ProjectionType::Enum projection_name_to_enum(const char* name)
+{
+	for (uint32_t i = 0; i < CE_COUNTOF(s_projection); ++i)
+	{
+		if (strcmp(name, s_projection[i].name) == 0)
+			return s_projection[i].type;
+	}
+
+	CE_FATAL("Bad projection type");
+	return (ProjectionType::Enum)0;
+}
+
+static LightType::Enum light_name_to_enum(const char* name)
+{
+	for (uint32_t i = 0; i < CE_COUNTOF(s_light); ++i)
+	{
+		if (strcmp(name, s_light[i].name) == 0)
+			return s_light[i].type;
+	}
+
+	CE_FATAL("Bad light type");
+	return (LightType::Enum)0;
+}
+
+static Buffer compile_transform(const char* json, CompileOptions& opts)
+{
+	TempAllocator4096 ta;
+	JsonObject obj(ta);
+	sjson::parse(json, obj);
+
+	TransformDesc td;
+	td.position = sjson::parse_vector3   (obj["position"]);
+	td.rotation = sjson::parse_quaternion(obj["rotation"]);
+	td.scale    = sjson::parse_vector3   (obj["scale"]);
+
+	Buffer buf(default_allocator());
+	array::push(buf, (char*)&td, sizeof(td));
+	return buf;
+}
+
+static Buffer compile_camera(const char* json, CompileOptions& opts)
+{
+	TempAllocator4096 ta;
+	JsonObject obj(ta);
+	sjson::parse(json, obj);
+
+	DynamicString type(ta);
+	sjson::parse_string(obj["projection"], type);
+
+	CameraDesc cd;
+	cd.type       = projection_name_to_enum(type.c_str());
+	cd.fov        = sjson::parse_float(obj["fov"]);
+	cd.near_range = sjson::parse_float(obj["near_range"]);
+	cd.far_range  = sjson::parse_float(obj["far_range"]);
+
+	Buffer buf(default_allocator());
+	array::push(buf, (char*)&cd, sizeof(cd));
+	return buf;
+}
+
+static Buffer compile_mesh_renderer(const char* json, CompileOptions& opts)
+{
+	TempAllocator4096 ta;
+	JsonObject obj(ta);
+	sjson::parse(json, obj);
+
+	MeshRendererDesc mrd;
+	mrd.mesh_resource     = sjson::parse_resource_id(obj["mesh_resource"]);
+	mrd.mesh_name         = sjson::parse_string_id  (obj["mesh_name"]);
+	mrd.material_resource = sjson::parse_resource_id(obj["material"]);
+	mrd.visible           = sjson::parse_bool       (obj["visible"]);
+
+	Buffer buf(default_allocator());
+	array::push(buf, (char*)&mrd, sizeof(mrd));
+	return buf;
+}
+
+static Buffer compile_sprite_renderer(const char* json, CompileOptions& opts)
+{
+	TempAllocator4096 ta;
+	JsonObject obj(ta);
+	sjson::parse(json, obj);
+
+	SpriteRendererDesc srd;
+	srd.sprite_resource   = sjson::parse_resource_id(obj["resource"]);
+	srd.material_resource = sjson::parse_resource_id(obj["material"]);
+	srd.visible           = sjson::parse_bool       (obj["visible"]);
+
+	Buffer buf(default_allocator());
+	array::push(buf, (char*)&srd, sizeof(srd));
+	return buf;
+}
+
+static Buffer compile_light(const char* json, CompileOptions& opts)
+{
+	TempAllocator4096 ta;
+	JsonObject obj(ta);
+	sjson::parse(json, obj);
+
+	DynamicString type(ta);
+	sjson::parse_string(obj["light"], type);
+
+	LightDesc ld;
+	ld.type       = light_name_to_enum(type.c_str());
+	ld.range      = sjson::parse_float  (obj["range"]);
+	ld.intensity  = sjson::parse_float  (obj["intensity"]);
+	ld.spot_angle = sjson::parse_float  (obj["spot_angle"]);
+	ld.color      = sjson::parse_vector3(obj["color"]);
+
+	// FIXME: remove conversion to radians
+	ld.spot_angle = to_rad(ld.spot_angle);
+
+	Buffer buf(default_allocator());
+	array::push(buf, (char*)&ld, sizeof(ld));
+	return buf;
+}
+
+UnitCompiler::UnitCompiler(CompileOptions& opts)
+	: _opts(opts)
+	, _num_units(0)
+	, _component_data(default_allocator())
+{
+	register_component_compiler("transform",       &compile_transform, 0.0f);
+	register_component_compiler("camera",          &compile_camera, 1.0f);
+	register_component_compiler("mesh_renderer",   &compile_mesh_renderer, 1.0f);
+	register_component_compiler("sprite_renderer", &compile_sprite_renderer, 1.0f);
+	register_component_compiler("light",           &compile_light, 1.0f);
+	register_component_compiler("controller",      &physics_resource::compile_controller, 1.0f);
+	register_component_compiler("collider",        &physics_resource::compile_collider, 1.0f);
+	register_component_compiler("actor",           &physics_resource::compile_actor, 1.0f);
+	register_component_compiler("joint",           &physics_resource::compile_joint, 1.0f);
+}
+
+void UnitCompiler::compile_unit(const char* path)
+{
+	Buffer buf = _opts.read(path);
+	array::push_back(buf, '\0');
+	array::pop_back(buf);
+	compile_unit_from_json(array::begin(buf));
+}
+
+void UnitCompiler::compile_unit_from_json(const char* json)
+{
+	TempAllocator4096 ta;
+	JsonObject obj(ta);
+	sjson::parse(json, obj);
+
+	const char* prefab = map::get(obj, FixedString("prefab"), (const char*)NULL);
+	if (prefab)
+	{
+		TempAllocator512 ta;
+		DynamicString path(ta);
+		sjson::parse_string(prefab, path);
+
+		path += "." UNIT_EXTENSION;
+		compile_unit(path.c_str());
+	}
+
+	const char* components = map::get(obj, FixedString("components"), (const char*)NULL);
+	if (components)
+	{
+		JsonObject keys(ta);
+		sjson::parse(components, keys);
+
+		const typename JsonObject::Node* begin = map::begin(keys);
+		const typename JsonObject::Node* end = map::end(keys);
+
+		for (; begin != end; ++begin)
+		{
+			const char* value = begin->pair.second;
+
+			TempAllocator512 ta;
+			JsonObject component(ta);
+			sjson::parse(value, component);
+
+			const StringId32 type = sjson::parse_string_id(component["type"]);
+
+			Buffer buf = compile_component(type, value);
+			add_component_data(type, buf, _num_units);
+		}
+
+		++_num_units;
+	}
+}
+
+void UnitCompiler::compile_multiple_units(const char* json)
+{
+	TempAllocator4096 ta;
+	JsonObject obj(ta);
+	sjson::parse(json, obj);
+
+	const JsonObject::Node* begin = map::begin(obj);
+	const JsonObject::Node* end = map::end(obj);
+
+	for (; begin != end; ++begin)
+	{
+		const char* unit = begin->pair.second;
+
+		compile_unit_from_json(unit);
+	}
+}
+
+Buffer UnitCompiler::get()
+{
+	UnitResource ur;
+	ur.version = UNIT_VERSION;
+	ur.num_units = _num_units;
+	ur.num_component_types = sort_map::size(_component_data);
+
+	Buffer buf(default_allocator());
+	array::push(buf, (char*)&ur, sizeof(ur));
+
+	const SortMap<StringId32, ComponentTypeData>::Entry* begin = sort_map::begin(_component_data);
+	const SortMap<StringId32, ComponentTypeData>::Entry* end = sort_map::end(_component_data);
+
+	while (begin != end)
+	{
+		const StringId32 type             = (end-1)->pair.first;
+		const Buffer& data                = (end-1)->pair.second._data;
+		const Array<uint32_t>& unit_index = (end-1)->pair.second._unit_index;
+		const uint32_t num                = (end-1)->pair.second._num;
+
+		ComponentData cd;
+		cd.type = type._id;
+		cd.num_instances = num;
+		cd.size = array::size(data) + sizeof(uint32_t)*array::size(unit_index);
+
+		array::push(buf, (char*)&cd, sizeof(cd));
+		array::push(buf, (char*)array::begin(unit_index), sizeof(uint32_t)*array::size(unit_index));
+		array::push(buf, array::begin(data), array::size(data));
+
+		--end;
+	}
+
+	return buf;
+}
+
+void UnitCompiler::add_component_data(StringId32 type, const Buffer& data, uint32_t unit_index)
+{
+	ComponentTypeData& ctd = const_cast<ComponentTypeData&>(sort_map::get(_component_data, type, ComponentTypeData(default_allocator())));
+
+	array::push(ctd._data, array::begin(data), array::size(data));
+	array::push_back(ctd._unit_index, unit_index);
+	++ctd._num;
+}
+
+void UnitCompiler::register_component_compiler(const char* type, CompileFunction fn, float spawn_order)
+{
+	ComponentTypeData ctd(default_allocator());
+	ctd._compiler = fn;
+
+	sort_map::set(_component_data, StringId32(type), ctd);
+	sort_map::sort(_component_data);
+}
+
+Buffer UnitCompiler::compile_component(StringId32 type, const char* json)
+{
+	RESOURCE_COMPILER_ASSERT(sort_map::has(_component_data, type), _opts, "Unknown component");
+
+	return sort_map::get(_component_data, type, ComponentTypeData(default_allocator()))._compiler(json, _opts);
+}
+
+} // namespace crown

+ 60 - 0
src/resource/unit_compiler.h

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors.
+ * License: https://github.com/taylor001/crown/blob/master/LICENSE
+ */
+
+#pragma once
+
+#include "container_types.h"
+#include "compile_options.h"
+
+namespace crown
+{
+
+class UnitCompiler
+{
+	typedef Buffer (*CompileFunction)(const char* json, CompileOptions& opts);
+
+public:
+
+	UnitCompiler(CompileOptions& opts);
+
+	void compile_unit(const char* path);
+	void compile_unit_from_json(const char* json);
+	void compile_multiple_units(const char* json);
+
+	Buffer get();
+
+private:
+
+	void register_component_compiler(const char* type, CompileFunction fn, float spawn_order);
+	Buffer compile_component(StringId32 type, const char* json);
+	void add_component_data(StringId32 type, const Buffer& data, uint32_t unit_index);
+
+private:
+
+	struct ComponentTypeData
+	{
+		ComponentTypeData(Allocator& a)
+			: _data(a)
+			, _unit_index(a)
+			, _num(0)
+		{
+		}
+
+		Buffer _data;
+		Array<uint32_t> _unit_index;
+		CompileFunction _compiler;
+		uint32_t _num;
+
+		ALLOCATOR_AWARE;
+	};
+
+	typedef SortMap<StringId32, ComponentTypeData> ComponentTypeMap;
+
+	CompileOptions& _opts;
+	uint32_t _num_units;
+	ComponentTypeMap _component_data;
+};
+
+} // namespace crown

+ 12 - 401
src/resource/unit_resource.cpp

@@ -6,426 +6,37 @@
 #include "allocator.h"
 #include "file.h"
 #include "filesystem.h"
-#include "string_utils.h"
-#include "json_parser.h"
-#include "vector.h"
-#include "log.h"
-#include "matrix4x4.h"
-#include "physics_types.h"
-#include "quaternion.h"
-#include "compile_options.h"
-#include "temp_allocator.h"
-#include "types.h"
-#include "vector3.h"
-#include "camera.h"
-#include "unit_resource.h"
-#include <algorithm> // std::sort
+#include "resource_types.h"
+#include "unit_compiler.h"
 
 namespace crown
 {
 namespace unit_resource
 {
-	struct Projection
-	{
-		const char* name;
-		ProjectionType::Enum type;
-	};
-
-	static const Projection s_projection[] =
-	{
-		{ "perspective",  ProjectionType::PERSPECTIVE  },
-		{ "orthographic", ProjectionType::ORTHOGRAPHIC }
-	};
-
-	static ProjectionType::Enum projection_name_to_enum(const char* name)
-	{
-		for (uint32_t i = 0; i < ProjectionType::COUNT; i++)
-		{
-			if (strcmp(name, s_projection[i].name) == 0)
-				return s_projection[i].type;
-		}
-
-		CE_FATAL("Bad projection type");
-		return (ProjectionType::Enum)0;
-	}
-
-	const StringId32 NO_PARENT(0xffffffff);
-
-	struct GraphNode
-	{
-		StringId32 name;
-		StringId32 parent;
-		Vector3 position;
-		Quaternion rotation;
-	};
-
-	struct GraphNodeDepth
-	{
-		StringId32 name;
-		uint32_t index;
-		uint32_t depth;
-
-		bool operator()(const GraphNodeDepth& a, const GraphNodeDepth& b)
-		{
-			return a.depth < b.depth;
-		}
-	};
-
-	uint32_t compute_link_depth(const GraphNode& node, const Array<GraphNode>& nodes)
-	{
-		if (node.parent == NO_PARENT) return 0;
-		else
-		{
-			for (uint32_t i = 0; i < array::size(nodes); i++)
-			{
-				if (nodes[i].name == node.parent)
-				{
-					return 1 + compute_link_depth(nodes[i], nodes);
-				}
-			}
-		}
-
-		CE_FATAL("Node not found");
-		return 0;
-	}
-
-	uint32_t find_node_index(StringId32 name, const Array<GraphNodeDepth>& node_depths)
-	{
-		for (uint32_t i = 0; i < array::size(node_depths); i++)
-		{
-			if (node_depths[i].name == name)
-			{
-				return i;
-			}
-		}
-
-		CE_FATAL("Node not found");
-		return 0;
-	}
-
-	int32_t find_node_parent_index(uint32_t node, const Array<GraphNode>& nodes, const Array<GraphNodeDepth>& node_depths)
-	{
-		StringId32 parent_name = nodes[node_depths[node].index].parent;
-
-		if (parent_name == NO_PARENT) return -1;
-		for (uint32_t i = 0; i < array::size(node_depths); i++)
-		{
-			if (parent_name == node_depths[i].name)
-			{
-				return i;
-			}
-		}
-
-		CE_FATAL("Node not found");
-		return 0;
-	}
-
-	void parse_nodes(JSONElement e, Array<GraphNode>& nodes, Array<GraphNodeDepth>& node_depths)
-	{
-		Vector<DynamicString> keys(default_allocator());
-		e.to_keys(keys);
-
-		for (uint32_t k = 0; k < vector::size(keys); k++)
-		{
-			const char* node_name = keys[k].c_str();
-			JSONElement node = e.key(node_name);
-
-			GraphNode gn;
-			gn.name = StringId32(node_name);
-			gn.parent = NO_PARENT;
-
-			if (!node.key("parent").is_nil())
-			{
-				gn.parent = node.key("parent").to_string_id();
-			}
-
-			gn.position = node.key("position").to_vector3();
-			gn.rotation = node.key("rotation").to_quaternion();
-
-			GraphNodeDepth gnd;
-			gnd.name = gn.name;
-			gnd.index = array::size(nodes);
-			gnd.depth = 0;
-
-			array::push_back(nodes, gn);
-			array::push_back(node_depths, gnd);
-		}
-	}
-
-	void parse_cameras(JSONElement e, Array<UnitCamera>& cameras, const Array<GraphNodeDepth>& node_depths)
-	{
-		Vector<DynamicString> keys(default_allocator());
-		e.to_keys(keys);
-
-		for (uint32_t k = 0; k < vector::size(keys); k++)
-		{
-			const char* camera_name = keys[k].c_str();
-			JSONElement camera = e.key(camera_name);
-			JSONElement node = camera.key("node");
-			JSONElement type = camera.key("type");
-
-			DynamicString node_name = node.to_string();
-			DynamicString camera_type = type.to_string();
-			StringId32 node_name_hash = node_name.to_string_id();
-
-			UnitCamera cn;
-			cn.name = StringId32(camera_name);
-			cn.node = find_node_index(node_name_hash, node_depths);
-			cn.type = projection_name_to_enum(camera_type.c_str());
-			cn.fov =  camera.key_or_nil("fov").to_float(16.0f / 9.0f);
-			cn.near = camera.key_or_nil("near_clip_distance").to_float(0.01f);
-			cn.far =  camera.key_or_nil("far_clip_distance").to_float(1000.0f);
-
-			array::push_back(cameras, cn);
-		}
-	}
-
-	void parse_renderables(JSONElement e, Array<UnitRenderable>& renderables, const Array<GraphNodeDepth>& node_depths)
-	{
-		Vector<DynamicString> keys(default_allocator());
-		e.to_keys(keys);
-
-		for (uint32_t k = 0; k < vector::size(keys); k++)
-		{
-			const char* renderable_name = keys[k].c_str();
-			JSONElement renderable = e.key(renderable_name);
-
-			StringId32 node_name_hash = renderable.key("node").to_string_id();
-
-			UnitRenderable rn;
-			rn.name = StringId32(renderable_name);
-			rn.node = find_node_index(node_name_hash, node_depths);
-			rn.visible = renderable.key("visible").to_bool();
-
-			DynamicString res_type = renderable.key("type").to_string();
-
-			if (res_type == "mesh")
-			{
-				rn.type = UnitRenderable::MESH;
-				rn.resource = renderable.key("resource").to_resource_id();
-			}
-			else if (res_type == "sprite")
-			{
-				rn.type = UnitRenderable::SPRITE;
-				rn.resource = renderable.key("resource").to_resource_id();
-			}
-			else
-			{
-				CE_ASSERT(false, "Oops, unknown renderable type: '%s'", res_type.c_str());
-			}
-
-			array::push_back(renderables, rn);
-		}
-	}
-
-	void parse_materials(JSONElement e, Array<UnitMaterial>& materials)
-	{
-		for (uint32_t i = 0; i < e.size(); i++)
-		{
-			ResourceId mat_id = e[i].to_resource_id();
-			UnitMaterial um;
-			um.id = mat_id;
-			array::push_back(materials, um);
-		}
-	}
-
 	void compile(const char* path, CompileOptions& opts)
 	{
-		Buffer buf = opts.read(path);
-		JSONParser json(buf);
-		JSONElement root = json.root();
-
-		ResourceId				m_physics_resource;
-		Array<GraphNode>		m_nodes(default_allocator());
-		Array<GraphNodeDepth>	m_node_depths(default_allocator());
-		Array<UnitCamera>		m_cameras(default_allocator());
-		Array<UnitRenderable>	m_renderables(default_allocator());
-		Array<UnitMaterial>		m_materials(default_allocator());
-
-		// Check for nodes
-		if (root.has_key("nodes")) parse_nodes(root.key("nodes"), m_nodes, m_node_depths);
-
-		for (uint32_t i = 0; i < array::size(m_nodes); i++)
-		{
-			m_node_depths[i].depth = compute_link_depth(m_nodes[i], m_nodes);
-		}
-
-		std::sort(array::begin(m_node_depths), array::end(m_node_depths), GraphNodeDepth());
-
-		if (root.has_key("renderables")) parse_renderables(root.key("renderables"), m_renderables, m_node_depths);
-		if (root.has_key("cameras")) parse_cameras(root.key("cameras"), m_cameras, m_node_depths);
-		if (root.has_key("materials")) parse_materials(root.key("materials"), m_materials);
-
-		// Check if the unit has a .physics resource
-		DynamicString unit_name(path);
-		unit_name.strip_trailing(".unit");
-		DynamicString physics_name = unit_name;
-		physics_name += ".physics";
-		if (opts._fs.exists(physics_name.c_str()))
-		{
-			m_physics_resource = ResourceId(unit_name.c_str());
-		}
-		else
-		{
-			m_physics_resource = ResourceId();
-		}
-
-		ResourceId sprite_anim;
-		if (root.has_key("sprite_animation"))
-			sprite_anim = root.key("sprite_animation").to_resource_id();
-
-		UnitResource ur;
-		ur.version = UNIT_VERSION;
-		ur.name = StringId64(unit_name.c_str());
-		ur.physics_resource = m_physics_resource;
-		ur.sprite_animation = sprite_anim;
-		ur.num_renderables = array::size(m_renderables);
-		ur.num_materials = array::size(m_materials);
-		ur.num_cameras = array::size(m_cameras);
-		ur.num_scene_graph_nodes = array::size(m_nodes);
+		Buffer unit_data(default_allocator());
 
-		uint32_t offt = sizeof(UnitResource);
-		ur.renderables_offset         = offt; offt += sizeof(UnitRenderable) * ur.num_renderables;
-		ur.materials_offset           = offt; offt += sizeof(UnitMaterial) * ur.num_materials;
-		ur.cameras_offset             = offt; offt += sizeof(UnitCamera) * ur.num_cameras;
-		ur.scene_graph_nodes_offset   = offt;
+		UnitCompiler uc(opts);
+		uc.compile_unit(path);
+		unit_data = uc.get();
 
-		opts.write(ur.version);
-		opts.write(ur._pad);
-		opts.write(ur.name);
-		opts.write(ur.physics_resource);
-		opts.write(ur.sprite_animation);
-		opts.write(ur.num_renderables);
-		opts.write(ur.renderables_offset);
-		opts.write(ur.num_materials);
-		opts.write(ur.materials_offset);
-		opts.write(ur.num_cameras);
-		opts.write(ur.cameras_offset);
-		opts.write(ur.num_scene_graph_nodes);
-		opts.write(ur.scene_graph_nodes_offset);
-
-		// Renderables
-		for (uint32_t i = 0; i < array::size(m_renderables); i++)
-		{
-			opts.write(m_renderables[i].type);
-			opts.write(m_renderables[i]._pad);
-			opts.write(m_renderables[i].resource);
-			opts.write(m_renderables[i].name);
-			opts.write(m_renderables[i].node);
-			opts.write(m_renderables[i].visible);
-			opts.write(m_renderables[i]._pad1[0]);
-			opts.write(m_renderables[i]._pad1[1]);
-			opts.write(m_renderables[i]._pad1[2]);
-			opts.write(m_renderables[i]._pad2[0]);
-			opts.write(m_renderables[i]._pad2[1]);
-			opts.write(m_renderables[i]._pad2[2]);
-			opts.write(m_renderables[i]._pad2[3]);
-		}
-
-		// Materials
-		for (uint32_t i = 0; i < array::size(m_materials); i++)
-		{
-			opts.write(m_materials[i]);
-		}
-
-		// Cameras
-		for (uint32_t i = 0; i < array::size(m_cameras); i++)
-		{
-			opts.write(m_cameras[i].name);
-			opts.write(m_cameras[i].node);
-			opts.write(m_cameras[i].type);
-			opts.write(m_cameras[i].fov);
-			opts.write(m_cameras[i].near);
-			opts.write(m_cameras[i].far);
-		}
-
-		// Write node poses
-		for (uint32_t i = 0; i < ur.num_scene_graph_nodes; i++)
-		{
-			uint32_t node_index = m_node_depths[i].index;
-			GraphNode& node = m_nodes[node_index];
-			UnitNode un;
-			un.name = node.name;
-			un.parent = find_node_parent_index(i, m_nodes, m_node_depths);
-			un.pose = matrix4x4(node.rotation, node.position);
-
-			opts.write(un.name);
-			opts.write(un.pose);
-			opts.write(un.parent);
-		}
+		opts.write(unit_data);
 	}
 
 	void* load(File& file, Allocator& a)
 	{
-		const uint32_t file_size = file.size();
-		void* res = a.allocate(file_size);
-		file.read(res, file_size);
+		const uint32_t size = file.size();
+		void* res = a.allocate(size);
+		file.read(res, size);
 		CE_ASSERT(*(uint32_t*)res == UNIT_VERSION, "Wrong version");
 		return res;
 	}
 
-	void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
-	StringId64 sprite_animation(const UnitResource* ur)
-	{
-		return ur->sprite_animation;
-	}
-
-	StringId64 physics_resource(const UnitResource* ur)
-	{
-		return ur->physics_resource;
-	}
-
-	uint32_t num_renderables(const UnitResource* ur)
+	void unload(Allocator& a, void* resource)
 	{
-		return ur->num_renderables;
-	}
-
-	const UnitRenderable* get_renderable(const UnitResource* ur, uint32_t i)
-	{
-		CE_ASSERT(i < num_renderables(ur), "Index out of bounds");
-
-		UnitRenderable* begin = (UnitRenderable*) ((char*)ur + ur->renderables_offset);
-		return &begin[i];
-	}
-
-	uint32_t num_materials(const UnitResource* ur)
-	{
-		return ur->num_materials;
-	}
-
-	const UnitMaterial* get_material(const UnitResource* ur, uint32_t i)
-	{
-		CE_ASSERT(i < num_materials(ur), "Index out of bounds");
-
-		UnitMaterial* begin = (UnitMaterial*) ((char*)ur + ur->materials_offset);
-		return &begin[i];
+		a.deallocate(resource);
 	}
 
-	uint32_t num_cameras(const UnitResource* ur)
-	{
-		return ur->num_cameras;
-	}
-
-	const UnitCamera* get_camera(const UnitResource* ur, uint32_t i)
-	{
-		CE_ASSERT(i < num_cameras(ur), "Index out of bounds");
-
-		UnitCamera* begin = (UnitCamera*) ((char*)ur + ur->cameras_offset);
-		return &begin[i];
-	}
-
-	uint32_t num_scene_graph_nodes(const UnitResource* ur)
-	{
-		return ur->num_scene_graph_nodes;
-	}
-
-	const UnitNode* scene_graph_nodes(const UnitResource* ur)
-	{
-		return (UnitNode*) ((char*)ur + ur->scene_graph_nodes_offset);
-	}
 } // namespace unit_resource
 } // namespace crown

+ 9 - 57
src/resource/unit_resource.h

@@ -6,65 +6,27 @@
 #pragma once
 
 #include "memory_types.h"
-#include "resource_types.h"
 #include "filesystem_types.h"
-#include "math_types.h"
 #include "compiler_types.h"
 
 namespace crown
 {
 
-// All offsets are absolute
 struct UnitResource
 {
 	uint32_t version;
-	uint32_t _pad;
-	StringId64 name;
-	StringId64 physics_resource;
-	StringId64 sprite_animation;
-	uint32_t num_renderables;
-	uint32_t renderables_offset;
-	uint32_t num_materials;
-	uint32_t materials_offset;
-	uint32_t num_cameras;
-	uint32_t cameras_offset;
-	uint32_t num_scene_graph_nodes;
-	uint32_t scene_graph_nodes_offset;
+	uint32_t num_units;
+	uint32_t num_component_types;
+//	ComponentData data[num_component_types]
 };
 
-struct UnitRenderable
+struct ComponentData
 {
-	enum Enum { MESH, SPRITE };
 	uint32_t type;
-	uint32_t _pad;
-	StringId64 resource;
-	StringId32 name;
-	int32_t node;
-	bool visible;
-	char _pad1[3];
-	char _pad2[4];
-};
-
-struct UnitMaterial
-{
-	StringId64 id;
-};
-
-struct UnitCamera
-{
-	StringId32 name;
-	int32_t node;
-	uint32_t type; // ProjectionType::Enum
-	float fov;
-	float near;
-	float far;
-};
-
-struct UnitNode
-{
-	StringId32 name;
-	Matrix4x4 pose;
-	int32_t parent;
+	uint32_t num_instances;
+	uint32_t size;
+//	uint32_t unit_index[num_instances]
+//	char data[size]
 };
 
 namespace unit_resource
@@ -72,16 +34,6 @@ namespace unit_resource
 	void compile(const char* path, CompileOptions& opts);
 	void* load(File& file, Allocator& a);
 	void unload(Allocator& allocator, void* resource);
-
-	StringId64 sprite_animation(const UnitResource* ur);
-	StringId64 physics_resource(const UnitResource* ur);
-	uint32_t num_renderables(const UnitResource* ur);
-	const UnitRenderable* get_renderable(const UnitResource* ur, uint32_t i);
-	uint32_t num_materials(const UnitResource* ur);
-	const UnitMaterial* get_material(const UnitResource* ur, uint32_t i);
-	uint32_t num_cameras(const UnitResource* ur);
-	const UnitCamera* get_camera(const UnitResource* ur, uint32_t i);
-	uint32_t num_scene_graph_nodes(const UnitResource* ur);
-	const UnitNode* scene_graph_nodes(const UnitResource* ur);
 } // namespace unit_resource
+
 } // namespace crown

Деякі файли не було показано, через те що забагато файлів було змінено