Browse Source

Prepare to use new compile()

Daniele Bartolini 11 years ago
parent
commit
08d2b3ea39
33 changed files with 2784 additions and 2138 deletions
  1. 53 149
      engine/compilers/bundle_compiler.cpp
  2. 10 6
      engine/compilers/bundle_compiler.h
  3. 2 3
      engine/compilers/compile_options.h
  4. 1 1
      engine/core/filesystem/reader_writer.h
  5. 1 1
      engine/main/main_linux.cpp
  6. 1 1
      engine/main/main_windows.cpp
  7. 77 49
      engine/resource/font_resource.cpp
  8. 12 30
      engine/resource/font_resource.h
  9. 491 0
      engine/resource/level_resource.bak
  10. 81 54
      engine/resource/level_resource.cpp
  11. 12 29
      engine/resource/level_resource.h
  12. 67 40
      engine/resource/lua_resource.cpp
  13. 12 29
      engine/resource/lua_resource.h
  14. 203 133
      engine/resource/material_resource.cpp
  15. 12 74
      engine/resource/material_resource.h
  16. 150 122
      engine/resource/mesh_resource.cpp
  17. 12 32
      engine/resource/mesh_resource.h
  18. 154 127
      engine/resource/package_resource.cpp
  19. 12 29
      engine/resource/package_resource.h
  20. 81 0
      engine/resource/pepper_resource.cpp
  21. 46 0
      engine/resource/pepper_resource.h
  22. 324 268
      engine/resource/physics_resource.cpp
  23. 25 58
      engine/resource/physics_resource.h
  24. 3 15
      engine/resource/resource.h
  25. 58 42
      engine/resource/resource_registry.cpp
  26. 1 0
      engine/resource/resource_registry.h
  27. 125 97
      engine/resource/sound_resource.cpp
  28. 12 33
      engine/resource/sound_resource.h
  29. 10 2
      engine/resource/sprite_resource.h
  30. 383 340
      engine/resource/texture_resource.cpp
  31. 12 44
      engine/resource/texture_resource.h
  32. 329 301
      engine/resource/unit_resource.cpp
  33. 12 29
      engine/resource/unit_resource.h

+ 53 - 149
engine/compilers/bundle_compiler.cpp

@@ -35,181 +35,85 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "path.h"
 #include "path.h"
 #include "disk_filesystem.h"
 #include "disk_filesystem.h"
 #include "compile_options.h"
 #include "compile_options.h"
+#include "resource_registry.h"
 #include <inttypes.h>
 #include <inttypes.h>
 
 
 namespace crown
 namespace crown
 {
 {
 
 
-namespace mesh_resource { extern void compile(Filesystem&, const char*, File*); }
-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*); }
-namespace material_resource { extern void compile(Filesystem&, const char*, File*); }
-namespace font_resource { extern void compile(Filesystem&, const char*, File*); }
-namespace level_resource { extern void compile(Filesystem&, const char*, File*); }
-namespace shader_resource { extern void compile(const char*, CompileOptions&); }
-namespace sprite_animation_resource { extern void compile(Filesystem&, const char*, File*); }
+//-----------------------------------------------------------------------------
+BundleCompiler::BundleCompiler(const char* source_dir, const char* bundle_dir)
+	: _source_fs(source_dir)
+	, _bundle_fs(bundle_dir)
+{
+	DiskFilesystem temp;
+	temp.create_directory(bundle_dir);
+}
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
-BundleCompiler::BundleCompiler()
+bool BundleCompiler::compile(const char* type, const char* name, const char* platform)
 {
 {
+	const ResourceId id(type, name);
+	char out_name[512];
+	snprintf(out_name, 512, "%.16"PRIx64"-%.16"PRIx64, id.type, id.name);
+	char path[512];
+	snprintf(path, 512, "%s.%s", name, type);
+
+	CE_LOGI("%s <= %s.%s", out_name, name, type);
+
+	File* outf = _bundle_fs.open(out_name, FOM_WRITE);
+	CompileOptions opts(_source_fs, outf, platform);
+	resource_on_compile(id.type, path, opts);
+	_bundle_fs.close(outf);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
-bool BundleCompiler::compile(const char* source_dir, const char* bundle_dir, const char* platform, const char* resource)
+bool BundleCompiler::compile_all(const char* platform)
 {
 {
 	Vector<DynamicString> files(default_allocator());
 	Vector<DynamicString> files(default_allocator());
+	BundleCompiler::scan("", files);
 
 
-	if (resource == NULL)
-	{
-		BundleCompiler::scan(source_dir, "", files);
-
-		DiskFilesystem temp;
-		temp.create_directory(bundle_dir);
-
-		DiskFilesystem src_fs(source_dir);
-		DiskFilesystem dst_fs(bundle_dir);
-
-		// Copy crown.config to bundle dir
-		if (src_fs.is_file("crown.config"))
-		{
-			File* src = src_fs.open("crown.config", FOM_READ);
-			File* dst = dst_fs.open("crown.config", FOM_WRITE);
-			src->copy_to(*dst, src->size());
-			src_fs.close(src);
-			dst_fs.close(dst);
-		}
-		else
-		{
-			CE_LOGD("'crown.config' does not exist.");
-			return false;
-		}
-	}
-	else
+	if (!_source_fs.is_file("crown.config"))
 	{
 	{
-		DynamicString filename(default_allocator());
-		filename = resource;
-		vector::push_back(files, filename);
+		CE_LOGD("'crown.config' does not exist.");
+		return false;
 	}
 	}
 
 
+	File* src = _source_fs.open("crown.config", FOM_READ);
+	File* dst = _bundle_fs.open("crown.config", FOM_WRITE);
+	src->copy_to(*dst, src->size());
+	_source_fs.close(src);
+	_bundle_fs.close(dst);
+
 	// Compile all resources
 	// Compile all resources
 	for (uint32_t i = 0; i < vector::size(files); i++)
 	for (uint32_t i = 0; i < vector::size(files); i++)
 	{
 	{
-		if (files[i].ends_with(".tga"))
-			continue;
-		if (files[i].ends_with(".dds"))
-			continue;
-		if (files[i].ends_with(".sh"))
-			continue;
-		if (files[i].ends_with(".sc"))
-			continue;
-		if (files[i].starts_with("."))
-			continue;
-		if (files[i].ends_with(".config"))
-			continue;
+		if (files[i].ends_with(".tga")
+			|| files[i].ends_with(".dds")
+			|| files[i].ends_with(".sh")
+			|| files[i].ends_with(".sc")
+			|| files[i].starts_with(".")
+			|| files[i].ends_with(".config"))
+		continue;
 
 
 		const char* filename = files[i].c_str();
 		const char* filename = files[i].c_str();
+		char type[256];
+		char name[256];
+		path::extension(filename, type, 256);
+		path::filename_without_extension(filename, name, 256);
 
 
-		char filename_extension[512];
-		char filename_without_extension[512];
-		path::extension(filename, filename_extension, 512);
-		path::filename_without_extension(filename, filename_without_extension, 512);
-
-		const ResourceId name(filename_extension, filename_without_extension);
-
-		char out_name[512];
-		snprintf(out_name, 512, "%.16"PRIx64"-%.16"PRIx64, name.type, name.name);
-		CE_LOGI("%s <= %s", out_name, filename);
-
-		DiskFilesystem root_fs(source_dir);
-		DiskFilesystem dest_fs(bundle_dir);
-
-		// Open destination file
-		File* out_file = dest_fs.open(out_name, FOM_WRITE);
-
-		if (out_file)
-		{
-			if (name.type == MESH_TYPE)
-			{
-				mesh_resource::compile(root_fs, filename, out_file);
-			}
-			else if (name.type == TEXTURE_TYPE)
-			{
-				texture_resource::compile(root_fs, filename, out_file);
-			}
-			else if (name.type == LUA_TYPE)
-			{
-				lua_resource::compile(root_fs, filename, out_file);
-			}
-			else if(name.type == SOUND_TYPE)
-			{
-				sound_resource::compile(root_fs, filename, out_file);
-			}
-			else if(name.type == SPRITE_TYPE)
-			{
-				sprite_resource::compile(root_fs, filename, out_file);
-			}
-			else if (name.type == PACKAGE_TYPE)
-			{
-				package_resource::compile(root_fs, filename, out_file);
-			}
-			else if (name.type == UNIT_TYPE)
-			{
-				unit_resource::compile(root_fs, filename, out_file);
-			}
-			else if (name.type == PHYSICS_TYPE)
-			{
-				physics_resource::compile(root_fs, filename, out_file);
-			}
-			else if (name.type == MATERIAL_TYPE)
-			{
-				material_resource::compile(root_fs, filename, out_file);
-			}
-			else if (name.type == PHYSICS_CONFIG_TYPE)
-			{
-				physics_config_resource::compile(root_fs, filename, out_file);
-			}
-			else if (name.type == FONT_TYPE)
-			{
-				font_resource::compile(root_fs, filename, out_file);
-			}
-			else if (name.type == LEVEL_TYPE)
-			{
-				level_resource::compile(root_fs, filename, out_file);
-			}
-			else if (name.type == SHADER_TYPE)
-			{
-				CompileOptions opts(root_fs, out_file, platform);
-				shader_resource::compile(filename, opts);
-			}
-			else if (name.type == SPRITE_ANIMATION_TYPE)
-			{
-				sprite_animation_resource::compile(root_fs, filename, out_file);
-			}
-			else
-			{
-				CE_LOGE("Oops, unknown resource type!");
-				return false;
-			}
-
-			dest_fs.close(out_file);
-		}
+		compile(type, name, platform);
 	}
 	}
 
 
 	return true;
 	return true;
 }
 }
 
 
-void BundleCompiler::scan(const char* source_dir, const char* cur_dir, Vector<DynamicString>& files)
+//-----------------------------------------------------------------------------
+void BundleCompiler::scan(const char* cur_dir, Vector<DynamicString>& files)
 {
 {
 	Vector<DynamicString> my_files(default_allocator());
 	Vector<DynamicString> my_files(default_allocator());
 
 
-	DiskFilesystem fs(source_dir);
-	fs.list_files(cur_dir, my_files);
+	_source_fs.list_files(cur_dir, my_files);
 
 
 	for (uint32_t i = 0; i < vector::size(my_files); i++)
 	for (uint32_t i = 0; i < vector::size(my_files); i++)
 	{
 	{
@@ -222,9 +126,9 @@ void BundleCompiler::scan(const char* source_dir, const char* cur_dir, Vector<Dy
 		}
 		}
 		file_i += my_files[i];
 		file_i += my_files[i];
 
 
-		if (fs.is_directory(file_i.c_str()))
+		if (_source_fs.is_directory(file_i.c_str()))
 		{
 		{
-			BundleCompiler::scan(source_dir, file_i.c_str(), files);
+			BundleCompiler::scan(file_i.c_str(), files);
 		}
 		}
 		else // Assume a regular file
 		else // Assume a regular file
 		{
 		{
@@ -239,7 +143,7 @@ namespace bundle_compiler
 	{
 	{
 		if (cls.do_compile)
 		if (cls.do_compile)
 		{
 		{
-			bool ok = bundle_compiler_globals::compiler()->compile(cls.source_dir, cls.bundle_dir, cls.platform);
+			bool ok = bundle_compiler_globals::compiler()->compile_all(cls.platform);
 			if (!ok || !cls.do_continue)
 			if (!ok || !cls.do_continue)
 			{
 			{
 				return false;
 				return false;
@@ -254,10 +158,10 @@ namespace bundle_compiler_globals
 {
 {
 	BundleCompiler* _compiler = NULL;
 	BundleCompiler* _compiler = NULL;
 
 
-	void init()
+	void init(const char* source_dir, const char* bundle_dir)
 	{
 	{
 #if CROWN_PLATFORM_LINUX || CROWN_PLATFORM_WINDOWS
 #if CROWN_PLATFORM_LINUX || CROWN_PLATFORM_WINDOWS
-		_compiler = CE_NEW(default_allocator(), BundleCompiler);
+		_compiler = CE_NEW(default_allocator(), BundleCompiler)(source_dir, bundle_dir);
 #endif
 #endif
 	}
 	}
 
 

+ 10 - 6
engine/compilers/bundle_compiler.h

@@ -26,7 +26,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 
 #pragma once
 #pragma once
 
 
-#include "filesystem.h"
+#include "disk_filesystem.h"
 #include "container_types.h"
 #include "container_types.h"
 #include "crown.h"
 #include "crown.h"
 
 
@@ -37,16 +37,20 @@ class BundleCompiler
 {
 {
 public:
 public:
 
 
-	BundleCompiler();
+	BundleCompiler(const char* source_dir, const char* bundle_dir);
+
+	bool compile(const char* type, const char* name, const char* platform = "linux");
 
 
 	/// Compiles all the resources found in @a source_dir and puts them in @a bundle_dir.
 	/// Compiles all the resources found in @a source_dir and puts them in @a bundle_dir.
-	/// If @a resource is not NULL, only that particular resource is compiled.
 	/// Returns true on success, false otherwise.
 	/// Returns true on success, false otherwise.
-	bool compile(const char* source_dir, const char* bundle_dir, const char* platform, const char* resource = NULL);
+	bool compile_all(const char* platform);
+
+	void scan(const char* cur_dir, Vector<DynamicString>& files);
 
 
 private:
 private:
 
 
-	static void scan(const char* source_dir, const char* cur_dir, Vector<DynamicString>& files);
+	DiskFilesystem _source_fs;
+	DiskFilesystem _bundle_fs;
 };
 };
 
 
 namespace bundle_compiler
 namespace bundle_compiler
@@ -57,7 +61,7 @@ namespace bundle_compiler
 namespace bundle_compiler_globals
 namespace bundle_compiler_globals
 {
 {
 	/// Creates the global resource compiler.
 	/// Creates the global resource compiler.
-	void init();
+	void init(const char* source_dir, const char* bundle_dir);
 
 
 	/// Destroys the global resource compiler.
 	/// Destroys the global resource compiler.
 	void shutdown();
 	void shutdown();

+ 2 - 3
engine/compilers/compile_options.h

@@ -70,9 +70,10 @@ struct CompileOptions
 	}
 	}
 
 
 	template <typename T>
 	template <typename T>
-	void write(const T& data)
+	BinaryWriter& write(const T& data)
 	{
 	{
 		_bw.write(data);
 		_bw.write(data);
+		return _bw;
 	}
 	}
 
 
 	const char* platform() const
 	const char* platform() const
@@ -80,8 +81,6 @@ struct CompileOptions
 		return _platform;
 		return _platform;
 	}
 	}
 
 
-private:
-
 	Filesystem& _fs;
 	Filesystem& _fs;
 	BinaryWriter _bw;
 	BinaryWriter _bw;
 	const char* _platform;
 	const char* _platform;

+ 1 - 1
engine/core/filesystem/reader_writer.h

@@ -128,7 +128,7 @@ public:
 		m_file.skip(bytes);
 		m_file.skip(bytes);
 	}
 	}
 
 
-private:
+//private:
 
 
 	File& m_file;
 	File& m_file;
 };
 };

+ 1 - 1
engine/main/main_linux.cpp

@@ -444,7 +444,7 @@ int main(int argc, char** argv)
 	console_server_globals::init();
 	console_server_globals::init();
 	console_server_globals::console().init(cs.console_port, cls.wait_console);
 	console_server_globals::console().init(cs.console_port, cls.wait_console);
 
 
-	bundle_compiler_globals::init();
+	bundle_compiler_globals::init(cls.source_dir, cls.bundle_dir);
 
 
 	bool do_continue = true;
 	bool do_continue = true;
 	int exitcode = EXIT_SUCCESS;
 	int exitcode = EXIT_SUCCESS;

+ 1 - 1
engine/main/main_windows.cpp

@@ -360,7 +360,7 @@ int main(int argc, char** argv)
 	console_server_globals::init();
 	console_server_globals::init();
 	console_server_globals::console().init(cs.console_port, cls.wait_console);
 	console_server_globals::console().init(cs.console_port, cls.wait_console);
 
 
-	bundle_compiler_globals::init();
+	bundle_compiler_globals::init(cls.source_dir, cls.bundle_dir);
 
 
 	bool do_continue = true;
 	bool do_continue = true;
 	int exitcode = EXIT_SUCCESS;
 	int exitcode = EXIT_SUCCESS;

+ 77 - 49
engine/resource/font_resource.cpp

@@ -37,67 +37,95 @@ namespace crown
 {
 {
 namespace font_resource
 namespace font_resource
 {
 {
+	//-----------------------------------------------------------------------------
+	void parse_glyph(JSONElement e, FontGlyphData& glyph)
+	{
+		JSONElement id = e.key("id");
+		JSONElement x = e.key("x");
+		JSONElement y = e.key("y");
+		JSONElement width = e.key("width");
+		JSONElement height = e.key("height");
+		JSONElement x_offset = e.key("x_offset");
+		JSONElement y_offset = e.key("y_offset");
+		JSONElement x_advance = e.key("x_advance");
+
+		glyph.id = id.to_int();
+		glyph.x = x.to_int();
+		glyph.y = y.to_int();
+		glyph.width = width.to_int();
+		glyph.height = height.to_int();
+		glyph.x_offset = x_offset.to_float();
+		glyph.y_offset = y_offset.to_float();
+		glyph.x_advance = x_advance.to_float();
+	}
 
 
-//-----------------------------------------------------------------------------
-void parse_glyph(JSONElement e, FontGlyphData& glyph)
-{
-	JSONElement id = e.key("id");
-	JSONElement x = e.key("x");
-	JSONElement y = e.key("y");
-	JSONElement width = e.key("width");
-	JSONElement height = e.key("height");
-	JSONElement x_offset = e.key("x_offset");
-	JSONElement y_offset = e.key("y_offset");
-	JSONElement x_advance = e.key("x_advance");
-
-	glyph.id = id.to_int();
-	glyph.x = x.to_int();
-	glyph.y = y.to_int();
-	glyph.width = width.to_int();
-	glyph.height = height.to_int();
-	glyph.x_offset = x_offset.to_float();
-	glyph.y_offset = y_offset.to_float();
-	glyph.x_advance = x_advance.to_float();
-}
-
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	File* file = fs.open(resource_path, FOM_READ);
-	JSONParser json(*file);
-	fs.close(file);
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
+	{
+		File* file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*file);
+		fs.close(file);
 
 
-	// Out buffer
-	FontHeader h;
-	Array<FontGlyphData> m_glyphs(default_allocator());
+		// Out buffer
+		FontHeader h;
+		Array<FontGlyphData> m_glyphs(default_allocator());
 
 
-	JSONElement root = json.root();
+		JSONElement root = json.root();
 
 
-	JSONElement count = root.key("count");
-	JSONElement size = root.key("size");
-	JSONElement font_size = root.key("font_size");
-	JSONElement glyphs = root.key("glyphs");
+		JSONElement count = root.key("count");
+		JSONElement size = root.key("size");
+		JSONElement font_size = root.key("font_size");
+		JSONElement glyphs = root.key("glyphs");
 
 
-	uint32_t num_glyphs = count.to_int();
+		uint32_t num_glyphs = count.to_int();
 
 
-	for (uint32_t i = 0; i < num_glyphs; i++)
-	{
-		FontGlyphData data;
-		parse_glyph(glyphs[i], data);
-		array::push_back(m_glyphs, data);
+		for (uint32_t i = 0; i < num_glyphs; i++)
+		{
+			FontGlyphData data;
+			parse_glyph(glyphs[i], data);
+			array::push_back(m_glyphs, data);
+		}
+
+		h.num_glyphs = array::size(m_glyphs);
+		h.texture_size = size.to_int();
+		h.font_size = font_size.to_int();
+
+		out_file->write((char*) &h, sizeof(FontHeader));
+
+		if (array::size(m_glyphs) > 0)
+		{
+			out_file->write((char*) array::begin(m_glyphs), sizeof(FontGlyphData) * h.num_glyphs);
+		}
 	}
 	}
 
 
-	h.num_glyphs = array::size(m_glyphs);
-	h.texture_size = size.to_int();
-	h.font_size = font_size.to_int();
+	//-----------------------------------------------------------------------------
+	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);
 
 
-	out_file->write((char*) &h, sizeof(FontHeader));
+		bundle.close(file);
 
 
-	if (array::size(m_glyphs) > 0)
+		return res;
+	}
+
+	//-----------------------------------------------------------------------------
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
 	{
 	{
-		out_file->write((char*) array::begin(m_glyphs), sizeof(FontGlyphData) * h.num_glyphs);
 	}
 	}
-}
 
 
+	//-----------------------------------------------------------------------------
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& allocator, void* resource)
+	{
+		allocator.deallocate(resource);
+	}
 } // namespace font_resource
 } // namespace font_resource
 } // namespace crown
 } // namespace crown

+ 12 - 30
engine/resource/font_resource.h

@@ -63,36 +63,6 @@ class FontResource
 {
 {
 public:
 public:
 
 
-	//-----------------------------------------------------------------------------
-	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(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
 	uint32_t num_glyphs() const
 	uint32_t num_glyphs() const
 	{
 	{
@@ -136,5 +106,17 @@ private:
 	FontResource();
 	FontResource();
 };
 };
 
 
+namespace font_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void unload(Allocator& allocator, void* resource);
+} // namespace font_resource
 } // namespace crown
 } // namespace crown
 
 

+ 491 - 0
engine/resource/level_resource.bak

@@ -0,0 +1,491 @@
+/*
+Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "level_resource.h"
+#include "array.h"
+#include "memory.h"
+#include "json_parser.h"
+#include "filesystem.h"
+#include "reader_writer.h"
+
+namespace crown
+{
+namespace level_resource
+{
+	//-----------------------------------------------------------------------------
+	void parse_units(JSONElement root, Array<LevelUnit>& units)
+	{
+		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("unit");
+			lu.position = e.key("position").to_vector3();
+			lu.rotation = e.key("rotation").to_quaternion();
+
+			array::push_back(units, lu);
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void parse_sounds(JSONElement root, Array<LevelSound>& sounds)
+	{
+		JSONElement sounds_arr = root.key("sounds");
+		const uint32_t size = sounds_arr.size();
+
+		for (uint32_t i = 0; i < size; i++)
+		{
+			JSONElement e = sounds_arr[i];
+
+			LevelSound ls;
+			ls.name = e.key("name").to_resource_id("sound");
+			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();
+
+			array::push_back(sounds, ls);
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
+	{
+/*		File* file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*file);
+		fs.close(file);
+
+		JSONElement root = json.root();
+
+		Array<LevelUnit> units(default_allocator());
+		Array<LevelSound> sounds(default_allocator());
+
+		parse_units(root, units);
+		parse_sounds(root, sounds);
+
+		LevelHeader lh;
+		lh.num_units = array::size(units);
+		lh.num_sounds = array::size(sounds);
+
+		uint32_t offt = sizeof(LevelHeader);
+		lh.units_offset = offt; offt += sizeof(LevelUnit) * lh.num_units;
+		lh.sounds_offset = offt;
+
+		out_file->write((char*) &lh, sizeof(LevelHeader));
+
+		if (lh.num_units)
+		{
+			out_file->write((char*) array::begin(units), sizeof(LevelUnit) * lh.num_units);
+		}
+		if (lh.num_sounds)
+		{
+			out_file->write((char*) array::begin(sounds), sizeof(LevelSound) * lh.num_sounds);
+		}*/
+	}
+
+	void compile(const char* path, CompileOptions& opts)
+	{
+		Buffer buf = opts.read(path);
+		JSONParser json(array::begin(buf));
+		JSONElement root = json.root();
+
+		Array<LevelUnit> units(default_allocator());
+		Array<LevelSound> sounds(default_allocator());
+		parse_units(root, units);
+		parse_sounds(root, sounds);
+
+		LevelHeader lh;
+		lh.num_units = array::size(units);
+		lh.num_sounds = array::size(sounds);
+
+		uint32_t offt = sizeof(LevelHeader);
+		lh.units_offset = offt; offt += sizeof(LevelUnit) * lh.num_units;
+		lh.sounds_offset = offt;
+
+		// Version 1
+		// opts.write(lh);
+		// if (lh.num_units)
+		// 	opts.write(array::begin(units), sizeof(LevelUnit) * lh.num_units);
+		// if (lh.num_sounds)
+		// 	opts.write(array::begin(sounds), sizeof(LevelSound) * lh.num_sounds);
+
+		// Version 2
+		// opts.write(lh.num_units);
+		// opts.write(lh.units_offset);
+		// opts.write(lh.num_sounds);
+		// opts.write(lh.sounds_offset);
+
+		// if (lh.num_units) {
+		// 	for (uint32_t i = 0; i < array::size(units); i++)
+		// 	{
+		// 		LevelUnit lu = units[i];
+		// 		opts.write(lu.name);
+		// 		opts.write(lu.position);
+		// 		opts.write(lu.rotation);
+		// 		opts.write(uint32_t(0xABABABAB));
+		// 	}
+		// }
+
+		// if (lh.num_sounds) {
+		// 	for (uint32_t i = 0; i < array::size(sounds); i++)
+		// 	{
+		// 		LevelSound ls = sounds[i];
+		// 		opts.write(ls.name);
+		// 		opts.write(ls.position);
+		// 		opts.write(ls.volume);
+		// 		opts.write(ls.range);
+		// 		opts.write(ls.loop);
+		// 		opts.write(uint8_t(0xff));
+		// 		opts.write(uint8_t(0xff));
+		// 		opts.write(uint8_t(0xff));
+		// 	}
+		// }
+
+		// Version 3
+		BinaryWriter& bw = opts._bw;
+		bw & lh;
+		bw & units;
+		bw & sounds;
+	}
+
+	//-----------------------------------------------------------------------------
+	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;
+	}
+
+	//-----------------------------------------------------------------------------
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
+
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& allocator, void* resource)
+	{
+		allocator.deallocate(resource);
+	}
+} // namespace level_resource
+} // namespace crown
+
+
+
+
+
+
+
+
+/*
+Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#pragma once
+
+#include "allocator.h"
+#include "assert.h"
+#include "bundle.h"
+#include "file.h"
+#include "resource.h"
+#include "types.h"
+#include "vector3.h"
+#include "quaternion.h"
+
+namespace crown
+{
+
+template <typename STREAM, typename T> inline STREAM& operator&(STREAM& stream, T& t)
+{
+	return t.serialize(stream);
+}
+
+template <> inline BinaryWriter& operator&<BinaryWriter, Vector3>(BinaryWriter& bw, Vector3& v)
+{
+	bw.write(v.x);
+	bw.write(v.y);
+	bw.write(v.z);
+	return bw;
+}
+
+template <> inline BinaryReader& operator& <BinaryReader, Vector3> (BinaryReader& br, Vector3& v)
+{
+	br.read(v.x);
+	br.read(v.y);
+	br.read(v.z);
+	return br;
+}
+
+template <> inline BinaryWriter& operator&<BinaryWriter, Quaternion>(BinaryWriter& bw, Quaternion& q)
+{
+	bw.write(q.x);
+	bw.write(q.y);
+	bw.write(q.z);
+	bw.write(q.w);
+	return bw;
+}
+
+template <> inline BinaryReader& operator& <BinaryReader, Quaternion> (BinaryReader& br, Quaternion& q)
+{
+	br.read(q.x);
+	br.read(q.y);
+	br.read(q.z);
+	br.read(q.w);
+	return br;
+}
+
+template <> inline BinaryWriter& operator&<BinaryWriter, bool>(BinaryWriter& bw, bool& v)
+{
+	bw.write(v);
+	return bw;
+}
+
+template <> inline BinaryReader& operator& <BinaryReader, bool> (BinaryReader& br, bool& v)
+{
+	br.read(v);
+	return br;
+}
+
+template <> inline BinaryWriter& operator&<BinaryWriter, float>(BinaryWriter& bw, float& v)
+{
+	bw.write(v);
+	return bw;
+}
+
+template <> inline BinaryReader& operator& <BinaryReader, float> (BinaryReader& br, float& v)
+{
+	br.read(v);
+	return br;
+}
+
+template <> inline BinaryWriter& operator&<BinaryWriter, uint8_t>(BinaryWriter& bw, uint8_t& v)
+{
+	bw.write(v);
+	return bw;
+}
+
+template <> inline BinaryReader& operator& <BinaryReader, uint8_t> (BinaryReader& br, uint8_t& v)
+{
+	br.read(v);
+	return br;
+}
+
+template <> inline BinaryWriter& operator&<BinaryWriter, uint32_t>(BinaryWriter& bw, uint32_t& v)
+{
+	bw.write(v);
+	return bw;
+}
+
+template <> inline BinaryReader& operator& <BinaryReader, uint32_t> (BinaryReader& br, uint32_t& v)
+{
+	br.read(v);
+	return br;
+}
+
+template <> inline BinaryWriter& operator&<BinaryWriter, ResourceId>(BinaryWriter& bw, ResourceId& id)
+{
+	bw.write(id.type);
+	bw.write(id.name);
+	return bw;
+}
+
+template <> inline BinaryReader& operator& <BinaryReader, ResourceId> (BinaryReader& br, ResourceId& id)
+{
+	br.read(id.type);
+	br.read(id.name);
+	return br;
+}
+
+struct LevelHeader
+{
+	template <typename STREAM>
+	inline STREAM& serialize(STREAM& stream)
+	{
+		return stream
+			& num_units
+			& units_offset
+			& num_sounds
+			& sounds_offset;
+	}
+
+	uint32_t num_units;
+	uint32_t units_offset;
+	uint32_t num_sounds;
+	uint32_t sounds_offset;
+};
+
+struct LevelUnit
+{
+	template <typename STREAM>
+	inline STREAM& serialize(STREAM& stream)
+	{
+		return stream
+			& name
+			& position
+			& rotation
+			& _pad0
+			& _pad1
+			& _pad2
+			& _pad3;
+	}
+
+	ResourceId name;
+	Vector3 position;
+	Quaternion rotation;
+	uint8_t _pad0;
+	uint8_t _pad1;
+	uint8_t _pad2;
+	uint8_t _pad3;
+};
+
+template <> inline BinaryWriter& operator&<BinaryWriter, Array<LevelUnit> >(BinaryWriter& bw, Array<LevelUnit>& arr)
+{
+	for (uint32_t i = 0; i < array::size(arr); i++)
+		bw & arr[i];
+	return bw;
+}
+
+template <> inline BinaryReader& operator& <BinaryReader, Array<LevelUnit> > (BinaryReader& br, Array<LevelUnit>& arr)
+{
+	return br;
+}
+
+struct LevelSound
+{
+	template <typename STREAM>
+	inline STREAM& serialize(STREAM& stream)
+	{
+		return stream & name
+			& position
+			& volume
+			& range
+			& loop
+			& _pad0
+			& _pad1
+			& _pad2;
+	}
+
+	ResourceId name;
+	Vector3 position;
+	float volume;
+	float range;
+	bool loop;
+	uint8_t _pad0;
+	uint8_t _pad1;
+	uint8_t _pad2;
+};
+
+template <> inline BinaryWriter& operator&<BinaryWriter, Array<LevelSound> >(BinaryWriter& bw, Array<LevelSound>& arr)
+{
+	for (uint32_t i = 0; i < array::size(arr); i++)
+		bw & arr[i];
+	return bw;
+}
+
+template <> inline BinaryReader& operator& <BinaryReader, Array<LevelSound> > (BinaryReader& br, Array<LevelSound>& arr)
+{
+	return br;
+}
+
+struct LevelResource
+{
+	//-----------------------------------------------------------------------------
+	uint32_t num_units() const
+	{
+		return ((LevelHeader*) this)->num_units;
+	}
+
+	//-----------------------------------------------------------------------------
+	const LevelUnit* get_unit(uint32_t i) const
+	{
+		CE_ASSERT(i < num_units(), "Index out of bounds");
+
+		const LevelHeader* h = (LevelHeader*) this;
+		const LevelUnit* begin = (LevelUnit*) (((char*) this) + h->units_offset);
+		return &begin[i];
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t num_sounds() const
+	{
+		return ((LevelHeader*) this)->num_sounds;
+	}
+
+	//-----------------------------------------------------------------------------
+	const LevelSound* get_sound(uint32_t i) const
+	{
+		CE_ASSERT(i < num_sounds(), "Index out of bounds");
+
+		const LevelHeader* h = (LevelHeader*) this;
+		const LevelSound* begin = (LevelSound*) (((char*) this) + h->sounds_offset);
+		return &begin[i];
+	}
+};
+
+namespace level_resource
+{
+	void compile(const char* path, CompileOptions& opts);
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void unload(Allocator& allocator, void* resource);
+} // namespace level_resource
+} // namespace crown

+ 81 - 54
engine/resource/level_resource.cpp

@@ -34,81 +34,108 @@ namespace crown
 {
 {
 namespace level_resource
 namespace level_resource
 {
 {
-
-//-----------------------------------------------------------------------------
-void parse_units(JSONElement root, Array<LevelUnit>& units)
-{
-	JSONElement units_arr = root.key("units");
-	const uint32_t size = units_arr.size();
-
-	for (uint32_t i = 0; i < size; i++)
+	//-----------------------------------------------------------------------------
+	void parse_units(JSONElement root, Array<LevelUnit>& units)
 	{
 	{
-		JSONElement e = units_arr[i];
+		JSONElement units_arr = root.key("units");
+		const uint32_t size = units_arr.size();
 
 
-		LevelUnit lu;
-		lu.name = e.key("name").to_resource_id("unit");
-		lu.position = e.key("position").to_vector3();
-		lu.rotation = e.key("rotation").to_quaternion();
+		for (uint32_t i = 0; i < size; i++)
+		{
+			JSONElement e = units_arr[i];
 
 
-		array::push_back(units, lu);
+			LevelUnit lu;
+			lu.name = e.key("name").to_resource_id("unit");
+			lu.position = e.key("position").to_vector3();
+			lu.rotation = e.key("rotation").to_quaternion();
+
+			array::push_back(units, lu);
+		}
 	}
 	}
-}
 
 
-//-----------------------------------------------------------------------------
-void parse_sounds(JSONElement root, Array<LevelSound>& sounds)
-{
-	JSONElement sounds_arr = root.key("sounds");
-	const uint32_t size = sounds_arr.size();
+	//-----------------------------------------------------------------------------
+	void parse_sounds(JSONElement root, Array<LevelSound>& sounds)
+	{
+		JSONElement sounds_arr = root.key("sounds");
+		const uint32_t size = sounds_arr.size();
+
+		for (uint32_t i = 0; i < size; i++)
+		{
+			JSONElement e = sounds_arr[i];
+
+			LevelSound ls;
+			ls.name = e.key("name").to_resource_id("sound");
+			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();
+
+			array::push_back(sounds, ls);
+		}
+	}
 
 
-	for (uint32_t i = 0; i < size; i++)
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	{
 	{
-		JSONElement e = sounds_arr[i];
+		File* file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*file);
+		fs.close(file);
 
 
-		LevelSound ls;
-		ls.name = e.key("name").to_resource_id("sound");
-		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();
+		JSONElement root = json.root();
 
 
-		array::push_back(sounds, ls);
-	}
-}
+		Array<LevelUnit> units(default_allocator());
+		Array<LevelSound> sounds(default_allocator());
 
 
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	File* file = fs.open(resource_path, FOM_READ);
-	JSONParser json(*file);
-	fs.close(file);
+		parse_units(root, units);
+		parse_sounds(root, sounds);
 
 
-	JSONElement root = json.root();
+		LevelHeader lh;
+		lh.num_units = array::size(units);
+		lh.num_sounds = array::size(sounds);
 
 
-	Array<LevelUnit> units(default_allocator());
-	Array<LevelSound> sounds(default_allocator());
+		uint32_t offt = sizeof(LevelHeader);
+		lh.units_offset = offt; offt += sizeof(LevelUnit) * lh.num_units;
+		lh.sounds_offset = offt;
 
 
-	parse_units(root, units);
-	parse_sounds(root, sounds);
+		out_file->write((char*) &lh, sizeof(LevelHeader));
 
 
-	LevelHeader lh;
-	lh.num_units = array::size(units);
-	lh.num_sounds = array::size(sounds);
+		if (lh.num_units)
+		{
+			out_file->write((char*) array::begin(units), sizeof(LevelUnit) * lh.num_units);
+		}
+		if (lh.num_sounds)
+		{
+			out_file->write((char*) array::begin(sounds), sizeof(LevelSound) * lh.num_sounds);
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	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);
 
 
-	uint32_t offt = sizeof(LevelHeader);
-	lh.units_offset = offt; offt += sizeof(LevelUnit) * lh.num_units;
-	lh.sounds_offset = offt;
+		bundle.close(file);
 
 
-	out_file->write((char*) &lh, sizeof(LevelHeader));
+		return res;
+	}
 
 
-	if (lh.num_units)
+	//-----------------------------------------------------------------------------
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
 	{
 	{
-		out_file->write((char*) array::begin(units), sizeof(LevelUnit) * lh.num_units);
 	}
 	}
-	if (lh.num_sounds)
+
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
 	{
 	{
-		out_file->write((char*) array::begin(sounds), sizeof(LevelSound) * lh.num_sounds);
 	}
 	}
-}
 
 
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& allocator, void* resource)
+	{
+		allocator.deallocate(resource);
+	}
 } // namespace level_resource
 } // namespace level_resource
 } // namespace crown
 } // namespace crown

+ 12 - 29
engine/resource/level_resource.h

@@ -64,35 +64,6 @@ struct LevelSound
 
 
 struct LevelResource
 struct LevelResource
 {
 {
-	//-----------------------------------------------------------------------------
-	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(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
 	uint32_t num_units() const
 	uint32_t num_units() const
 	{
 	{
@@ -126,4 +97,16 @@ struct LevelResource
 	}
 	}
 };
 };
 
 
+namespace level_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void unload(Allocator& allocator, void* resource);
+} // namespace level_resource
 } // namespace crown
 } // namespace crown

+ 67 - 40
engine/resource/lua_resource.cpp

@@ -48,55 +48,82 @@ namespace crown
 {
 {
 namespace lua_resource
 namespace lua_resource
 {
 {
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
+	{
+		TempAllocator1024 alloc;
+		DynamicString res_abs_path(alloc);
+		TempAllocator1024 alloc2;
+		DynamicString bc_abs_path(alloc2);
+		fs.get_absolute_path(resource_path, res_abs_path);
+		fs.get_absolute_path("bc.tmp", bc_abs_path);
+
+		const char* luajit[] =
+		{
+			LUAJIT_EXECUTABLE,
+			LUAJIT_FLAGS,
+			res_abs_path.c_str(),
+			bc_abs_path.c_str(),
+			NULL
+		};
+
+		os::execute_process(luajit);
+
+		size_t program_size = 0;
+		char* program = NULL;
+
+		File* bc = fs.open(bc_abs_path.c_str(), FOM_READ);
+		if (bc != NULL)
+		{
+			program_size = bc->size();
+			program = (char*) default_allocator().allocate(program_size);
+			bc->read(program, program_size);
+			fs.close(bc);
+			fs.delete_file(bc_abs_path.c_str());
+		}
+		else
+		{
+			CE_LOGE("Error while reading luajit bytecode");
+			return;
+		}
+
+		LuaHeader header;
+		header.version = LUA_RESOURCE_VERSION;
+		header.size = program_size;
+
+		out_file->write((char*)&header, sizeof(LuaHeader));
+		out_file->write((char*)program, program_size);
+
+		default_allocator().deallocate(program);
+	}
 
 
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	TempAllocator1024 alloc;
-	DynamicString res_abs_path(alloc);
-	TempAllocator1024 alloc2;
-	DynamicString bc_abs_path(alloc2);
-	fs.get_absolute_path(resource_path, res_abs_path);
-	fs.get_absolute_path("bc.tmp", bc_abs_path);
-
-	const char* luajit[] =
+	//-----------------------------------------------------------------------------
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
 	{
 	{
-		LUAJIT_EXECUTABLE,
-		LUAJIT_FLAGS,
-		res_abs_path.c_str(),
-		bc_abs_path.c_str(),
-		NULL
-	};
+		File* file = bundle.open(id);
+		const size_t file_size = file->size();
 
 
-	os::execute_process(luajit);
+		void* res = allocator.allocate(file_size);
+		file->read(res, file_size);
 
 
-	size_t program_size = 0;
-	char* program = NULL;
+		bundle.close(file);
 
 
-	File* bc = fs.open(bc_abs_path.c_str(), FOM_READ);
-	if (bc != NULL)
-	{
-		program_size = bc->size();
-		program = (char*) default_allocator().allocate(program_size);
-		bc->read(program, program_size);
-		fs.close(bc);
-		fs.delete_file(bc_abs_path.c_str());
+		return res;
 	}
 	}
-	else
+
+	//-----------------------------------------------------------------------------
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
 	{
 	{
-		CE_LOGE("Error while reading luajit bytecode");
-		return;
 	}
 	}
 
 
-	LuaHeader header;
-	header.version = LUA_RESOURCE_VERSION;
-	header.size = program_size;
-
-	out_file->write((char*)&header, sizeof(LuaHeader));
-	out_file->write((char*)program, program_size);
-
-	default_allocator().deallocate(program);
-}
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
 
 
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& allocator, void* resource)
+	{
+		allocator.deallocate(resource);
+	}
 } // namespace lua_resource
 } // namespace lua_resource
 } // namespace crown
 } // namespace crown

+ 12 - 29
engine/resource/lua_resource.h

@@ -46,35 +46,6 @@ struct LuaHeader
 
 
 struct LuaResource
 struct LuaResource
 {
 {
-	//-----------------------------------------------------------------------------
-	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(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
 	/// Returns the size in bytes of the lua program.
 	/// Returns the size in bytes of the lua program.
 	uint32_t size() const
 	uint32_t size() const
 	{
 	{
@@ -93,4 +64,16 @@ private:
 	LuaResource();
 	LuaResource();
 };
 };
 
 
+namespace lua_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void unload(Allocator& allocator, void* resource);
+} // namespace lua_resource
 } // namespace crown
 } // namespace crown

+ 203 - 133
engine/resource/material_resource.cpp

@@ -37,166 +37,236 @@ namespace crown
 {
 {
 namespace material_resource
 namespace material_resource
 {
 {
+	struct Data
+	{
+		Array<TextureData> textures;
+		Array<UniformData> uniforms;
+		Array<char> dynamic;
+
+		Data()
+			: textures(default_allocator())
+			, uniforms(default_allocator())
+			, dynamic(default_allocator())
+		{}
+	};
+
+	// Returns offset to start of data
+	template <typename T>
+	static uint32_t reserve_dynamic_data(T data, Array<char>& dynamic)
+	{
+		uint32_t offt = array::size(dynamic);
+		array::push(dynamic, (char*) &data, sizeof(data));
+		return offt;
+	}
 
 
-struct Data
-{
-	Array<TextureData> textures;
-	Array<UniformData> uniforms;
-	Array<char> dynamic;
-
-	Data()
-		: textures(default_allocator())
-		, uniforms(default_allocator())
-		, dynamic(default_allocator())
-	{}
-};
-
-// Returns offset to start of data
-template <typename T>
-static uint32_t reserve_dynamic_data(T data, Array<char>& dynamic)
-{
-	uint32_t offt = array::size(dynamic);
-	array::push(dynamic, (char*) &data, sizeof(data));
-	return offt;
-}
+	static void parse_textures(JSONElement root, Array<TextureData>& textures, Array<char>& dynamic)
+	{
+		using namespace vector;
 
 
-static void parse_textures(JSONElement root, Array<TextureData>& textures, Array<char>& dynamic)
-{
-	using namespace vector;
+		Vector<DynamicString> keys(default_allocator());
+		root.key("textures").to_keys(keys);
 
 
-	Vector<DynamicString> keys(default_allocator());
-	root.key("textures").to_keys(keys);
+		for (uint32_t i = 0; i < size(keys); i++)
+		{
+			TextureHandle th;
+			th.sampler_handle = 0;
+			th.texture_handle = 0;
 
 
-	for (uint32_t i = 0; i < size(keys); i++)
+			ResourceId texid = root.key("textures").key(keys[i].c_str()).to_resource_id("texture");
+
+			TextureData td;
+			td.id = texid.name;
+			td.data_offset = reserve_dynamic_data(th, dynamic);
+			strncpy(td.sampler_name, keys[i].c_str(), 256);
+
+			array::push_back(textures, td);
+		}
+	}
+
+	struct UniformTypeInfo
 	{
 	{
-		TextureHandle th;
-		th.sampler_handle = 0;
-		th.texture_handle = 0;
+		const char* name;
+		UniformType::Enum type;
+		uint8_t size;
+	};
 
 
-		ResourceId texid = root.key("textures").key(keys[i].c_str()).to_resource_id("texture");
+	static const UniformTypeInfo s_uniform_type_info[UniformType::COUNT] =
+	{
+		{ "float",   UniformType::FLOAT,    4 },
+		{ "vector2", UniformType::VECTOR2,  8 },
+		{ "vector3", UniformType::VECTOR3, 12 },
+		{ "vector4", UniformType::VECTOR4, 16 }
+	};
 
 
-		TextureData td;
-		td.id = texid.name;
-		td.data_offset = reserve_dynamic_data(th, dynamic);
-		strncpy(td.sampler_name, keys[i].c_str(), 256);
+	static UniformType::Enum string_to_uniform_type(const char* str)
+	{
+		for (uint32_t i = 0; i < UniformType::COUNT; i++)
+		{
+			if (string::strcmp(str, s_uniform_type_info[i].name) == 0)
+				return s_uniform_type_info[i].type;
+		}
 
 
-		array::push_back(textures, td);
+		CE_FATAL("Unknown uniform type");
+		return UniformType::COUNT;
 	}
 	}
-}
 
 
-struct UniformTypeInfo
-{
-	const char* name;
-	UniformType::Enum type;
-	uint8_t size;
-};
+	static void parse_uniforms(JSONElement root, Array<UniformData>& uniforms, Array<char>& dynamic)
+	{
+		using namespace vector;
 
 
-static const UniformTypeInfo s_uniform_type_info[UniformType::COUNT] =
-{
-	{ "float",   UniformType::FLOAT,    4 },
-	{ "vector2", UniformType::VECTOR2,  8 },
-	{ "vector3", UniformType::VECTOR3, 12 },
-	{ "vector4", UniformType::VECTOR4, 16 }
-};
+		Vector<DynamicString> keys(default_allocator());
+		root.key("uniforms").to_keys(keys);
 
 
-static UniformType::Enum string_to_uniform_type(const char* str)
-{
-	for (uint32_t i = 0; i < UniformType::COUNT; i++)
+		for (uint32_t i = 0; i < size(keys); i++)
+		{
+			UniformHandle uh;
+			uh.uniform_handle = 0;
+
+			DynamicString type;
+			root.key("uniforms").key(keys[i].c_str()).key("type").to_string(type);
+
+			UniformData ud;
+			ud.type = string_to_uniform_type(type.c_str());
+			ud.data_offset = reserve_dynamic_data(uh, dynamic);
+
+			strncpy(ud.name, keys[i].c_str(), 256);
+
+			switch (ud.type)
+			{
+				case UniformType::FLOAT:
+				{
+					float data = root.key("uniforms").key(keys[i].c_str()).key("value").to_float();
+					reserve_dynamic_data(data, dynamic);
+					break;
+				}
+				case UniformType::VECTOR2:
+				{
+					Vector2 data = root.key("uniforms").key(keys[i].c_str()).key("value").to_vector2();
+					reserve_dynamic_data(data, dynamic);
+					break;
+				}
+				case UniformType::VECTOR3:
+				{
+					Vector3 data = root.key("uniforms").key(keys[i].c_str()).key("value").to_vector3();
+					reserve_dynamic_data(data, dynamic);
+					break;
+				}
+				case UniformType::VECTOR4:
+				{
+					Vector4 data = root.key("uniforms").key(keys[i].c_str()).key("value").to_vector4();
+					reserve_dynamic_data(data, dynamic);
+					break;
+				}
+				default: CE_FATAL("Oops"); break;
+			}
+
+			array::push_back(uniforms, ud);
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	{
 	{
-		if (string::strcmp(str, s_uniform_type_info[i].name) == 0)
-			return s_uniform_type_info[i].type;
+		File* file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*file);
+		fs.close(file);
+
+		JSONElement root = json.root();
+
+		Array<TextureData> texdata(default_allocator());
+		Array<UniformData> unidata(default_allocator());
+		Array<char> dynblob(default_allocator());
+
+		ResourceId shader = root.key("shader").to_resource_id("shader");
+		parse_textures(root, texdata, dynblob);
+		parse_uniforms(root, unidata, dynblob);
+
+		MaterialHeader mh;
+		mh.version = MATERIAL_VERSION;
+		mh.shader = shader.name;
+		mh.num_textures = array::size(texdata);
+		mh.texture_data_offset = sizeof(mh);
+		mh.num_uniforms = array::size(unidata);
+		mh.uniform_data_offset = sizeof(mh) + sizeof(TextureData) * array::size(texdata);
+		mh.dynamic_data_size = array::size(dynblob);
+		mh.dynamic_data_offset = sizeof(mh) + sizeof(TextureData) * array::size(texdata) + sizeof(UniformData) * array::size(unidata);
+
+		out_file->write((char*) &mh, sizeof(mh));
+		out_file->write((char*) array::begin(texdata), sizeof(TextureData) * array::size(texdata));
+		out_file->write((char*) array::begin(unidata), sizeof(UniformData) * array::size(unidata));
+		out_file->write((char*) array::begin(dynblob), sizeof(char) * array::size(dynblob));
 	}
 	}
 
 
-	CE_FATAL("Unknown uniform type");
-	return UniformType::COUNT;
-}
+	//-----------------------------------------------------------------------------
+	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);
 
 
-static void parse_uniforms(JSONElement root, Array<UniformData>& uniforms, Array<char>& dynamic)
-{
-	using namespace vector;
+		bundle.close(file);
 
 
-	Vector<DynamicString> keys(default_allocator());
-	root.key("uniforms").to_keys(keys);
+		return res;
+	}
 
 
-	for (uint32_t i = 0; i < size(keys); i++)
+	//-----------------------------------------------------------------------------
+	void online(StringId64 id, ResourceManager& rm)
 	{
 	{
-		UniformHandle uh;
-		uh.uniform_handle = 0;
+		ResourceId res_id;
+		res_id.type = MATERIAL_TYPE;
+		res_id.name = id;
+		MaterialResource* mr = (MaterialResource*) rm.get(res_id);
 
 
-		DynamicString type;
-		root.key("uniforms").key(keys[i].c_str()).key("type").to_string(type);
+		char* base = (char*) mr + mr->dynamic_data_offset();
 
 
-		UniformData ud;
-		ud.type = string_to_uniform_type(type.c_str());
-		ud.data_offset = reserve_dynamic_data(uh, dynamic);
+		for (uint32_t i = 0; i < mr->num_textures(); i++)
+		{
+			TextureData* ud = mr->get_texture_data(i);
+			TextureHandle* th = mr->get_texture_handle(i, base);
+			th->sampler_handle = bgfx::createUniform(ud->sampler_name, bgfx::UniformType::Uniform1iv).idx;
+		}
+
+		for (uint32_t i = 0; i < mr->num_uniforms(); i++)
+		{
+			UniformData* ud = mr->get_uniform_data(i);
+			UniformHandle* uh = mr->get_uniform_handle(i, base);
+			uh->uniform_handle = bgfx::createUniform(ud->name, bgfx::UniformType::Uniform4fv).idx;
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void offline(StringId64 id, ResourceManager& rm)
+	{
+		ResourceId res_id;
+		res_id.type = MATERIAL_TYPE;
+		res_id.name = id;
+		MaterialResource* mr = (MaterialResource*) rm.get(res_id);
 
 
-		strncpy(ud.name, keys[i].c_str(), 256);
+		char* base = (char*) mr + mr->dynamic_data_offset();
 
 
-		switch (ud.type)
+		for (uint32_t i = 0; i < mr->num_textures(); i++)
 		{
 		{
-			case UniformType::FLOAT:
-			{
-				float data = root.key("uniforms").key(keys[i].c_str()).key("value").to_float();
-				reserve_dynamic_data(data, dynamic);
-				break;
-			}
-			case UniformType::VECTOR2:
-			{
-				Vector2 data = root.key("uniforms").key(keys[i].c_str()).key("value").to_vector2();
-				reserve_dynamic_data(data, dynamic);
-				break;
-			}
-			case UniformType::VECTOR3:
-			{
-				Vector3 data = root.key("uniforms").key(keys[i].c_str()).key("value").to_vector3();
-				reserve_dynamic_data(data, dynamic);
-				break;
-			}
-			case UniformType::VECTOR4:
-			{
-				Vector4 data = root.key("uniforms").key(keys[i].c_str()).key("value").to_vector4();
-				reserve_dynamic_data(data, dynamic);
-				break;
-			}
-			default: CE_FATAL("Oops"); break;
+			TextureHandle* th = mr->get_texture_handle(i, base);
+			bgfx::UniformHandle sh;
+			sh.idx = th->sampler_handle;
+			bgfx::destroyUniform(sh);
 		}
 		}
 
 
-		array::push_back(uniforms, ud);
+		for (uint32_t i = 0; i < mr->num_uniforms(); i++)
+		{
+			UniformHandle* uh = mr->get_uniform_handle(i, base);
+			bgfx::UniformHandle bgfx_uh;
+			bgfx_uh.idx = uh->uniform_handle;
+			bgfx::destroyUniform(bgfx_uh);
+		}
 	}
 	}
-}
-
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	File* file = fs.open(resource_path, FOM_READ);
-	JSONParser json(*file);
-	fs.close(file);
-
-	JSONElement root = json.root();
-
-	Array<TextureData> texdata(default_allocator());
-	Array<UniformData> unidata(default_allocator());
-	Array<char> dynblob(default_allocator());
-
-	ResourceId shader = root.key("shader").to_resource_id("shader");
-	parse_textures(root, texdata, dynblob);
-	parse_uniforms(root, unidata, dynblob);
-
-	MaterialHeader mh;
-	mh.version = MATERIAL_VERSION;
-	mh.shader = shader.name;
-	mh.num_textures = array::size(texdata);
-	mh.texture_data_offset = sizeof(mh);
-	mh.num_uniforms = array::size(unidata);
-	mh.uniform_data_offset = sizeof(mh) + sizeof(TextureData) * array::size(texdata);
-	mh.dynamic_data_size = array::size(dynblob);
-	mh.dynamic_data_offset = sizeof(mh) + sizeof(TextureData) * array::size(texdata) + sizeof(UniformData) * array::size(unidata);
-
-	out_file->write((char*) &mh, sizeof(mh));
-	out_file->write((char*) array::begin(texdata), sizeof(TextureData) * array::size(texdata));
-	out_file->write((char*) array::begin(unidata), sizeof(UniformData) * array::size(unidata));
-	out_file->write((char*) array::begin(dynblob), sizeof(char) * array::size(dynblob));
-}
 
 
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& a, void* res)
+	{
+		a.deallocate(res);
+	}
 } // namespace material_resource
 } // namespace material_resource
 } // namespace crown
 } // namespace crown

+ 12 - 74
engine/resource/material_resource.h

@@ -95,80 +95,6 @@ struct UniformHandle
 
 
 struct MaterialResource
 struct MaterialResource
 {
 {
-public:
-
-	//-----------------------------------------------------------------------------
-	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(StringId64 id, ResourceManager& rm)
-	{
-		ResourceId res_id;
-		res_id.type = MATERIAL_TYPE;
-		res_id.name = id;
-		MaterialResource* mr = (MaterialResource*) rm.get(res_id);
-
-		char* base = (char*) mr + mr->dynamic_data_offset();
-
-		for (uint32_t i = 0; i < mr->num_textures(); i++)
-		{
-			TextureData* ud = mr->get_texture_data(i);
-			TextureHandle* th = mr->get_texture_handle(i, base);
-			th->sampler_handle = bgfx::createUniform(ud->sampler_name, bgfx::UniformType::Uniform1iv).idx;
-		}
-
-		for (uint32_t i = 0; i < mr->num_uniforms(); i++)
-		{
-			UniformData* ud = mr->get_uniform_data(i);
-			UniformHandle* uh = mr->get_uniform_handle(i, base);
-			uh->uniform_handle = bgfx::createUniform(ud->name, bgfx::UniformType::Uniform4fv).idx;
-		}
-	}
-
-	//-----------------------------------------------------------------------------
-	static void offline(StringId64 id, ResourceManager& rm)
-	{
-		ResourceId res_id;
-		res_id.type = MATERIAL_TYPE;
-		res_id.name = id;
-		MaterialResource* mr = (MaterialResource*) rm.get(res_id);
-
-		char* base = (char*) mr + mr->dynamic_data_offset();
-
-		for (uint32_t i = 0; i < mr->num_textures(); i++)
-		{
-			TextureHandle* th = mr->get_texture_handle(i, base);
-			bgfx::UniformHandle sh;
-			sh.idx = th->sampler_handle;
-			bgfx::destroyUniform(sh);
-		}
-
-		for (uint32_t i = 0; i < mr->num_uniforms(); i++)
-		{
-			UniformHandle* uh = mr->get_uniform_handle(i, base);
-			bgfx::UniformHandle bgfx_uh;
-			bgfx_uh.idx = uh->uniform_handle;
-			bgfx::destroyUniform(bgfx_uh);
-		}
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& a, void* res)
-	{
-		a.deallocate(res);
-	}
-
 	uint32_t dynamic_data_size() const
 	uint32_t dynamic_data_size() const
 	{
 	{
 		MaterialHeader* mh = (MaterialHeader*) this;
 		MaterialHeader* mh = (MaterialHeader*) this;
@@ -255,4 +181,16 @@ private:
 	MaterialResource();
 	MaterialResource();
 };
 };
 
 
+namespace material_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 id, ResourceManager& rm);
+	void offline(StringId64 id, ResourceManager& rm);
+	void unload(Allocator& a, void* res);
+} // namespace material_resource
 } // namespace crown
 } // namespace crown

+ 150 - 122
engine/resource/mesh_resource.cpp

@@ -36,166 +36,194 @@ namespace crown
 {
 {
 namespace mesh_resource
 namespace mesh_resource
 {
 {
-
-struct MeshVertex
-{
-	Vector3 position;
-	Vector3 normal;
-	Vector2 texcoord;
-
-	bool operator==(const MeshVertex& other)
+	struct MeshVertex
 	{
 	{
-		return position == other.position &&
-				normal == other.normal &&
-				texcoord == other.texcoord;
-	}
-};
-
-MeshHeader			m_mesh_header;
-bool				m_has_normal;
-bool				m_has_texcoord;
-
-Array<MeshVertex>	m_vertices(default_allocator());
-Array<uint16_t>		m_indices(default_allocator());
-
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	File* file = fs.open(resource_path, FOM_READ);
-	JSONParser json(*file);
-	fs.close(file);
+		Vector3 position;
+		Vector3 normal;
+		Vector2 texcoord;
 
 
-	JSONElement root = json.root();
+		bool operator==(const MeshVertex& other)
+		{
+			return position == other.position &&
+					normal == other.normal &&
+					texcoord == other.texcoord;
+		}
+	};
 
 
-	// Read data arrays
-	JSONElement position = root.key_or_nil("position");
-	JSONElement normal = root.key_or_nil("normal");
-	JSONElement texcoord = root.key_or_nil("texcoord");
+	MeshHeader			m_mesh_header;
+	bool				m_has_normal;
+	bool				m_has_texcoord;
 
 
-	m_has_normal = false;
-	m_has_texcoord = false;
+	Array<MeshVertex>	m_vertices(default_allocator());
+	Array<uint16_t>		m_indices(default_allocator());
 
 
-	if (position.is_nil())
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	{
 	{
-		CE_LOGE("Bad mesh: array 'position' not found.");
-		return;
-	}
-	Array<float> position_array(default_allocator());
-	position.to_array(position_array);
+		File* file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*file);
+		fs.close(file);
 
 
+		JSONElement root = json.root();
 
 
-	Array<float> normal_array(default_allocator());
-	if (!normal.is_nil())
-	{
-		m_has_normal = true;
-		normal.to_array(normal_array);
-	}
+		// Read data arrays
+		JSONElement position = root.key_or_nil("position");
+		JSONElement normal = root.key_or_nil("normal");
+		JSONElement texcoord = root.key_or_nil("texcoord");
 
 
-	Array<float> texcoord_array(default_allocator());
-	if (!texcoord.is_nil())
-	{
-		m_has_texcoord = true;
-		texcoord.to_array(texcoord_array);
-	}
+		m_has_normal = false;
+		m_has_texcoord = false;
 
 
-	// Read index arrays
-	JSONElement index = root.key_or_nil("index");
-	if (index.is_nil())
-	{
-		CE_LOGE("Bad mesh: array 'index' not found.");
-		return;
-	}
+		if (position.is_nil())
+		{
+			CE_LOGE("Bad mesh: array 'position' not found.");
+			return;
+		}
+		Array<float> position_array(default_allocator());
+		position.to_array(position_array);
 
 
-	Array<uint16_t> position_index(default_allocator());
-	Array<uint16_t> normal_index(default_allocator());
-	Array<uint16_t> texcoord_index(default_allocator());
 
 
-	index[0].to_array(position_index);
+		Array<float> normal_array(default_allocator());
+		if (!normal.is_nil())
+		{
+			m_has_normal = true;
+			normal.to_array(normal_array);
+		}
 
 
-	if (m_has_normal)
-	{
-		index[1].to_array(normal_index);
-	}
+		Array<float> texcoord_array(default_allocator());
+		if (!texcoord.is_nil())
+		{
+			m_has_texcoord = true;
+			texcoord.to_array(texcoord_array);
+		}
 
 
-	if (m_has_texcoord)
-	{
-		index[2].to_array(texcoord_index);
-	}
+		// Read index arrays
+		JSONElement index = root.key_or_nil("index");
+		if (index.is_nil())
+		{
+			CE_LOGE("Bad mesh: array 'index' not found.");
+			return;
+		}
 
 
-	// Generate vb/ib
-	uint32_t idx = 0;
-	for (uint32_t i = 0; i < array::size(position_index); i++)
-	{
-		MeshVertex v;
+		Array<uint16_t> position_index(default_allocator());
+		Array<uint16_t> normal_index(default_allocator());
+		Array<uint16_t> texcoord_index(default_allocator());
 
 
-		uint16_t p_idx = position_index[i] * 3;
-		v.position = Vector3(position_array[p_idx], position_array[p_idx + 1], position_array[p_idx + 2]);
+		index[0].to_array(position_index);
 
 
 		if (m_has_normal)
 		if (m_has_normal)
 		{
 		{
-			uint16_t n_idx = normal_index[i] * 3;
-			v.normal = Vector3(normal_array[n_idx], normal_array[n_idx + 1], normal_array[n_idx + 2]);
+			index[1].to_array(normal_index);
 		}
 		}
 
 
 		if (m_has_texcoord)
 		if (m_has_texcoord)
 		{
 		{
-			uint16_t t_idx = texcoord_index[i] * 2;
-			v.texcoord = Vector2(texcoord_array[t_idx], texcoord_array[t_idx + 1]);
+			index[2].to_array(texcoord_index);
 		}
 		}
 
 
-
-		uint32_t f_idx = 0;
-		bool found = false;
-		for (; f_idx < array::size(m_vertices); f_idx++)
+		// Generate vb/ib
+		uint32_t idx = 0;
+		for (uint32_t i = 0; i < array::size(position_index); i++)
 		{
 		{
-			if (m_vertices[f_idx] == v)
+			MeshVertex v;
+
+			uint16_t p_idx = position_index[i] * 3;
+			v.position = Vector3(position_array[p_idx], position_array[p_idx + 1], position_array[p_idx + 2]);
+
+			if (m_has_normal)
 			{
 			{
-				found = true;
-				break;
+				uint16_t n_idx = normal_index[i] * 3;
+				v.normal = Vector3(normal_array[n_idx], normal_array[n_idx + 1], normal_array[n_idx + 2]);
 			}
 			}
-		}
 
 
-		if (found)
-		{
-			array::push_back(m_indices, (uint16_t) f_idx);
-		}
-		else
-		{
-			array::push_back(m_vertices, v);
-			array::push_back(m_indices, (uint16_t) idx);
-			idx++;
+			if (m_has_texcoord)
+			{
+				uint16_t t_idx = texcoord_index[i] * 2;
+				v.texcoord = Vector2(texcoord_array[t_idx], texcoord_array[t_idx + 1]);
+			}
+
+
+			uint32_t f_idx = 0;
+			bool found = false;
+			for (; f_idx < array::size(m_vertices); f_idx++)
+			{
+				if (m_vertices[f_idx] == v)
+				{
+					found = true;
+					break;
+				}
+			}
+
+			if (found)
+			{
+				array::push_back(m_indices, (uint16_t) f_idx);
+			}
+			else
+			{
+				array::push_back(m_vertices, v);
+				array::push_back(m_indices, (uint16_t) idx);
+				idx++;
+			}
 		}
 		}
-	}
 
 
-	m_mesh_header.version = MESH_VERSION;
-	m_mesh_header.num_meshes = 1;
-	m_mesh_header.num_joints = 0;
-	//m_mesh_header.padding[0] = 0xCECECECE;
+		m_mesh_header.version = MESH_VERSION;
+		m_mesh_header.num_meshes = 1;
+		m_mesh_header.num_joints = 0;
+		//m_mesh_header.padding[0] = 0xCECECECE;
+
+		MeshData data;
+		data.vertices.num_vertices = array::size(m_vertices);
+		// data.vertices.format = VertexFormat::P3_N3_T2;
+		data.vertices.offset = sizeof(MeshHeader) + sizeof(MeshData);
+
+		data.indices.num_indices = array::size(m_indices);
+		data.indices.offset = sizeof(MeshHeader) + sizeof(MeshData) + array::size(m_vertices) * sizeof(MeshVertex);
+
+		// Write header
+		out_file->write((char*)&m_mesh_header, sizeof(MeshHeader));
 
 
-	MeshData data;
-	data.vertices.num_vertices = array::size(m_vertices);
-	// data.vertices.format = VertexFormat::P3_N3_T2;
-	data.vertices.offset = sizeof(MeshHeader) + sizeof(MeshData);
+		// Write mesh metadata
+		out_file->write((char*)&data, sizeof(MeshData));
+
+		// Write vertices
+		out_file->write((char*) array::begin(m_vertices), array::size(m_vertices) * sizeof(MeshVertex));
+
+		// Write indices
+		out_file->write((char*) array::begin(m_indices), array::size(m_indices) * sizeof(uint16_t));
+
+		// Cleanup
+		array::clear(m_vertices);
+		array::clear(m_indices);
+	}
 
 
-	data.indices.num_indices = array::size(m_indices);
-	data.indices.offset = sizeof(MeshHeader) + sizeof(MeshData) + array::size(m_vertices) * sizeof(MeshVertex);
+	//-----------------------------------------------------------------------------
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+		File* file = bundle.open(id);
+		const size_t file_size = file->size();
 
 
-	// Write header
-	out_file->write((char*)&m_mesh_header, sizeof(MeshHeader));
+		void* res = allocator.allocate(file_size);
+		file->read(res, file_size);
 
 
-	// Write mesh metadata
-	out_file->write((char*)&data, sizeof(MeshData));
+		bundle.close(file);
 
 
-	// Write vertices
-	out_file->write((char*) array::begin(m_vertices), array::size(m_vertices) * sizeof(MeshVertex));
+		return res;
+	}
 
 
-	// Write indices
-	out_file->write((char*) array::begin(m_indices), array::size(m_indices) * sizeof(uint16_t));
+	//-----------------------------------------------------------------------------
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
 
 
-	// Cleanup
-	array::clear(m_vertices);
-	array::clear(m_indices);
-}
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
 
 
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& a, void* res)
+	{
+		CE_ASSERT_NOT_NULL(res);
+		a.deallocate(res);
+	}
 } // namespace mesh_resource
 } // namespace mesh_resource
 } // namespace crown
 } // namespace crown

+ 12 - 32
engine/resource/mesh_resource.h

@@ -69,38 +69,6 @@ struct MeshData
 
 
 struct MeshResource
 struct MeshResource
 {
 {
-public:
-
-	//-----------------------------------------------------------------------------
-	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(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& a, void* res)
-	{
-		CE_ASSERT_NOT_NULL(res);
-		a.deallocate(res);
-	}
-
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
 	uint32_t num_vertices() const
 	uint32_t num_vertices() const
 	{
 	{
@@ -135,4 +103,16 @@ private:
 	MeshResource();
 	MeshResource();
 };
 };
 
 
+namespace mesh_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void unload(Allocator& a, void* res);
+}
 } // namespace crown
 } // namespace crown

+ 154 - 127
engine/resource/package_resource.cpp

@@ -35,138 +35,165 @@ namespace crown
 {
 {
 namespace package_resource
 namespace package_resource
 {
 {
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
+	{
+		File* file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*file);
+		fs.close(file);
+
+		JSONElement root = json.root();
+		BinaryWriter bw(*out_file);
+
+		JSONElement texture  = root.key_or_nil("texture");
+		JSONElement script   = root.key_or_nil("lua");
+		JSONElement sound    = root.key_or_nil("sound");
+		JSONElement mesh     = root.key_or_nil("mesh");
+		JSONElement unit     = root.key_or_nil("unit");
+		JSONElement sprite   = root.key_or_nil("sprite");
+		JSONElement physics  = root.key_or_nil("physics");
+		JSONElement material = root.key_or_nil("material");
+		JSONElement font     = root.key_or_nil("font");
+		JSONElement level    = root.key_or_nil("level");
+		JSONElement phyconf  = root.key_or_nil("physics_config");
+		JSONElement shader   = root.key_or_nil("shader");
+		JSONElement sprite_animation = root.key_or_nil("sprite_animation");
+
+		const uint32_t num_textures  = texture.is_nil() ? 0 : texture.size();
+		const uint32_t num_scripts   = script.is_nil() ? 0 : script.size();
+		const uint32_t num_sounds    = sound.is_nil() ? 0 : sound.size();
+		const uint32_t num_meshes    = mesh.is_nil() ? 0 : mesh.size();
+		const uint32_t num_units     = unit.is_nil() ? 0 : unit.size();
+		const uint32_t num_sprites   = sprite.is_nil() ? 0 : sprite.size();
+		const uint32_t num_physics   = physics.is_nil() ? 0 : physics.size();
+		const uint32_t num_materials = material.is_nil() ? 0 : material.size();
+		const uint32_t num_fonts     = font.is_nil() ? 0 : font.size();
+		const uint32_t num_levels    = level.is_nil() ? 0 : level.size();
+		const uint32_t num_phyconfs  = phyconf.is_nil() ? 0 : phyconf.size();
+		const uint32_t num_shaders   = shader.is_nil() ? 0 : shader.size();
+		const uint32_t num_sprite_animations = sprite_animation.is_nil() ? 0 : sprite_animation.size();
+
+		// Write header
+		bw.write(num_textures);
+		uint32_t offt = sizeof(PackageHeader);
+		bw.write(offt);
+
+		bw.write(num_scripts);
+		offt += sizeof(ResourceId) * num_textures;
+		bw.write(offt);
+
+		bw.write(num_sounds);
+		offt += sizeof(ResourceId) * num_scripts;
+		bw.write(offt);
+
+		bw.write(num_meshes);
+		offt += sizeof(ResourceId) * num_sounds;
+		bw.write(offt);
+
+		bw.write(num_units);
+		offt += sizeof(ResourceId) * num_meshes;
+		bw.write(offt);
+
+		bw.write(num_sprites);
+		offt += sizeof(ResourceId) * num_units;
+		bw.write(offt);
+
+		bw.write(num_physics);
+		offt += sizeof(ResourceId) * num_sprites;
+		bw.write(offt);
+
+		bw.write(num_materials);
+		offt += sizeof(ResourceId) * num_physics;
+		bw.write(offt);
+
+		bw.write(num_fonts);
+		offt += sizeof(ResourceId) * num_materials;
+		bw.write(offt);
+
+		bw.write(num_levels);
+		offt += sizeof(ResourceId) * num_fonts;
+		bw.write(offt);
+
+		bw.write(num_phyconfs);
+		offt += sizeof(ResourceId) * num_levels;
+		bw.write(offt);
+
+		bw.write(num_shaders);
+		offt += sizeof(ResourceId) * num_phyconfs;
+		bw.write(offt);
+
+		bw.write(num_sprite_animations);
+		offt += sizeof(ResourceId) * num_shaders;
+		bw.write(offt);
+
+		// Write resource ids
+		for (uint32_t i = 0; i < num_textures; i++)
+			bw.write(texture[i].to_resource_id("texture"));
+
+		for (uint32_t i = 0; i < num_scripts; i++)
+			bw.write(script[i].to_resource_id("lua"));
+
+		for (uint32_t i = 0; i < num_sounds; i++)
+			bw.write(sound[i].to_resource_id("sound"));
+
+		for (uint32_t i = 0; i < num_meshes; i++)
+			bw.write(mesh[i].to_resource_id("mesh"));
+
+		for (uint32_t i = 0; i < num_units; i++)
+			bw.write(unit[i].to_resource_id("unit"));
+
+		for (uint32_t i = 0; i < num_sprites; i++)
+			bw.write(sprite[i].to_resource_id("sprite"));
+
+		for (uint32_t i = 0; i < num_physics; i++)
+			bw.write(physics[i].to_resource_id("physics"));
+
+		for (uint32_t i = 0; i < num_materials; i++)
+			bw.write(material[i].to_resource_id("material"));
+
+		for (uint32_t i = 0; i < num_fonts; i++)
+			bw.write(font[i].to_resource_id("font"));
+
+		for (uint32_t i = 0; i < num_levels; i++)
+			bw.write(level[i].to_resource_id("level"));
 
 
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	File* file = fs.open(resource_path, FOM_READ);
-	JSONParser json(*file);
-	fs.close(file);
-
-	JSONElement root = json.root();
-	BinaryWriter bw(*out_file);
-
-	JSONElement texture  = root.key_or_nil("texture");
-	JSONElement script   = root.key_or_nil("lua");
-	JSONElement sound    = root.key_or_nil("sound");
-	JSONElement mesh     = root.key_or_nil("mesh");
-	JSONElement unit     = root.key_or_nil("unit");
-	JSONElement sprite   = root.key_or_nil("sprite");
-	JSONElement physics  = root.key_or_nil("physics");
-	JSONElement material = root.key_or_nil("material");
-	JSONElement font     = root.key_or_nil("font");
-	JSONElement level    = root.key_or_nil("level");
-	JSONElement phyconf  = root.key_or_nil("physics_config");
-	JSONElement shader   = root.key_or_nil("shader");
-	JSONElement sprite_animation = root.key_or_nil("sprite_animation");
-
-	const uint32_t num_textures  = texture.is_nil() ? 0 : texture.size();
-	const uint32_t num_scripts   = script.is_nil() ? 0 : script.size();
-	const uint32_t num_sounds    = sound.is_nil() ? 0 : sound.size();
-	const uint32_t num_meshes    = mesh.is_nil() ? 0 : mesh.size();
-	const uint32_t num_units     = unit.is_nil() ? 0 : unit.size();
-	const uint32_t num_sprites   = sprite.is_nil() ? 0 : sprite.size();
-	const uint32_t num_physics   = physics.is_nil() ? 0 : physics.size();
-	const uint32_t num_materials = material.is_nil() ? 0 : material.size();
-	const uint32_t num_fonts     = font.is_nil() ? 0 : font.size();
-	const uint32_t num_levels    = level.is_nil() ? 0 : level.size();
-	const uint32_t num_phyconfs  = phyconf.is_nil() ? 0 : phyconf.size();
-	const uint32_t num_shaders   = shader.is_nil() ? 0 : shader.size();
-	const uint32_t num_sprite_animations = sprite_animation.is_nil() ? 0 : sprite_animation.size();
-
-	// Write header
-	bw.write(num_textures);
-	uint32_t offt = sizeof(PackageHeader);
-	bw.write(offt);
-
-	bw.write(num_scripts);
-	offt += sizeof(ResourceId) * num_textures;
-	bw.write(offt);
-
-	bw.write(num_sounds);
-	offt += sizeof(ResourceId) * num_scripts;
-	bw.write(offt);
-
-	bw.write(num_meshes);
-	offt += sizeof(ResourceId) * num_sounds;
-	bw.write(offt);
-
-	bw.write(num_units);
-	offt += sizeof(ResourceId) * num_meshes;
-	bw.write(offt);
-
-	bw.write(num_sprites);
-	offt += sizeof(ResourceId) * num_units;
-	bw.write(offt);
-
-	bw.write(num_physics);
-	offt += sizeof(ResourceId) * num_sprites;
-	bw.write(offt);
-
-	bw.write(num_materials);
-	offt += sizeof(ResourceId) * num_physics;
-	bw.write(offt);
-
-	bw.write(num_fonts);
-	offt += sizeof(ResourceId) * num_materials;
-	bw.write(offt);
-
-	bw.write(num_levels);
-	offt += sizeof(ResourceId) * num_fonts;
-	bw.write(offt);
-
-	bw.write(num_phyconfs);
-	offt += sizeof(ResourceId) * num_levels;
-	bw.write(offt);
-
-	bw.write(num_shaders);
-	offt += sizeof(ResourceId) * num_phyconfs;
-	bw.write(offt);
-
-	bw.write(num_sprite_animations);
-	offt += sizeof(ResourceId) * num_shaders;
-	bw.write(offt);
-
-	// Write resource ids
-	for (uint32_t i = 0; i < num_textures; i++)
-		bw.write(texture[i].to_resource_id("texture"));
-
-	for (uint32_t i = 0; i < num_scripts; i++)
-		bw.write(script[i].to_resource_id("lua"));
-
-	for (uint32_t i = 0; i < num_sounds; i++)
-		bw.write(sound[i].to_resource_id("sound"));
-
-	for (uint32_t i = 0; i < num_meshes; i++)
-		bw.write(mesh[i].to_resource_id("mesh"));
-
-	for (uint32_t i = 0; i < num_units; i++)
-		bw.write(unit[i].to_resource_id("unit"));
-
-	for (uint32_t i = 0; i < num_sprites; i++)
-		bw.write(sprite[i].to_resource_id("sprite"));
-
-	for (uint32_t i = 0; i < num_physics; i++)
-		bw.write(physics[i].to_resource_id("physics"));
-
-	for (uint32_t i = 0; i < num_materials; i++)
-		bw.write(material[i].to_resource_id("material"));
-
-	for (uint32_t i = 0; i < num_fonts; i++)
-		bw.write(font[i].to_resource_id("font"));
+		for (uint32_t i = 0; i < num_phyconfs; i++)
+			bw.write(phyconf[i].to_resource_id("physics_config"));
+
+		for (uint32_t i = 0; i < num_shaders; i++)
+			bw.write(shader[i].to_resource_id("shader"));
+
+		for (uint32_t i = 0; i < num_sprite_animations; i++)
+			bw.write(sprite_animation[i].to_resource_id("sprite_animation"));
+	}
+
+	//-----------------------------------------------------------------------------
+	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);
 
 
-	for (uint32_t i = 0; i < num_levels; i++)
-		bw.write(level[i].to_resource_id("level"));
+		bundle.close(file);
 
 
-	for (uint32_t i = 0; i < num_phyconfs; i++)
-		bw.write(phyconf[i].to_resource_id("physics_config"));
+		return res;
+	}
 
 
-	for (uint32_t i = 0; i < num_shaders; i++)
-		bw.write(shader[i].to_resource_id("shader"));
+	//-----------------------------------------------------------------------------
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
 
 
-	for (uint32_t i = 0; i < num_sprite_animations; i++)
-		bw.write(sprite_animation[i].to_resource_id("sprite_animation"));
-}
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
 
 
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& allocator, void* resource)
+	{
+		allocator.deallocate(resource);
+	}
 } // namespace package_resource
 } // namespace package_resource
 } // namespace crown
 } // namespace crown

+ 12 - 29
engine/resource/package_resource.h

@@ -68,35 +68,6 @@ struct PackageHeader
 
 
 struct PackageResource
 struct PackageResource
 {
 {
-	//-----------------------------------------------------------------------------
-	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(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
 	uint32_t num_textures() const
 	uint32_t num_textures() const
 	{
 	{
@@ -298,4 +269,16 @@ private:
 	PackageResource();
 	PackageResource();
 };
 };
 
 
+namespace package_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void unload(Allocator& allocator, void* resource);
+} // namespace package_resource
 } // namespace crown
 } // namespace crown

+ 81 - 0
engine/resource/pepper_resource.cpp

@@ -0,0 +1,81 @@
+/*
+Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pepper_resource.h"
+#include "json_parser.h"
+
+namespace crown
+{
+namespace pepper_resource
+{
+	void compile(const char* path, CompileOptions& opts)
+	{
+		Buffer buf = opts.read(path);
+		JSONParser json(array::begin(buf));
+		JSONElement root = json.root();
+
+		DynamicString vs_code;
+		DynamicString fs_code;
+		DynamicString varying_def;
+
+		root.key("vs_code").to_string(vs_code);
+		root.key("fs_code").to_string(fs_code);
+		root.key("varying_def").to_string(varying_def);
+
+		DynamicString vs_code_path;
+		DynamicString fs_code_path;
+		DynamicString varying_def_path;
+		DynamicString tmpvs_path;
+		DynamicString tmpfs_path;
+
+		opts.get_absolute_path(vs_code.c_str(), vs_code_path);
+		opts.get_absolute_path(fs_code.c_str(), fs_code_path);
+		opts.get_absolute_path(varying_def.c_str(), varying_def_path);
+		opts.get_absolute_path("tmpvs", tmpvs_path);
+		opts.get_absolute_path("tmpfs", tmpfs_path);
+	}
+
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+
+	}
+
+	void online(StringId64 id, ResourceManager& rm)
+	{
+
+	}
+
+	void offline(StringId64 id, ResourceManager& rm)
+	{
+
+	}
+
+	void unload(Allocator& a, void* resource)
+	{
+
+	}
+} // namespace pepper_resource
+} // namespace crown

+ 46 - 0
engine/resource/pepper_resource.h

@@ -0,0 +1,46 @@
+/*
+Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#pragma once
+
+#include "resource_manager.h"
+#include "bundle.h"
+#include "file.h"
+#include "reader_writer.h"
+#include "memory.h"
+#include "compile_options.h"
+
+namespace crown
+{
+namespace pepper_resource
+{
+	void compile(const char* path, CompileOptions& opts);
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 id, ResourceManager& rm);
+	void offline(StringId64 id, ResourceManager& rm);
+	void unload(Allocator& a, void* resource);
+} // namespace pepper_resource
+} // namespace crown

+ 324 - 268
engine/resource/physics_resource.cpp

@@ -39,322 +39,350 @@ namespace crown
 {
 {
 namespace physics_resource
 namespace physics_resource
 {
 {
-
-//-----------------------------------------------------------------------------
-static uint32_t shape_type_to_enum(const char* type)
-{
-	if (string::strcmp("sphere", type) == 0) 		return PhysicsShapeType::SPHERE;
-	else if (string::strcmp("capsule", type) == 0) 	return PhysicsShapeType::CAPSULE;
-	else if (string::strcmp("box", type) == 0) 		return PhysicsShapeType::BOX;
-	else if (string::strcmp("plane", type) == 0) 	return PhysicsShapeType::PLANE;
-
-	CE_FATAL("Bad shape type");
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static uint32_t joint_type_to_enum(const char* type)
-{
-	if (string::strcmp("fixed", type) == 0) 			return PhysicsJointType::FIXED;
-	else if (string::strcmp("spherical", type) == 0) 	return PhysicsJointType::SPHERICAL;
-	else if (string::strcmp("revolute", type) == 0) 	return PhysicsJointType::REVOLUTE;
-	else if (string::strcmp("prismatic", type) == 0) 	return PhysicsJointType::PRISMATIC;
-	else if (string::strcmp("distance", type) == 0) 	return PhysicsJointType::DISTANCE;
-	else if (string::strcmp("d6", type) == 0) 			return PhysicsJointType::D6;
-
-	CE_FATAL("Bad joint type");
-	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");
-	JSONElement collision_filter 	= e.key("collision_filter");
-
-	controller.name = name.to_string_id();
-	controller.height = height.to_float();
-	controller.radius = radius.to_float();
-	controller.slope_limit = slope_limit.to_float();
-	controller.step_offset = step_offset.to_float();
-	controller.contact_offset = contact_offset.to_float();
-	controller.collision_filter = collision_filter.to_string_id();
-}
-
-//-----------------------------------------------------------------------------
-void parse_shapes(JSONElement e, Array<PhysicsShape>& shapes)
-{
-	Vector<DynamicString> keys(default_allocator());
-	e.to_keys(keys);
-
-	for (uint32_t k = 0; k < vector::size(keys); k++)
+	//-----------------------------------------------------------------------------
+	static uint32_t shape_type_to_enum(const char* type)
 	{
 	{
-		JSONElement shape 		= e.key(keys[k].c_str());
-		JSONElement clasz		= shape.key("class");
-		JSONElement type		= shape.key("type");
-		JSONElement material	= shape.key("material");
-
-		PhysicsShape ps;
-		ps.name = keys[k].to_string_id();
-		ps.shape_class = clasz.to_string_id();
-		ps.material = material.to_string_id();
-		DynamicString stype; type.to_string(stype);
-		ps.type = shape_type_to_enum(stype.c_str());
-		ps.position = shape.key("position").to_vector3();
-		ps.rotation = shape.key("rotation").to_quaternion();
-
-		switch (ps.type)
-		{
-			case PhysicsShapeType::SPHERE:
-			{
-				JSONElement radius = shape.key("radius");
-				ps.data_0 = radius.to_float();
+		if (string::strcmp("sphere", type) == 0) 		return PhysicsShapeType::SPHERE;
+		else if (string::strcmp("capsule", type) == 0) 	return PhysicsShapeType::CAPSULE;
+		else if (string::strcmp("box", type) == 0) 		return PhysicsShapeType::BOX;
+		else if (string::strcmp("plane", type) == 0) 	return PhysicsShapeType::PLANE;
 
 
-				break;
-			}
-			case PhysicsShapeType::CAPSULE:
-			{
-				JSONElement radius = shape.key("radius");
-				JSONElement half_height = shape.key("half_height");
+		CE_FATAL("Bad shape type");
+		return 0;
+	}
 
 
-				ps.data_0 = radius.to_float();
-				ps.data_1 = half_height.to_float();
+	//-----------------------------------------------------------------------------
+	static uint32_t joint_type_to_enum(const char* type)
+	{
+		if (string::strcmp("fixed", type) == 0) 			return PhysicsJointType::FIXED;
+		else if (string::strcmp("spherical", type) == 0) 	return PhysicsJointType::SPHERICAL;
+		else if (string::strcmp("revolute", type) == 0) 	return PhysicsJointType::REVOLUTE;
+		else if (string::strcmp("prismatic", type) == 0) 	return PhysicsJointType::PRISMATIC;
+		else if (string::strcmp("distance", type) == 0) 	return PhysicsJointType::DISTANCE;
+		else if (string::strcmp("d6", type) == 0) 			return PhysicsJointType::D6;
+
+		CE_FATAL("Bad joint type");
+		return 0;
+	}
 
 
-				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");
+	//-----------------------------------------------------------------------------
+	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");
+		JSONElement collision_filter 	= e.key("collision_filter");
+
+		controller.name = name.to_string_id();
+		controller.height = height.to_float();
+		controller.radius = radius.to_float();
+		controller.slope_limit = slope_limit.to_float();
+		controller.step_offset = step_offset.to_float();
+		controller.contact_offset = contact_offset.to_float();
+		controller.collision_filter = collision_filter.to_string_id();
+	}
 
 
-				ps.data_0 = half_x.to_float();
-				ps.data_1 = half_y.to_float();
-				ps.data_2 = half_z.to_float();
+	//-----------------------------------------------------------------------------
+	void parse_shapes(JSONElement e, Array<PhysicsShape>& shapes)
+	{
+		Vector<DynamicString> keys(default_allocator());
+		e.to_keys(keys);
 
 
-				break;
-			}
-			case PhysicsShapeType::PLANE:
+		for (uint32_t k = 0; k < vector::size(keys); k++)
+		{
+			JSONElement shape 		= e.key(keys[k].c_str());
+			JSONElement clasz		= shape.key("class");
+			JSONElement type		= shape.key("type");
+			JSONElement material	= shape.key("material");
+
+			PhysicsShape ps;
+			ps.name = keys[k].to_string_id();
+			ps.shape_class = clasz.to_string_id();
+			ps.material = material.to_string_id();
+			DynamicString stype; type.to_string(stype);
+			ps.type = shape_type_to_enum(stype.c_str());
+			ps.position = shape.key("position").to_vector3();
+			ps.rotation = shape.key("rotation").to_quaternion();
+
+			switch (ps.type)
 			{
 			{
-				JSONElement n_x = shape.key("n_x");
-				JSONElement n_y = shape.key("n_y");
-				JSONElement n_z = shape.key("n_z");
-				JSONElement distance = shape.key("distance");
-
-				ps.data_0 = n_x.to_float();
-				ps.data_1 = n_y.to_float();
-				ps.data_2 = n_z.to_float();
-				ps.data_3 = distance.to_float();
-
-				break;
+				case PhysicsShapeType::SPHERE:
+				{
+					JSONElement radius = shape.key("radius");
+					ps.data_0 = radius.to_float();
+
+					break;
+				}
+				case PhysicsShapeType::CAPSULE:
+				{
+					JSONElement radius = shape.key("radius");
+					JSONElement half_height = shape.key("half_height");
+
+					ps.data_0 = radius.to_float();
+					ps.data_1 = half_height.to_float();
+
+					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");
+
+					ps.data_0 = half_x.to_float();
+					ps.data_1 = half_y.to_float();
+					ps.data_2 = half_z.to_float();
+
+					break;
+				}
+				case PhysicsShapeType::PLANE:
+				{
+					JSONElement n_x = shape.key("n_x");
+					JSONElement n_y = shape.key("n_y");
+					JSONElement n_z = shape.key("n_z");
+					JSONElement distance = shape.key("distance");
+
+					ps.data_0 = n_x.to_float();
+					ps.data_1 = n_y.to_float();
+					ps.data_2 = n_z.to_float();
+					ps.data_3 = distance.to_float();
+
+					break;
+				}
+				case PhysicsShapeType::CONVEX_MESH:
+				{
+					ps.resource = shape.key("mesh").to_resource_id("mesh");
+
+					break;
+				}
 			}
 			}
-			case PhysicsShapeType::CONVEX_MESH:
-			{
-				ps.resource = shape.key("mesh").to_resource_id("mesh");
 
 
-				break;
-			}
+			array::push_back(shapes, ps);
 		}
 		}
-
-		array::push_back(shapes, ps);
 	}
 	}
-}
-
-//-----------------------------------------------------------------------------
-void parse_actors(JSONElement e, Array<PhysicsActor>& actors, Array<PhysicsShape>& actor_shapes, Array<uint32_t>& shape_indices)
-{
-	Vector<DynamicString> keys(default_allocator());
-	e.to_keys(keys);
 
 
-	for (uint32_t k = 0; k < vector::size(keys); k++)
+	//-----------------------------------------------------------------------------
+	void parse_actors(JSONElement e, Array<PhysicsActor>& actors, Array<PhysicsShape>& actor_shapes, Array<uint32_t>& shape_indices)
 	{
 	{
-		JSONElement actor 	= e.key(keys[k].c_str());
-		JSONElement node 	= actor.key("node");
-		JSONElement clasz	= actor.key("class");
-		JSONElement shapes	= actor.key("shapes");
-		JSONElement mass	= actor.key("mass");
-
-		PhysicsActor pa;
-		pa.name = keys[k].to_string_id();
-		pa.node = node.to_string_id();
-		pa.actor_class = clasz.to_string_id();
-		pa.mass = mass.to_float();
-		pa.num_shapes = shapes.size();
-
-		array::push_back(actors, pa);
-		array::push_back(shape_indices, array::size(shape_indices));
-
-		parse_shapes(shapes, actor_shapes);
-	}
-}
+		Vector<DynamicString> keys(default_allocator());
+		e.to_keys(keys);
 
 
-//-----------------------------------------------------------------------------
-void parse_joints(JSONElement e, Array<PhysicsJoint>& joints)
-{
-	Vector<DynamicString> keys(default_allocator());
-	e.to_keys(keys);
+		for (uint32_t k = 0; k < vector::size(keys); k++)
+		{
+			JSONElement actor 	= e.key(keys[k].c_str());
+			JSONElement node 	= actor.key("node");
+			JSONElement clasz	= actor.key("class");
+			JSONElement shapes	= actor.key("shapes");
+			JSONElement mass	= actor.key("mass");
+
+			PhysicsActor pa;
+			pa.name = keys[k].to_string_id();
+			pa.node = node.to_string_id();
+			pa.actor_class = clasz.to_string_id();
+			pa.mass = mass.to_float();
+			pa.num_shapes = shapes.size();
+
+			array::push_back(actors, pa);
+			array::push_back(shape_indices, array::size(shape_indices));
+
+			parse_shapes(shapes, actor_shapes);
+		}
+	}
 
 
-	for (uint32_t k = 0; k < vector::size(keys); k++)
+	//-----------------------------------------------------------------------------
+	void parse_joints(JSONElement e, Array<PhysicsJoint>& joints)
 	{
 	{
-		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.to_string(jtype);
-		pj.type = joint_type_to_enum(jtype.c_str());
-		pj.actor_0 = actor_0.to_string_id();
-		pj.actor_1 = actor_1.to_string_id();
-		pj.anchor_0 = Vector3(anchor_0[0].to_float(), anchor_0[1].to_float(), anchor_0[2].to_float());
-		pj.anchor_1 = Vector3(anchor_1[0].to_float(), anchor_1[1].to_float(), anchor_1[2].to_float());
-		pj.restitution = restitution.is_nil() 	? 0.5f : restitution.to_float();
-		pj.spring = spring.is_nil() 			? 100.0f : spring.to_float();
-		pj.damping = damping.is_nil() 			? 0.0f : damping.to_float();
-		pj.distance = distance.is_nil() 		? 1.0f : distance.to_float();
-		pj.breakable = breakable.is_nil() 		? false : breakable.to_bool();
-		pj.break_force = break_force.is_nil() 	? 3000.0f : break_force.to_float();
-		pj.break_torque = break_torque.is_nil() ? 1000.0f : break_torque.to_float();
-
-		switch (pj.type)
+		Vector<DynamicString> keys(default_allocator());
+		e.to_keys(keys);
+
+		for (uint32_t k = 0; k < vector::size(keys); k++)
 		{
 		{
-			case PhysicsJointType::FIXED:
+			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.to_string(jtype);
+			pj.type = joint_type_to_enum(jtype.c_str());
+			pj.actor_0 = actor_0.to_string_id();
+			pj.actor_1 = actor_1.to_string_id();
+			pj.anchor_0 = Vector3(anchor_0[0].to_float(), anchor_0[1].to_float(), anchor_0[2].to_float());
+			pj.anchor_1 = Vector3(anchor_1[0].to_float(), anchor_1[1].to_float(), anchor_1[2].to_float());
+			pj.restitution = restitution.is_nil() 	? 0.5f : restitution.to_float();
+			pj.spring = spring.is_nil() 			? 100.0f : spring.to_float();
+			pj.damping = damping.is_nil() 			? 0.0f : damping.to_float();
+			pj.distance = distance.is_nil() 		? 1.0f : distance.to_float();
+			pj.breakable = breakable.is_nil() 		? false : breakable.to_bool();
+			pj.break_force = break_force.is_nil() 	? 3000.0f : break_force.to_float();
+			pj.break_torque = break_torque.is_nil() ? 1000.0f : break_torque.to_float();
+
+			switch (pj.type)
 			{
 			{
-				return;
+				case PhysicsJointType::FIXED:
+				{
+					return;
+				}
+				case PhysicsJointType::SPHERICAL:
+				{
+					JSONElement y_limit_angle = joint.key_or_nil("y_limit_angle");
+					JSONElement z_limit_angle = joint.key_or_nil("z_limit_angle");
+					JSONElement contact_dist = joint.key_or_nil("contact_dist");
+
+					pj.y_limit_angle = y_limit_angle.is_nil() ? math::HALF_PI : y_limit_angle.to_float();
+					pj.z_limit_angle = z_limit_angle.is_nil() ? math::HALF_PI : z_limit_angle.to_float();
+					pj.contact_dist = contact_dist.is_nil() ? 0.0f : contact_dist.to_float();
+
+					break;
+				}
+				case PhysicsJointType::REVOLUTE:
+				case PhysicsJointType::PRISMATIC:
+				{
+					JSONElement lower_limit = joint.key_or_nil("lower_limit");
+					JSONElement upper_limit = joint.key_or_nil("upper_limit");
+					JSONElement contact_dist = joint.key_or_nil("contact_dist");
+
+					pj.lower_limit = lower_limit.is_nil() ? 0.0f : lower_limit.to_float();
+					pj.upper_limit = upper_limit.is_nil() ? 0.0f : upper_limit.to_float();
+					pj.contact_dist = contact_dist.is_nil() ? 0.0f : contact_dist.to_float();
+
+					break;
+				}
+				case PhysicsJointType::DISTANCE:
+				{
+					JSONElement max_distance = joint.key_or_nil("max_distance");
+					pj.max_distance = max_distance.is_nil() ? 0.0f : max_distance.to_float();
+
+					break;
+				}
+				case PhysicsJointType::D6:
+				{
+					// Must be implemented
+
+					break;
+				}
 			}
 			}
-			case PhysicsJointType::SPHERICAL:
-			{
-				JSONElement y_limit_angle = joint.key_or_nil("y_limit_angle");
-				JSONElement z_limit_angle = joint.key_or_nil("z_limit_angle");
-				JSONElement contact_dist = joint.key_or_nil("contact_dist");
 
 
-				pj.y_limit_angle = y_limit_angle.is_nil() ? math::HALF_PI : y_limit_angle.to_float();
-				pj.z_limit_angle = z_limit_angle.is_nil() ? math::HALF_PI : z_limit_angle.to_float();
-				pj.contact_dist = contact_dist.is_nil() ? 0.0f : contact_dist.to_float();
-
-				break;
-			}
-			case PhysicsJointType::REVOLUTE:
-			case PhysicsJointType::PRISMATIC:
-			{
-				JSONElement lower_limit = joint.key_or_nil("lower_limit");
-				JSONElement upper_limit = joint.key_or_nil("upper_limit");
-				JSONElement contact_dist = joint.key_or_nil("contact_dist");
+			array::push_back(joints, pj);
+		}
+	}
 
 
-				pj.lower_limit = lower_limit.is_nil() ? 0.0f : lower_limit.to_float();
-				pj.upper_limit = upper_limit.is_nil() ? 0.0f : upper_limit.to_float();
-				pj.contact_dist = contact_dist.is_nil() ? 0.0f : contact_dist.to_float();
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
+	{
+		File* file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*file);
+		fs.close(file);
 
 
-				break;
-			}
-			case PhysicsJointType::DISTANCE:
-			{
-				JSONElement max_distance = joint.key_or_nil("max_distance");
-				pj.max_distance = max_distance.is_nil() ? 0.0f : max_distance.to_float();
+		JSONElement root = json.root();
 
 
-				break;
-			}
-			case PhysicsJointType::D6:
-			{
-				// Must be implemented
+		bool m_has_controller = false;
+		PhysicsController m_controller;
 
 
-				break;
-			}
+		// Read controller
+		JSONElement controller = root.key_or_nil("controller");
+		if (controller.is_nil())
+		{
+			m_has_controller = false;
+		}
+		else
+		{
+			parse_controller(controller, m_controller);
+			m_has_controller = true;
 		}
 		}
 
 
-		array::push_back(joints, pj);
-	}
-}
-
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	File* file = fs.open(resource_path, FOM_READ);
-	JSONParser json(*file);
-	fs.close(file);
+		Array<PhysicsActor> m_actors(default_allocator());
+		Array<uint32_t> m_shapes_indices(default_allocator());
+		Array<PhysicsShape> m_shapes(default_allocator());
+		Array<PhysicsJoint> m_joints(default_allocator());
 
 
-	JSONElement root = json.root();
+		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);
 
 
-	bool m_has_controller = false;
-	PhysicsController m_controller;
+		PhysicsHeader h;
+		h.version = 1;
+		h.num_controllers = m_has_controller ? 1 : 0;
+		h.num_actors = array::size(m_actors);
+		h.num_shapes_indices = array::size(m_shapes_indices);
+		h.num_shapes = array::size(m_shapes);
+		h.num_joints = array::size(m_joints);
 
 
-	// Read controller
-	JSONElement controller = root.key_or_nil("controller");
-	if (controller.is_nil())
-	{
-		m_has_controller = false;
-	}
-	else
-	{
-		parse_controller(controller, m_controller);
-		m_has_controller = true;
-	}
+		uint32_t offt = sizeof(PhysicsHeader);
+		h.controller_offset = offt; offt += sizeof(PhysicsController) * h.num_controllers;
+		h.actors_offset = offt; offt += sizeof(PhysicsActor) * h.num_actors;
+		h.shapes_indices_offset = offt; offt += sizeof(uint32_t) * h.num_shapes_indices;
+		h.shapes_offset = offt; offt += sizeof(PhysicsShape) * h.num_shapes;
+		h.joints_offset = offt;
 
 
-	Array<PhysicsActor> m_actors(default_allocator());
-	Array<uint32_t> m_shapes_indices(default_allocator());
-	Array<PhysicsShape> m_shapes(default_allocator());
-	Array<PhysicsJoint> m_joints(default_allocator());
+		out_file->write((char*) &h, sizeof(PhysicsHeader));
 
 
-	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);
+		if (m_has_controller)
+		{
+			out_file->write((char*) &m_controller, sizeof(PhysicsController));
+		}
 
 
-	PhysicsHeader h;
-	h.version = 1;
-	h.num_controllers = m_has_controller ? 1 : 0;
-	h.num_actors = array::size(m_actors);
-	h.num_shapes_indices = array::size(m_shapes_indices);
-	h.num_shapes = array::size(m_shapes);
-	h.num_joints = array::size(m_joints);
+		if (array::size(m_actors))
+		{
+			out_file->write((char*) array::begin(m_actors), sizeof(PhysicsActor) * array::size(m_actors));
+		}
 
 
-	uint32_t offt = sizeof(PhysicsHeader);
-	h.controller_offset = offt; offt += sizeof(PhysicsController) * h.num_controllers;
-	h.actors_offset = offt; offt += sizeof(PhysicsActor) * h.num_actors;
-	h.shapes_indices_offset = offt; offt += sizeof(uint32_t) * h.num_shapes_indices;
-	h.shapes_offset = offt; offt += sizeof(PhysicsShape) * h.num_shapes;
-	h.joints_offset = offt;
+		if (array::size(m_shapes_indices))
+		{
+			out_file->write((char*) array::begin(m_shapes_indices), sizeof(uint32_t) * array::size(m_shapes_indices));
+		}
 
 
-	out_file->write((char*) &h, sizeof(PhysicsHeader));
+		if (array::size(m_shapes))
+		{
+			out_file->write((char*) array::begin(m_shapes), sizeof(PhysicsShape) * array::size(m_shapes));
+		}
 
 
-	if (m_has_controller)
-	{
-		out_file->write((char*) &m_controller, sizeof(PhysicsController));
+		if (array::size(m_joints))
+		{
+			out_file->write((char*) array::begin(m_joints), sizeof(PhysicsJoint) * array::size(m_joints));
+		}
 	}
 	}
 
 
-	if (array::size(m_actors))
+	//-----------------------------------------------------------------------------
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
 	{
 	{
-		out_file->write((char*) array::begin(m_actors), sizeof(PhysicsActor) * array::size(m_actors));
+		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;
 	}
 	}
 
 
-	if (array::size(m_shapes_indices))
+	//-----------------------------------------------------------------------------
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
 	{
 	{
-		out_file->write((char*) array::begin(m_shapes_indices), sizeof(uint32_t) * array::size(m_shapes_indices));
 	}
 	}
 
 
-	if (array::size(m_shapes))
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
 	{
 	{
-		out_file->write((char*) array::begin(m_shapes), sizeof(PhysicsShape) * array::size(m_shapes));
 	}
 	}
 
 
-	if (array::size(m_joints))
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& allocator, void* resource)
 	{
 	{
-		out_file->write((char*) array::begin(m_joints), sizeof(PhysicsJoint) * array::size(m_joints));
+		allocator.deallocate(resource);
 	}
 	}
-}
 } // namespace physics_resource
 } // namespace physics_resource
 
 
 namespace physics_config_resource
 namespace physics_config_resource
@@ -651,5 +679,33 @@ namespace physics_config_resource
 		CE_DELETE(default_allocator(), s_ftm);
 		CE_DELETE(default_allocator(), s_ftm);
 	}
 	}
 
 
+	//-----------------------------------------------------------------------------
+	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;
+	}
+
+	//-----------------------------------------------------------------------------
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
+
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& allocator, void* resource)
+	{
+		allocator.deallocate(resource);
+	}
 } // namespace physics_config_resource
 } // namespace physics_config_resource
 } // namespace crown
 } // namespace crown

+ 25 - 58
engine/resource/physics_resource.h

@@ -155,35 +155,6 @@ struct PhysicsJoint
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 struct PhysicsResource
 struct PhysicsResource
 {
 {
-	//-----------------------------------------------------------------------------
-	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(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
 	bool has_controller() const
 	bool has_controller() const
 	{
 	{
@@ -268,6 +239,19 @@ private:
 	PhysicsResource();
 	PhysicsResource();
 };
 };
 
 
+namespace physics_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void unload(Allocator& allocator, void* resource);
+} // namespace physics_resource
+
 struct PhysicsConfigHeader
 struct PhysicsConfigHeader
 {
 {
 	uint32_t num_materials;
 	uint32_t num_materials;
@@ -318,35 +302,6 @@ struct PhysicsActor2
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 struct PhysicsConfigResource
 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(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
 	uint32_t num_materials() const
 	uint32_t num_materials() const
 	{
 	{
@@ -453,4 +408,16 @@ private:
 	PhysicsConfigResource();
 	PhysicsConfigResource();
 };
 };
 
 
+namespace physics_config_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void unload(Allocator& allocator, void* resource);
+} // namespace physics_resource
 } // namespace crown
 } // namespace crown

+ 3 - 15
engine/resource/resource.h

@@ -29,6 +29,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "types.h"
 #include "types.h"
 #include "string_utils.h"
 #include "string_utils.h"
 #include "string_utils.h"
 #include "string_utils.h"
+#include "compile_options.h"
 
 
 namespace crown
 namespace crown
 {
 {
@@ -80,20 +81,7 @@ struct ResourceId
 class Allocator;
 class Allocator;
 class Bundle;
 class Bundle;
 class ResourceManager;
 class ResourceManager;
-
-typedef void*	(*ResourceLoadCallback)(Allocator& a, Bundle& b, ResourceId id);
-typedef void	(*ResourceOnlineCallback)(StringId64 id, ResourceManager& rm);
-typedef void	(*ResourceOfflineCallback)(StringId64 id, ResourceManager& rm);
-typedef void	(*ResourceUnloadCallback)(Allocator& a, void* resource);
-
-struct ResourceCallback
-{
-	uint64_t					type;
-	ResourceLoadCallback		on_load;
-	ResourceUnloadCallback		on_unload;
-	ResourceOnlineCallback		on_online;
-	ResourceOfflineCallback		on_offline;
-};
+class Filesystem;
+class File;
 
 
 } // namespace crown
 } // namespace crown
-

+ 58 - 42
engine/resource/resource_registry.cpp

@@ -41,23 +41,54 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 namespace crown
 {
 {
 
 
+namespace pcr = physics_config_resource;
+namespace phr = physics_resource;
+namespace pkr = package_resource;
+namespace sdr = sound_resource;
+namespace mhr = mesh_resource;
+namespace utr = unit_resource;
+namespace txr = texture_resource;
+namespace mtr = material_resource;
+namespace lur = lua_resource;
+namespace ftr = font_resource;
+namespace lvr = level_resource;
+namespace spr = sprite_resource;
+namespace shr = shader_resource;
+namespace sar = sprite_animation_resource;
+
+typedef void  (*ResourceCompileCallback)(const char* path, CompileOptions& opts);
+typedef void* (*ResourceLoadCallback)(Allocator& a, Bundle& b, ResourceId id);
+typedef void  (*ResourceOnlineCallback)(StringId64 id, ResourceManager& rm);
+typedef void  (*ResourceOfflineCallback)(StringId64 id, ResourceManager& rm);
+typedef void  (*ResourceUnloadCallback)(Allocator& a, void* resource);
+
+struct ResourceCallback
+{
+	uint64_t type;
+	ResourceCompileCallback on_compile;
+	ResourceLoadCallback on_load;
+	ResourceUnloadCallback on_unload;
+	ResourceOnlineCallback on_online;
+	ResourceOfflineCallback on_offline;
+};
+
 static const ResourceCallback RESOURCE_CALLBACK_REGISTRY[] =
 static const ResourceCallback RESOURCE_CALLBACK_REGISTRY[] =
 {
 {
-	{ LUA_TYPE, LuaResource::load, LuaResource::unload, LuaResource::online, LuaResource::offline },
-	{ TEXTURE_TYPE, TextureResource::load, TextureResource::unload, TextureResource::online, TextureResource::offline },
-	{ MESH_TYPE, MeshResource::load, MeshResource::unload, MeshResource::online, MeshResource::offline },
-	{ SOUND_TYPE, SoundResource::load, SoundResource::unload, SoundResource::online, SoundResource::offline },
-	{ UNIT_TYPE, UnitResource::load, UnitResource::unload, UnitResource::online, UnitResource::offline },
-	{ SPRITE_TYPE, sprite_resource::load, sprite_resource::unload, sprite_resource::online, sprite_resource::offline},
-	{ 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 },
-	{ PHYSICS_CONFIG_TYPE, PhysicsConfigResource::load, PhysicsConfigResource::unload, PhysicsConfigResource::online, PhysicsConfigResource::offline },
-	{ FONT_TYPE, FontResource::load, FontResource::unload, FontResource::online, FontResource::offline },
-	{ LEVEL_TYPE, LevelResource::load, LevelResource::unload, LevelResource::online, LevelResource::offline },
-	{ SHADER_TYPE, shader_resource::load, shader_resource::unload, shader_resource::online, shader_resource::offline },
-	{ SPRITE_ANIMATION_TYPE, sprite_animation_resource::load, sprite_animation_resource::unload, sprite_animation_resource::online, sprite_animation_resource::offline },
-	{ 0, NULL, NULL, NULL, NULL }
+	{ LUA_TYPE,              lur::compile, lur::load, lur::unload, lur::online, lur::offline },
+	{ TEXTURE_TYPE,          txr::compile, txr::load, txr::unload, txr::online, txr::offline },
+	{ MESH_TYPE,             mhr::compile, mhr::load, mhr::unload, mhr::online, mhr::offline },
+	{ SOUND_TYPE,            sdr::compile, sdr::load, sdr::unload, sdr::online, sdr::offline },
+	{ UNIT_TYPE,             utr::compile, utr::load, utr::unload, utr::online, utr::offline },
+	{ SPRITE_TYPE,           spr::compile, spr::load, spr::unload, spr::online, spr::offline },
+	{ PACKAGE_TYPE,          pkr::compile, pkr::load, pkr::unload, pkr::online, pkr::offline },
+	{ PHYSICS_TYPE,          phr::compile, phr::load, phr::unload, phr::online, phr::offline },
+	{ MATERIAL_TYPE,         mtr::compile, mtr::load, mtr::unload, mtr::online, mtr::offline },
+	{ PHYSICS_CONFIG_TYPE,   pcr::compile, pcr::load, pcr::unload, pcr::online, pcr::offline },
+	{ FONT_TYPE,             ftr::compile, ftr::load, ftr::unload, ftr::online, ftr::offline },
+	{ LEVEL_TYPE,            lvr::compile, lvr::load, lvr::unload, lvr::online, lvr::offline },
+	{ SHADER_TYPE,           shr::compile, shr::load, shr::unload, shr::online, shr::offline },
+	{ SPRITE_ANIMATION_TYPE, sar::compile, sar::load, sar::unload, sar::online, sar::offline },
+	{ 0,                     NULL,         NULL,      NULL,        NULL,        NULL         }
 };
 };
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -65,57 +96,42 @@ static const ResourceCallback* find_callback(uint64_t type)
 {
 {
 	const ResourceCallback* c = RESOURCE_CALLBACK_REGISTRY;
 	const ResourceCallback* c = RESOURCE_CALLBACK_REGISTRY;
 
 
-	while (c->type != 0)
+	while (c->type != 0 && c->type != type)
 	{
 	{
-		if (c->type == type)
-		{
-			return c;
-		}
-
 		c++;
 		c++;
 	}
 	}
 
 
-	return NULL;
+	CE_ASSERT_NOT_NULL(c);
+	return c;
+}
+
+void resource_on_compile(uint64_t type, const char* path, CompileOptions& opts)
+{
+	return find_callback(type)->on_compile(path, opts);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 void* resource_on_load(uint64_t type, Allocator& allocator, Bundle& bundle, ResourceId id)
 void* resource_on_load(uint64_t type, Allocator& allocator, Bundle& bundle, ResourceId id)
 {
 {
-	const ResourceCallback* c = find_callback(type);
-
-	CE_ASSERT_NOT_NULL(c);
-
-	return c->on_load(allocator, bundle, id);
+	return find_callback(type)->on_load(allocator, bundle, id);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 void resource_on_unload(uint64_t type, Allocator& allocator, void* resource)
 void resource_on_unload(uint64_t type, Allocator& allocator, void* resource)
 {
 {
-	const ResourceCallback* c = find_callback(type);
-
-	CE_ASSERT_NOT_NULL(c);
-
-	return c->on_unload(allocator, resource);
+	return find_callback(type)->on_unload(allocator, resource);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 void resource_on_online(uint64_t type, StringId64 id, ResourceManager& rm)
 void resource_on_online(uint64_t type, StringId64 id, ResourceManager& rm)
 {
 {
-	const ResourceCallback* c = find_callback(type);
-
-	CE_ASSERT_NOT_NULL(c);
-
-	return c->on_online(id, rm);
+	return find_callback(type)->on_online(id, rm);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 void resource_on_offline(uint64_t type, StringId64 id, ResourceManager& rm)
 void resource_on_offline(uint64_t type, StringId64 id, ResourceManager& rm)
 {
 {
-	const ResourceCallback* c = find_callback(type);
-
-	CE_ASSERT_NOT_NULL(c);
-
-	return c->on_offline(id, rm);
+	return find_callback(type)->on_offline(id, rm);
 }
 }
 
 
 } // namespace crown
 } // namespace crown

+ 1 - 0
engine/resource/resource_registry.h

@@ -31,6 +31,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 namespace crown
 {
 {
 
 
+void resource_on_compile(uint64_t type, const char* path, CompileOptions& opts);
 void* resource_on_load(uint64_t type, Allocator& allocator, Bundle& bundle, ResourceId id);
 void* resource_on_load(uint64_t type, Allocator& allocator, Bundle& bundle, ResourceId id);
 void resource_on_online(uint64_t type, StringId64 id, ResourceManager& rm);
 void resource_on_online(uint64_t type, StringId64 id, ResourceManager& rm);
 void resource_on_offline(uint64_t type, StringId64 id, ResourceManager& rm);
 void resource_on_offline(uint64_t type, StringId64 id, ResourceManager& rm);

+ 125 - 97
engine/resource/sound_resource.cpp

@@ -40,138 +40,166 @@ namespace crown
 {
 {
 namespace sound_resource
 namespace sound_resource
 {
 {
+	//-----------------------------------------------------------------------------
+	struct WAVHeader
+	{
+		char 			riff[4];				// Should contains 'RIFF'
+		int32_t			chunk_size;				// Not Needed
+		char 			wave[4];				// Should contains 'WAVE'
+		char 			fmt[4];					// Should contains 'fmt '
+		int32_t			fmt_size;				// Size of format chunk
+		int16_t			fmt_tag;				// Identifies way data is stored, 1 means no compression
+		int16_t			fmt_channels;			// Channel, 1 means mono, 2 means stereo
+		int32_t			fmt_sample_rate;		// Sample per second
+		int32_t			fmt_avarage;			// Avarage bytes per sample
+		int16_t			fmt_block_align;		// Block alignment
+		int16_t			fmt_bits_ps;			// Number of bits per sample
+		char 			data[4];				// Should contains 'data'
+		int32_t			data_size;				// Data dimension
+	};
+
+	SoundHeader			m_sound_header;
+	size_t				m_sound_data_size = 0;
+	uint8_t*			m_sound_data = NULL;
+
+	//-----------------------------------------------------------------------------
+	size_t compile_if_wav(Filesystem& fs, const char* resource_path)
+	{
+		File* in_file = fs.open(resource_path, FOM_READ);
 
 
-//-----------------------------------------------------------------------------
-struct WAVHeader
-{
-	char 			riff[4];				// Should contains 'RIFF'
-	int32_t			chunk_size;				// Not Needed
-	char 			wave[4];				// Should contains 'WAVE'
-	char 			fmt[4];					// Should contains 'fmt '
-	int32_t			fmt_size;				// Size of format chunk
-	int16_t			fmt_tag;				// Identifies way data is stored, 1 means no compression
-	int16_t			fmt_channels;			// Channel, 1 means mono, 2 means stereo
-	int32_t			fmt_sample_rate;		// Sample per second
-	int32_t			fmt_avarage;			// Avarage bytes per sample
-	int16_t			fmt_block_align;		// Block alignment
-	int16_t			fmt_bits_ps;			// Number of bits per sample
-	char 			data[4];				// Should contains 'data'
-	int32_t			data_size;				// Data dimension
-};
-
-SoundHeader			m_sound_header;
-size_t				m_sound_data_size = 0;
-uint8_t*			m_sound_data = NULL;
-
-//-----------------------------------------------------------------------------
-size_t compile_if_wav(Filesystem& fs, const char* resource_path)
-{
-	File* in_file = fs.open(resource_path, FOM_READ);
-
-	WAVHeader header;
+		WAVHeader header;
 
 
-	in_file->read((char*)&header, sizeof(WAVHeader));
+		in_file->read((char*)&header, sizeof(WAVHeader));
 
 
-	if (header.riff[0] != 'R' && header.riff[1] != 'I' && header.riff[2] != 'F' && header.riff[3] != 'F')
-	{
-		if (header.wave[0] != 'W' && header.wave[1] != 'A' && header.wave[2] != 'V' && header.wave[3] != 'E')
+		if (header.riff[0] != 'R' && header.riff[1] != 'I' && header.riff[2] != 'F' && header.riff[3] != 'F')
 		{
 		{
-			if (header.fmt[0] != 'f' && header.fmt[1] != 'm' && header.fmt[2] != 't' && header.fmt[3] != ' ')
+			if (header.wave[0] != 'W' && header.wave[1] != 'A' && header.wave[2] != 'V' && header.wave[3] != 'E')
 			{
 			{
-				fs.close(in_file);
-				return 0;
+				if (header.fmt[0] != 'f' && header.fmt[1] != 'm' && header.fmt[2] != 't' && header.fmt[3] != ' ')
+				{
+					fs.close(in_file);
+					return 0;
+				}
 			}
 			}
 		}
 		}
-	}
 
 
-	m_sound_header.version = SOUND_VERSION;
-	m_sound_header.size = header.data_size;
-	m_sound_header.sample_rate = header.fmt_sample_rate;
-	m_sound_header.avg_bytes_ps = header.fmt_avarage;
-	m_sound_header.channels = header.fmt_channels;
-	m_sound_header.block_size = header.fmt_block_align;
-	m_sound_header.bits_ps = header.fmt_bits_ps;
-	m_sound_header.sound_type = SoundType::WAV;
+		m_sound_header.version = SOUND_VERSION;
+		m_sound_header.size = header.data_size;
+		m_sound_header.sample_rate = header.fmt_sample_rate;
+		m_sound_header.avg_bytes_ps = header.fmt_avarage;
+		m_sound_header.channels = header.fmt_channels;
+		m_sound_header.block_size = header.fmt_block_align;
+		m_sound_header.bits_ps = header.fmt_bits_ps;
+		m_sound_header.sound_type = SoundType::WAV;
 
 
-	m_sound_data_size = header.data_size;
-	m_sound_data = (uint8_t*)default_allocator().allocate(m_sound_data_size);
+		m_sound_data_size = header.data_size;
+		m_sound_data = (uint8_t*)default_allocator().allocate(m_sound_data_size);
 
 
-	in_file->read((char*)m_sound_data, m_sound_data_size);
+		in_file->read((char*)m_sound_data, m_sound_data_size);
 
 
-	fs.close(in_file);
+		fs.close(in_file);
 
 
-	return sizeof(SoundHeader) + m_sound_data_size;
-}
+		return sizeof(SoundHeader) + m_sound_data_size;
+	}
 
 
-// //-----------------------------------------------------------------------------
-// size_t compile_if_ogg(Filesystem& fs, const char* resource_path)
-// {
-// 	// Retrieves resource absolute path
-// 	DynamicString s(default_allocator());
-// 	fs.get_absolute_path(resource_path, s);
-// 	const char* abs_path = s.c_str();
+	// //-----------------------------------------------------------------------------
+	// size_t compile_if_ogg(Filesystem& fs, const char* resource_path)
+	// {
+	// 	// Retrieves resource absolute path
+	// 	DynamicString s(default_allocator());
+	// 	fs.get_absolute_path(resource_path, s);
+	// 	const char* abs_path = s.c_str();
 
 
-// 	OggVorbis_File ogg_stream;
+	// 	OggVorbis_File ogg_stream;
 
 
-// 	bool result = ov_fopen(os::normalize_path(abs_path), &ogg_stream) == 0;
+	// 	bool result = ov_fopen(os::normalize_path(abs_path), &ogg_stream) == 0;
 
 
-// 	if (result == false)
-// 	{
-// 		return 0;
-// 	}
+	// 	if (result == false)
+	// 	{
+	// 		return 0;
+	// 	}
 
 
-// 	vorbis_info* info = ov_info(&ogg_stream, -1);
+	// 	vorbis_info* info = ov_info(&ogg_stream, -1);
 
 
-// 	int64_t size = ov_raw_total(&ogg_stream, -1);
-// 	int32_t rate = info->rate;
-// 	int32_t channels = info->channels;
+	// 	int64_t size = ov_raw_total(&ogg_stream, -1);
+	// 	int32_t rate = info->rate;
+	// 	int32_t channels = info->channels;
 
 
-// 	ov_clear(&ogg_stream);
+	// 	ov_clear(&ogg_stream);
 
 
-// 	File* in_file = fs.open(resource_path, FOM_READ);
+	// 	File* in_file = fs.open(resource_path, FOM_READ);
 
 
-// 	m_sound_header.version = SOUND_VERSION;
-// 	m_sound_header.size = size;
-// 	m_sound_header.sample_rate = rate;
-// 	m_sound_header.block_size = (channels * 16) / 8;
-// 	m_sound_header.avg_bytes_ps = rate * ((channels * 16) / 8);
-// 	m_sound_header.channels = channels;
-// 	m_sound_header.bits_ps = 16;
-// 	m_sound_header.sound_type = SoundType::OGG;
+	// 	m_sound_header.version = SOUND_VERSION;
+	// 	m_sound_header.size = size;
+	// 	m_sound_header.sample_rate = rate;
+	// 	m_sound_header.block_size = (channels * 16) / 8;
+	// 	m_sound_header.avg_bytes_ps = rate * ((channels * 16) / 8);
+	// 	m_sound_header.channels = channels;
+	// 	m_sound_header.bits_ps = 16;
+	// 	m_sound_header.sound_type = SoundType::OGG;
 
 
-// 	m_sound_data_size = size;
-// 	m_sound_data = (uint8_t*)default_allocator().allocate(m_sound_data_size);
+	// 	m_sound_data_size = size;
+	// 	m_sound_data = (uint8_t*)default_allocator().allocate(m_sound_data_size);
 
 
-// 	in_file->read((char*)m_sound_data, m_sound_data_size);
+	// 	in_file->read((char*)m_sound_data, m_sound_data_size);
 
 
-// 	fs.close(in_file);
+	// 	fs.close(in_file);
 
 
-// 	return sizeof(SoundHeader) + m_sound_data_size;
-// }
+	// 	return sizeof(SoundHeader) + m_sound_data_size;
+	// }
 
 
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	size_t size = 0;
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
+	{
+		size_t size = 0;
+
+		size = compile_if_wav(fs, resource_path);
+
+		if (size == 0)
+		{
+			size = 0; // compile_if_ogg(fs, resource_path);
+		}
+
+		out_file->write((char*)&m_sound_header, sizeof(SoundHeader));
+		out_file->write((char*)m_sound_data, m_sound_data_size);
 
 
-	size = compile_if_wav(fs, resource_path);
+		if (m_sound_data)
+		{
 
 
-	if (size == 0)
+			default_allocator().deallocate(m_sound_data);
+			m_sound_data_size = 0;
+			m_sound_data = NULL;
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
 	{
 	{
-		size = 0; // compile_if_ogg(fs, resource_path);
+		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;
 	}
 	}
 
 
-	out_file->write((char*)&m_sound_header, sizeof(SoundHeader));
-	out_file->write((char*)m_sound_data, m_sound_data_size);
+	//-----------------------------------------------------------------------------
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
 
 
-	if (m_sound_data)
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
 	{
 	{
+	}
 
 
-		default_allocator().deallocate(m_sound_data);
-		m_sound_data_size = 0;
-		m_sound_data = NULL;
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& allocator, void* resource)
+	{
+		allocator.deallocate(resource);
 	}
 	}
-}
 
 
 } // namespace sound_resource
 } // namespace sound_resource
 } // namespace crown
 } // namespace crown

+ 12 - 33
engine/resource/sound_resource.h

@@ -63,39 +63,6 @@ struct SoundHeader
 
 
 struct SoundResource
 struct SoundResource
 {
 {
-public:
-
-	//-----------------------------------------------------------------------------
-	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(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
-public:
-
 	uint32_t size() const
 	uint32_t size() const
 	{
 	{
 		return ((SoundHeader*) this)->size;
 		return ((SoundHeader*) this)->size;
@@ -142,4 +109,16 @@ private:
 	SoundResource();
 	SoundResource();
 };
 };
 
 
+namespace sound_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void unload(Allocator& allocator, void* resource);
+} // namespace sound_resource
 } // namespace crown
 } // namespace crown

+ 10 - 2
engine/resource/sprite_resource.h

@@ -67,7 +67,11 @@ struct SpriteResource
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 namespace sprite_resource
 namespace sprite_resource
 {
 {
-	void compile(crown::Filesystem&, char const*, crown::File*);
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
 	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
 	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
 	void online(StringId64 id, ResourceManager& rm);
 	void online(StringId64 id, ResourceManager& rm);
 	void offline(StringId64 id, ResourceManager& rm);
 	void offline(StringId64 id, ResourceManager& rm);
@@ -96,7 +100,11 @@ struct SpriteAnimationData
 
 
 namespace sprite_animation_resource
 namespace sprite_animation_resource
 {
 {
-	void compile(crown::Filesystem&, char const*, crown::File*);
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
 	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
 	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
 	void online(StringId64 id, ResourceManager& rm);
 	void online(StringId64 id, ResourceManager& rm);
 	void offline(StringId64 id, ResourceManager& rm);
 	void offline(StringId64 id, ResourceManager& rm);

+ 383 - 340
engine/resource/texture_resource.cpp

@@ -187,78 +187,57 @@ namespace pixel_format
 
 
 namespace texture_resource
 namespace texture_resource
 {
 {
+	struct ImageData
+	{
+		uint32_t width;
+		uint32_t height;
+		uint32_t pitch;
+		PixelFormat::Enum format;
+		uint32_t num_mips;
+		char* data;
+	};
 
 
-struct ImageData
-{
-	uint32_t width;
-	uint32_t height;
-	uint32_t pitch;
-	PixelFormat::Enum format;
-	uint32_t num_mips;
-	char* data;
-};
-
-struct MipData
-{
-	uint32_t width;
-	uint32_t height;
-	PixelFormat::Enum format;
-	uint32_t size;
-	char* data;
-};
-
-//-----------------------------------------------------------------------------
-void read_mip_image(const ImageData& image, uint8_t mip, MipData& data)
-{
-	uint32_t width = image.width;
-	uint32_t height = image.height;
-	//uint32_t pitch = image.pitch;
-	uint32_t cur_mip = 0;
-	char* src = image.data;
+	struct MipData
+	{
+		uint32_t width;
+		uint32_t height;
+		PixelFormat::Enum format;
+		uint32_t size;
+		char* data;
+	};
 
 
-	while (1)
+	//-----------------------------------------------------------------------------
+	void read_mip_image(const ImageData& image, uint8_t mip, MipData& data)
 	{
 	{
-		const uint32_t size = width * height * pixel_format::size(image.format);
+		uint32_t width = image.width;
+		uint32_t height = image.height;
+		//uint32_t pitch = image.pitch;
+		uint32_t cur_mip = 0;
+		char* src = image.data;
 
 
-		if (cur_mip == mip)
+		while (1)
 		{
 		{
-			data.width = width;
-			data.height = height;
-			data.format = image.format;
-			data.size = size;
-			data.data = src;
-			return;
-		}
+			const uint32_t size = width * height * pixel_format::size(image.format);
 
 
-		width = math::max(1u, width >> 1);
-		height = math::max(1u, height >> 1);
-		cur_mip++;
-		src += size;
-	}
-}
-
-//-----------------------------------------------------------------------------
-void swap_red_blue(uint32_t width, uint32_t height, uint8_t channels, char* data)
-{
-	uint32_t i = 0;
-
-	for (uint32_t h = 0; h < height; h++)
-	{
-		for (uint32_t w = 0; w < width; w++)
-		{
-			const uint8_t tmp = data[i + 0];
-			data[i + 0] = data[i + 2];
-			data[i + 2] = tmp;
+			if (cur_mip == mip)
+			{
+				data.width = width;
+				data.height = height;
+				data.format = image.format;
+				data.size = size;
+				data.data = src;
+				return;
+			}
 
 
-			i += channels;
+			width = math::max(1u, width >> 1);
+			height = math::max(1u, height >> 1);
+			cur_mip++;
+			src += size;
 		}
 		}
 	}
 	}
-}
 
 
-//-----------------------------------------------------------------------------
-void read_tga_uncompressed(BinaryReader& br, uint32_t width, uint32_t height, uint8_t channels, ImageData& image)
-{
-	if (channels == 2)
+	//-----------------------------------------------------------------------------
+	void swap_red_blue(uint32_t width, uint32_t height, uint8_t channels, char* data)
 	{
 	{
 		uint32_t i = 0;
 		uint32_t i = 0;
 
 
@@ -266,70 +245,63 @@ void read_tga_uncompressed(BinaryReader& br, uint32_t width, uint32_t height, ui
 		{
 		{
 			for (uint32_t w = 0; w < width; w++)
 			for (uint32_t w = 0; w < width; w++)
 			{
 			{
-				uint16_t data;
-				br.read(data);
-
-				image.data[i + 0] = (data & 0x7c) >> 10;
-				image.data[i + 1] = (data & 0x3e) >> 5;
-				image.data[i + 2] = (data & 0x1f);
+				const uint8_t tmp = data[i + 0];
+				data[i + 0] = data[i + 2];
+				data[i + 2] = tmp;
 
 
-				i += 3;
+				i += channels;
 			}
 			}
 		}
 		}
 	}
 	}
-	else
-	{
-		br.read(image.data, width * height * channels);
-		swap_red_blue(width, height, channels, image.data);
-	}
-}
 
 
-//-----------------------------------------------------------------------------
-void read_tga_compressed(BinaryReader& br, uint32_t width, uint32_t height, uint8_t channels, ImageData& image)
-{
-	uint8_t rle_id = 0;
-	uint32_t i = 0;
-	uint32_t colors_read = 0;
-
-	// Can't be more than 4 channels
-	uint8_t colors[4];
-
-	while (i < width * height)
+	//-----------------------------------------------------------------------------
+	void read_tga_uncompressed(BinaryReader& br, uint32_t width, uint32_t height, uint8_t channels, ImageData& image)
 	{
 	{
-		br.read(rle_id);
-
-		// If MSB == 1
-		if (rle_id & 0x80)
+		if (channels == 2)
 		{
 		{
-			rle_id -= 127;
-
-			br.read(colors[0]);
-			br.read(colors[1]);
-			br.read(colors[2]);
-
-			if (channels == 4)
-				br.read(colors[3]);
+			uint32_t i = 0;
 
 
-			while (rle_id)
+			for (uint32_t h = 0; h < height; h++)
 			{
 			{
-				image.data[colors_read + 0] = colors[2];
-				image.data[colors_read + 1] = colors[1];
-				image.data[colors_read + 2] = colors[0];
+				for (uint32_t w = 0; w < width; w++)
+				{
+					uint16_t data;
+					br.read(data);
 
 
-				if (channels == 4)
-					image.data[colors_read + 3] = colors[3];
+					image.data[i + 0] = (data & 0x7c) >> 10;
+					image.data[i + 1] = (data & 0x3e) >> 5;
+					image.data[i + 2] = (data & 0x1f);
 
 
-				rle_id--;
-				colors_read += channels;
-				i++;
+					i += 3;
+				}
 			}
 			}
 		}
 		}
 		else
 		else
 		{
 		{
-			rle_id++;
+			br.read(image.data, width * height * channels);
+			swap_red_blue(width, height, channels, image.data);
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void read_tga_compressed(BinaryReader& br, uint32_t width, uint32_t height, uint8_t channels, ImageData& image)
+	{
+		uint8_t rle_id = 0;
+		uint32_t i = 0;
+		uint32_t colors_read = 0;
 
 
-			while (rle_id)
+		// Can't be more than 4 channels
+		uint8_t colors[4];
+
+		while (i < width * height)
+		{
+			br.read(rle_id);
+
+			// If MSB == 1
+			if (rle_id & 0x80)
 			{
 			{
+				rle_id -= 127;
+
 				br.read(colors[0]);
 				br.read(colors[0]);
 				br.read(colors[1]);
 				br.read(colors[1]);
 				br.read(colors[2]);
 				br.read(colors[2]);
@@ -337,304 +309,375 @@ void read_tga_compressed(BinaryReader& br, uint32_t width, uint32_t height, uint
 				if (channels == 4)
 				if (channels == 4)
 					br.read(colors[3]);
 					br.read(colors[3]);
 
 
-				image.data[colors_read + 0] = colors[2];
-				image.data[colors_read + 1] = colors[1];
-				image.data[colors_read + 2] = colors[0];
+				while (rle_id)
+				{
+					image.data[colors_read + 0] = colors[2];
+					image.data[colors_read + 1] = colors[1];
+					image.data[colors_read + 2] = colors[0];
 
 
-				if (channels == 4)
-					image.data[colors_read + 3] = colors[3];
+					if (channels == 4)
+						image.data[colors_read + 3] = colors[3];
 
 
-				rle_id--;
-				colors_read += channels;
-				i++;
+					rle_id--;
+					colors_read += channels;
+					i++;
+				}
+			}
+			else
+			{
+				rle_id++;
+
+				while (rle_id)
+				{
+					br.read(colors[0]);
+					br.read(colors[1]);
+					br.read(colors[2]);
+
+					if (channels == 4)
+						br.read(colors[3]);
+
+					image.data[colors_read + 0] = colors[2];
+					image.data[colors_read + 1] = colors[1];
+					image.data[colors_read + 2] = colors[0];
+
+					if (channels == 4)
+						image.data[colors_read + 3] = colors[3];
+
+					rle_id--;
+					colors_read += channels;
+					i++;
+				}
 			}
 			}
 		}
 		}
+
+		swap_red_blue(width, height, channels, image.data);
 	}
 	}
 
 
-	swap_red_blue(width, height, channels, image.data);
-}
+	//-----------------------------------------------------------------------------
+	void parse_tga(BinaryReader& br, ImageData& image)
+	{
+		uint8_t id;
+		br.read(id);
 
 
-//-----------------------------------------------------------------------------
-void parse_tga(BinaryReader& br, ImageData& image)
-{
-	uint8_t id;
-	br.read(id);
+		uint8_t cmap_type;
+		br.read(cmap_type);
 
 
-	uint8_t cmap_type;
-	br.read(cmap_type);
+		uint8_t image_type;
+		br.read(image_type);
 
 
-	uint8_t image_type;
-	br.read(image_type);
+		uint8_t garbage;
+		for (uint32_t i = 0; i < 5; i++)
+			br.read(garbage);
 
 
-	uint8_t garbage;
-	for (uint32_t i = 0; i < 5; i++)
-		br.read(garbage);
+		uint16_t x_offt;
+		br.read(x_offt);
 
 
-	uint16_t x_offt;
-	br.read(x_offt);
+		uint16_t y_offt;
+		br.read(y_offt);
 
 
-	uint16_t y_offt;
-	br.read(y_offt);
+		uint16_t width;
+		br.read(width);
 
 
-	uint16_t width;
-	br.read(width);
+		uint16_t height;
+		br.read(height);
 
 
-	uint16_t height;
-	br.read(height);
+		uint8_t depth;
+		br.read(depth);
 
 
-	uint8_t depth;
-	br.read(depth);
+		uint8_t desc;
+		br.read(desc);
 
 
-	uint8_t desc;
-	br.read(desc);
+		// Skip TGA ID
+		br.skip(id);
 
 
-	// Skip TGA ID
-	br.skip(id);
+		CE_ASSERT(image_type != 0, "TGA does not contain image data");
+		CE_ASSERT(image_type == 2 || image_type == 10, "TGA image format not supported");
 
 
-	CE_ASSERT(image_type != 0, "TGA does not contain image data");
-	CE_ASSERT(image_type == 2 || image_type == 10, "TGA image format not supported");
+		const uint32_t channels = depth / 8;
 
 
-	const uint32_t channels = depth / 8;
+		image.width = width;
+		image.height = height;
+		image.num_mips = 1;
 
 
-	image.width = width;
-	image.height = height;
-	image.num_mips = 1;
+		switch (channels)
+		{
+			case 2: image.format = PixelFormat::R8G8B8; break;
+			case 3: image.format = PixelFormat::R8G8B8; break;
+			case 4: image.format = PixelFormat::R8G8B8A8; break;
+			default: CE_FATAL("TGA channels not supported"); break;
+		}
 
 
-	switch (channels)
-	{
-		case 2: image.format = PixelFormat::R8G8B8; break;
-		case 3: image.format = PixelFormat::R8G8B8; break;
-		case 4: image.format = PixelFormat::R8G8B8A8; break;
-		default: CE_FATAL("TGA channels not supported"); break;
-	}
+		image.data = (char*) default_allocator().allocate(pixel_format::size(image.format) * width * height);
 
 
-	image.data = (char*) default_allocator().allocate(pixel_format::size(image.format) * width * height);
+		if (image_type == 2)
+		{
+			read_tga_uncompressed(br, width, height, channels, image);
+		}
+		else if (image_type == 10)
+		{
+			read_tga_compressed(br, width, height, channels, image);
+		}
 
 
-	if (image_type == 2)
-	{
-		read_tga_uncompressed(br, width, height, channels, image);
-	}
-	else if (image_type == 10)
-	{
-		read_tga_compressed(br, width, height, channels, image);
+		return;
 	}
 	}
 
 
-	return;
-}
+	//-----------------------------------------------------------------------------
+	void parse_dds(BinaryReader& br, ImageData& image)
+	{
+		// Read header
+		uint32_t magic;
+		br.read(magic);
+		CE_ASSERT(magic == DDSD_MAGIC, "DDS bad magic number");
 
 
-//-----------------------------------------------------------------------------
-void parse_dds(BinaryReader& br, ImageData& image)
-{
-	// Read header
-	uint32_t magic;
-	br.read(magic);
-	CE_ASSERT(magic == DDSD_MAGIC, "DDS bad magic number");
+		uint32_t hsize;
+		br.read(hsize);
+		CE_ASSERT(hsize == DDSD_HEADERSIZE, "DDS bas header size");
 
 
-	uint32_t hsize;
-	br.read(hsize);
-	CE_ASSERT(hsize == DDSD_HEADERSIZE, "DDS bas header size");
+		uint32_t flags;
+		br.read(flags);
+		CE_ASSERT(flags & (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), "DDS bad header flags");
 
 
-	uint32_t flags;
-	br.read(flags);
-	CE_ASSERT(flags & (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), "DDS bad header flags");
+		uint32_t height;
+		br.read(height);
 
 
-	uint32_t height;
-	br.read(height);
+		uint32_t width;
+		br.read(width);
 
 
-	uint32_t width;
-	br.read(width);
+		uint32_t pitch;
+		br.read(pitch);
 
 
-	uint32_t pitch;
-	br.read(pitch);
+		uint32_t depth;
+		br.read(depth);
 
 
-	uint32_t depth;
-	br.read(depth);
+		uint32_t num_mips;
+		br.read(num_mips);
 
 
-	uint32_t num_mips;
-	br.read(num_mips);
+		// Skip reserved bits
+		br.skip(sizeof(uint32_t) * 11);
 
 
-	// Skip reserved bits
-	br.skip(sizeof(uint32_t) * 11);
+		// Read pixel format
+		uint32_t pf_hsize;
+		br.read(pf_hsize);
+		CE_ASSERT(pf_hsize == DDPF_HEADERSIZE, "DDS bad pf header size");
 
 
-	// Read pixel format
-	uint32_t pf_hsize;
-	br.read(pf_hsize);
-	CE_ASSERT(pf_hsize == DDPF_HEADERSIZE, "DDS bad pf header size");
+		uint32_t pf_flags;
+		br.read(pf_flags);
 
 
-	uint32_t pf_flags;
-	br.read(pf_flags);
+		uint32_t pf_fourcc;
+		br.read(pf_fourcc);
 
 
-	uint32_t pf_fourcc;
-	br.read(pf_fourcc);
+		uint32_t pf_bitcount;
+		br.read(pf_bitcount);
 
 
-	uint32_t pf_bitcount;
-	br.read(pf_bitcount);
+		uint32_t pf_rmask;
+		br.read(pf_rmask);
 
 
-	uint32_t pf_rmask;
-	br.read(pf_rmask);
+		uint32_t pf_gmask;
+		br.read(pf_gmask);
 
 
-	uint32_t pf_gmask;
-	br.read(pf_gmask);
+		uint32_t pf_bmask;
+		br.read(pf_bmask);
 
 
-	uint32_t pf_bmask;
-	br.read(pf_bmask);
+		uint32_t pf_amask;
+		br.read(pf_amask);
 
 
-	uint32_t pf_amask;
-	br.read(pf_amask);
+		uint32_t caps;
+		br.read(caps);
+		CE_ASSERT((caps & DDSCAPS_TEXTURE), "DDS bad caps");
 
 
-	uint32_t caps;
-	br.read(caps);
-	CE_ASSERT((caps & DDSCAPS_TEXTURE), "DDS bad caps");
+		uint32_t caps2;
+		br.read(caps2);
 
 
-	uint32_t caps2;
-	br.read(caps2);
+		uint32_t caps3;
+		br.read(caps3);
 
 
-	uint32_t caps3;
-	br.read(caps3);
+		uint32_t caps4;
+		br.read(caps4);
 
 
-	uint32_t caps4;
-	br.read(caps4);
+		uint32_t reserved2;
+		br.read(reserved2);
 
 
-	uint32_t reserved2;
-	br.read(reserved2);
+		CE_LOGD("width = %u", width);
+		CE_LOGD("height = %u", height);
+		CE_LOGD("mips = %u", num_mips);
+		CE_LOGD("pitch = %u (valid = %s)", pitch, flags & DDSD_PITCH ? "yes" : "no");
+		CE_LOGD("pfflags = %.8x", pf_flags);
 
 
-	CE_LOGD("width = %u", width);
-	CE_LOGD("height = %u", height);
-	CE_LOGD("mips = %u", num_mips);
-	CE_LOGD("pitch = %u (valid = %s)", pitch, flags & DDSD_PITCH ? "yes" : "no");
-	CE_LOGD("pfflags = %.8x", pf_flags);
+		image.width = width;
+		image.height = height;
+		image.pitch = pitch;
+		image.num_mips = (flags & DDSD_MIPMAPCOUNT) ? num_mips : 1;
+		image.data = (char*) (uintptr_t) DDS_DATA_OFFSET;
 
 
-	image.width = width;
-	image.height = height;
-	image.pitch = pitch;
-	image.num_mips = (flags & DDSD_MIPMAPCOUNT) ? num_mips : 1;
-	image.data = (char*) (uintptr_t) DDS_DATA_OFFSET;
+		const uint32_t raw_fmt = (pf_flags & DDPF_FOURCC) ? pf_fourcc : pf_flags;
+		switch (raw_fmt)
+		{
+			case DDPF_FOURCC_DXT1: image.format = PixelFormat::DXT1; break;
+			case DDPF_FOURCC_DXT3: image.format = PixelFormat::DXT3; break;
+			case DDPF_FOURCC_DXT5: image.format = PixelFormat::DXT5; break;
+			case DDS_RGB: image.format = PixelFormat::R8G8B8; break;
+			case DDS_RGBA: image.format = PixelFormat::R8G8B8A8; break;
+			default: image.format = PixelFormat::COUNT; break;
+		}
 
 
-	const uint32_t raw_fmt = (pf_flags & DDPF_FOURCC) ? pf_fourcc : pf_flags;
-	switch (raw_fmt)
-	{
-		case DDPF_FOURCC_DXT1: image.format = PixelFormat::DXT1; break;
-		case DDPF_FOURCC_DXT3: image.format = PixelFormat::DXT3; break;
-		case DDPF_FOURCC_DXT5: image.format = PixelFormat::DXT5; break;
-		case DDS_RGB: image.format = PixelFormat::R8G8B8; break;
-		case DDS_RGBA: image.format = PixelFormat::R8G8B8A8; break;
-		default: image.format = PixelFormat::COUNT; break;
+		CE_ASSERT(image.format != PixelFormat::COUNT, "DDS pixel format not supported");
+		CE_LOGD("PixelFormat = %u", image.format);
 	}
 	}
 
 
-	CE_ASSERT(image.format != PixelFormat::COUNT, "DDS pixel format not supported");
-	CE_LOGD("PixelFormat = %u", image.format);
-}
-
-//-----------------------------------------------------------------------------
-void write_dds(BinaryWriter& bw, const ImageData& image)
-{
-	bw.write(DDSD_MAGIC);
-
-	// Header
-	bw.write(DDSD_HEADERSIZE); // dwSize
-	bw.write(DDS_HEADER_FLAGS_TEXTURE
-		| DDSD_MIPMAPCOUNT
-		| (pixel_format::is_compressed(image.format) ? DDSD_LINEARSIZE : DDSD_PITCH)
-		| (image.num_mips ? DDSD_MIPMAPCOUNT : 0)); // dwFlags
-	bw.write(image.height); // dwHeight
-	bw.write(image.width); // dwWidth
-
-	const uint32_t pitch = pixel_format::is_compressed(image.format) ? 0 // fixme
-							: (image.width * pixel_format::size(image.format) * 8 + 7) / 8;
-
-	bw.write(pitch); // dwPitchOrLinearSize
-	bw.write(DDSD_UNUSED); // dwDepth
-	bw.write(image.num_mips); // dwMipMapCount;
-
-	for (uint32_t i = 0; i < 11; i++)
-		bw.write(DDSD_UNUSED); // dwReserved1[11];
-
-	// Pixel format
-	bw.write(DDPF_HEADERSIZE); // dwSize;
-	uint32_t pf = 0;
-	switch (image.format)
+	//-----------------------------------------------------------------------------
+	void write_dds(BinaryWriter& bw, const ImageData& image)
 	{
 	{
-		case PixelFormat::DXT1:     pf = DDPF_FOURCC_DXT1; break;
-		case PixelFormat::DXT3:     pf = DDPF_FOURCC_DXT3; break;
-		case PixelFormat::DXT5:     pf = DDPF_FOURCC_DXT5; break;
-		case PixelFormat::R8G8B8:   pf = DDS_RGB; break;
-		case PixelFormat::R8G8B8A8: pf = DDS_RGBA; break;
-		default: CE_FATAL("Pixel format unknown"); break;
+		bw.write(DDSD_MAGIC);
+
+		// Header
+		bw.write(DDSD_HEADERSIZE); // dwSize
+		bw.write(DDS_HEADER_FLAGS_TEXTURE
+			| DDSD_MIPMAPCOUNT
+			| (pixel_format::is_compressed(image.format) ? DDSD_LINEARSIZE : DDSD_PITCH)
+			| (image.num_mips ? DDSD_MIPMAPCOUNT : 0)); // dwFlags
+		bw.write(image.height); // dwHeight
+		bw.write(image.width); // dwWidth
+
+		const uint32_t pitch = pixel_format::is_compressed(image.format) ? 0 // fixme
+								: (image.width * pixel_format::size(image.format) * 8 + 7) / 8;
+
+		bw.write(pitch); // dwPitchOrLinearSize
+		bw.write(DDSD_UNUSED); // dwDepth
+		bw.write(image.num_mips); // dwMipMapCount;
+
+		for (uint32_t i = 0; i < 11; i++)
+			bw.write(DDSD_UNUSED); // dwReserved1[11];
+
+		// Pixel format
+		bw.write(DDPF_HEADERSIZE); // dwSize;
+		uint32_t pf = 0;
+		switch (image.format)
+		{
+			case PixelFormat::DXT1:     pf = DDPF_FOURCC_DXT1; break;
+			case PixelFormat::DXT3:     pf = DDPF_FOURCC_DXT3; break;
+			case PixelFormat::DXT5:     pf = DDPF_FOURCC_DXT5; break;
+			case PixelFormat::R8G8B8:   pf = DDS_RGB; break;
+			case PixelFormat::R8G8B8A8: pf = DDS_RGBA; break;
+			default: CE_FATAL("Pixel format unknown"); break;
+		}
+		bw.write(pixel_format::is_compressed(image.format) ? DDPF_FOURCC : pf); // dwFlags;
+		bw.write(pixel_format::is_compressed(image.format) ? pf : DDSD_UNUSED); // dwFourCC;
+		bw.write(uint32_t(pixel_format::size(image.format) * 8)); // dwRGBBitCount;
+		bw.write(uint32_t(0x00FF0000)); // dwRBitMask;
+		bw.write(uint32_t(0x0000FF00)); // dwGBitMask;
+		bw.write(uint32_t(0x000000FF)); // dwBBitMask;
+		bw.write(uint32_t(0xFF000000)); // dwABitMask;
+
+		bw.write(DDSCAPS_TEXTURE
+			| (image.num_mips > 1 ? DDSCAPS_COMPLEX : DDSD_UNUSED) // also for cubemap, depth mipmap
+			| (image.num_mips > 1 ? DDSCAPS_MIPMAP : DDSD_UNUSED)); // dwCaps;
+		bw.write(DDSD_UNUSED); // dwCaps2;
+		bw.write(DDSD_UNUSED); // dwCaps3;
+		bw.write(DDSD_UNUSED); // dwCaps4;
+		bw.write(DDSD_UNUSED); // dwReserved2;
+
+		// Image data
+		for (uint32_t i = 0; i < image.num_mips; i++)
+		{
+			MipData mip;
+			read_mip_image(image, i, mip);
+
+			// CE_LOGD("Writing mip: (%ux%u) byes = %u", mip.width, mip.height, mip.size);
+			bw.write(mip.data, mip.size);
+		}
 	}
 	}
-	bw.write(pixel_format::is_compressed(image.format) ? DDPF_FOURCC : pf); // dwFlags;
-	bw.write(pixel_format::is_compressed(image.format) ? pf : DDSD_UNUSED); // dwFourCC;
-	bw.write(uint32_t(pixel_format::size(image.format) * 8)); // dwRGBBitCount;
-	bw.write(uint32_t(0x00FF0000)); // dwRBitMask;
-	bw.write(uint32_t(0x0000FF00)); // dwGBitMask;
-	bw.write(uint32_t(0x000000FF)); // dwBBitMask;
-	bw.write(uint32_t(0xFF000000)); // dwABitMask;
-
-	bw.write(DDSCAPS_TEXTURE
-		| (image.num_mips > 1 ? DDSCAPS_COMPLEX : DDSD_UNUSED) // also for cubemap, depth mipmap
-		| (image.num_mips > 1 ? DDSCAPS_MIPMAP : DDSD_UNUSED)); // dwCaps;
-	bw.write(DDSD_UNUSED); // dwCaps2;
-	bw.write(DDSD_UNUSED); // dwCaps3;
-	bw.write(DDSD_UNUSED); // dwCaps4;
-	bw.write(DDSD_UNUSED); // dwReserved2;
-
-	// Image data
-	for (uint32_t i = 0; i < image.num_mips; i++)
+
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	{
 	{
-		MipData mip;
-		read_mip_image(image, i, mip);
+		File* in_file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*in_file);
+		fs.close(in_file);
 
 
-		// CE_LOGD("Writing mip: (%ux%u) byes = %u", mip.width, mip.height, mip.size);
-		bw.write(mip.data, mip.size);
-	}
-}
+		// Read source file
+		JSONElement root = json.root();
+		DynamicString name;
+		root.key("source").to_string(name);
 
 
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	File* in_file = fs.open(resource_path, FOM_READ);
-	JSONParser json(*in_file);
-	fs.close(in_file);
+		File* source = fs.open(name.c_str(), FOM_READ);
+		BinaryReader br(*source);
+		ImageData image;
 
 
-	// Read source file
-	JSONElement root = json.root();
-	DynamicString name;
-	root.key("source").to_string(name);
+		if (name.ends_with(".tga"))
+		{
+			parse_tga(br, image);
+		}
+		else if (name.ends_with(".dds"))
+		{
+			// parse_dds(br, image);
+			// size_t size = source->size();
+			// image.data = (char*) default_allocator().allocate(size);
+			// source->seek(0);
+			// source->read(image.data, size);
+			// image.data += DDS_DATA_OFFSET;
+
+			// BinaryWriter bw(*out_file);
+			// write_dds(bw, image);
+		}
+		else
+		{
+			CE_FATAL("Source image not supported");
+		}
 
 
-	File* source = fs.open(name.c_str(), FOM_READ);
-	BinaryReader br(*source);
-	ImageData image;
+		fs.close(source);
 
 
-	if (name.ends_with(".tga"))
-	{
-		parse_tga(br, image);
+		BinaryWriter bw(*out_file);
+		// Write DDS
+		bw.write(uint32_t(1)); // Version
+		bw.write(uint32_t(0)); // Size
+		write_dds(bw, image);
+
+		default_allocator().deallocate(image.data);
 	}
 	}
-	else if (name.ends_with(".dds"))
+
+	//-----------------------------------------------------------------------------
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
 	{
 	{
-		// parse_dds(br, image);
-		// size_t size = source->size();
-		// image.data = (char*) default_allocator().allocate(size);
-		// source->seek(0);
-		// source->read(image.data, size);
-		// image.data += DDS_DATA_OFFSET;
-
-		// BinaryWriter bw(*out_file);
-		// write_dds(bw, image);
+		File* file = bundle.open(id);
+		const size_t file_size = file->size();
+		file->skip(sizeof(TextureHeader));
+		const bgfx::Memory* mem = bgfx::alloc(file_size);
+		file->read(mem->data, file_size - sizeof(TextureHeader));
+		bundle.close(file);
+
+		TextureImage* teximg = (TextureImage*) default_allocator().allocate(sizeof(TextureImage));
+		teximg->mem = mem;
+		teximg->handle.idx = bgfx::invalidHandle;
+
+		return teximg;
 	}
 	}
-	else
+
+	//-----------------------------------------------------------------------------
+	void online(StringId64 id, ResourceManager& rm)
 	{
 	{
-		CE_FATAL("Source image not supported");
-	}
+		ResourceId res_id;
+		res_id.type = TEXTURE_TYPE;
+		res_id.name = id;
 
 
-	fs.close(source);
+		TextureImage* teximg = (TextureImage*) rm.get(res_id);
+		teximg->handle = bgfx::createTexture(teximg->mem);
+	}
 
 
-	BinaryWriter bw(*out_file);
-	// Write DDS
-	bw.write(uint32_t(1)); // Version
-	bw.write(uint32_t(0)); // Size
-	write_dds(bw, image);
+	void offline(StringId64 id, ResourceManager& rm)
+	{
+		ResourceId res_id;
+		res_id.type = TEXTURE_TYPE;
+		res_id.name = id;
 
 
-	default_allocator().deallocate(image.data);
-}
+		TextureImage* teximg = (TextureImage*) rm.get(res_id);
+		bgfx::destroyTexture(teximg->handle);
+	}
+	
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& a, void* resource)
+	{
+		a.deallocate(resource);
+	}
 
 
 } // namespace texture_resource
 } // namespace texture_resource
 } // namespace crown
 } // namespace crown

+ 12 - 44
engine/resource/texture_resource.h

@@ -52,54 +52,22 @@ struct TextureImage
 
 
 struct TextureResource
 struct TextureResource
 {
 {
-	//-----------------------------------------------------------------------------
-	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
-	{
-		File* file = bundle.open(id);
-		const size_t file_size = file->size();
-		file->skip(sizeof(TextureHeader));
-		const bgfx::Memory* mem = bgfx::alloc(file_size);
-		file->read(mem->data, file_size - sizeof(TextureHeader));
-		bundle.close(file);
-
-		TextureImage* teximg = (TextureImage*) default_allocator().allocate(sizeof(TextureImage));
-		teximg->mem = mem;
-		teximg->handle.idx = bgfx::invalidHandle;
-
-		return teximg;
-	}
-
-	//-----------------------------------------------------------------------------
-	static void online(StringId64 id, ResourceManager& rm)
-	{
-		ResourceId res_id;
-		res_id.type = TEXTURE_TYPE;
-		res_id.name = id;
-
-		TextureImage* teximg = (TextureImage*) rm.get(res_id);
-		teximg->handle = bgfx::createTexture(teximg->mem);
-	}
-
-	static void offline(StringId64 id, ResourceManager& rm)
-	{
-		ResourceId res_id;
-		res_id.type = TEXTURE_TYPE;
-		res_id.name = id;
-
-		TextureImage* teximg = (TextureImage*) rm.get(res_id);
-		bgfx::destroyTexture(teximg->handle);
-	}
-	
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& a, void* resource)
-	{
-		a.deallocate(resource);
-	}
-
 private:
 private:
 
 
 	// Disable construction
 	// Disable construction
 	TextureResource();
 	TextureResource();
 };
 };
 
 
+namespace texture_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void offline(StringId64 id, ResourceManager& rm);
+	void online(StringId64 id, ResourceManager& rm);
+	void unload(Allocator& a, void* resource);
+} // namespace texture_resource
 } // namespace crown
 } // namespace crown

+ 329 - 301
engine/resource/unit_resource.cpp

@@ -45,382 +45,410 @@ namespace crown
 {
 {
 namespace unit_resource
 namespace unit_resource
 {
 {
+	static ProjectionType::Enum projection_name_to_enum(const char* name)
+	{
+		if (string::strcmp(name, "perspective") == 0) return ProjectionType::PERSPECTIVE;
+		else if (string::strcmp(name, "orthographic") == 0) return ProjectionType::ORTHOGRAPHIC;
 
 
-static ProjectionType::Enum projection_name_to_enum(const char* name)
-{
-	if (string::strcmp(name, "perspective") == 0) return ProjectionType::PERSPECTIVE;
-	else if (string::strcmp(name, "orthographic") == 0) return ProjectionType::ORTHOGRAPHIC;
-
-	CE_FATAL("Unknown projection type");
-	return (ProjectionType::Enum) 0;
-}
-
-const StringId32 NO_PARENT = 0xFFFFFFFF;
+		CE_FATAL("Unknown projection type");
+		return (ProjectionType::Enum) 0;
+	}
 
 
-struct GraphNode
-{
-	StringId32 name;
-	StringId32 parent;
-	Vector3 position;
-	Quaternion rotation;
-};
+	const StringId32 NO_PARENT = 0xFFFFFFFF;
 
 
-struct GraphNodeDepth
-{
-	StringId32 name;
-	uint32_t index;
-	uint32_t depth;
+	struct GraphNode
+	{
+		StringId32 name;
+		StringId32 parent;
+		Vector3 position;
+		Quaternion rotation;
+	};
 
 
-	bool operator()(const GraphNodeDepth& a, const GraphNodeDepth& b)
+	struct GraphNodeDepth
 	{
 	{
-		return a.depth < b.depth;
-	}
-};
+		StringId32 name;
+		uint32_t index;
+		uint32_t depth;
 
 
-//-----------------------------------------------------------------------------
-uint32_t compute_link_depth(const GraphNode& node, const Array<GraphNode>& nodes)
-{
-	if (node.parent == NO_PARENT) return 0;
-	else
+		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)
 	{
 	{
-		for (uint32_t i = 0; i < array::size(nodes); i++)
+		if (node.parent == NO_PARENT) return 0;
+		else
 		{
 		{
-			if (nodes[i].name == node.parent)
+			for (uint32_t i = 0; i < array::size(nodes); i++)
 			{
 			{
-				return 1 + compute_link_depth(nodes[i], nodes);
+				if (nodes[i].name == node.parent)
+				{
+					return 1 + compute_link_depth(nodes[i], nodes);
+				}
 			}
 			}
 		}
 		}
-	}
 
 
-	CE_FATAL("Node not found");
-	return 0;
-}
+		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++)
+	//-----------------------------------------------------------------------------
+	uint32_t find_node_index(StringId32 name, const Array<GraphNodeDepth>& node_depths)
 	{
 	{
-		if (node_depths[i].name == name)
+		for (uint32_t i = 0; i < array::size(node_depths); i++)
 		{
 		{
-			return 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;
+		CE_FATAL("Node not found");
+		return 0;
+	}
 
 
-	if (parent_name == NO_PARENT) return -1;
-	for (uint32_t i = 0; i < array::size(node_depths); i++)
+	//-----------------------------------------------------------------------------
+	int32_t find_node_parent_index(uint32_t node, const Array<GraphNode>& nodes, const Array<GraphNodeDepth>& node_depths)
 	{
 	{
-		if (parent_name == node_depths[i].name)
+		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++)
 		{
 		{
-			return 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);
+		CE_FATAL("Node not found");
+		return 0;
+	}
 
 
-	for (uint32_t k = 0; k < vector::size(keys); k++)
+	//-----------------------------------------------------------------------------
+	void parse_nodes(JSONElement e, Array<GraphNode>& nodes, Array<GraphNodeDepth>& node_depths)
 	{
 	{
-		const char* node_name = keys[k].c_str();
-		JSONElement node = e.key(node_name);
+		Vector<DynamicString> keys(default_allocator());
+		e.to_keys(keys);
 
 
-		GraphNode gn;
-		gn.name = string::murmur2_32(node_name, string::strlen(node_name));
-		gn.parent = NO_PARENT;
-
-		if (!node.key("parent").is_nil())
+		for (uint32_t k = 0; k < vector::size(keys); k++)
 		{
 		{
-			DynamicString parent_name;
-			node.key("parent").to_string(parent_name);
-			gn.parent = string::murmur2_32(parent_name.c_str(), parent_name.length(), 0);
-		}
+			const char* node_name = keys[k].c_str();
+			JSONElement node = e.key(node_name);
 
 
-		JSONElement pos = node.key("position");
-		JSONElement rot = node.key("rotation");
-		gn.position = Vector3(pos[0].to_float(), pos[1].to_float(), pos[2].to_float());
-		gn.rotation = Quaternion(Vector3(rot[0].to_float(), rot[1].to_float(), rot[2].to_float()), rot[3].to_float());
+			GraphNode gn;
+			gn.name = string::murmur2_32(node_name, string::strlen(node_name));
+			gn.parent = NO_PARENT;
 
 
-		GraphNodeDepth gnd;
-		gnd.name = gn.name;
-		gnd.index = array::size(nodes);
-		gnd.depth = 0;
+			if (!node.key("parent").is_nil())
+			{
+				DynamicString parent_name;
+				node.key("parent").to_string(parent_name);
+				gn.parent = string::murmur2_32(parent_name.c_str(), parent_name.length(), 0);
+			}
 
 
-		array::push_back(nodes, gn);
-		array::push_back(node_depths, gnd);
-	}
-}
+			JSONElement pos = node.key("position");
+			JSONElement rot = node.key("rotation");
+			gn.position = Vector3(pos[0].to_float(), pos[1].to_float(), pos[2].to_float());
+			gn.rotation = Quaternion(Vector3(rot[0].to_float(), rot[1].to_float(), rot[2].to_float()), rot[3].to_float());
 
 
-//-----------------------------------------------------------------------------
-void parse_cameras(JSONElement e, Array<UnitCamera>& cameras, const Array<GraphNodeDepth>& node_depths)
-{
-	Vector<DynamicString> keys(default_allocator());
-	e.to_keys(keys);
+			GraphNodeDepth gnd;
+			gnd.name = gn.name;
+			gnd.index = array::size(nodes);
+			gnd.depth = 0;
 
 
-	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");
-		JSONElement fov = camera.key_or_nil("fov");
-		JSONElement near = camera.key_or_nil("near_clip_distance");
-		JSONElement far = camera.key_or_nil("far_clip_distance");
-
-		DynamicString node_name;
-		node.to_string(node_name);
-		DynamicString camera_type;
-		type.to_string(camera_type);
-
-		StringId32 node_name_hash = string::murmur2_32(node_name.c_str(), node_name.length());
-
-		UnitCamera cn;
-		cn.name = string::murmur2_32(camera_name, string::strlen(camera_name));
-		cn.node = find_node_index(node_name_hash, node_depths);
-		cn.type = projection_name_to_enum(camera_type.c_str());
-		cn.fov = fov.is_nil() ? 16.0f / 9.0f : fov.to_float();
-		cn.near = near.is_nil() ? 0.01f : near.to_float();
-		cn.far = far.is_nil() ? 1000 : far.to_float();
-
-		array::push_back(cameras, cn);
+			array::push_back(nodes, gn);
+			array::push_back(node_depths, gnd);
+		}
 	}
 	}
-}
-
-//-----------------------------------------------------------------------------
-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++)
+	//-----------------------------------------------------------------------------
+	void parse_cameras(JSONElement e, Array<UnitCamera>& cameras, const Array<GraphNodeDepth>& node_depths)
 	{
 	{
-		const char* renderable_name = keys[k].c_str();
-		JSONElement renderable = e.key(renderable_name);
-
-		DynamicString node_name; renderable.key("node").to_string(node_name);
-		StringId32 node_name_hash = string::murmur2_32(node_name.c_str(), node_name.length(), 0);
-
-		UnitRenderable rn;
-		rn.name = string::murmur2_32(renderable_name, string::strlen(renderable_name), 0);
-		rn.node = find_node_index(node_name_hash, node_depths);
-		rn.visible = renderable.key("visible").to_bool();
+		Vector<DynamicString> keys(default_allocator());
+		e.to_keys(keys);
 
 
-		DynamicString res_type;
-		renderable.key("type").to_string(res_type);
-
-		if (res_type == "mesh")
-		{
-			rn.type = UnitRenderable::MESH;
-			rn.resource = renderable.key("resource").to_resource_id("mesh");
-		}
-		else if (res_type == "sprite")
+		for (uint32_t k = 0; k < vector::size(keys); k++)
 		{
 		{
-			rn.type = UnitRenderable::SPRITE;
-			rn.resource = renderable.key("resource").to_resource_id("sprite");
+			const char* camera_name = keys[k].c_str();
+			JSONElement camera = e.key(camera_name);
+			JSONElement node = camera.key("node");
+			JSONElement type = camera.key("type");
+			JSONElement fov = camera.key_or_nil("fov");
+			JSONElement near = camera.key_or_nil("near_clip_distance");
+			JSONElement far = camera.key_or_nil("far_clip_distance");
+
+			DynamicString node_name;
+			node.to_string(node_name);
+			DynamicString camera_type;
+			type.to_string(camera_type);
+
+			StringId32 node_name_hash = string::murmur2_32(node_name.c_str(), node_name.length());
+
+			UnitCamera cn;
+			cn.name = string::murmur2_32(camera_name, string::strlen(camera_name));
+			cn.node = find_node_index(node_name_hash, node_depths);
+			cn.type = projection_name_to_enum(camera_type.c_str());
+			cn.fov = fov.is_nil() ? 16.0f / 9.0f : fov.to_float();
+			cn.near = near.is_nil() ? 0.01f : near.to_float();
+			cn.far = far.is_nil() ? 1000 : far.to_float();
+
+			array::push_back(cameras, cn);
 		}
 		}
-		else
-		{
-			CE_ASSERT(false, "Oops, unknown renderable type: '%s'", res_type.c_str());
-		}
-
-		array::push_back(renderables, rn);
 	}
 	}
-}
-
-//-----------------------------------------------------------------------------
-void parse_keys(JSONElement e, Array<Key>& generic_keys, Array<char>& values)
-{
-	Vector<DynamicString> keys(default_allocator());
-	e.to_keys(keys);
 
 
-	for (uint32_t k = 0; k < vector::size(keys); k++)
+	//-----------------------------------------------------------------------------
+	void parse_renderables(JSONElement e, Array<UnitRenderable>& renderables, const Array<GraphNodeDepth>& node_depths)
 	{
 	{
-		const char* key = keys[k].c_str();
-		JSONElement value = e.key(key);
+		Vector<DynamicString> keys(default_allocator());
+		e.to_keys(keys);
 
 
-		Key out_key;
-		out_key.name = string::murmur2_32(key, string::strlen(key));
-		out_key.offset = array::size(values);
+		for (uint32_t k = 0; k < vector::size(keys); k++)
+		{
+			const char* renderable_name = keys[k].c_str();
+			JSONElement renderable = e.key(renderable_name);
 
 
-		if (value.is_bool()) out_key.type = ValueType::BOOL;
-		else if (value.is_number()) out_key.type = ValueType::FLOAT;
-		else if (value.is_string()) out_key.type = ValueType::STRING;
-		else if (value.is_array() && value.size() == 3) out_key.type = ValueType::VECTOR3;
-		else CE_FATAL("Value type not supported");
+			DynamicString node_name; renderable.key("node").to_string(node_name);
+			StringId32 node_name_hash = string::murmur2_32(node_name.c_str(), node_name.length(), 0);
 
 
-		array::push_back(generic_keys, out_key);
+			UnitRenderable rn;
+			rn.name = string::murmur2_32(renderable_name, string::strlen(renderable_name), 0);
+			rn.node = find_node_index(node_name_hash, node_depths);
+			rn.visible = renderable.key("visible").to_bool();
 
 
-		switch (out_key.type)
-		{
-			case ValueType::BOOL:
-			{
-				uint32_t val = value.to_bool();
-				array::push(values, (char*) &val, sizeof(uint32_t));
-				break;
-			}
-			case ValueType::FLOAT:
+			DynamicString res_type;
+			renderable.key("type").to_string(res_type);
+
+			if (res_type == "mesh")
 			{
 			{
-				float val = value.to_float();
-				array::push(values, (char*) &val, sizeof(float));
-				break;
+				rn.type = UnitRenderable::MESH;
+				rn.resource = renderable.key("resource").to_resource_id("mesh");
 			}
 			}
-			case ValueType::STRING:
+			else if (res_type == "sprite")
 			{
 			{
-				DynamicString val;
-				value.to_string(val);
-				StringId32 val_hash = string::murmur2_32(val.c_str(), val.length());
-				array::push(values, (char*) &val_hash, sizeof(StringId32));
-				break;
+				rn.type = UnitRenderable::SPRITE;
+				rn.resource = renderable.key("resource").to_resource_id("sprite");
 			}
 			}
-			case ValueType::VECTOR3:
+			else
 			{
 			{
-				float val[3];
-				val[0] = value[0].to_float();
-				val[1] = value[1].to_float();
-				val[2] = value[2].to_float();
-				array::push(values, (char*) val, sizeof(float) * 3);
-				break;
+				CE_ASSERT(false, "Oops, unknown renderable type: '%s'", res_type.c_str());
 			}
 			}
-			default:
+
+			array::push_back(renderables, rn);
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void parse_keys(JSONElement e, Array<Key>& generic_keys, Array<char>& values)
+	{
+		Vector<DynamicString> keys(default_allocator());
+		e.to_keys(keys);
+
+		for (uint32_t k = 0; k < vector::size(keys); k++)
+		{
+			const char* key = keys[k].c_str();
+			JSONElement value = e.key(key);
+
+			Key out_key;
+			out_key.name = string::murmur2_32(key, string::strlen(key));
+			out_key.offset = array::size(values);
+
+			if (value.is_bool()) out_key.type = ValueType::BOOL;
+			else if (value.is_number()) out_key.type = ValueType::FLOAT;
+			else if (value.is_string()) out_key.type = ValueType::STRING;
+			else if (value.is_array() && value.size() == 3) out_key.type = ValueType::VECTOR3;
+			else CE_FATAL("Value type not supported");
+
+			array::push_back(generic_keys, out_key);
+
+			switch (out_key.type)
 			{
 			{
-				CE_FATAL("Oops, you should not be here");
-				return;
+				case ValueType::BOOL:
+				{
+					uint32_t val = value.to_bool();
+					array::push(values, (char*) &val, sizeof(uint32_t));
+					break;
+				}
+				case ValueType::FLOAT:
+				{
+					float val = value.to_float();
+					array::push(values, (char*) &val, sizeof(float));
+					break;
+				}
+				case ValueType::STRING:
+				{
+					DynamicString val;
+					value.to_string(val);
+					StringId32 val_hash = string::murmur2_32(val.c_str(), val.length());
+					array::push(values, (char*) &val_hash, sizeof(StringId32));
+					break;
+				}
+				case ValueType::VECTOR3:
+				{
+					float val[3];
+					val[0] = value[0].to_float();
+					val[1] = value[1].to_float();
+					val[2] = value[2].to_float();
+					array::push(values, (char*) val, sizeof(float) * 3);
+					break;
+				}
+				default:
+				{
+					CE_FATAL("Oops, you should not be here");
+					return;
+				}
 			}
 			}
 		}
 		}
 	}
 	}
-}
 
 
-void parse_materials(JSONElement e, Array<UnitMaterial>& materials)
-{
-	for (uint32_t i = 0; i < e.size(); i++)
+	void parse_materials(JSONElement e, Array<UnitMaterial>& materials)
 	{
 	{
-		ResourceId mat_id = e[i].to_resource_id("material");
-		UnitMaterial um;
-		um.id = mat_id.name;
-		array::push_back(materials, um);
+		for (uint32_t i = 0; i < e.size(); i++)
+		{
+			ResourceId mat_id = e[i].to_resource_id("material");
+			UnitMaterial um;
+			um.id = mat_id.name;
+			array::push_back(materials, um);
+		}
 	}
 	}
-}
 
 
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	File* file = fs.open(resource_path, FOM_READ);
-	JSONParser json(*file);
-	fs.close(file);
+	//-----------------------------------------------------------------------------
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
+	{
+		File* file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*file);
+		fs.close(file);
 
 
-	JSONElement root = json.root();
+		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<Key>				m_keys(default_allocator());
-	Array<char>				m_values(default_allocator());
-	Array<UnitMaterial>		m_materials(default_allocator());
+		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<Key>				m_keys(default_allocator());
+		Array<char>				m_values(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);
+		// 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);
-	}
+		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());
+		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("keys")) parse_keys(root.key("keys"), m_keys, m_values);
-	if (root.has_key("materials")) parse_materials(root.key("materials"), m_materials);
+		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("keys")) parse_keys(root.key("keys"), m_keys, m_values);
+		if (root.has_key("materials")) parse_materials(root.key("materials"), m_materials);
+
+		// Check if the unit has a .physics resource
+		DynamicString unit_name(resource_path);
+		unit_name.strip_trailing(".unit");
+		DynamicString physics_name = unit_name;
+		physics_name += ".physics";
+		if (fs.exists(physics_name.c_str()))
+		{
+			m_physics_resource = ResourceId("physics", unit_name.c_str());
+		}
+		else
+		{
+			m_physics_resource = ResourceId();
+		}
 
 
-	// Check if the unit has a .physics resource
-	DynamicString unit_name(resource_path);
-	unit_name.strip_trailing(".unit");
-	DynamicString physics_name = unit_name;
-	physics_name += ".physics";
-	if (fs.exists(physics_name.c_str()))
+		ResourceId sprite_anim;
+		sprite_anim.type = 0;
+		sprite_anim.name = 0;
+		if (root.has_key("sprite_animation"))
+			sprite_anim = root.key("sprite_animation").to_resource_id("sprite_animation");
+
+		UnitHeader h;
+		h.physics_resource = m_physics_resource;
+		h.sprite_animation = sprite_anim.name;
+		h.num_renderables = array::size(m_renderables);
+		h.num_materials = array::size(m_materials);
+		h.num_cameras = array::size(m_cameras);
+		h.num_scene_graph_nodes = array::size(m_nodes);
+		h.num_keys = array::size(m_keys);
+		h.values_size = array::size(m_values);
+
+		uint32_t offt = sizeof(UnitHeader);
+		h.renderables_offset         = offt; offt += sizeof(UnitRenderable) * h.num_renderables;
+		h.materials_offset           = offt; offt += sizeof(UnitMaterial) * h.num_materials;
+		h.cameras_offset             = offt; offt += sizeof(UnitCamera) * h.num_cameras;
+		h.scene_graph_nodes_offset   = offt; offt += sizeof(UnitNode) * h.num_scene_graph_nodes;
+		h.keys_offset                = offt; offt += sizeof(Key) * h.num_keys;
+		h.values_offset              = offt;
+
+		// Write header
+		out_file->write((char*) &h, sizeof(UnitHeader));
+
+		// Write renderables
+		if (array::size(m_renderables))
+			out_file->write((char*) array::begin(m_renderables), sizeof(UnitRenderable) * h.num_renderables);
+
+		// Write materials
+		if (array::size(m_materials))
+			out_file->write((char*) array::begin(m_materials), sizeof(UnitMaterial) * h.num_materials);
+
+		// Write cameras
+		if (array::size(m_cameras))
+			out_file->write((char*) array::begin(m_cameras), sizeof(UnitCamera) * h.num_cameras);
+
+		// Write node poses
+		for (uint32_t i = 0; i < h.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);
+			out_file->write((char*) &un, sizeof(UnitNode));
+		}
+
+		// Write key/values
+		if (array::size(m_keys))
+		{
+			out_file->write((char*) array::begin(m_keys), sizeof(Key) * h.num_keys);
+			out_file->write((char*) array::begin(m_values), array::size(m_values));
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
 	{
 	{
-		m_physics_resource = ResourceId("physics", unit_name.c_str());
+		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;
 	}
 	}
-	else
+
+	//-----------------------------------------------------------------------------
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
 	{
 	{
-		m_physics_resource = ResourceId();
 	}
 	}
 
 
-	ResourceId sprite_anim;
-	sprite_anim.type = 0;
-	sprite_anim.name = 0;
-	if (root.has_key("sprite_animation"))
-		sprite_anim = root.key("sprite_animation").to_resource_id("sprite_animation");
-
-	UnitHeader h;
-	h.physics_resource = m_physics_resource;
-	h.sprite_animation = sprite_anim.name;
-	h.num_renderables = array::size(m_renderables);
-	h.num_materials = array::size(m_materials);
-	h.num_cameras = array::size(m_cameras);
-	h.num_scene_graph_nodes = array::size(m_nodes);
-	h.num_keys = array::size(m_keys);
-	h.values_size = array::size(m_values);
-
-	uint32_t offt = sizeof(UnitHeader);
-	h.renderables_offset         = offt; offt += sizeof(UnitRenderable) * h.num_renderables;
-	h.materials_offset           = offt; offt += sizeof(UnitMaterial) * h.num_materials;
-	h.cameras_offset             = offt; offt += sizeof(UnitCamera) * h.num_cameras;
-	h.scene_graph_nodes_offset   = offt; offt += sizeof(UnitNode) * h.num_scene_graph_nodes;
-	h.keys_offset                = offt; offt += sizeof(Key) * h.num_keys;
-	h.values_offset              = offt;
-
-	// Write header
-	out_file->write((char*) &h, sizeof(UnitHeader));
-
-	// Write renderables
-	if (array::size(m_renderables))
-		out_file->write((char*) array::begin(m_renderables), sizeof(UnitRenderable) * h.num_renderables);
-
-	// Write materials
-	if (array::size(m_materials))
-		out_file->write((char*) array::begin(m_materials), sizeof(UnitMaterial) * h.num_materials);
-
-	// Write cameras
-	if (array::size(m_cameras))
-		out_file->write((char*) array::begin(m_cameras), sizeof(UnitCamera) * h.num_cameras);
-
-	// Write node poses
-	for (uint32_t i = 0; i < h.num_scene_graph_nodes; i++)
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
 	{
 	{
-		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);
-		out_file->write((char*) &un, sizeof(UnitNode));
 	}
 	}
 
 
-	// Write key/values
-	if (array::size(m_keys))
+	//-----------------------------------------------------------------------------
+	void unload(Allocator& allocator, void* resource)
 	{
 	{
-		out_file->write((char*) array::begin(m_keys), sizeof(Key) * h.num_keys);
-		out_file->write((char*) array::begin(m_values), array::size(m_values));
+		allocator.deallocate(resource);
 	}
 	}
-}
 
 
 } // namespace unit_resource
 } // namespace unit_resource
 } // namespace crown
 } // namespace crown

+ 12 - 29
engine/resource/unit_resource.h

@@ -109,35 +109,6 @@ struct Key
 
 
 struct UnitResource
 struct UnitResource
 {
 {
-	//-----------------------------------------------------------------------------
-	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(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
 	ResourceId sprite_animation() const
 	ResourceId sprite_animation() const
 	{
 	{
 		ResourceId id;
 		ResourceId id;
@@ -275,4 +246,16 @@ private:
 	UnitResource();
 	UnitResource();
 };
 };
 
 
+namespace unit_resource
+{
+	void compile(Filesystem& fs, const char* resource_path, File* out_file);
+	inline void compile(const char* path, CompileOptions& opts)
+	{
+		compile(opts._fs, path, &opts._bw.m_file);
+	}
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/);
+	void unload(Allocator& allocator, void* resource);
+} // namespace unit_resource
 } // namespace crown
 } // namespace crown