Browse Source

resource: output properly aligned data

Daniele Bartolini 5 years ago
parent
commit
e7611a55f1

+ 14 - 0
src/core/filesystem/reader_writer.h

@@ -20,6 +20,9 @@ struct BinaryWriter
 	///
 	BinaryWriter(File& file);
 
+	///
+	void align(const u32 align);
+
 	///
 	void write(const void* data, u32 size);
 
@@ -27,6 +30,10 @@ struct BinaryWriter
 	template <typename T>
 	void write(const T& data);
 
+	///
+	template <typename T>
+	void write_unaligned(const T& data);
+
 	///
 	void skip(u32 bytes);
 };
@@ -41,6 +48,9 @@ struct BinaryReader
 	///
 	BinaryReader(File& file);
 
+	///
+	void align(const u32 align);
+
 	///
 	void read(void* data, u32 size);
 
@@ -48,6 +58,10 @@ struct BinaryReader
 	template <typename T>
 	void read(T& data);
 
+	///
+	template <typename T>
+	void read_unaligned(T& data);
+
 	///
 	void skip(u32 bytes);
 };

+ 32 - 0
src/core/filesystem/reader_writer.inl

@@ -15,6 +15,16 @@ inline BinaryWriter::BinaryWriter(File& file)
 {
 }
 
+inline void BinaryWriter::align(const u32 align)
+{
+	const u32 mask = align-1;
+	const u32 pos = (_file.position() + mask) & ~mask;
+	const u32 pad = pos - _file.position();
+	const char val = 0;
+	for (u32 ii = 0; ii < pad; ++ii)
+		_file.write(&val, 1);
+}
+
 inline void BinaryWriter::write(const void* data, u32 size)
 {
 	_file.write(data, size);
@@ -22,6 +32,13 @@ inline void BinaryWriter::write(const void* data, u32 size)
 
 template <typename T>
 inline void BinaryWriter::write(const T& data)
+{
+	align(alignof(T));
+	_file.write(&data, sizeof(T));
+}
+
+template <typename T>
+inline void BinaryWriter::write_unaligned(const T& data)
 {
 	_file.write(&data, sizeof(T));
 }
@@ -36,6 +53,14 @@ inline BinaryReader::BinaryReader(File& file)
 {
 }
 
+inline void BinaryReader::align(const u32 align)
+{
+	const u32 mask = align-1;
+	const u32 pos = (_file.position() + mask) & ~mask;
+	const u32 pad = pos - _file.position();
+	_file.skip(pad);
+}
+
 inline void BinaryReader::read(void* data, u32 size)
 {
 	_file.read(data, size);
@@ -43,6 +68,13 @@ inline void BinaryReader::read(void* data, u32 size)
 
 template <typename T>
 inline void BinaryReader::read(T& data)
+{
+	align(alignof(T));
+	_file.read(&data, sizeof(T));
+}
+
+template <typename T>
+inline void BinaryReader::read_unaligned(T& data)
 {
 	_file.read(&data, sizeof(T));
 }

+ 12 - 5
src/resource/compile_options.cpp

@@ -13,6 +13,7 @@
 #include "core/filesystem/file.h"
 #include "core/filesystem/filesystem.h"
 #include "core/filesystem/path.h"
+#include "core/filesystem/reader_writer.inl"
 #include "core/guid.h"
 #include "core/memory/temp_allocator.inl"
 #include "core/os.h"
@@ -20,12 +21,12 @@
 #include "core/strings/dynamic_string.inl"
 #include "core/strings/string_stream.h"
 #include "device/log.h"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/data_compiler.h"
 
 namespace crown
 {
-CompileOptions::CompileOptions(Buffer& output
+CompileOptions::CompileOptions(File& output
 	, HashMap<DynamicString, u32>& new_dependencies
 	, HashMap<DynamicString, u32>& new_requirements
 	, DataCompiler& dc
@@ -34,7 +35,8 @@ CompileOptions::CompileOptions(Buffer& output
 	, const DynamicString& source_path
 	, const char* platform
 	)
-	: _output(output)
+	: _file(output)
+	, _binary_writer(_file)
 	, _new_dependencies(new_dependencies)
 	, _new_requirements(new_requirements)
 	, _data_compiler(dc)
@@ -184,14 +186,19 @@ DeleteResult CompileOptions::delete_file(const char* path)
 	return _data_filesystem.delete_file(path);
 }
 
+void CompileOptions::align(const u32 align)
+{
+	_binary_writer.align(align);
+}
+
 void CompileOptions::write(const void* data, u32 size)
 {
-	array::push(_output, (const char*)data, size);
+	_binary_writer.write(data, size);
 }
 
 void CompileOptions::write(const Buffer& data)
 {
-	array::push(_output, array::begin(data), array::size(data));
+	write(array::begin(data), array::size(data));
 }
 
 const char* CompileOptions::platform() const

+ 8 - 6
src/resource/compile_options.h

@@ -10,6 +10,7 @@
 #if CROWN_CAN_COMPILE
 
 #include "core/containers/types.h"
+#include "core/filesystem/reader_writer.h"
 #include "core/filesystem/types.h"
 #include "core/os.h"
 #include "core/strings/dynamic_string.h"
@@ -61,7 +62,8 @@ namespace crown
 {
 struct CompileOptions
 {
-	Buffer& _output;
+	File& _file;
+	BinaryWriter _binary_writer;
 	HashMap<DynamicString, u32>& _new_dependencies;
 	HashMap<DynamicString, u32>& _new_requirements;
 	DataCompiler& _data_compiler;
@@ -71,7 +73,7 @@ struct CompileOptions
 	ResourceId _resource_id;
 
 	///
-	CompileOptions(Buffer& output
+	CompileOptions(File& output
 		, HashMap<DynamicString, u32>& new_dependencies
 		, HashMap<DynamicString, u32>& new_requirements
 		, DataCompiler& dc
@@ -134,15 +136,15 @@ struct CompileOptions
 	///
 	DeleteResult delete_file(const char* path);
 
+	///
+	void align(const u32 align);
+
 	///
 	void write(const void* data, u32 size);
 
 	///
 	template <typename T>
-	void write(const T& data)
-	{
-		write(&data, sizeof(data));
-	}
+	void write(const T& data);
 
 	///
 	void write(const Buffer& data);

+ 23 - 0
src/resource/compile_options.inl

@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012-2020 Daniele Bartolini and individual contributors.
+ * License: https://github.com/dbartolini/crown/blob/master/LICENSE
+ */
+
+#pragma once
+
+#include "core/filesystem/reader_writer.inl"
+#include "resource/compile_options.h"
+
+#if CROWN_CAN_COMPILE
+namespace crown
+{
+///
+template <typename T>
+void CompileOptions::write(const T& data)
+{
+	_binary_writer.write(data);
+}
+
+} // namespace crown
+
+#endif // CROWN_CAN_COMPILE

+ 1 - 1
src/resource/config_resource.cpp

@@ -10,7 +10,7 @@
 #include "core/memory/allocator.h"
 #include "core/memory/temp_allocator.inl"
 #include "core/strings/dynamic_string.inl"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/config_resource.h"
 #include "resource/types.h"
 

+ 5 - 3
src/resource/data_compiler.cpp

@@ -11,6 +11,7 @@
 #include "core/containers/hash_set.inl"
 #include "core/containers/vector.inl"
 #include "core/filesystem/file.h"
+#include "core/filesystem/file_buffer.inl"
 #include "core/filesystem/filesystem_disk.h"
 #include "core/filesystem/path.h"
 #include "core/guid.inl"
@@ -26,7 +27,7 @@
 #include "device/console_server.h"
 #include "device/device_options.h"
 #include "device/log.h"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/config_resource.h"
 #include "resource/data_compiler.h"
 #include "resource/font_resource.h"
@@ -1043,12 +1044,13 @@ bool DataCompiler::compile(const char* data_dir, const char* platform)
 			// "foo.unit" from a package, you do not want the list of
 			// requirements to include "foo.unit" again the next time that
 			// package is compiled.
-			Buffer output(default_allocator());
 			HashMap<DynamicString, u32> new_dependencies(default_allocator());
 			HashMap<DynamicString, u32> new_requirements(default_allocator());
 
+			Buffer output(default_allocator());
+			FileBuffer file_buffer(output);
 			// Invoke compiler
-			CompileOptions opts(output
+			CompileOptions opts(file_buffer
 				, new_dependencies
 				, new_requirements
 				, *this

+ 1 - 1
src/resource/font_resource.cpp

@@ -12,7 +12,7 @@
 #include "core/memory/allocator.h"
 #include "core/memory/temp_allocator.inl"
 #include "core/strings/string.inl"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/font_resource.h"
 #include "resource/types.h"
 #include <algorithm>

+ 12 - 12
src/resource/level_resource.cpp

@@ -11,7 +11,7 @@
 #include "core/memory/globals.h"
 #include "core/memory/temp_allocator.inl"
 #include "core/strings/dynamic_string.inl"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/level_resource.h"
 #include "resource/unit_compiler.h"
 
@@ -93,10 +93,11 @@ namespace level_resource_internal
 		LevelResource lr;
 		lr.version           = RESOURCE_HEADER(RESOURCE_VERSION_LEVEL);
 		lr.num_units         = uc._num_units;
-		lr.unit_names_offset = sizeof(lr);
-		lr.units_offset      = lr.unit_names_offset + (lr.num_units * sizeof(StringId32));
 		lr.num_sounds        = array::size(sounds);
-		lr.sounds_offset     = lr.units_offset + array::size(unit_blob);
+		lr.sounds_offset     = sizeof(lr);
+		lr.unit_names_offset = lr.sounds_offset + sizeof(LevelSound) * lr.num_sounds;
+		lr.units_offset      = lr.unit_names_offset + sizeof(StringId32) * lr.num_units;
+		lr.units_offset      = (u32)(uintptr_t)memory::align_top((void*)(uintptr_t)lr.units_offset, 16);
 
 		opts.write(lr.version);
 		opts.write(lr.num_units);
@@ -105,14 +106,6 @@ namespace level_resource_internal
 		opts.write(lr.num_sounds);
 		opts.write(lr.sounds_offset);
 
-		// Write unit names
-		for (u32 i = 0; i < array::size(uc._unit_names); ++i)
-			opts.write(uc._unit_names[i]._id);
-
-		// Write units
-		opts.write(unit_blob);
-		// Alignment to sizeof(ComponentData) ensured by UnitCompiler
-
 		// Write level sounds
 		for (u32 i = 0; i < array::size(sounds); ++i)
 		{
@@ -123,6 +116,13 @@ namespace level_resource_internal
 			opts.write(sounds[i].loop);
 		}
 
+		// Write unit names
+		for (u32 i = 0; i < array::size(uc._unit_names); ++i)
+			opts.write(uc._unit_names[i]._id);
+
+		// Write units
+		opts.align(16);
+		opts.write(unit_blob);
 		return 0;
 	}
 

+ 1 - 1
src/resource/material_resource.cpp

@@ -15,7 +15,7 @@
 #include "core/strings/string_id.inl"
 #include "core/strings/string_view.inl"
 #include "device/device.h"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/material_resource.h"
 #include "resource/resource_manager.h"
 #include "world/material_manager.h"

+ 1 - 1
src/resource/mesh_resource.cpp

@@ -19,7 +19,7 @@
 #include "core/strings/dynamic_string.inl"
 #include "core/strings/string_id.inl"
 #include "device/log.h"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/mesh_resource.h"
 #include "resource/resource_manager.h"
 

+ 1 - 1
src/resource/package_resource.cpp

@@ -16,7 +16,7 @@
 #include "core/memory/temp_allocator.inl"
 #include "core/strings/dynamic_string.inl"
 #include "core/strings/string_id.inl"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/data_compiler.h"
 #include "resource/package_resource.h"
 #include "resource/resource_id.inl"

+ 82 - 43
src/resource/physics_resource.cpp

@@ -7,6 +7,7 @@
 #include "core/containers/array.inl"
 #include "core/containers/hash_map.inl"
 #include "core/filesystem/file.h"
+#include "core/filesystem/file_buffer.inl"
 #include "core/filesystem/filesystem.h"
 #include "core/json/json_object.inl"
 #include "core/json/sjson.h"
@@ -18,7 +19,7 @@
 #include "core/strings/dynamic_string.inl"
 #include "core/strings/string.inl"
 #include "core/strings/string_id.inl"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/physics_resource.h"
 #include "world/types.h"
 
@@ -174,12 +175,17 @@ namespace physics_resource_internal
 		cd.type     = st;
 		cd.local_tm = MATRIX4X4_IDENTITY;
 		cd.size     = 0;
+
+		Array<Vector3> points(default_allocator());
+		Array<u16> point_indices(default_allocator());
+
 		DynamicString source(ta);
 		if (json_object::has(obj, "source"))
 			sjson::parse_string(source, obj["source"]);
 		bool explicit_collider = source == "mesh" || json_object::has(obj, "scene");
 
-		if (explicit_collider) {
+		if (explicit_collider)
+		{
 			// Parse .mesh
 			DynamicString scene(ta);
 			DynamicString name(ta);
@@ -223,7 +229,6 @@ namespace physics_resource_internal
 			sjson::parse_array(indices_data, indices["data"]);
 			sjson::parse_array(position_indices, indices_data[0]);
 
-			Array<Vector3> points(default_allocator());
 			for (u32 i = 0; i < array::size(positions); i += 3)
 			{
 				Vector3 p;
@@ -233,7 +238,6 @@ namespace physics_resource_internal
 				array::push_back(points, p);
 			}
 
-			Array<u16> point_indices(default_allocator());
 			for (u32 i = 0; i < array::size(position_indices); ++i)
 			{
 				array::push_back(point_indices, (u16)sjson::parse_int(position_indices[i]));
@@ -250,30 +254,9 @@ namespace physics_resource_internal
 				DATA_COMPILER_ASSERT(false, opts, "Not implemented yet");
 				break;
 			}
-
-			const u32 num_points  = array::size(points);
-			const u32 num_indices = array::size(point_indices);
-
-			const bool needs_points = cd.type == ColliderType::CONVEX_HULL
-				|| cd.type == ColliderType::MESH;
-
-			cd.size += (needs_points ? sizeof(u32) + sizeof(Vector3)*array::size(points) : 0);
-			cd.size += (cd.type == ColliderType::MESH ? sizeof(u32) + sizeof(u16)*array::size(point_indices) : 0);
-
-			array::push(output, (char*)&cd, sizeof(cd));
-
-			if (needs_points)
-			{
-				array::push(output, (char*)&num_points, sizeof(num_points));
-				array::push(output, (char*)array::begin(points), sizeof(Vector3)*array::size(points));
-			}
-			if (cd.type == ColliderType::MESH)
-			{
-				array::push(output, (char*)&num_indices, sizeof(num_indices));
-				array::push(output, (char*)array::begin(point_indices), sizeof(u16)*array::size(point_indices));
-			}
-
-		} else {
+		}
+		else
+		{
 			JsonObject collider_data(ta);
 			JsonArray org(ta);
 			DATA_COMPILER_ASSERT(json_object::has(obj, "collider_data")
@@ -289,17 +272,50 @@ namespace physics_resource_internal
 			if (cd.type == ColliderType::SPHERE) {
 				cd.sphere.radius = sjson::parse_float(collider_data["radius"]);
 			} else if (cd.type == ColliderType::BOX) {
-				JsonArray ext(ta);
-				sjson::parse_array(ext, collider_data["half_extents"]);
 				cd.box.half_size = sjson::parse_vector3(collider_data["half_extents"]);;
 			} else if (cd.type == ColliderType::CAPSULE) {
 				cd.capsule.radius = sjson::parse_float(collider_data["radius"]);
 				cd.capsule.height = sjson::parse_float(collider_data["height"]);
 			}
+		}
 
-			array::push(output, (char*)&cd, sizeof(cd));
+		const bool needs_points = cd.type == ColliderType::CONVEX_HULL
+			|| cd.type == ColliderType::MESH;
+		if (needs_points)
+		{
+			cd.size += sizeof(u32) + sizeof(Vector3)*array::size(points);
+			if (cd.type == ColliderType::MESH)
+				cd.size += sizeof(u32) + sizeof(u16)*array::size(point_indices);
 		}
 
+		FileBuffer fb(output);
+		BinaryWriter bw(fb);
+		bw.write(cd.type);
+		bw.write(cd.local_tm);
+		bw.write(cd.sphere.radius);
+		bw.write(cd.capsule.radius);
+		bw.write(cd.capsule.height);
+		bw.write(cd.box.half_size);
+		bw.write(cd.heightfield.width);
+		bw.write(cd.heightfield.length);
+		bw.write(cd.heightfield.height_scale);
+		bw.write(cd.heightfield.height_min);
+		bw.write(cd.heightfield.height_max);
+		bw.write(cd.size);
+
+		if (needs_points)
+		{
+			bw.write(array::size(points));
+			for (u32 ii = 0; ii < array::size(points); ++ii)
+				bw.write(points[ii]);
+
+			if (cd.type == ColliderType::MESH)
+			{
+				bw.write(array::size(point_indices));
+				for (u32 ii = 0; ii < array::size(point_indices); ++ii)
+					bw.write(point_indices[ii]);
+			}
+		}
 		return 0;
 	}
 
@@ -309,22 +325,28 @@ namespace physics_resource_internal
 		JsonObject obj(ta);
 		sjson::parse(obj, json);
 
+		u32 flags = 0;
+		flags |= (json_object::has(obj, "lock_translation_x") && sjson::parse_bool(obj["lock_translation_x"])) ? ActorFlags::LOCK_TRANSLATION_X : 0;
+		flags |= (json_object::has(obj, "lock_translation_y") && sjson::parse_bool(obj["lock_translation_y"])) ? ActorFlags::LOCK_TRANSLATION_Y : 0;
+		flags |= (json_object::has(obj, "lock_translation_z") && sjson::parse_bool(obj["lock_translation_z"])) ? ActorFlags::LOCK_TRANSLATION_Z : 0;
+		flags |= (json_object::has(obj, "lock_rotation_x") && sjson::parse_bool(obj["lock_rotation_x"])) ? ActorFlags::LOCK_ROTATION_X : 0;
+		flags |= (json_object::has(obj, "lock_rotation_y") && sjson::parse_bool(obj["lock_rotation_y"])) ? ActorFlags::LOCK_ROTATION_Y : 0;
+		flags |= (json_object::has(obj, "lock_rotation_z") && sjson::parse_bool(obj["lock_rotation_z"])) ? ActorFlags::LOCK_ROTATION_Z : 0;
+
 		ActorResource ar;
 		ar.actor_class      = sjson::parse_string_id(obj["class"]);
 		ar.mass             = sjson::parse_float    (obj["mass"]);
+		ar.flags            = flags;
 		ar.collision_filter = sjson::parse_string_id(obj["collision_filter"]);
 		ar.material         = sjson::parse_string_id(obj["material"]);
 
-		ar.flags = 0;
-		ar.flags |= (json_object::has(obj, "lock_translation_x") && sjson::parse_bool(obj["lock_translation_x"])) ? ActorFlags::LOCK_TRANSLATION_X : 0;
-		ar.flags |= (json_object::has(obj, "lock_translation_y") && sjson::parse_bool(obj["lock_translation_y"])) ? ActorFlags::LOCK_TRANSLATION_Y : 0;
-		ar.flags |= (json_object::has(obj, "lock_translation_z") && sjson::parse_bool(obj["lock_translation_z"])) ? ActorFlags::LOCK_TRANSLATION_Z : 0;
-		ar.flags |= (json_object::has(obj, "lock_rotation_x") && sjson::parse_bool(obj["lock_rotation_x"])) ? ActorFlags::LOCK_ROTATION_X : 0;
-		ar.flags |= (json_object::has(obj, "lock_rotation_y") && sjson::parse_bool(obj["lock_rotation_y"])) ? ActorFlags::LOCK_ROTATION_Y : 0;
-		ar.flags |= (json_object::has(obj, "lock_rotation_z") && sjson::parse_bool(obj["lock_rotation_z"])) ? ActorFlags::LOCK_ROTATION_Z : 0;
-
-		array::push(output, (char*)&ar, sizeof(ar));
-
+		FileBuffer fb(output);
+		BinaryWriter bw(fb);
+		bw.write(ar.actor_class);
+		bw.write(ar.mass);
+		bw.write(ar.flags);
+		bw.write(ar.collision_filter);
+		bw.write(ar.material);
 		return 0;
 	}
 
@@ -361,8 +383,25 @@ namespace physics_resource_internal
 			break;
 		}
 
-		array::push(output, (char*)&jd, sizeof(jd));
-
+		FileBuffer fb(output);
+		BinaryWriter bw(fb);
+		bw.write(jd.type);
+		bw.write(jd.anchor_0);
+		bw.write(jd.anchor_1);
+		bw.write(jd.breakable);
+		bw.write(jd._pad[0]);
+		bw.write(jd._pad[1]);
+		bw.write(jd._pad[2]);
+		bw.write(jd.break_force);
+		bw.write(jd.hinge);
+		bw.write(jd.hinge.axis);
+		bw.write(jd.hinge.use_motor);
+		bw.write(jd.hinge.target_velocity);
+		bw.write(jd.hinge.max_motor_impulse);
+		bw.write(jd.hinge.use_limits);
+		bw.write(jd.hinge.lower_limit);
+		bw.write(jd.hinge.upper_limit);
+		bw.write(jd.hinge.bounciness);
 		return 0;
 	}
 

+ 1 - 1
src/resource/shader_resource.cpp

@@ -14,7 +14,7 @@
 #include "core/strings/dynamic_string.inl"
 #include "core/strings/string_stream.inl"
 #include "device/device.h"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/resource_manager.h"
 #include "resource/shader_resource.h"
 #include "world/shader_manager.h"

+ 1 - 1
src/resource/sound_resource.cpp

@@ -11,7 +11,7 @@
 #include "core/memory/allocator.h"
 #include "core/memory/temp_allocator.inl"
 #include "core/strings/dynamic_string.inl"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/sound_resource.h"
 
 namespace crown

+ 1 - 1
src/resource/sprite_resource.cpp

@@ -14,7 +14,7 @@
 #include "core/math/vector4.inl"
 #include "core/memory/temp_allocator.inl"
 #include "core/strings/string.inl"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/resource_manager.h"
 #include "resource/sprite_resource.h"
 

+ 11 - 2
src/resource/state_machine_resource.cpp

@@ -16,7 +16,7 @@
 #include "core/memory/temp_allocator.inl"
 #include "core/strings/dynamic_string.inl"
 #include "core/strings/string_id.inl"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/expression_language.h"
 #include "resource/state_machine_resource.h"
 #include "resource/types.h"
@@ -76,7 +76,7 @@ namespace state_machine
 	const Animation* animation(const AnimationArray* aa, u32 index)
 	{
 		CE_ASSERT(index < aa->num, "Index out of bounds");
-		Animation* first = (Animation*)(&aa[1]);
+		Animation* first = (Animation*)(memory::align_top((void*)&aa[1], alignof(Animation)));
 		return &first[index];
 	}
 
@@ -146,13 +146,22 @@ namespace state_machine_internal
 		{
 		}
 
+		void align(u32 align)
+		{
+			_offset = (u32)(uintptr_t)memory::align_top((void*)(uintptr_t)_offset, align);
+		}
+
 		// Returns the offset of
 		u32 offset(u32 num_animations, u32 num_transitions)
 		{
 			const u32 offt = _offset;
+			align(alignof(State));
 			_offset += sizeof(State);
+			align(alignof(Transition));
 			_offset += sizeof(Transition) * num_transitions;
+			align(alignof(AnimationArray));
 			_offset += sizeof(AnimationArray);
+			align(alignof(Animation));
 			_offset += sizeof(Animation) * num_animations;
 			return offt;
 		}

+ 1 - 1
src/resource/texture_resource.cpp

@@ -11,7 +11,7 @@
 #include "core/process.h"
 #include "core/strings/dynamic_string.inl"
 #include "core/strings/string_stream.inl"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/resource_manager.h"
 #include "resource/texture_resource.h"
 

+ 7 - 7
src/resource/types.h

@@ -57,21 +57,21 @@ struct UnitResource;
 
 #define RESOURCE_FULL_REBUILD_COUNT       u32(0) //!< How many times we required a full asset rebuild?
 #define RESOURCE_VERSION(ver)             (RESOURCE_FULL_REBUILD_COUNT + ver)
-#define RESOURCE_VERSION_STATE_MACHINE    RESOURCE_VERSION(2)
+#define RESOURCE_VERSION_STATE_MACHINE    RESOURCE_VERSION(3)
 #define RESOURCE_VERSION_CONFIG           RESOURCE_VERSION(1)
 #define RESOURCE_VERSION_FONT             RESOURCE_VERSION(1)
-#define RESOURCE_VERSION_UNIT             RESOURCE_VERSION(5)
-#define RESOURCE_VERSION_LEVEL            (RESOURCE_VERSION_UNIT + 3) //!< Level embeds UnitResource
+#define RESOURCE_VERSION_UNIT             RESOURCE_VERSION(6)
+#define RESOURCE_VERSION_LEVEL            (RESOURCE_VERSION_UNIT + 4) //!< Level embeds UnitResource
 #define RESOURCE_VERSION_MATERIAL         RESOURCE_VERSION(2)
-#define RESOURCE_VERSION_MESH             RESOURCE_VERSION(1)
-#define RESOURCE_VERSION_PACKAGE          RESOURCE_VERSION(4)
+#define RESOURCE_VERSION_MESH             RESOURCE_VERSION(2)
+#define RESOURCE_VERSION_PACKAGE          RESOURCE_VERSION(5)
 #define RESOURCE_VERSION_PHYSICS_CONFIG   RESOURCE_VERSION(1)
 #define RESOURCE_VERSION_SCRIPT           RESOURCE_VERSION(1)
-#define RESOURCE_VERSION_SHADER           RESOURCE_VERSION(6)
+#define RESOURCE_VERSION_SHADER           RESOURCE_VERSION(7)
 #define RESOURCE_VERSION_SOUND            RESOURCE_VERSION(1)
 #define RESOURCE_VERSION_SPRITE_ANIMATION RESOURCE_VERSION(1)
 #define RESOURCE_VERSION_SPRITE           RESOURCE_VERSION(2)
-#define RESOURCE_VERSION_TEXTURE          RESOURCE_VERSION(4)
+#define RESOURCE_VERSION_TEXTURE          RESOURCE_VERSION(5)
 
 #define RESOURCE_MAGIC                    u32(0x9B) //!< Non-UTF8 to early out on file type detection
 #define RESOURCE_HEADER(version)          u32((version & 0x00ffffff) << 8 | RESOURCE_MAGIC)

+ 84 - 45
src/resource/unit_compiler.cpp

@@ -9,6 +9,7 @@
 
 #include "core/containers/array.inl"
 #include "core/containers/hash_map.inl"
+#include "core/filesystem/file_buffer.inl"
 #include "core/guid.inl"
 #include "core/json/json_object.inl"
 #include "core/json/sjson.h"
@@ -16,7 +17,7 @@
 #include "core/memory/temp_allocator.inl"
 #include "core/strings/dynamic_string.inl"
 #include "core/strings/string_id.inl"
-#include "resource/compile_options.h"
+#include "resource/compile_options.inl"
 #include "resource/physics_resource.h"
 #include "resource/unit_compiler.h"
 #include "resource/unit_resource.h"
@@ -85,8 +86,11 @@ static s32 compile_transform(Buffer& output, const char* json, CompileOptions& /
 	td.rotation = sjson::parse_quaternion(obj["rotation"]);
 	td.scale    = sjson::parse_vector3   (obj["scale"]);
 
-	array::push(output, (char*)&td, sizeof(td));
-
+	FileBuffer fb(output);
+	BinaryWriter bw(fb);
+	bw.write(td.position);
+	bw.write(td.rotation);
+	bw.write(td.scale);
 	return 0;
 }
 
@@ -112,8 +116,12 @@ static s32 compile_camera(Buffer& output, const char* json, CompileOptions& opts
 	cd.near_range = sjson::parse_float(obj["near_range"]);
 	cd.far_range  = sjson::parse_float(obj["far_range"]);
 
-	array::push(output, (char*)&cd, sizeof(cd));
-
+	FileBuffer fb(output);
+	BinaryWriter bw(fb);
+	bw.write(cd.type);
+	bw.write(cd.fov);
+	bw.write(cd.near_range);
+	bw.write(cd.far_range);
 	return 0;
 }
 
@@ -141,15 +149,22 @@ static s32 compile_mesh_renderer(Buffer& output, const char* json, CompileOption
 
 	MeshRendererDesc mrd;
 	mrd.mesh_resource     = sjson::parse_resource_name(obj["mesh_resource"]);
-	mrd.geometry_name     = sjson::parse_string_id    (obj["geometry_name"]);
 	mrd.material_resource = sjson::parse_resource_name(obj["material"]);
+	mrd.geometry_name     = sjson::parse_string_id    (obj["geometry_name"]);
 	mrd.visible           = sjson::parse_bool         (obj["visible"]);
 	mrd._pad0[0]          = 0;
 	mrd._pad0[1]          = 0;
 	mrd._pad0[2]          = 0;
 
-	array::push(output, (char*)&mrd, sizeof(mrd));
-
+	FileBuffer fb(output);
+	BinaryWriter bw(fb);
+	bw.write(mrd.mesh_resource);
+	bw.write(mrd.material_resource);
+	bw.write(mrd.geometry_name);
+	bw.write(mrd.visible);
+	bw.write(mrd._pad0[0]);
+	bw.write(mrd._pad0[1]);
+	bw.write(mrd._pad0[2]);
 	return 0;
 }
 
@@ -189,8 +204,20 @@ static s32 compile_sprite_renderer(Buffer& output, const char* json, CompileOpti
 	srd._pad1[2]          = 0;
 	srd._pad1[3]          = 0;
 
-	array::push(output, (char*)&srd, sizeof(srd));
-
+	FileBuffer fb(output);
+	BinaryWriter bw(fb);
+	bw.write(srd.sprite_resource);
+	bw.write(srd.material_resource);
+	bw.write(srd.layer);
+	bw.write(srd.depth);
+	bw.write(srd.visible);
+	bw.write(srd._pad0[0]);
+	bw.write(srd._pad0[1]);
+	bw.write(srd._pad0[2]);
+	bw.write(srd._pad1[0]);
+	bw.write(srd._pad1[1]);
+	bw.write(srd._pad1[2]);
+	bw.write(srd._pad1[3]);
 	return 0;
 }
 
@@ -217,8 +244,13 @@ static s32 compile_light(Buffer& output, const char* json, CompileOptions& opts)
 	ld.spot_angle = sjson::parse_float  (obj["spot_angle"]);
 	ld.color      = sjson::parse_vector3(obj["color"]);
 
-	array::push(output, (char*)&ld, sizeof(ld));
-
+	FileBuffer fb(output);
+	BinaryWriter bw(fb);
+	bw.write(ld.type);
+	bw.write(ld.range);
+	bw.write(ld.intensity);
+	bw.write(ld.spot_angle);
+	bw.write(ld.color);
 	return 0;
 }
 
@@ -239,8 +271,9 @@ static s32 compile_script(Buffer& output, const char* json, CompileOptions& opts
 	ScriptDesc sd;
 	sd.script_resource = sjson::parse_resource_name(obj["script_resource"]);
 
-	array::push(output, (char*)&sd, sizeof(sd));
-
+	FileBuffer fb(output);
+	BinaryWriter bw(fb);
+	bw.write(sd.script_resource);
 	return 0;
 }
 
@@ -261,8 +294,9 @@ static s32 compile_animation_state_machine(Buffer& output, const char* json, Com
 	AnimationStateMachineDesc asmd;
 	asmd.state_machine_resource = sjson::parse_resource_name(obj["state_machine_resource"]);
 
-	array::push(output, (char*)&asmd, sizeof(asmd));
-
+	FileBuffer fb(output);
+	BinaryWriter bw(fb);
+	bw.write(asmd.state_machine_resource);
 	return 0;
 }
 
@@ -528,25 +562,31 @@ s32 UnitCompiler::compile_multiple_units(const char* json)
 
 Buffer UnitCompiler::blob()
 {
-	UnitResource ur;
-	ur.version = RESOURCE_HEADER(RESOURCE_VERSION_UNIT);
-	ur.num_units = _num_units;
-	ur.num_component_types = 0;
+	Buffer output(default_allocator());
+	FileBuffer fb(output);
+	BinaryWriter bw(fb);
 
+	// Count component types
+	u32 num_component_types = 0;
 	auto cur = hash_map::begin(_component_data);
 	auto end = hash_map::end(_component_data);
 	for (; cur != end; ++cur)
 	{
 		HASH_MAP_SKIP_HOLE(_component_data, cur);
 
-		const u32 num = cur->second._num;
-
-		if (num > 0)
-			++ur.num_component_types;
+		if (cur->second._num > 0)
+			++num_component_types;
 	}
 
-	Buffer buf(default_allocator());
-	array::push(buf, (char*)&ur, sizeof(ur));
+	// Write header
+	UnitResource ur;
+	ur.version = RESOURCE_HEADER(RESOURCE_VERSION_UNIT);
+	ur.num_units = _num_units;
+	ur.num_component_types = num_component_types;
+
+	bw.write(ur.version);
+	bw.write(ur.num_units);
+	bw.write(ur.num_component_types);
 
 	for (u32 ii = 0; ii < array::size(_component_info); ++ii)
 	{
@@ -557,27 +597,26 @@ Buffer UnitCompiler::blob()
 		const Array<u32>& unit_index = ctd._unit_index;
 		const u32 num                = ctd._num;
 
-		if (num > 0)
-		{
-			ComponentData cd;
-			cd.type = type;
-			cd.num_instances = num;
-			cd.size = array::size(data) + sizeof(u32)*array::size(unit_index);
-
-			const u32 pad = cd.size % alignof(cd);
-			cd.size += pad;
-
-			array::push(buf, (char*)&cd, sizeof(cd));
-			array::push(buf, (char*)array::begin(unit_index), sizeof(u32)*array::size(unit_index));
-			array::push(buf, array::begin(data), array::size(data));
-
-			// Insert padding
-			for (u32 jj = 0; jj < pad; ++jj)
-				array::push_back(buf, (char)0);
-		}
+		if (num == 0)
+			continue;
+
+		// Write component data
+		ComponentData cd;
+		cd.type = type;
+		cd.num_instances = num;
+		cd.data_size = array::size(data);
+
+		bw.align(alignof(cd));
+		bw.write(cd.type);
+		bw.write(cd.num_instances);
+		bw.write(cd.data_size);
+		for (u32 jj = 0; jj < array::size(unit_index); ++jj)
+			bw.write(unit_index[jj]);
+		bw.align(16);
+		bw.write(array::begin(data), array::size(data));
 	}
 
-	return buf;
+	return output;
 }
 
 void UnitCompiler::add_component_data(StringId32 type, const Buffer& data, u32 unit_index)

+ 1 - 1
src/resource/unit_compiler.h

@@ -12,7 +12,7 @@
 #include "core/containers/types.h"
 #include "core/json/types.h"
 #include "core/strings/string_id.h"
-#include "resource/compile_options.h"
+#include "resource/types.h"
 
 namespace crown
 {

+ 11 - 0
src/resource/unit_resource.cpp

@@ -6,7 +6,9 @@
 #include "config.h"
 #include "core/containers/array.inl"
 #include "core/memory/globals.h"
+#include "resource/compile_options.inl"
 #include "resource/unit_compiler.h"
+#include "resource/unit_resource.h"
 
 namespace crown
 {
@@ -28,4 +30,13 @@ namespace unit_resource_internal
 } // namespace unit_resource_internal
 #endif // CROWN_CAN_COMPILE
 
+namespace unit_resource
+{
+	const ComponentData* component_data(const UnitResource* ur)
+	{
+		return (ComponentData*)(&ur[1]);
+	}
+
+} // namespace unit_resource
+
 } // namespace crown

+ 10 - 1
src/resource/unit_resource.h

@@ -7,6 +7,7 @@
 
 #include "core/filesystem/types.h"
 #include "core/memory/types.h"
+#include "core/strings/string_id.h"
 #include "resource/types.h"
 
 namespace crown
@@ -23,8 +24,9 @@ struct ComponentData
 {
 	StringId32 type;
 	u32 num_instances;
-	u32 size;
+	u32 data_size;
 //	u32 unit_index[num_instances]
+//	Padding to 16-bytes boundary
 //	char data[size]
 };
 
@@ -34,4 +36,11 @@ namespace unit_resource_internal
 
 } // namespace unit_resource_internal
 
+namespace unit_resource
+{
+	/// Returns the first component data in the unit resource @ur.
+	const ComponentData* component_data(const UnitResource* ur);
+
+} // namespace unit_resource
+
 } // namespace crown

+ 1 - 1
src/world/debug_line.cpp

@@ -251,7 +251,7 @@ void DebugLine::add_unit(ResourceManager& rm, const Matrix4x4& tm, StringId64 na
 			}
 		}
 
-		component_data += component->size + sizeof(ComponentData);
+		component_data += component->data_size + sizeof(ComponentData);
 	}
 }
 

+ 8 - 4
src/world/world.cpp

@@ -578,11 +578,12 @@ void spawn_units(World& w, const UnitResource& ur, const Vector3& pos, const Qua
 	ScriptWorld* script_world = w._script_world;
 	AnimationStateMachine* animation_state_machine = w._animation_state_machine;
 
-	const ComponentData* component = (ComponentData*)(&ur + 1);
-	for (u32 cc = 0; cc < ur.num_component_types; ++cc, component = (ComponentData*)((char*)component + component->size + sizeof(*component)))
+	// Create components
+	const ComponentData* component = unit_resource::component_data(&ur);
+	for (u32 cc = 0; cc < ur.num_component_types; ++cc)
 	{
-		const u32* unit_index = (const u32*)(component + 1);
-		const char* data = (const char*)(unit_index + component->num_instances);
+		const u32* unit_index = (u32*)(component + 1);
+		const char* data = (char*)memory::align_top(unit_index + component->num_instances, 16);
 
 		if (component->type == COMPONENT_TYPE_TRANSFORM)
 		{
@@ -678,6 +679,9 @@ void spawn_units(World& w, const UnitResource& ur, const Vector3& pos, const Qua
 		{
 			CE_FATAL("Unknown component type");
 		}
+
+		// Advance to next component type
+		component = (ComponentData*)memory::align_top(data + component->data_size, alignof(*component));
 	}
 
 	for (u32 i = 0; i < ur.num_units; ++i)