Przeglądaj źródła

Implemented scene exporting to a map file
Added methods for component exporting to every SystemScene and some SystemObjects (components)
Added a method to export setup data to every System and SystemScene
Added scene exporting to a map file from ComponentsConstructionInfo in SceneLoader
Added ComponentConstructionInfo container to the SelectedEntity in EditorWindow, to store all data about an entity, instead of manual variable declaration
Added loaded Prefab listing in EditorWindow
Added Metadata, Spatial, ObjectMaterial, Camera, Light, RigidBody, Lua components in inspector in EditorWindow
Added Lua script variable edit in inspector in EditorWindow
Added open and save scene file browser dialogs to EditorWindow
Added rendering pass type identifier to every RenderPass (for exporting)
Added a way to store a looader prefab name for an entity in MetadataComponent
Added data-driven (loaded from a scene file) component pool size reservation in every SystemScene
Added a way to get all loaded rendering passes in RendererFrontend (required for setup data exporting)
Added more change handling in Camera, GuiSequence, Light, Lua, ObjectMaterial, RigidBody, SoundListener components
Added explicit definitions of transform matrices with and without scale during changes in Graphics, Physics and World scenes and their components
Added a way to check if a loaded texture is default (placeholder given when a texture file cannot be found or loaded) in TextureLoader
Added more Config variables
Added more errors and error strings
Added dependency of imgui_stdlib containing wrappers for C++ STL types for InputText (std::string instead of char*)
Fixed a bug in SpatialManager of scale being applied during the calculation of world transform matrix
Fixed play/pause/restart buttons not being centered in EditorWindow
Fixed a bool value exporting to string returning 0/1 instead of false/true in PropertySet

Paul A 2 lat temu
rodzic
commit
e6ca8e1f76
76 zmienionych plików z 3344 dodań i 457 usunięć
  1. 85 0
      Dependencies/include/imgui/imgui_stdlib.cpp
  2. 21 0
      Dependencies/include/imgui/imgui_stdlib.h
  3. 42 40
      Praxis3D/Data/error-strings-eng.data
  4. 3 0
      Praxis3D/Praxis3D.vcxproj
  5. 9 0
      Praxis3D/Praxis3D.vcxproj.filters
  6. 1 1
      Praxis3D/Source/AtmScatteringPass.h
  7. 62 13
      Praxis3D/Source/AudioScene.cpp
  8. 27 0
      Praxis3D/Source/AudioScene.h
  9. 1 1
      Praxis3D/Source/BloomCompositePass.h
  10. 1 1
      Praxis3D/Source/BloomPass.h
  11. 1 1
      Praxis3D/Source/BlurPass.h
  12. 10 3
      Praxis3D/Source/CameraComponent.h
  13. 1 1
      Praxis3D/Source/ChangeController.cpp
  14. 9 1
      Praxis3D/Source/CollisionShapeComponent.h
  15. 2 0
      Praxis3D/Source/ComponentConstructorInfo.h
  16. 9 2
      Praxis3D/Source/Config.cpp
  17. 60 14
      Praxis3D/Source/Config.h
  18. 5 5
      Praxis3D/Source/Containers.h
  19. 851 86
      Praxis3D/Source/EditorWindow.cpp
  20. 338 12
      Praxis3D/Source/EditorWindow.h
  21. 2 0
      Praxis3D/Source/ErrorCodes.h
  22. 1 0
      Praxis3D/Source/ErrorHandler.cpp
  23. 6 0
      Praxis3D/Source/Filesystem.h
  24. 1 1
      Praxis3D/Source/FinalPass.h
  25. 1 1
      Praxis3D/Source/GUIPass.h
  26. 42 17
      Praxis3D/Source/GUIScene.cpp
  27. 25 4
      Praxis3D/Source/GUIScene.h
  28. 5 0
      Praxis3D/Source/GUISequenceComponent.h
  29. 3 3
      Praxis3D/Source/GeometryPass.h
  30. 1 1
      Praxis3D/Source/GraphicsObject.h
  31. 1 1
      Praxis3D/Source/HdrMappingPass.h
  32. 1 1
      Praxis3D/Source/LenseFlareCompositePass.h
  33. 1 1
      Praxis3D/Source/LenseFlarePass.h
  34. 68 33
      Praxis3D/Source/LightComponent.h
  35. 1 1
      Praxis3D/Source/LightingPass.h
  36. 29 1
      Praxis3D/Source/LuaComponent.h
  37. 8 0
      Praxis3D/Source/LuaScript.cpp
  38. 11 0
      Praxis3D/Source/LuaScript.h
  39. 1 1
      Praxis3D/Source/LuminancePass.h
  40. 7 4
      Praxis3D/Source/Math.h
  41. 10 2
      Praxis3D/Source/MetadataComponent.h
  42. 49 1
      Praxis3D/Source/ModelComponent.h
  43. 3 1
      Praxis3D/Source/NullObjects.cpp
  44. 1 1
      Praxis3D/Source/NullSystemObjects.cpp
  45. 9 0
      Praxis3D/Source/ObjectMaterialComponent.h
  46. 7 0
      Praxis3D/Source/ObserverBase.h
  47. 52 10
      Praxis3D/Source/PhysicsScene.cpp
  48. 38 0
      Praxis3D/Source/PhysicsScene.h
  49. 1 1
      Praxis3D/Source/PostProcessPass.h
  50. 5 1
      Praxis3D/Source/PropertySet.h
  51. 1 1
      Praxis3D/Source/ReflectionPass.h
  52. 3 1
      Praxis3D/Source/RenderPassBase.h
  53. 15 0
      Praxis3D/Source/RendererFrontend.cpp
  54. 2 0
      Praxis3D/Source/RendererFrontend.h
  55. 84 9
      Praxis3D/Source/RendererScene.cpp
  56. 54 0
      Praxis3D/Source/RendererScene.h
  57. 43 0
      Praxis3D/Source/RendererSystem.cpp
  58. 2 0
      Praxis3D/Source/RendererSystem.h
  59. 156 0
      Praxis3D/Source/RigidBodyComponent.cpp
  60. 47 54
      Praxis3D/Source/RigidBodyComponent.h
  61. 505 28
      Praxis3D/Source/SceneLoader.cpp
  62. 19 0
      Praxis3D/Source/SceneLoader.h
  63. 1 1
      Praxis3D/Source/ScriptObject.h
  64. 40 16
      Praxis3D/Source/ScriptScene.cpp
  65. 19 1
      Praxis3D/Source/ScriptScene.h
  66. 1 1
      Praxis3D/Source/SkyPass.h
  67. 3 1
      Praxis3D/Source/SoundListenerComponent.h
  68. 87 34
      Praxis3D/Source/SpatialDataManager.h
  69. 2 2
      Praxis3D/Source/System.cpp
  70. 12 7
      Praxis3D/Source/System.h
  71. 8 0
      Praxis3D/Source/TextureLoader.h
  72. 2 2
      Praxis3D/Source/Universal.cpp
  73. 1 1
      Praxis3D/Source/Universal.h
  74. 84 17
      Praxis3D/Source/WorldScene.cpp
  75. 38 0
      Praxis3D/Source/WorldScene.h
  76. 187 13
      Praxis3D/imgui.ini

+ 85 - 0
Dependencies/include/imgui/imgui_stdlib.cpp

@@ -0,0 +1,85 @@
+// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
+// This is also an example of how you may wrap your own similar types.
+
+// Changelog:
+// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
+
+// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
+//   https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
+
+#include "imgui.h"
+#include "imgui_stdlib.h"
+
+// Clang warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wsign-conversion"    // warning: implicit conversion changes signedness
+#endif
+
+struct InputTextCallback_UserData
+{
+    std::string*            Str;
+    ImGuiInputTextCallback  ChainCallback;
+    void*                   ChainCallbackUserData;
+};
+
+static int InputTextCallback(ImGuiInputTextCallbackData* data)
+{
+    InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData;
+    if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
+    {
+        // Resize string callback
+        // If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want.
+        std::string* str = user_data->Str;
+        IM_ASSERT(data->Buf == str->c_str());
+        str->resize(data->BufTextLen);
+        data->Buf = (char*)str->c_str();
+    }
+    else if (user_data->ChainCallback)
+    {
+        // Forward to user callback, if any
+        data->UserData = user_data->ChainCallbackUserData;
+        return user_data->ChainCallback(data);
+    }
+    return 0;
+}
+
+bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
+{
+    IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
+    flags |= ImGuiInputTextFlags_CallbackResize;
+
+    InputTextCallback_UserData cb_user_data;
+    cb_user_data.Str = str;
+    cb_user_data.ChainCallback = callback;
+    cb_user_data.ChainCallbackUserData = user_data;
+    return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
+}
+
+bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
+{
+    IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
+    flags |= ImGuiInputTextFlags_CallbackResize;
+
+    InputTextCallback_UserData cb_user_data;
+    cb_user_data.Str = str;
+    cb_user_data.ChainCallback = callback;
+    cb_user_data.ChainCallbackUserData = user_data;
+    return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data);
+}
+
+bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
+{
+    IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
+    flags |= ImGuiInputTextFlags_CallbackResize;
+
+    InputTextCallback_UserData cb_user_data;
+    cb_user_data.Str = str;
+    cb_user_data.ChainCallback = callback;
+    cb_user_data.ChainCallbackUserData = user_data;
+    return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif

+ 21 - 0
Dependencies/include/imgui/imgui_stdlib.h

@@ -0,0 +1,21 @@
+// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
+// This is also an example of how you may wrap your own similar types.
+
+// Changelog:
+// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
+
+// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
+//   https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
+
+#pragma once
+
+#include <string>
+
+namespace ImGui
+{
+    // ImGui::InputText() with std::string
+    // Because text input needs dynamic resizing, we need to setup a callback to grow the capacity
+    IMGUI_API bool  InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
+    IMGUI_API bool  InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
+    IMGUI_API bool  InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
+}

+ 42 - 40
Praxis3D/Data/error-strings-eng.data

@@ -1,46 +1,47 @@
 {
 	"Error Codes":
 	{
-		"Undefined"									: "Undefined",
-		"Success"										: "Succeed",
-		"Failure"										: "Failed",
-		"Initialize_success"				: "Has been initialized",
-		"Initialize_failure"				: "Failed to initialized",
-		"File_not_found"						: "File missing",
-		"Filename_empty"						: "Filename is empty",
-		"Audio_no_drivers"					: "System has no sound devices",
-		"Audio_system_init_failed"	: "Audio system has failed to initialize",
-		"Destroy_obj_not_found"			: "Destruction: object not found",
-		"Glew_failed"								: "OpenGL Extension Wrangler Library has failed to initialize",
-		"Ifstream_failed"						: "Unable to read input file stream",
-		"Clock_QueryFrequency"			: "Unable to query the clock frequency",
-		"Framebuffer_failed"				: "Framebuffer has failed to load",
-		"Geometrybuffer_failed"			: "Geometry buffer has failed to load",
-		"GL_context_missing"				: "Failed to get GL context handle",
-		"Window_handle_missing"			: "Failed to get window handle",
-		"AssimpScene_failed"				: "Assimp scene has failed to load",
-		"ObjectPool_full"						: "Object pool overflow",
-		"Collision_invalid"					: "Invalid collision type",
-		"Collision_missing"					: "Collision shape missing",
-		"Kinematic_has_mass"				: "Kinematic object has a mass greater than zero",
-		"Property_missing_size"			: "Missing 'Size' property",
-		"Property_missing_radius"		: "Missing 'Radius' property",
-		"Property_missing_type"			: "Missing 'Type' property",
-		"Property_no_filename"			: "No filename specified",
-		"Shader_attach_failed"			: "Attaching shaders to GPU program has failed",
-		"Shader_compile_failed"			: "Shader compilation from source code has failed to load",
-		"Shader_creation_failed"		: "Shader handle creation has failed",
-		"Shader_link_failed"				: "Shader linking has failed",
-		"Shader_loading_failed"			: "Shader has failed to load",
-		"GameObjects_missing"				: "GameObjects missing from the map file",
-		"Texture_not_found"					: "Texture was not found",
-		"Texture_empty"							: "Texture data was not found",
-		"Invalid_num_vid_displays"	: "Invalid number of video displays",
-		"SDL_video_init_failed"			: "SDL Video has failed to initialize",
-		"SDL_vsync_failed"					: "Failed to change vertical synchronization mode",
-		"Window_creation_failed"		: "Unable to create a window",
-		"Invalid_object_id"					: "Invalid game object ID",
-		"Duplicate_object_id"				: "Duplicate game object ID"
+		"Undefined"												: "Undefined",
+		"Success"													: "Succeed",
+		"Failure"													: "Failed",
+		"Initialize_success"							: "Has been initialized",
+		"Initialize_failure"							: "Failed to initialized",
+		"File_not_found"									: "File missing",
+		"Filename_empty"									: "Filename is empty",
+		"Audio_no_drivers"								: "System has no sound devices",
+		"Audio_system_init_failed"				: "Audio system has failed to initialize",
+		"Destroy_obj_not_found"						: "Destruction: object not found",
+		"Glew_failed"											: "OpenGL Extension Wrangler Library has failed to initialize",
+		"Ifstream_failed"									: "Unable to read input file stream",
+		"Clock_QueryFrequency"						: "Unable to query the clock frequency",
+		"Framebuffer_failed"							: "Framebuffer has failed to load",
+		"Geometrybuffer_failed"						: "Geometry buffer has failed to load",
+		"Editor_path_outside_current_dir"	: "Selected file path is outside of current working directory",
+		"GL_context_missing"							: "Failed to get GL context handle",
+		"Window_handle_missing"						: "Failed to get window handle",
+		"AssimpScene_failed"							: "Assimp scene has failed to load",
+		"ObjectPool_full"									: "Object pool overflow",
+		"Collision_invalid"								: "Invalid collision type",
+		"Collision_missing"								: "Collision shape missing",
+		"Kinematic_has_mass"							: "Kinematic object has a mass greater than zero",
+		"Property_missing_size"						: "Missing 'Size' property",
+		"Property_missing_radius"					: "Missing 'Radius' property",
+		"Property_missing_type"						: "Missing 'Type' property",
+		"Property_no_filename"						: "No filename specified",
+		"Shader_attach_failed"						: "Attaching shaders to GPU program has failed",
+		"Shader_compile_failed"						: "Shader compilation from source code has failed to load",
+		"Shader_creation_failed"					: "Shader handle creation has failed",
+		"Shader_link_failed"							: "Shader linking has failed",
+		"Shader_loading_failed"						: "Shader has failed to load",
+		"GameObjects_missing"							: "GameObjects missing from the map file",
+		"Texture_not_found"								: "Texture was not found",
+		"Texture_empty"										: "Texture data was not found",
+		"Invalid_num_vid_displays"				: "Invalid number of video displays",
+		"SDL_video_init_failed"						: "SDL Video has failed to initialize",
+		"SDL_vsync_failed"								: "Failed to change vertical synchronization mode",
+		"Window_creation_failed"					: "Unable to create a window",
+		"Invalid_object_id"								: "Invalid game object ID",
+		"Duplicate_object_id"							: "Duplicate game object ID"
 	},
 	"Error Sources":
 	{
@@ -65,6 +66,7 @@
 		"Source_GeometryPass"							: "Geometry Rendering Pass",
 		"Source_GraphicsObject"						: "Graphics Object",
 		"Source_GUI"											: "GUI",
+		"Source_GUIEditor"								: "Editor",
 		"Source_GUIObject"								: "GUI Object",
 		"Source_GUIPass"									: "GUI Rendering Pass",
 		"Source_GUISequenceComponent"			: "GUI Sequence Component",

+ 3 - 0
Praxis3D/Praxis3D.vcxproj

@@ -135,6 +135,7 @@
     <ClCompile Include="..\Dependencies\include\imgui\imgui.cpp" />
     <ClCompile Include="..\Dependencies\include\imgui\imgui_demo.cpp" />
     <ClCompile Include="..\Dependencies\include\imgui\imgui_draw.cpp" />
+    <ClCompile Include="..\Dependencies\include\imgui\imgui_stdlib.cpp" />
     <ClCompile Include="..\Dependencies\include\imgui\imgui_tables.cpp" />
     <ClCompile Include="..\Dependencies\include\imgui\imgui_widgets.cpp" />
     <ClCompile Include="..\Dependencies\include\imgui_tex_inspect\imgui_tex_inspect.cpp" />
@@ -189,6 +190,7 @@
     <ClCompile Include="Source\RendererScene.cpp" />
     <ClCompile Include="Source\RendererSystem.cpp" />
     <ClCompile Include="Source\RenderTask.cpp" />
+    <ClCompile Include="Source\RigidBodyComponent.cpp" />
     <ClCompile Include="Source\Scancodes.cpp" />
     <ClCompile Include="Source\SceneLoader.cpp" />
     <ClCompile Include="Source\ScriptScene.cpp" />
@@ -216,6 +218,7 @@
     <ClInclude Include="..\Dependencies\include\imgui\imconfig.h" />
     <ClInclude Include="..\Dependencies\include\imgui\imgui.h" />
     <ClInclude Include="..\Dependencies\include\imgui\imgui_internal.h" />
+    <ClInclude Include="..\Dependencies\include\imgui\imgui_stdlib.h" />
     <ClInclude Include="..\Dependencies\include\imgui_tex_inspect\imgui_tex_inspect.h" />
     <ClInclude Include="..\Dependencies\include\imgui_tex_inspect\imgui_tex_inspect_internal.h" />
     <ClInclude Include="..\Dependencies\include\imgui_tex_inspect\tex_inspect_opengl.h" />

+ 9 - 0
Praxis3D/Praxis3D.vcxproj.filters

@@ -441,6 +441,12 @@
     <ClCompile Include="..\Dependencies\include\ImGuiFileDialog\ImGuiFileDialog.cpp">
       <Filter>3rd Party\ImGuiFileDialog</Filter>
     </ClCompile>
+    <ClCompile Include="Source\RigidBodyComponent.cpp">
+      <Filter>Physics\Components\Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\Dependencies\include\imgui\imgui_stdlib.cpp">
+      <Filter>3rd Party\imgui\Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Source\ErrorCodes.h">
@@ -923,6 +929,9 @@
     <ClInclude Include="..\Dependencies\include\imgui_tex_inspect\tex_inspect_opengl.h">
       <Filter>3rd Party\imgui_tex_inspect\Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\Dependencies\include\imgui\imgui_stdlib.h">
+      <Filter>3rd Party\imgui\Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="Data\config.ini" />

+ 1 - 1
Praxis3D/Source/AtmScatteringPass.h

@@ -8,7 +8,7 @@ class AtmScatteringPass : public RenderPass
 {
 public:
 	AtmScatteringPass(RendererFrontend &p_renderer) :
-		RenderPass(p_renderer),
+		RenderPass(p_renderer, RenderPassType::RenderPassType_AtmScattering),
 		m_useConstantSolarSpectrum(false),
 		m_useOzone(true),
 		m_useCombinedTextures(true),

+ 62 - 13
Praxis3D/Source/AudioScene.cpp

@@ -5,7 +5,7 @@
 #include "TaskManagerLocator.h"
 #include "WorldScene.h"
 
-AudioScene::AudioScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader)
+AudioScene::AudioScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader, Properties::PropertyID::Audio)
 {
 	m_audioTask = nullptr;
 	m_coreSystem = nullptr;
@@ -193,19 +193,12 @@ ErrorCode AudioScene::setup(const PropertySet &p_properties)
 	// Get the world scene required for reserving the component pools
 	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
 
-	// Reserve every component type that belongs to this scene
-	worldScene->reserve<SoundComponent>(Config::objectPoolVar().sound_component_default_pool_size);
-	worldScene->reserve<SoundListenerComponent>(Config::objectPoolVar().camera_component_default_pool_size);
+	// Get the property set containing object pool size
+	auto &objectPoolSizeProperty = p_properties.getPropertySetByID(Properties::ObjectPoolSize);
 
-	for(decltype(p_properties.getNumProperties()) i = 0, size = p_properties.getNumProperties(); i < size; i++)
-	{
-		switch(p_properties[i].getPropertyID())
-		{
-		case Properties::ObjectPoolSize:
-
-			break;
-		}
-	}
+	// Reserve every component type that belongs to this scene (and set the minimum number of objects based on default config)
+	worldScene->reserve<SoundComponent>(std::max(Config::objectPoolVar().sound_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::SoundComponent).getInt()));
+	worldScene->reserve<SoundListenerComponent>(std::max(Config::objectPoolVar().sound_listener_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::SoundListenerComponent).getInt()));
 
 	FMOD::Studio::Bank *defaultSoundBank = nullptr;
 
@@ -232,8 +225,12 @@ ErrorCode AudioScene::setup(const PropertySet &p_properties)
 				FMOD::Studio::Bank *soundBank = nullptr;
 
 				if(fmodErrorLog(m_studioSystem->loadBankFile((Config::filepathVar().sound_path + filename).c_str(), FMOD_STUDIO_LOAD_BANK_NORMAL, &soundBank), filename))
+				{
 					if(fmodErrorLog(soundBank->loadSampleData(), filename))
 						addImpactSoundBank(soundBank);
+
+					m_bankFilenames.push_back(std::make_pair(filename, soundBank));
+				}
 			}
 		}
 	}
@@ -293,6 +290,24 @@ ErrorCode AudioScene::setup(const PropertySet &p_properties)
 	return ErrorCode::Success;
 }
 
+void AudioScene::exportSetup(PropertySet &p_propertySet)
+{
+	// Get the world scene required for getting the pool sizes
+	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
+
+	// Add object pool sizes
+	auto &objectPoolSizePropertySet = p_propertySet.addPropertySet(Properties::ObjectPoolSize);
+	objectPoolSizePropertySet.addProperty(Properties::SoundComponent, (int)worldScene->getPoolSize<SoundComponent>());
+	objectPoolSizePropertySet.addProperty(Properties::SoundListenerComponent, (int)worldScene->getPoolSize<SoundListenerComponent>());
+
+	// Add sound banks
+	auto &banksPropertySet = p_propertySet.addPropertySet(Properties::Banks);
+	for(const auto &filenameAndBank : m_bankFilenames)
+	{
+		banksPropertySet.addPropertySet(Properties::ArrayEntry).addProperty(Properties::Filename, filenameAndBank.first);
+	}
+}
+
 void AudioScene::activate()
 {
 }
@@ -496,6 +511,40 @@ std::vector<SystemObject*> AudioScene::createComponents(const EntityID p_entityI
 	return createComponents(p_entityID, p_constructionInfo.m_audioComponents, p_startLoading);
 }
 
+void AudioScene::exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo)
+{
+	exportComponents(p_entityID, p_constructionInfo.m_audioComponents);
+}
+
+void AudioScene::exportComponents(const EntityID p_entityID, AudioComponentsConstructionInfo &p_constructionInfo)
+{
+	// Get the world scene required for getting the entity registry
+	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
+
+	// Get the entity registry 
+	auto &entityRegistry = worldScene->getEntityRegistry();
+
+	// Export SoundComponent
+	auto *soundComponent = entityRegistry.try_get<SoundComponent>(p_entityID);
+	if(soundComponent != nullptr)
+	{
+		if(p_constructionInfo.m_soundConstructionInfo == nullptr)
+			p_constructionInfo.m_soundConstructionInfo = new SoundComponent::SoundComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_soundConstructionInfo, *soundComponent);
+	}
+
+	// Export SoundListenerComponent
+	auto *soundListenerComponent = entityRegistry.try_get<SoundListenerComponent>(p_entityID);
+	if(soundListenerComponent != nullptr)
+	{
+		if(p_constructionInfo.m_soundListenerConstructionInfo == nullptr)
+			p_constructionInfo.m_soundListenerConstructionInfo = new SoundListenerComponent::SoundListenerComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_soundListenerConstructionInfo, *soundListenerComponent);
+	}
+}
+
 SystemObject *AudioScene::createComponent(const EntityID &p_entityID, const SoundComponent::SoundComponentConstructionInfo &p_constructionInfo, const bool p_startLoading)
 {
 	// If valid type was not specified, or object creation failed, return a null object instead

+ 27 - 0
Praxis3D/Source/AudioScene.h

@@ -66,6 +66,8 @@ public:
 
 	ErrorCode setup(const PropertySet &p_properties);
 
+	void exportSetup(PropertySet &p_propertySet);
+
 	void activate();
 
 	void deactivate();
@@ -90,8 +92,32 @@ public:
 		return components;
 	}
 
+	void exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo);
+	void exportComponents(const EntityID p_entityID, AudioComponentsConstructionInfo &p_constructionInfo);
+
 	SystemObject *createComponent(const EntityID &p_entityID, const SoundComponent::SoundComponentConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
 	SystemObject *createComponent(const EntityID &p_entityID, const SoundListenerComponent::SoundListenerComponentConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
+
+	void exportComponent(SoundComponent::SoundComponentConstructionInfo &p_constructionInfo, const SoundComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+
+		p_constructionInfo.m_loop = p_component.m_loop;
+		p_constructionInfo.m_soundFilename = p_component.m_soundFilename;
+		p_constructionInfo.m_soundType = p_component.m_soundType;
+		p_constructionInfo.m_spatialized = p_component.m_spatialized;
+		p_constructionInfo.m_startPlaying = p_component.m_startPlaying;
+		p_constructionInfo.m_volume = p_component.m_volume;
+	}
+	void exportComponent(SoundListenerComponent::SoundListenerComponentConstructionInfo &p_constructionInfo, const SoundListenerComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+
+		p_constructionInfo.m_listenerID = p_component.getListenerID();
+	}
+
 	ErrorCode destroyObject(SystemObject *p_systemObject);
 
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) { }
@@ -187,6 +213,7 @@ private:
 	//std::vector<FMOD::Studio::EventDescription*> m_impactSounds;
 	//std::unordered_map<std::string, std::size_t> m_impactSoundsIndexMap;
 	std::unordered_map<std::string, FMOD::Studio::EventDescription*> m_impactSounds;
+	std::vector<std::pair<std::string, FMOD::Studio::Bank *>> m_bankFilenames;
 
 	float m_dTime;
 };

+ 1 - 1
Praxis3D/Source/BloomCompositePass.h

@@ -7,7 +7,7 @@ class BloomCompositePass : public RenderPass
 {
 public:
 	BloomCompositePass(RendererFrontend &p_renderer) :
-		RenderPass(p_renderer)
+		RenderPass(p_renderer, RenderPassType::RenderPassType_BloomComposite)
 	{
 		m_bloomCompositeShader = nullptr;
 	}

+ 1 - 1
Praxis3D/Source/BloomPass.h

@@ -7,7 +7,7 @@ class BloomPass : public RenderPass
 {
 public:
 	BloomPass(RendererFrontend &p_renderer) :
-		RenderPass(p_renderer),
+		RenderPass(p_renderer, RenderPassType::RenderPassType_Bloom),
 		m_lensDirtTexture(Loaders::texture2D().load(Config::rendererVar().lens_flare_dirt_texture)),
 		m_bloomDownscaleShader(nullptr),
 		m_bloomUpscaleShader(nullptr) { }

+ 1 - 1
Praxis3D/Source/BlurPass.h

@@ -7,7 +7,7 @@ class BlurPass : public RenderPass
 {
 public:
 	BlurPass(RendererFrontend &p_renderer) :
-		RenderPass(p_renderer) { }
+		RenderPass(p_renderer, RenderPassType::RenderPassType_Blur) { }
 
 	~BlurPass() { }
 

+ 10 - 3
Praxis3D/Source/CameraComponent.h

@@ -19,7 +19,7 @@ public:
 
 	CameraComponent(SystemScene *p_systemScene, std::string p_name, const EntityID p_entityID, std::size_t p_id = 0) : SystemObject(p_systemScene, p_name, Properties::PropertyID::CameraComponent, p_entityID)
 	{
-
+		m_fov = Config::graphicsVar().fov;
 	}
 	~CameraComponent() { }
 
@@ -81,8 +81,15 @@ public:
 	BitMask getDesiredSystemChanges() final override { return Systems::Changes::Graphics::Camera; }
 	BitMask getPotentialSystemChanges() final override { return Systems::Changes::None; }
 
-	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) { }
+	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) 
+	{
+		if(CheckBitmask(p_changeType, Systems::Changes::Generic::Active))
+		{
+			// Get the active flag from the subject and set the active flag accordingly
+			setActive(p_subject->getBool(this, Systems::Changes::Generic::Active));
+		}
+	}
 
 private:
-
+	float m_fov;
 };

+ 1 - 1
Praxis3D/Source/ChangeController.cpp

@@ -3,7 +3,7 @@
 #include "ErrorHandlerLocator.h"
 #include "TaskManager.h"
 
-ChangeController::ChangeController() : m_lastID(0), m_tlsNotifyList(TLS_OUT_OF_INDEXES), m_taskManager(nullptr)
+ChangeController::ChangeController() : Observer(Properties::PropertyID::ChangeController), m_lastID(0), m_tlsNotifyList(TLS_OUT_OF_INDEXES), m_taskManager(nullptr)
 {
 	m_systemsToNotify = Systems::Changes::None;
 	m_changesToDistribute = Systems::Changes::None;

+ 9 - 1
Praxis3D/Source/CollisionShapeComponent.h

@@ -15,12 +15,14 @@ public:
 		CollisionShapeType_Cone,
 		CollisionShapeType_ConvexHull,
 		CollisionShapeType_Cylinder,
-		CollisionShapeType_Sphere
+		CollisionShapeType_Sphere,
+		CollisionShapeType_NumOfTypes
 	};
 
 	CollisionShapeComponent(SystemScene *p_systemScene, std::string p_name, std::size_t p_id = 0) : SystemObject(p_systemScene, p_name, Properties::PropertyID::CollisionShapeComponent)
 	{
 		m_collisionShapeType = CollisionShapeType::CollisionShapeType_Null;
+		m_collisionShape.m_boxShape = nullptr;
 	}
 	~CollisionShapeComponent()
 	{
@@ -152,6 +154,12 @@ public:
 	BitMask getDesiredSystemChanges() final override { return Systems::Changes::None; }
 	BitMask getPotentialSystemChanges() final override { return Systems::Changes::None; }
 
+	inline const char **getCollisionTypeText() const
+	{
+		const char *collisionTypeText[] = { "null", "Box", "Capsule", "Cone", "Convex hull", "Cylinder", "Sphere"};
+		return collisionTypeText;
+	}
+
 	const inline CollisionShapeType getCollisionShapeType() const { return m_collisionShapeType; }
 	inline btCollisionShape *getCollisionShape()
 	{

+ 2 - 0
Praxis3D/Source/ComponentConstructorInfo.h

@@ -73,6 +73,8 @@ struct ComponentsConstructionInfo
 	std::string m_name;
 	EntityID m_id;
 	EntityID m_parent;
+
+	std::string m_prefab;
 };
 
 typedef std::vector<ComponentsConstructionInfo> EntitiesConstructionInfo;

+ 9 - 2
Praxis3D/Source/Config.cpp

@@ -184,14 +184,20 @@ void Config::init()
 	AddVariablePredef(m_GUIVar, gui_render);
 	AddVariablePredef(m_GUIVar, gui_dark_style);
 	AddVariablePredef(m_GUIVar, gui_sequence_array_reserve_size);
+	AddVariablePredef(m_GUIVar, editor_float_slider_speed); 
+	AddVariablePredef(m_GUIVar, editor_lua_variables_max_height);
 	AddVariablePredef(m_GUIVar, gui_file_dialog_min_size_x);
 	AddVariablePredef(m_GUIVar, gui_file_dialog_min_size_y);
 	AddVariablePredef(m_GUIVar, gui_file_dialog_dir_color_R);
 	AddVariablePredef(m_GUIVar, gui_file_dialog_dir_color_G);
-	AddVariablePredef(m_GUIVar, gui_file_dialog_dir_color_B);
+	AddVariablePredef(m_GUIVar, gui_file_dialog_dir_color_B); 
+	AddVariablePredef(m_GUIVar, editor_button_add_texture);
+	AddVariablePredef(m_GUIVar, editor_button_delete_entry_texture);
 	AddVariablePredef(m_GUIVar, editor_button_gui_sequence_texture);
+	AddVariablePredef(m_GUIVar, editor_button_open_file_texture);
 	AddVariablePredef(m_GUIVar, editor_button_pause_texture);
 	AddVariablePredef(m_GUIVar, editor_button_play_texture);
+	AddVariablePredef(m_GUIVar, editor_button_reload_texture);
 	AddVariablePredef(m_GUIVar, editor_button_restart_texture);
 	AddVariablePredef(m_GUIVar, editor_button_scripting_enabled_texture);
 	AddVariablePredef(m_GUIVar, gui_editor_window_name);
@@ -257,7 +263,8 @@ void Config::init()
 	AddVariablePredef(m_objPoolVar, shader_component_default_pool_size);
 	AddVariablePredef(m_objPoolVar, spatial_component_default_pool_size);
 	AddVariablePredef(m_objPoolVar, spot_light_pool_size);
-	AddVariablePredef(m_objPoolVar, sound_component_default_pool_size);
+	AddVariablePredef(m_objPoolVar, sound_component_default_pool_size); 
+	AddVariablePredef(m_objPoolVar, sound_listener_component_default_pool_size); 
 
 	// File-path variables
 	AddVariablePredef(m_filepathVar, config_path);

+ 60 - 14
Praxis3D/Source/Config.h

@@ -37,6 +37,8 @@ enum DataType : uint32_t
 	DataType_EnableGUISequence,
 	DataType_EditorWindow,
 	DataType_FileBrowserDialog,
+	// Physics
+	DataType_SimulationActive,
 	// Scripting
 	DataType_EnableLuaScripting
 };
@@ -152,6 +154,14 @@ namespace Systems
 			static constexpr BitMask Shared20	= (BitMask)1 << 20;
 			static constexpr BitMask Shared21	= (BitMask)1 << 21;
 		}
+		namespace Unique
+		{
+			static constexpr BitMask Unique1 = (BitMask)1 << 30;
+			static constexpr BitMask Unique2 = (BitMask)1 << 31;
+			static constexpr BitMask Unique3 = (BitMask)1 << 32;
+			static constexpr BitMask Unique4 = (BitMask)1 << 33;
+			static constexpr BitMask Unique5 = (BitMask)1 << 34;
+		}
 		namespace Type
 		{
 			static constexpr BitMask Generic	= (BitMask)1 << 63;
@@ -161,6 +171,7 @@ namespace Systems
 			static constexpr BitMask GUI		= (BitMask)1 << 59;
 			static constexpr BitMask Physics	= (BitMask)1 << 58;
 			static constexpr BitMask Script		= (BitMask)1 << 57;
+			static constexpr BitMask World		= (BitMask)1 << 56;
 		}
 
 		namespace Generic
@@ -169,9 +180,12 @@ namespace Systems
 			static constexpr BitMask DeleteObject		= Changes::Type::Generic + Changes::Common::Shared2;
 			static constexpr BitMask ExtendObject		= Changes::Type::Generic + Changes::Common::Shared3;
 			static constexpr BitMask UnextendObject		= Changes::Type::Generic + Changes::Common::Shared4;
-			static constexpr BitMask Name				= Changes::Type::Generic + Changes::Common::Shared5;
-			static constexpr BitMask Link				= Changes::Type::Generic + Changes::Common::Shared6;
-			static constexpr BitMask All				= CreateObject | DeleteObject | ExtendObject | Name | Link;
+			static constexpr BitMask Link				= Changes::Type::Generic + Changes::Common::Shared5;
+
+			static constexpr BitMask Active				= Changes::Type::Generic + Changes::Unique::Unique1;
+			static constexpr BitMask Name				= Changes::Type::Generic + Changes::Unique::Unique2;
+
+			static constexpr BitMask All				= CreateObject | DeleteObject | ExtendObject | Link | Active | Name;
 		}
 		namespace Spatial
 		{
@@ -197,7 +211,9 @@ namespace Systems
 		}
 		namespace Audio
 		{
-			static constexpr BitMask All					= Changes::Type::Audio + Changes::Common::Shared1;
+			static constexpr BitMask ListenerID				= Changes::Type::Audio + Changes::Common::Shared1;
+
+			static constexpr BitMask All					= ListenerID;
 		}
 		namespace Graphics
 		{
@@ -231,19 +247,31 @@ namespace Systems
 		namespace GUI
 		{
 			static constexpr BitMask Sequence				= Changes::Type::GUI + Changes::Common::Shared1;
-			static constexpr BitMask Placholder				= Changes::Type::GUI + Changes::Common::Shared2;
-			static constexpr BitMask All					= Sequence | Placholder;
+			static constexpr BitMask StaticSequence			= Changes::Type::GUI + Changes::Common::Shared2;
+			static constexpr BitMask All					= Sequence | StaticSequence;
 		}
 		namespace Physics
 		{
-			static constexpr BitMask Placholder1			= Changes::Type::Physics + Changes::Common::Shared1;
-			static constexpr BitMask Placholder2			= Changes::Type::Physics + Changes::Common::Shared2;
-			static constexpr BitMask All = Placholder1 | Placholder2;
+			static constexpr BitMask CollisionShapeSize		= Changes::Type::Physics + Changes::Common::Shared1;
+			static constexpr BitMask CollisionShapeType		= Changes::Type::Physics + Changes::Common::Shared2;
+			static constexpr BitMask Friction				= Changes::Type::Physics + Changes::Common::Shared3;
+			static constexpr BitMask Mass					= Changes::Type::Physics + Changes::Common::Shared4;
+			static constexpr BitMask Restitution			= Changes::Type::Physics + Changes::Common::Shared5;
+			static constexpr BitMask Kinematic				= Changes::Type::Physics + Changes::Common::Shared6;
+			//static constexpr BitMask LinearVelocity			= Changes::Type::Physics + Changes::Common::Shared7;
+
+			static constexpr BitMask All					= CollisionShapeType | CollisionShapeSize | Friction | Mass | Restitution | Kinematic;
 		}
 		namespace Script
 		{
-			static constexpr BitMask Placholder				= Changes::Type::GUI + Changes::Common::Shared1;
-			static constexpr BitMask All					= Placholder;
+			static constexpr BitMask Filename				= Changes::Type::GUI + Changes::Common::Shared1;
+			static constexpr BitMask Reload					= Changes::Type::GUI + Changes::Common::Shared2;
+			static constexpr BitMask All					= Filename | Reload;
+		}
+		namespace World
+		{
+			static constexpr BitMask ObjectMaterialType		= Changes::Type::World + Changes::Common::Shared1;
+			static constexpr BitMask All					= ObjectMaterialType;
 		}
 
 		static constexpr BitMask None = 0;
@@ -258,6 +286,7 @@ namespace Properties
 	/* General */ \
 	Code(Active,) \
 	Code(ArrayEntry,) \
+	Code(ChangeController,) \
 	Code(Components,) \
 	Code(Default,) \
 	Code(Filename,) \
@@ -271,6 +300,8 @@ namespace Properties
 	Code(System,) \
 	Code(Systems,) \
 	Code(Type,) \
+	Code(UniversalObject,) \
+	Code(UniversalScene,) \
 	Code(Value,) \
 	Code(Variables,) \
 	/* Audio */ \
@@ -397,6 +428,7 @@ namespace Properties
 	/* Physics */ \
 	Code(Box,) \
 	Code(Capsule,) \
+	Code(CollisionEventComponent,) \
 	Code(CollisionShape,) \
 	Code(CollisionShapeComponent,) \
 	Code(Cone,) \
@@ -876,15 +908,21 @@ public:
 			gui_render = true;
 			gui_dark_style = true;
 			gui_sequence_array_reserve_size = 50;
+			editor_float_slider_speed = 0.01f;
+			editor_lua_variables_max_height = 200.0f;
 			gui_file_dialog_min_size_x = 400.0f;
 			gui_file_dialog_min_size_y = 200.0f;
 			gui_file_dialog_dir_color_R = 0.905f;
 			gui_file_dialog_dir_color_G = 0.623f;
 			gui_file_dialog_dir_color_B = 0.314f;
+			editor_button_add_texture = "buttons\\button_add_3.png";
+			editor_button_delete_entry_texture = "buttons\\button_delete_5.png";
 			editor_button_gui_sequence_texture = "buttons\\button_gui_sequence_1.png";
-			editor_button_pause_texture = "buttons\\button_editor_pause_1.png";
-			editor_button_play_texture = "buttons\\button_editor_play_1.png";
-			editor_button_restart_texture = "buttons\\button_editor_restart_1.png";
+			editor_button_open_file_texture = "buttons\\button_open_file_1.png";
+			editor_button_pause_texture = "buttons\\button_editor_pause_2.png";
+			editor_button_play_texture = "buttons\\button_editor_play_2.png";
+			editor_button_reload_texture = "buttons\\button_reload_3.png";
+			editor_button_restart_texture = "buttons\\button_editor_restart_2.png";
 			editor_button_scripting_enabled_texture = "buttons\\button_scripting_1.png";
 			gui_editor_window_name = "Editor window";
 		}
@@ -892,14 +930,20 @@ public:
 		bool gui_render;
 		bool gui_dark_style;
 		int gui_sequence_array_reserve_size;
+		float editor_float_slider_speed;
+		float editor_lua_variables_max_height;
 		float gui_file_dialog_min_size_x;
 		float gui_file_dialog_min_size_y;
 		float gui_file_dialog_dir_color_R;
 		float gui_file_dialog_dir_color_G;
 		float gui_file_dialog_dir_color_B;
+		std::string editor_button_add_texture;
+		std::string editor_button_delete_entry_texture;
 		std::string editor_button_gui_sequence_texture;
+		std::string editor_button_open_file_texture;
 		std::string editor_button_pause_texture;
 		std::string editor_button_play_texture;
+		std::string editor_button_reload_texture;
 		std::string editor_button_restart_texture;
 		std::string editor_button_scripting_enabled_texture;
 		std::string gui_editor_window_name;
@@ -1022,6 +1066,7 @@ public:
 			spatial_component_default_pool_size = 100;
 			spot_light_pool_size = 25;
 			sound_component_default_pool_size = 50;
+			sound_listener_component_default_pool_size = 50;
 		}
 
 		int camera_component_default_pool_size;
@@ -1036,6 +1081,7 @@ public:
 		int spatial_component_default_pool_size;
 		int spot_light_pool_size;
 		int sound_component_default_pool_size;
+		int sound_listener_component_default_pool_size;
 	};
 	struct PathsVariables
 	{

+ 5 - 5
Praxis3D/Source/Containers.h

@@ -51,26 +51,26 @@ struct SpatialTransformData
 	{
 		clear();
 	}
-	SpatialTransformData(const SpatialData &p_spatialData, const glm::mat4 &p_transformMat) : m_spatialData(p_spatialData), m_transformMat(p_transformMat) { }
+	SpatialTransformData(const SpatialData &p_spatialData, const glm::mat4 &p_transformMat) : m_spatialData(p_spatialData), m_transformMatNoScale(p_transformMat) { }
 
 	friend const inline SpatialTransformData operator+(const SpatialTransformData &p_left, const SpatialTransformData &p_right)
 	{
-		return SpatialTransformData(p_left.m_spatialData + p_right.m_spatialData, p_left.m_transformMat * p_right.m_transformMat);
+		return SpatialTransformData(p_left.m_spatialData + p_right.m_spatialData, p_left.m_transformMatNoScale * p_right.m_transformMatNoScale);
 	}
 	const inline SpatialTransformData operator+=(const SpatialTransformData &p_data)
 	{ 
-		return SpatialTransformData(m_spatialData + p_data.m_spatialData, m_transformMat * p_data.m_transformMat);
+		return SpatialTransformData(m_spatialData + p_data.m_spatialData, m_transformMatNoScale * p_data.m_transformMatNoScale);
 	}
 
 	// Set all the data to default
 	void clear()
 	{
 		m_spatialData.clear();
-		m_transformMat = glm::mat4(1.0f);
+		m_transformMatNoScale = glm::mat4(1.0f);
 	}
 
 	SpatialData m_spatialData;
-	glm::mat4 m_transformMat;
+	glm::mat4 m_transformMatNoScale;
 };
 
 // Stores all GUI data

Plik diff jest za duży
+ 851 - 86
Praxis3D/Source/EditorWindow.cpp


+ 338 - 12
Praxis3D/Source/EditorWindow.h

@@ -1,19 +1,24 @@
 #pragma once
 
+#include "ComponentConstructorInfo.h"
 #include "ErrorHandlerLocator.h"
 #include "GUIHandler.h"
+#include "LightComponent.h"
 #include "Loaders.h"
 #include "InheritanceObjects.h"
+#include "RigidBodyComponent.h"
 #include "System.h"
 
+struct FileBrowserDialog;
+
 class EditorWindow : public SystemObject
 {
 	friend class GUIScene;
 public:
 	EditorWindow(SystemScene *p_systemScene, std::string p_name, const EntityID p_entityID, std::size_t p_id = 0) : 
-		SystemObject(p_systemScene, p_name, Properties::PropertyID::EditorWindow, p_entityID)
+		SystemObject(p_systemScene, p_name, Properties::PropertyID::EditorWindow, p_entityID),
+		m_selectedEntity(*this)
 	{
-		m_selectedEntity = NULL_ENTITY_ID;
 		m_renderSceneToTexture = true;
 		m_GUISequenceEnabled = false;
 		m_LUAScriptingEnabled = true;
@@ -21,6 +26,16 @@ public:
 
 		m_selectedTexture = nullptr;
 		m_textureInspectorTabFlags = 0;
+
+		m_colorEditFlags = ImGuiColorEditFlags_Float;
+		m_browseButtonWidth = 60.0f;
+		m_currentlyOpenedFileBrowser = FileBrowserActivated::FileBrowserActivated_None;
+		m_fileBrowserDialog.m_name = "EditorFileBrowserDialog";
+
+		m_luaVariableTypeStrings = { "null", "bool", "int", "float", "double", "vec2i", "vec2f", "vec3f", "vec4f", "string", "propertyID" };
+
+		for(unsigned int i = 0; i < ObjectMaterialType::NumberOfMaterialTypes; i++)
+			m_physicalMaterialProperties.push_back(GetString(static_cast<ObjectMaterialType>(i)));
 	}
 	~EditorWindow() { }
 
@@ -109,10 +124,217 @@ public:
 
 	void setup(EditorWindowSettings &p_editorWindowSettings);
 
+	const inline glm::quat &getQuaternion(const Observer *p_observer, BitMask p_changedBits) const
+	{
+		return m_selectedEntity.m_spatialDataManager.getQuaternion(p_observer, p_changedBits);
+	}
+	const glm::vec3 &getVec3(const Observer *p_observer, BitMask p_changedBits)	const 
+	{ 
+		if((p_changedBits & Systems::Changes::Type::Spatial) != 0)
+		{
+			return m_selectedEntity.m_spatialDataManager.getVec3(p_observer, p_changedBits);
+		}
+		else
+		{
+			switch(p_changedBits)
+			{
+				case Systems::Changes::Graphics::Color:
+				{
+					switch(m_selectedEntity.m_lightType)
+					{
+					case LightComponent::LightComponentType::LightComponentType_directional:
+						return m_selectedEntity.m_componentData.m_graphicsComponents.m_lightConstructionInfo->m_color;
+						break;
+					case LightComponent::LightComponentType::LightComponentType_point:
+						return m_selectedEntity.m_componentData.m_graphicsComponents.m_lightConstructionInfo->m_color;
+						break;
+					case LightComponent::LightComponentType::LightComponentType_spot:
+						return m_selectedEntity.m_componentData.m_graphicsComponents.m_lightConstructionInfo->m_color;
+						break;
+					}
+				}
+				break;
+				case Systems::Changes::Physics::CollisionShapeSize:
+				{
+					return m_selectedEntity.m_componentData.m_physicsComponents.m_rigidBodyConstructionInfo->m_collisionShapeSize;
+				}
+				break;
+			}
+		}
+
+		return NullObjects::NullVec3f;
+	}
+	const inline glm::mat4 &getMat4(const Observer *p_observer, BitMask p_changedBits) const
+	{
+			return m_selectedEntity.m_spatialDataManager.getMat4(p_observer, p_changedBits);
+	}
+
+	const bool getBool(const Observer *p_observer, BitMask p_changedBits) const 
+	{ 
+		switch(p_changedBits)
+		{
+			case Systems::Changes::Physics::Kinematic:
+			{
+				return m_selectedEntity.m_componentData.m_physicsComponents.m_rigidBodyConstructionInfo->m_kinematic;
+			}
+			break;
+
+			case Systems::Changes::GUI::StaticSequence:
+			{
+				return m_selectedEntity.m_componentData.m_guiComponents.m_guiSequenceConstructionInfo->m_staticSequence;
+			}
+			break;
+
+			case Systems::Changes::Generic::Active:
+			{
+				switch(p_observer->getObjectType())
+				{
+					case Properties::PropertyID::SoundComponent:
+						return m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_active;
+					case Properties::PropertyID::SoundListenerComponent:
+						return m_selectedEntity.m_componentData.m_audioComponents.m_soundListenerConstructionInfo->m_active;
+
+					case Properties::PropertyID::CameraComponent:
+						return m_selectedEntity.m_componentData.m_graphicsComponents.m_cameraConstructionInfo->m_active;
+					case Properties::PropertyID::LightComponent:
+						return m_selectedEntity.m_componentData.m_graphicsComponents.m_lightConstructionInfo->m_active;
+					case Properties::PropertyID::ModelComponent:
+						return m_selectedEntity.m_componentData.m_graphicsComponents.m_modelConstructionInfo->m_active;
+					case Properties::PropertyID::ShaderComponent:
+						return m_selectedEntity.m_componentData.m_graphicsComponents.m_shaderConstructionInfo->m_active;
+
+					case Properties::PropertyID::GUISequenceComponent:
+						return m_selectedEntity.m_componentData.m_guiComponents.m_guiSequenceConstructionInfo->m_active;
+
+					case Properties::PropertyID::RigidBodyComponent:
+						return m_selectedEntity.m_componentData.m_physicsComponents.m_rigidBodyConstructionInfo->m_active;
+
+					case Properties::PropertyID::LuaComponent:
+						return m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_active;
+
+					case Properties::PropertyID::ObjectMaterialComponent:
+						return m_selectedEntity.m_componentData.m_worldComponents.m_objectMaterialConstructionInfo->m_active;
+					case Properties::PropertyID::SpatialComponent:
+						return m_selectedEntity.m_componentData.m_worldComponents.m_spatialConstructionInfo->m_active;
+				}
+			}
+			break;
+		}
+
+		return NullObjects::NullBool; 
+	}
+	const int getInt(const Observer *p_observer, BitMask p_changedBits) const 
+	{ 
+		switch(p_changedBits)
+		{
+		case Systems::Changes::Audio::ListenerID:
+			{
+				if(m_selectedEntity.m_componentData.m_audioComponents.m_soundListenerConstructionInfo->m_listenerID >= 0)
+					return m_selectedEntity.m_componentData.m_audioComponents.m_soundListenerConstructionInfo->m_listenerID;
+			}
+			break;
+
+		case Systems::Changes::Physics::CollisionShapeType:
+			{
+				if(m_selectedEntity.m_collisionShapeType >= 0 && m_selectedEntity.m_collisionShapeType < RigidBodyComponent::CollisionShapeType::CollisionShapeType_NumOfTypes)
+					return m_selectedEntity.m_collisionShapeType;
+			}
+			break;
+		}
+
+		return NullObjects::NullInt; 
+	}
+	const unsigned int getUnsignedInt(const Observer *p_observer, BitMask p_changedBits) const 
+	{ 
+		switch(p_changedBits)
+		{
+		case Systems::Changes::World::ObjectMaterialType:
+			{
+				if(m_selectedEntity.m_objectMaterialType >= 0 && m_selectedEntity.m_objectMaterialType < ObjectMaterialType::NumberOfMaterialTypes)
+					return (unsigned int)m_selectedEntity.m_objectMaterialType;
+			}
+			break;
+		}
+
+		return NullObjects::NullUnsignedInt; 
+	}
+	const float getFloat(const Observer *p_observer, BitMask p_changedBits) const 
+	{
+		switch(p_changedBits)
+		{
+			case Systems::Changes::Graphics::CutoffAngle:
+			{
+				if(m_selectedEntity.m_lightType == LightComponent::LightComponentType::LightComponentType_spot)
+					return m_selectedEntity.m_componentData.m_graphicsComponents.m_lightConstructionInfo->m_cutoffAngle;
+			}
+			break;
+
+			case Systems::Changes::Graphics::Intensity:
+			{
+				switch(m_selectedEntity.m_lightType)
+				{
+					case LightComponent::LightComponentType::LightComponentType_directional:
+					case LightComponent::LightComponentType::LightComponentType_point:
+					case LightComponent::LightComponentType::LightComponentType_spot:
+						return m_selectedEntity.m_componentData.m_graphicsComponents.m_lightConstructionInfo->m_intensity;
+					break;
+				}
+			}
+			break;
+
+			case Systems::Changes::Physics::Friction:
+			{
+				return m_selectedEntity.m_componentData.m_physicsComponents.m_rigidBodyConstructionInfo->m_friction;
+			}
+			break;
+
+			case Systems::Changes::Physics::Mass:
+			{
+				return m_selectedEntity.m_componentData.m_physicsComponents.m_rigidBodyConstructionInfo->m_mass;
+			}
+			break;
+
+			case Systems::Changes::Physics::Restitution:
+			{
+				return m_selectedEntity.m_componentData.m_physicsComponents.m_rigidBodyConstructionInfo->m_restitution;
+			}
+			break;
+		}
+
+		return NullObjects::NullFloat; 
+	}
+	const std::string &getString(const Observer *p_observer, BitMask p_changedBits)	const 
+	{
+		switch(p_changedBits)
+		{
+			case Systems::Changes::Generic::Name:
+				{
+					return m_selectedEntity.m_componentData.m_name;
+				}
+				break;
+
+			case Systems::Changes::Script::Filename:
+				{
+					return m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_luaScriptFilename;
+				}
+				break;
+		}
+
+		return NullObjects::NullString; 
+	}
+	const inline SpatialData &getSpatialData(const Observer *p_observer, BitMask p_changedBits) const
+	{
+		return m_selectedEntity.m_spatialDataManager.getSpatialData(p_observer, p_changedBits);
+	}
+	const inline SpatialTransformData &getSpatialTransformData(const Observer *p_observer, BitMask p_changedBits) const
+	{
+		return m_selectedEntity.m_spatialDataManager.getSpatialTransformData(p_observer, p_changedBits);
+	}
+
 private:
 	struct ComponentListEntry
 	{
-		ComponentListEntry(EntityID p_entityID, const std::string &p_name, const std::string &p_combinedEntityIdAndName) : m_entityID(p_entityID), m_name(p_name), m_combinedEntityIdAndName(p_combinedEntityIdAndName) { }
+		ComponentListEntry(const EntityID p_entityID, const std::string &p_name, const std::string &p_combinedEntityIdAndName) : m_entityID(p_entityID), m_name(p_name), m_combinedEntityIdAndName(p_combinedEntityIdAndName) { }
 
 		EntityID m_entityID;
 		std::string m_name;
@@ -120,7 +342,7 @@ private:
 	};
 	struct EntityListEntry
 	{
-		EntityListEntry(EntityID p_entityID, EntityID p_parentEntityID, const std::string &p_name, const std::string &p_combinedEntityIdAndName) : m_entityID(p_entityID), m_parentEntityID(p_parentEntityID), m_name(p_name), m_combinedEntityIdAndName(p_combinedEntityIdAndName), m_componentFlag(Systems::AllComponentTypes::None) { }
+		EntityListEntry(const EntityID p_entityID, const EntityID p_parentEntityID, const std::string &p_name, const std::string &p_combinedEntityIdAndName) : m_entityID(p_entityID), m_parentEntityID(p_parentEntityID), m_name(p_name), m_combinedEntityIdAndName(p_combinedEntityIdAndName), m_componentFlag(Systems::AllComponentTypes::None) { }
 		EntityListEntry(const EntityListEntry &p_entityListEntry) : m_entityID(p_entityListEntry.m_entityID), m_parentEntityID(p_entityListEntry.m_parentEntityID), m_name(p_entityListEntry.m_name), m_combinedEntityIdAndName(p_entityListEntry.m_combinedEntityIdAndName), m_componentFlag(Systems::AllComponentTypes::None) { }
 		bool operator==(const EntityListEntry &p_entityListEntry) { return m_entityID == p_entityListEntry.m_entityID; }
 
@@ -133,7 +355,7 @@ private:
 	struct EntityHierarchyEntry
 	{
 		EntityHierarchyEntry() : m_entityID(NULL_ENTITY_ID), m_parent(NULL_ENTITY_ID), m_componentFlag(Systems::AllComponentTypes::None) { }
-		EntityHierarchyEntry(EntityID p_entityID, EntityID p_parent, const std::string &p_name, const std::string &p_combinedEntityIdAndName, const BitMask p_componentFlag) : m_entityID(p_entityID), m_parent(p_parent), m_name(p_name), m_combinedEntityIdAndName(p_combinedEntityIdAndName), m_componentFlag(p_componentFlag){ }
+		EntityHierarchyEntry(const EntityID p_entityID, const EntityID p_parent, const std::string &p_name, const std::string &p_combinedEntityIdAndName, const BitMask p_componentFlag) : m_entityID(p_entityID), m_parent(p_parent), m_name(p_name), m_combinedEntityIdAndName(p_combinedEntityIdAndName), m_componentFlag(p_componentFlag){ }
 
 		bool operator==(const EntityHierarchyEntry &p_childEntityEntry) { return m_entityID == p_childEntityEntry.m_entityID; }
 
@@ -185,6 +407,74 @@ private:
 		std::string m_combinedEntityIdAndName;
 		std::vector<EntityHierarchyEntry> m_children;
 	};
+	struct SelectedEntity
+	{
+		SelectedEntity(const Observer &p_parent) : m_spatialDataManager(p_parent)
+		{ 
+			m_entityID = NULL_ENTITY_ID;
+			m_objectMaterialType = ObjectMaterialType::Concrete;
+			m_lightType = LightComponent::LightComponentType::LightComponentType_null;
+			m_collisionShapeType = RigidBodyComponent::CollisionShapeType::CollisionShapeType_Null;
+
+			m_luaVariablesModified = false;
+			m_luaScriptFilenameModified = false;
+
+			m_componentData.m_audioComponents.m_soundConstructionInfo = new SoundComponent::SoundComponentConstructionInfo();
+			m_componentData.m_audioComponents.m_soundListenerConstructionInfo = new SoundListenerComponent::SoundListenerComponentConstructionInfo();
+
+			m_componentData.m_graphicsComponents.m_cameraConstructionInfo = new CameraComponent::CameraComponentConstructionInfo();
+			m_componentData.m_graphicsComponents.m_lightConstructionInfo = new LightComponent::LightComponentConstructionInfo();
+			m_componentData.m_graphicsComponents.m_modelConstructionInfo = new ModelComponent::ModelComponentConstructionInfo();
+			m_componentData.m_graphicsComponents.m_shaderConstructionInfo = new ShaderComponent::ShaderComponentConstructionInfo();
+
+			m_componentData.m_guiComponents.m_guiSequenceConstructionInfo = new GUISequenceComponent::GUISequenceComponentConstructionInfo();
+
+			m_componentData.m_physicsComponents.m_rigidBodyConstructionInfo = new RigidBodyComponent::RigidBodyComponentConstructionInfo();
+
+			m_componentData.m_scriptComponents.m_luaConstructionInfo = new LuaComponent::LuaComponentConstructionInfo();
+
+			m_componentData.m_worldComponents.m_objectMaterialConstructionInfo = new ObjectMaterialComponent::ObjectMaterialComponentConstructionInfo();
+			m_componentData.m_worldComponents.m_spatialConstructionInfo = new SpatialComponent::SpatialComponentConstructionInfo();
+		}
+
+		inline operator bool() const { return m_entityID != NULL_ENTITY_ID; }
+
+		void setEntity(const EntityID p_entityID)
+		{
+			m_entityID = p_entityID;
+			m_luaVariablesModified = false;
+			m_luaScriptFilenameModified = false;
+		}
+
+		void unselect()
+		{
+			m_entityID = NULL_ENTITY_ID;
+			m_luaVariablesModified = false;
+			m_luaScriptFilenameModified = false;
+		}
+
+		EntityID m_entityID;
+
+		ComponentsConstructionInfo m_componentData;
+
+		// SpatialComponent data
+		SpatialDataManager m_spatialDataManager;
+
+		// ObjectMaterialComponent data 
+		int m_objectMaterialType;
+
+		// LightComponent data
+		int m_lightType;
+
+		// RigidBodyComponent data
+		int m_collisionShapeType;
+
+		// An array of external lua variables
+		std::vector<std::pair<std::string, Property>> m_luaVariables;
+
+		bool m_luaVariablesModified;
+		bool m_luaScriptFilenameModified;
+	};
 
 	enum ButtonTextureType : unsigned int
 	{
@@ -193,16 +483,42 @@ private:
 		ButtonTextureType_Restart,
 		ButtonTextureType_GUISequence,
 		ButtonTextureType_ScriptingEnable,
+		ButtonTextureType_DeleteEntry,
+		ButtonTextureType_Add,
+		ButtonTextureType_OpenFile,
+		ButtonTextureType_Reload,
 		ButtonTextureType_NumOfTypes
 	};
-
 	enum EditorSceneState : unsigned int
 	{
 		EditorSceneState_Play,
 		EditorSceneState_Pause
 	};
+	enum FileBrowserActivated : unsigned int
+	{
+		FileBrowserActivated_None,
+		FileBrowserActivated_LuaScript,
+		FileBrowserActivated_LoadScene,
+		FileBrowserActivated_SaveScene
+	};
 
 	void drawEntityHierarchyEntry(EntityHierarchyEntry &p_entityEntry);
+	inline void drawLeftAlignedLabelText(const char *p_labelText, float p_nextWidgetOffset)
+	{
+		ImGui::AlignTextToFramePadding();
+		ImGui::Text(p_labelText);
+		ImGui::SameLine();
+		ImGui::SetCursorPosX(p_nextWidgetOffset);
+		ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - p_nextWidgetOffset);
+	}
+	inline void drawLeftAlignedLabelText(const char *p_labelText, float p_nextWidgetOffset, float p_nextItemWidth)
+	{
+		ImGui::AlignTextToFramePadding();
+		ImGui::Text(p_labelText);
+		ImGui::SameLine();
+		ImGui::SetCursorPosX(p_nextWidgetOffset);
+		ImGui::SetNextItemWidth(p_nextItemWidth);
+	}
 	//void getComponentsOfEntity(std::vector<ComponentListEntry> &p_componentList, EntityID p_entityID);
 
 	void updateEntityList();
@@ -322,22 +638,32 @@ private:
 	bool show_another_window;
 	float clear_color;
 
-	// Texture inspector variables
-	Texture2D *m_selectedTexture;
-	ImGuiTabItemFlags m_textureInspectorTabFlags;
-	DoubleBufferedContainer<FunctorSequence> m_textureInspectorSequence;
-
 	bool m_renderSceneToTexture;
 	bool m_GUISequenceEnabled;
 	bool m_LUAScriptingEnabled;
 	EditorSceneState m_sceneState;
 	glm::ivec2 m_centerWindowSize;
+	std::vector<const char *> m_physicalMaterialProperties;
+
+	// GUI settings
+	ImGuiColorEditFlags m_colorEditFlags;
+	float m_browseButtonWidth;
+	FileBrowserActivated m_currentlyOpenedFileBrowser;
+	FileBrowserDialog m_fileBrowserDialog;
+
+	// LUA variables editor data
+	std::vector<const char *> m_luaVariableTypeStrings;
+
+	// Texture inspector variables
+	Texture2D *m_selectedTexture;
+	ImGuiTabItemFlags m_textureInspectorTabFlags;
+	DoubleBufferedContainer<FunctorSequence> m_textureInspectorSequence;
 
 	// Scene entities
 	std::vector<ComponentListEntry> m_componentList;
 	std::vector<EntityListEntry> m_entityList;
 	std::vector<EntityHierarchyEntry> m_entityHierarchy;
-	EntityID m_selectedEntity;
+	SelectedEntity m_selectedEntity;
 
 	// Button textures
 	std::vector<TextureLoader2D::Texture2DHandle> m_buttonTextures;

+ 2 - 0
Praxis3D/Source/ErrorCodes.h

@@ -54,6 +54,7 @@ DECLARE_ENUM(ErrorType, ERROR_TYPES)
 	Code(Framebuffer_failed,) \
 	Code(Geometrybuffer_failed,) \
 	/* GUI errors */ \
+	Code(Editor_path_outside_current_dir,) \
 	Code(GL_context_missing,) \
 	Code(Window_handle_missing,) \
 	/* Model loader errors */ \
@@ -115,6 +116,7 @@ DECLARE_ENUM(ErrorCode, ERROR_CODES)
     Code(Source_GeometryPass,) \
     Code(Source_GraphicsObject,) \
     Code(Source_GUI,) \
+    Code(Source_GUIEditor,) \
     Code(Source_GUIObject,) \
     Code(Source_GUIPass,) \
     Code(Source_GUISequenceComponent,) \

+ 1 - 0
Praxis3D/Source/ErrorHandler.cpp

@@ -36,6 +36,7 @@ ErrorHandler::ErrorHandler()
 	AssignErrorType(Clock_QueryFrequency, FatalError);
 	AssignErrorType(Framebuffer_failed, FatalError);
 	AssignErrorType(Geometrybuffer_failed, FatalError);
+	AssignErrorType(Editor_path_outside_current_dir, Warning);
 	AssignErrorType(GL_context_missing, Error);
 	AssignErrorType(Window_handle_missing, Error);
 	AssignErrorType(AssimpScene_failed, Error);

+ 6 - 0
Praxis3D/Source/Filesystem.h

@@ -62,4 +62,10 @@ public:
 	{
 		return std::filesystem::exists(p_file);
 	}
+
+	static std::string getCurrentDirectory()
+	{
+		std::filesystem::path path = std::filesystem::current_path();
+		return path.string();
+	}
 };

+ 1 - 1
Praxis3D/Source/FinalPass.h

@@ -7,7 +7,7 @@ class FinalPass : public RenderPass
 {
 public:
 	FinalPass(RendererFrontend &p_renderer) : 
-		RenderPass(p_renderer) { }
+		RenderPass(p_renderer, RenderPassType::RenderPassType_Final) { }
 
 	~FinalPass() { }
 

+ 1 - 1
Praxis3D/Source/GUIPass.h

@@ -7,7 +7,7 @@
 class GUIPass : public RenderPass
 {
 public:
-	GUIPass(RendererFrontend &p_renderer) : RenderPass(p_renderer) { }
+	GUIPass(RendererFrontend &p_renderer) : RenderPass(p_renderer, RenderPassType::RenderPassType_GUI) { }
 
 	~GUIPass() { }
 

+ 42 - 17
Praxis3D/Source/GUIScene.cpp

@@ -4,12 +4,13 @@
 
 #include "WorldScene.h"
 #include "ComponentConstructorInfo.h"
+#include "EditorWindow.h"
 #include "GUIHandlerLocator.h"
 #include "GUIScene.h"
 #include "NullSystemObjects.h"
 #include "TaskManagerLocator.h"
 
-GUIScene::GUIScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader)
+GUIScene::GUIScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader, Properties::PropertyID::GUI)
 {
 	 m_GUITask = nullptr;
 	 m_editorWindow = nullptr;
@@ -41,29 +42,29 @@ ErrorCode GUIScene::init()
 }
 
 ErrorCode GUIScene::setup(const PropertySet& p_properties)
-{	
-	// Get default object pool size
-	int objectPoolSize = Config::objectPoolVar().object_pool_size;
-
-	for(decltype(p_properties.getNumProperties()) i = 0, size = p_properties.getNumProperties(); i < size; i++)
-	{
-		switch(p_properties[i].getPropertyID())
-		{
-		case Properties::ObjectPoolSize:
-			objectPoolSize = p_properties[i].getInt();
-			break;
-		}
-	}
-
+{
 	// Get the world scene required for reserving the component pools
 	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
 
-	// Reserve every component type that belongs to this scene
-	worldScene->reserve<GUISequenceComponent>(Config::objectPoolVar().gui_sequence_component_default_pool_size);
+	// Get the property set containing object pool size
+	auto &objectPoolSizeProperty = p_properties.getPropertySetByID(Properties::ObjectPoolSize);
+
+	// Reserve every component type that belongs to this scene (and set the minimum number of objects based on default config)
+	worldScene->reserve<GUISequenceComponent>(std::max(Config::objectPoolVar().gui_sequence_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::GUISequenceComponent).getInt()));
 
 	return ErrorCode::Success;
 }
 
+void GUIScene::exportSetup(PropertySet &p_propertySet)
+{
+	// Get the world scene required for getting the pool sizes
+	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
+
+	// Add object pool sizes
+	auto &objectPoolSizePropertySet = p_propertySet.addPropertySet(Properties::ObjectPoolSize);
+	objectPoolSizePropertySet.addProperty(Properties::GUISequenceComponent, (int)worldScene->getPoolSize<GUISequenceComponent>());
+}
+
 void GUIScene::update(const float p_deltaTime)
 {
 	if(Config::GUIVar().gui_render)
@@ -192,6 +193,30 @@ std::vector<SystemObject*> GUIScene::createComponents(const EntityID p_entityID,
 	return createComponents(p_entityID, p_constructionInfo.m_guiComponents, p_startLoading);
 }
 
+void GUIScene::exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo)
+{
+	exportComponents(p_entityID, p_constructionInfo.m_guiComponents);
+}
+
+void GUIScene::exportComponents(const EntityID p_entityID, GUIComponentsConstructionInfo &p_constructionInfo)
+{
+	// Get the world scene required for getting the entity registry
+	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
+
+	// Get the entity registry 
+	auto &entityRegistry = worldScene->getEntityRegistry();
+
+	// Export GUISequenceComponent
+	auto *guiSequenceComponent = entityRegistry.try_get<GUISequenceComponent>(p_entityID);
+	if(guiSequenceComponent != nullptr)
+	{
+		if(p_constructionInfo.m_guiSequenceConstructionInfo == nullptr)
+			p_constructionInfo.m_guiSequenceConstructionInfo = new GUISequenceComponent::GUISequenceComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_guiSequenceConstructionInfo, *guiSequenceComponent);
+	}
+}
+
 SystemObject *GUIScene::createComponent(const EntityID p_entityID, const GUISequenceComponent::GUISequenceComponentConstructionInfo &p_constructionInfo, const bool p_startLoading)
 {	
 	// If valid type was not specified, or object creation failed, return a null object instead

+ 25 - 4
Praxis3D/Source/GUIScene.h

@@ -1,6 +1,5 @@
 #pragma once
 
-#include "EditorWindow.h"
 #include "GUIObject.h"
 #include "GUITask.h"
 #include "ObjectPool.h"
@@ -34,6 +33,14 @@ struct GUIComponentsConstructionInfo
 
 struct FileBrowserDialog
 {
+	enum FileBrowserDialogFlags : unsigned int
+	{
+		FileBrowserDialogFlags_None = 0,
+		FileBrowserDialogFlags_ConfirmOverwrite = (1 << 0),
+		FileBrowserDialogFlags_DontShowHiddenFiles = (1 << 1),
+		FileBrowserDialogFlags_DisableCreateDirectoryButton = (1 << 2)
+	};
+
 	FileBrowserDialog()
 	{
 		m_opened = false;
@@ -41,7 +48,7 @@ struct FileBrowserDialog
 		m_success = false;
 		m_rootPath = ".";
 		m_numOfSelectableFiles = 1;
-		m_flags = 0;
+		m_flags = FileBrowserDialogFlags_None;
 	}
 
 	// Only reset the values that are assigned after opening the dialog
@@ -65,8 +72,8 @@ struct FileBrowserDialog
 				m_filename,
 				m_filePathName;
 
-	int m_numOfSelectableFiles,
-		m_flags;
+	int m_numOfSelectableFiles;
+	unsigned int m_flags;
 
 	bool m_opened,
 		 m_closed,
@@ -83,6 +90,8 @@ public:
 
 	ErrorCode setup(const PropertySet& p_properties);
 
+	void exportSetup(PropertySet &p_propertySet);
+
 	void update(const float p_deltaTime);
 
 	ErrorCode preload();
@@ -100,7 +109,19 @@ public:
 		return components;
 	}
 
+	void exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo);
+	void exportComponents(const EntityID p_entityID, GUIComponentsConstructionInfo &p_constructionInfo);
+
 	SystemObject *createComponent(const EntityID p_entityID, const GUISequenceComponent::GUISequenceComponentConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
+
+	void exportComponent(GUISequenceComponent::GUISequenceComponentConstructionInfo &p_constructionInfo, const GUISequenceComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+
+		p_constructionInfo.m_staticSequence = p_component.isStaticSequence();
+	}
+
 	ErrorCode destroyObject(SystemObject *p_systemObject);
 
 	void changeOccurred(ObservedSubject* p_subject, BitMask p_changeType) { }

+ 5 - 0
Praxis3D/Source/GUISequenceComponent.h

@@ -114,6 +114,8 @@ public:
 	BitMask getDesiredSystemChanges() final override { return Systems::Changes::GUI::All; }
 	BitMask getPotentialSystemChanges() final override { return Systems::Changes::None; }
 
+	const inline bool isStaticSequence() const { return m_staticSequence; }
+
 	const Functors &getFunctors(const Observer *p_observer, BitMask p_changedBits)
 	{
 		if(CheckBitmask(p_changedBits, Systems::Changes::Type::GUI))
@@ -124,6 +126,9 @@ public:
 	{
 		if(CheckBitmask(p_changeType, Systems::Changes::GUI::Sequence))
 			m_guiSequence = p_subject->getFunctors(this, Systems::Changes::GUI::Sequence);
+
+		if(CheckBitmask(p_changeType, Systems::Changes::GUI::StaticSequence))
+			m_staticSequence = p_subject->getBool(this, Systems::Changes::GUI::StaticSequence);
 	}
 
 	void clearSequence()

+ 3 - 3
Praxis3D/Source/GeometryPass.h

@@ -5,7 +5,7 @@
 class GeometryPass : public RenderPass
 {
 public:
-	GeometryPass(RendererFrontend &p_renderer) : RenderPass(p_renderer) { }
+	GeometryPass(RendererFrontend &p_renderer) : RenderPass(p_renderer, RenderPassType::RenderPassType_Geometry) { }
 
 	~GeometryPass() { }
 
@@ -83,7 +83,7 @@ public:
 					m_renderer.queueForDrawing(modelData[i],
 						geomShaderHandle,
 						geomUniformUpdater,
-						spatialData.getSpatialDataChangeManager().getWorldTransform(),
+						spatialData.getSpatialDataChangeManager().getWorldTransformWithScale(),
 						m_renderer.m_viewProjMatrix);
 				}
 			}
@@ -106,7 +106,7 @@ public:
 						m_renderer.queueForDrawing(modelData[i],
 							shader.getShaderData()->m_shader.getShaderHandle(),
 							shader.getShaderData()->m_shader.getUniformUpdater(),
-							spatialData.getSpatialDataChangeManager().getWorldTransform(),
+							spatialData.getSpatialDataChangeManager().getWorldTransformWithScale(),
 							m_renderer.m_viewProjMatrix);
 					}
 				}

+ 1 - 1
Praxis3D/Source/GraphicsObject.h

@@ -232,7 +232,7 @@ public:
 			}
 
 			// Calculate model matrix
-			//m_worldSpace.m_transformMat = Math::createTransformMat(m_worldSpace.m_spatialData.m_position, m_worldSpace.m_spatialData.m_rotationEuler, m_worldSpace.m_spatialData.m_scale);
+			//m_worldSpace.m_transformMatNoScale = Math::createTransformMat(m_worldSpace.m_spatialData.m_position, m_worldSpace.m_spatialData.m_rotationEuler, m_worldSpace.m_spatialData.m_scale);
 
 			// Update components
 			if(modelComponentPresent())

+ 1 - 1
Praxis3D/Source/HdrMappingPass.h

@@ -7,7 +7,7 @@ class HdrMappingPass : public RenderPass
 {
 public:
 	HdrMappingPass(RendererFrontend &p_renderer) :
-		RenderPass(p_renderer),
+		RenderPass(p_renderer, RenderPassType::RenderPassType_HdrMapping),
 		m_HDRSSBuffer(BufferType_ShaderStorage, BufferBindTarget_Uniform, BufferUsageHint_DynamicCopy) 
 	{
 		m_hdrMappingShader = nullptr;

+ 1 - 1
Praxis3D/Source/LenseFlareCompositePass.h

@@ -7,7 +7,7 @@ class LenseFlareCompositePass : public RenderPass
 {
 public:
 	LenseFlareCompositePass(RendererFrontend &p_renderer) :
-		RenderPass(p_renderer), 
+		RenderPass(p_renderer, RenderPassType::RenderPassType_LenseFlareComposite),
 		m_lensFlareDirt(Loaders::texture2D().load(Config::rendererVar().lens_flare_dirt_texture)),
 		m_lenseFlareStarburst(Loaders::texture2D().load(Config::rendererVar().lens_flare_starburst_texture))
 	{

+ 1 - 1
Praxis3D/Source/LenseFlarePass.h

@@ -7,7 +7,7 @@ class LenseFlarePass : public RenderPass
 {
 public:
 	LenseFlarePass(RendererFrontend &p_renderer) :
-		RenderPass(p_renderer), 
+		RenderPass(p_renderer, RenderPassType::RenderPassType_LenseFlare),
 		m_lensFlareParamBuffer(BufferType_Uniform, BufferBindTarget_Uniform, BufferUsageHint_DynamicDraw),
 		m_lensFlareGhostGradient(Loaders::texture2D().load(Config::rendererVar().lens_flare_ghost_gradient_texture))
 	{

+ 68 - 33
Praxis3D/Source/LightComponent.h

@@ -63,15 +63,15 @@ public:
 
 		switch(m_lightComponentType)
 		{
-		case LightComponent::LightComponentType_directional:
-			m_lightComponent.m_directional = p_other.m_lightComponent.m_directional;
-			break;
-		case LightComponent::LightComponentType_point:
-			m_lightComponent.m_point = p_other.m_lightComponent.m_point;
-			break;
-		case LightComponent::LightComponentType_spot:
-			m_lightComponent.m_spot = p_other.m_lightComponent.m_spot;
-			break;
+			case LightComponent::LightComponentType_directional:
+				m_lightComponent.m_directional = p_other.m_lightComponent.m_directional;
+				break;
+			case LightComponent::LightComponentType_point:
+				m_lightComponent.m_point = p_other.m_lightComponent.m_point;
+				break;
+			case LightComponent::LightComponentType_spot:
+				m_lightComponent.m_spot = p_other.m_lightComponent.m_spot;
+				break;
 		}
 	}
 	LightComponent(LightComponent &&p_other) noexcept
@@ -80,15 +80,15 @@ public:
 
 		switch(m_lightComponentType)
 		{
-		case LightComponent::LightComponentType_directional:
-			m_lightComponent.m_directional = p_other.m_lightComponent.m_directional;
-			break;
-		case LightComponent::LightComponentType_point:
-			m_lightComponent.m_point = p_other.m_lightComponent.m_point;
-			break;
-		case LightComponent::LightComponentType_spot:
-			m_lightComponent.m_spot = p_other.m_lightComponent.m_spot;
-			break;
+			case LightComponent::LightComponentType_directional:
+				m_lightComponent.m_directional = p_other.m_lightComponent.m_directional;
+				break;
+			case LightComponent::LightComponentType_point:
+				m_lightComponent.m_point = p_other.m_lightComponent.m_point;
+				break;
+			case LightComponent::LightComponentType_spot:
+				m_lightComponent.m_spot = p_other.m_lightComponent.m_spot;
+				break;
 		}
 	}
 
@@ -97,12 +97,12 @@ public:
 		// Nothing to delete so far
 		switch(m_lightComponentType)
 		{
-		case LightComponent::LightComponentType_directional:
-			break;
-		case LightComponent::LightComponentType_point:
-			break;
-		case LightComponent::LightComponentType_spot:
-			break;
+			case LightComponent::LightComponentType_directional:
+				break;
+			case LightComponent::LightComponentType_point:
+				break;
+			case LightComponent::LightComponentType_spot:
+				break;
 		}
 	}
 
@@ -112,15 +112,15 @@ public:
 
 		switch(m_lightComponentType)
 		{
-		case LightComponent::LightComponentType_directional:
-			m_lightComponent.m_directional = p_other.m_lightComponent.m_directional;
-			break;
-		case LightComponent::LightComponentType_point:
-			m_lightComponent.m_point = p_other.m_lightComponent.m_point;
-			break;
-		case LightComponent::LightComponentType_spot:
-			m_lightComponent.m_spot = p_other.m_lightComponent.m_spot;
-			break;
+			case LightComponent::LightComponentType_directional:
+				m_lightComponent.m_directional = p_other.m_lightComponent.m_directional;
+				break;
+			case LightComponent::LightComponentType_point:
+				m_lightComponent.m_point = p_other.m_lightComponent.m_point;
+				break;
+			case LightComponent::LightComponentType_spot:
+				m_lightComponent.m_spot = p_other.m_lightComponent.m_spot;
+				break;
 		}
 
 		return *this;
@@ -340,6 +340,41 @@ public:
 	// Get the spot light data set. If the type of light is not spot, returns a null pointer
 	inline SpotLightDataSet *getSpotLightSafe() { return (m_lightComponentType == LightComponentType::LightComponentType_spot) ? &m_lightComponent.m_spot : nullptr; }
 
+	const inline glm::vec3 getColor() const
+	{
+		switch(m_lightComponentType)
+		{
+			case LightComponent::LightComponentType_directional:
+				return m_lightComponent.m_directional.m_color;
+				break;
+			case LightComponent::LightComponentType_point:
+				return m_lightComponent.m_point.m_color;
+				break;
+			case LightComponent::LightComponentType_spot:
+				return m_lightComponent.m_spot.m_color;
+				break;
+		}
+
+		return glm::vec3(1.0f);
+	}
+	const inline float getIntensity() const
+	{
+		switch(m_lightComponentType)
+		{
+			case LightComponent::LightComponentType_directional:
+				return m_lightComponent.m_directional.m_intensity;
+				break;
+			case LightComponent::LightComponentType_point:
+				return m_lightComponent.m_point.m_intensity;
+				break;
+			case LightComponent::LightComponentType_spot:
+				return m_lightComponent.m_spot.m_intensity;
+				break;
+		}
+
+		return 1.0f;
+	}
+
 private:
 	inline void updateColor(const glm::vec3 &p_color)
 	{

+ 1 - 1
Praxis3D/Source/LightingPass.h

@@ -6,7 +6,7 @@ class LightingPass : public RenderPass
 {
 public:
 	LightingPass(RendererFrontend &p_renderer) : 
-		RenderPass(p_renderer), 
+		RenderPass(p_renderer, RenderPassType::RenderPassType_Lighting),
 		m_pointLightBuffer(BufferType_Uniform, BufferBindTarget_Uniform, BufferUsageHint_DynamicDraw),
 		m_spotLightBuffer(BufferType_Uniform, BufferBindTarget_Uniform, BufferUsageHint_DynamicDraw),
 		m_shaderLightPass(nullptr),

+ 29 - 1
Praxis3D/Source/LuaComponent.h

@@ -197,8 +197,36 @@ public:
 
 		return NullObjects::NullFunctors;
 	}
+	const inline LuaScript *getLuaScript() const { return m_luaScript; }
 
-	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) { }
+	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) 
+	{
+		if(CheckBitmask(p_changeType, Systems::Changes::Script::Filename))
+		{
+			if(m_luaScript != nullptr)
+			{
+				// Get the new LUA script filename from the observed subject
+				auto luaScriptFilename = p_subject->getString(this, Systems::Changes::Script::Filename);
+
+				// Check if the lua script exists
+				if(!luaScriptFilename.empty())
+				{
+					m_luaScript->setScriptFilename(luaScriptFilename);
+
+					m_luaScript->reload();
+				}
+			}
+		}
+
+		if(CheckBitmask(p_changeType, Systems::Changes::Script::Reload))
+		{
+			// Check if the lua script exists
+			if(m_luaScript != nullptr)
+			{
+				m_luaScript->reload();
+			}
+		}
+	}
 
 	void setSpatialDataManagerReference(const SpatialDataManager &p_spatialData) 
 	{ 

+ 8 - 0
Praxis3D/Source/LuaScript.cpp

@@ -13,6 +13,11 @@ namespace LuaDefinitions
 }
 
 LuaScript::~LuaScript()
+{
+	terminate();
+}
+
+void LuaScript::terminate()
 {
 	// Unbind all created key commands
 	for(decltype(m_keyCommands.size()) i = 0; i < m_keyCommands.size(); i++)
@@ -23,10 +28,12 @@ LuaScript::~LuaScript()
 			delete m_keyCommands[i];
 		}
 	}
+	m_keyCommands.clear();
 
 	// Delete all created conditionals
 	for(decltype(m_conditionals.size()) i = 0; i < m_conditionals.size(); i++)
 		delete m_conditionals[i];
+	m_conditionals.clear();
 
 	// Delete all created component construction info objects
 	for(decltype(m_componentsConstructionInfo.size()) i = 0; i < m_componentsConstructionInfo.size(); i++)
@@ -34,6 +41,7 @@ LuaScript::~LuaScript()
 		m_componentsConstructionInfo[i]->deleteConstructionInfo();
 		delete m_componentsConstructionInfo[i];
 	}
+	m_componentsConstructionInfo.clear();
 }
 
 void LuaScript::setDefinitions()

+ 11 - 0
Praxis3D/Source/LuaScript.h

@@ -69,6 +69,7 @@ struct Conditional
 
 class LuaScript
 {
+	friend class LuaComponent;
 public:
 	LuaScript(SystemScene *p_scriptScene, SpatialDataManager &p_spatialData, GUIDataManager &p_GUIData) : m_scriptScene(p_scriptScene), m_spatialData(p_spatialData), m_GUIData(p_GUIData)
 	{ 
@@ -160,8 +161,18 @@ public:
 	}
 
 	const inline std::string &getLuaScriptFilename() const { return m_luaScriptFilename; }
+	const inline std::vector<std::pair<std::string, Property>> &getLuaVariables() const { return m_variables; }
 
 private:
+	// Terminate the current LUA script and initialize it again
+	void reload()
+	{
+		terminate();
+		init();
+	}
+	// Remove the LUA script and delete all objects created by it
+	void terminate();
+
 	// Sets lua tables with various definitions and values
 	void setDefinitions();
 	// Binds functions, so that they can be called from the lua script

+ 1 - 1
Praxis3D/Source/LuminancePass.h

@@ -6,7 +6,7 @@ class LuminancePass : public RenderPass
 {
 public:
 	LuminancePass(RendererFrontend &p_renderer) :
-		RenderPass(p_renderer),
+		RenderPass(p_renderer, RenderPassType::RenderPassType_Luminance),
 		m_histogramBuffer(BufferType_ElementArray, BufferBindTarget_ShaderStorage, BufferUsageHint_DynamicDraw),
 		m_luminanceAverageTexture(Loaders::texture2D().create("LuminanceTexture", 1, 1, TextureFormat_Red, TextureDataFormat_R16F, TextureDataType_Float)),
 		m_luminanceHistogramShader(nullptr),

+ 7 - 4
Praxis3D/Source/Math.h

@@ -77,11 +77,12 @@ namespace Math
 	}
 	const inline glm::quat eulerDegreesToQuaterion(const glm::vec3 &p_degrees) noexcept
 	{
-		glm::quat qPitch = glm::angleAxis(glm::radians(p_degrees.x), glm::vec3(1, 0, 0));
-		glm::quat qYaw = glm::angleAxis(glm::radians(p_degrees.y), glm::vec3(0, 1, 0));
-		glm::quat qRoll = glm::angleAxis(glm::radians(p_degrees.z), glm::vec3(0, 0, 1));
+		return glm::quat{glm::radians(p_degrees)};
+		//glm::quat qPitch = glm::angleAxis(glm::radians(p_degrees.x), glm::vec3(1, 0, 0));
+		//glm::quat qYaw = glm::angleAxis(glm::radians(p_degrees.y), glm::vec3(0, 1, 0));
+		//glm::quat qRoll = glm::angleAxis(glm::radians(p_degrees.z), glm::vec3(0, 0, 1));
 
-		return glm::normalize(qPitch * qYaw * qRoll);
+		//return glm::normalize(qPitch * qYaw * qRoll);
 	}
 
 	const inline FMOD_VECTOR toFmodVector(const glm::vec3 &p_vec) noexcept { return FMOD_VECTOR{ p_vec.x, p_vec.y, p_vec.z }; }
@@ -96,6 +97,8 @@ namespace Math
 
 	const inline glm::vec3 toGlmVec3(const btVector3 &p_vec) noexcept { return glm::vec3(p_vec.getX(), p_vec.getY(), p_vec.getZ()); }
 
+	const inline glm::vec4 toGlmVec4(const glm::quat &p_quat) noexcept { return glm::vec4(p_quat.x, p_quat.y, p_quat.z, p_quat.w); }
+
 	const inline glm::quat toGlmQuat(const btQuaternion &p_quat) noexcept { return glm::quat(p_quat.getW(), p_quat.getX(), p_quat.getY(), p_quat.getZ()); }
 
 	const inline btQuaternion toBtQuaternion(const glm::quat &p_quat) noexcept { return btQuaternion(p_quat.x, p_quat.y, p_quat.z, p_quat.w); }

+ 10 - 2
Praxis3D/Source/MetadataComponent.h

@@ -36,16 +36,24 @@ public:
 	BitMask getSystemType() final override { return Systems::World; }
 
 	BitMask getDesiredSystemChanges() final override { return Systems::Changes::None; }
-	BitMask getPotentialSystemChanges() final override { return Systems::Changes::None; }
+	BitMask getPotentialSystemChanges() final override { return Systems::Changes::Generic::Name; }
 	inline EntityID getParentEntityID() const { return m_parent; }
+	const inline std::string getPrefabName() const { return m_prefab; }
+	const inline bool getUsesPrefab() const { return !m_prefab.empty(); }
 
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType)
 	{
-
+		if(CheckBitmask(p_changeType, Systems::Changes::Generic::Name))
+		{
+			setName(p_subject->getString(this, Systems::Changes::Generic::Name));
+		}
 	}
 
 private:
 	inline void setParent(const EntityID p_parentEntityID) { m_parent = p_parentEntityID; }
+	inline void setPrefabName(const std::string p_prefabName) { m_prefab = p_prefabName; }
 
 	EntityID m_parent;
+
+	std::string m_prefab;
 };

+ 49 - 1
Praxis3D/Source/ModelComponent.h

@@ -58,7 +58,7 @@ public:
 
 		std::size_t m_numOfMeshes;
 		std::vector<std::vector<std::string>> m_meshMaterials;
-		std::vector< std::vector<glm::vec2>> m_meshMaterialsScale;
+		std::vector<std::vector<glm::vec2>> m_meshMaterialsScale;
 		std::vector<float> m_alphaThreshold;
 		std::vector<float> m_heightScale;
 		std::vector<bool> m_present;
@@ -443,6 +443,54 @@ public:
 
 	const inline std::vector<ModelData> &getModelData() const { return m_modelData; }
 
+	inline void getMeshMaterialsProperties(MeshMaterialsProperties &p_modelsProperties) const
+	{
+		// Go over each model
+		for(decltype(m_modelData.size()) modelSize = m_modelData.size(), modelIndex = 0; modelIndex < modelSize; modelIndex++)
+		{
+			// Loop over each mesh
+			for(decltype(m_modelData[modelIndex].m_meshes.size()) meshSize = m_modelData[modelIndex].m_meshes.size(), meshIndex = 0; meshIndex < meshSize; meshIndex++)
+			{
+				// Declaration of material and scale vectors, that are filled in during the material loop
+				std::vector<std::string> meshMaterials;
+				std::vector<glm::vec2> meshMaterialScales;
+				bool materialPresent = false;
+
+				// Loop over each material
+				for(unsigned int materialIndex = 0; materialIndex < MaterialType::MaterialType_NumOfTypes; materialIndex++)
+				{
+					// Add texture filename only if the texture is not a default placeholder
+					if(Loaders::texture2D().isTextureDefault(m_modelData[modelIndex].m_meshes[meshIndex].m_materials[materialIndex].m_texture))
+						meshMaterials.push_back(std::string());
+					else
+					{
+						meshMaterials.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_materials[materialIndex].m_texture.getFilename());
+						materialPresent = true;
+					}
+
+					// Add texture scale
+					meshMaterialScales.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_materials[materialIndex].m_textureScale);
+				}
+
+				p_modelsProperties.m_meshMaterials.push_back(meshMaterials);
+				p_modelsProperties.m_meshMaterialsScale.push_back(meshMaterialScales);
+				p_modelsProperties.m_alphaThreshold.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_alphaThreshold);
+				p_modelsProperties.m_heightScale.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_heightScale);
+				p_modelsProperties.m_present.push_back(materialPresent);
+				p_modelsProperties.m_numOfMeshes++;
+			}
+		}
+	}
+	inline void getModelsProperties(ModelsProperties &p_modelsProperties) const
+	{
+		// Go over each model
+		for(decltype(m_modelData.size()) modelSize = m_modelData.size(), modelIndex = 0; modelIndex < modelSize; modelIndex++)
+		{
+			// Add model filename to the models properties
+			p_modelsProperties.m_modelNames.emplace_back(m_modelData[modelIndex].m_model.getFilename());
+		}
+	}
+
 private:
 	inline MaterialData loadMaterialData(PropertySet &p_materialProperty, Model::MaterialArrays &p_materialArraysFromModel, MaterialType p_materialType, std::size_t p_meshIndex)
 	{

+ 3 - 1
Praxis3D/Source/NullObjects.cpp

@@ -11,10 +11,12 @@
 class NullObserver : public Observer
 {
 public:
+	NullObserver() : Observer(Properties::PropertyID::Null) { }
+
 	virtual void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) { }
 };
 
-constexpr NullObserver nullObserver;
+const NullObserver nullObserver;
 
 const glm::quat				NullObjects::NullQuaterion = glm::quat();
 const glm::vec3				NullObjects::NullVec3f = glm::vec3(1.0f);

+ 1 - 1
Praxis3D/Source/NullSystemObjects.cpp

@@ -14,7 +14,7 @@ SystemScene *NullSystemBase::getScene()
 	return &m_nullSystemScene;
 }
 
-NullSystemScene::NullSystemScene(SystemBase *p_system) : SystemScene(p_system, nullptr)
+NullSystemScene::NullSystemScene(SystemBase *p_system) : SystemScene(p_system, nullptr, Properties::PropertyID::Null)
 {
 	m_nullSystemTask.setSystemScene(this);
 }

+ 9 - 0
Praxis3D/Source/ObjectMaterialComponent.h

@@ -47,7 +47,16 @@ public:
 
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType)
 	{
+		if(CheckBitmask(p_changeType, Systems::Changes::World::ObjectMaterialType))
+		{
+			// Get the new material type from the observed subject
+			auto newMaterialType = p_subject->getUnsignedInt(this, Systems::Changes::World::ObjectMaterialType);
 
+			// If the new material type number is within the bounds of the ObjectMaterialType enum, 
+			// cast the number to the enum and assign it as the material type of this component
+			if(newMaterialType < ObjectMaterialType::NumberOfMaterialTypes)
+				m_materialType = static_cast<ObjectMaterialType>(newMaterialType);
+		}
 	}
 
 	inline ObjectMaterialType getObjectMaterialType() const noexcept { return m_materialType; }

+ 7 - 0
Praxis3D/Source/ObserverBase.h

@@ -37,12 +37,19 @@ class ObservedSubject;
 class Observer
 {
 public:
+	Observer(Properties::PropertyID p_objectType) : m_objectType(p_objectType) { }
 	//virtual ~Observer() = 0;
 
 	// This method gets called when data that we are interested changed in observed subject
 	virtual void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) = 0;
 
 	virtual void receiveData(const DataType p_dataType, void *p_data, const bool p_deleteAfterReceiving) { }
+
+	inline Properties::PropertyID getObjectType() const { return m_objectType; }
+	inline void setObjectType(const Properties::PropertyID p_objectType) { m_objectType = p_objectType; }
+
+protected:
+	Properties::PropertyID m_objectType;
 };
 
 class ObservedSubject

+ 52 - 10
Praxis3D/Source/PhysicsScene.cpp

@@ -6,7 +6,7 @@
 
 PhysicsScene *PhysicsScene::s_currentPhysicsScene = nullptr;
 
-PhysicsScene::PhysicsScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader)
+PhysicsScene::PhysicsScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader, Properties::PropertyID::Physics)
 {
 	m_physicsTask = nullptr;
 	m_collisionConfiguration = nullptr;
@@ -14,6 +14,7 @@ PhysicsScene::PhysicsScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : S
 	m_collisionDispatcher = nullptr;
 	m_collisionBroadphase = nullptr;
 	m_dynamicsWorld = nullptr;
+	m_simulationRunning = true;
 }
 
 PhysicsScene::~PhysicsScene()
@@ -92,9 +93,6 @@ ErrorCode PhysicsScene::setup(const PropertySet &p_properties)
 	{
 		switch(p_properties[i].getPropertyID())
 		{
-		case Properties::ObjectPoolSize:
-
-			break;
 		case Properties::Gravity:
 			m_dynamicsWorld->setGravity(Math::toBtVector3(p_properties[i].getVec3f()));
 			break;
@@ -104,13 +102,30 @@ ErrorCode PhysicsScene::setup(const PropertySet &p_properties)
 	// Get the world scene required for reserving the component pools
 	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
 
-	// Reserve every component type that belongs to this scene
-	worldScene->reserve<RigidBodyComponent>(Config::objectPoolVar().regid_body_component_default_pool_size);
-	worldScene->reserve<CollisionEventComponent>(Config::objectPoolVar().regid_body_component_default_pool_size);
+	// Get the property set containing object pool size
+	auto &objectPoolSizeProperty = p_properties.getPropertySetByID(Properties::ObjectPoolSize);
+
+	// Reserve every component type that belongs to this scene (and set the minimum number of objects based on default config)
+	worldScene->reserve<RigidBodyComponent>(std::max(Config::objectPoolVar().regid_body_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::RigidBodyComponent).getInt()));
+	worldScene->reserve<CollisionEventComponent>(std::max(Config::objectPoolVar().regid_body_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::CollisionEventComponent).getInt()));
 
 	return ErrorCode::Success;
 }
 
+void PhysicsScene::exportSetup(PropertySet &p_propertySet)
+{
+	// Get the world scene required for getting the pool sizes
+	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
+
+	// Add object pool sizes
+	auto &objectPoolSizePropertySet = p_propertySet.addPropertySet(Properties::ObjectPoolSize);
+	objectPoolSizePropertySet.addProperty(Properties::RigidBodyComponent, (int)worldScene->getPoolSize<RigidBodyComponent>());
+	objectPoolSizePropertySet.addProperty(Properties::CollisionEventComponent, (int)worldScene->getPoolSize<CollisionEventComponent>());
+
+	// Add physics world properties
+	p_propertySet.addProperty(Properties::Gravity, Math::toGlmVec3(m_dynamicsWorld->getGravity()));
+}
+
 void PhysicsScene::update(const float p_deltaTime)
 {
 	// Get double buffering index
@@ -132,8 +147,11 @@ void PhysicsScene::update(const float p_deltaTime)
 		component.m_numOfStaticCollisions[dbIndex] = 0;
 	}
 
-	// Perform the physics simulation for the time step of the last frame
-	m_dynamicsWorld->stepSimulation(p_deltaTime);
+	if(m_simulationRunning)
+	{
+		// Perform the physics simulation for the time step of the last frame
+		m_dynamicsWorld->stepSimulation(p_deltaTime);
+	}
 
 	// Get the rigid body component view and iterate every entity that contains is
 	auto rigidBodyView = worldScene->getEntityRegistry().view<RigidBodyComponent>();
@@ -329,6 +347,30 @@ std::vector<SystemObject*> PhysicsScene::createComponents(const EntityID p_entit
 	return createComponents(p_entityID, p_constructionInfo.m_physicsComponents, p_startLoading);
 }
 
+void PhysicsScene::exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo)
+{
+	exportComponents(p_entityID, p_constructionInfo.m_physicsComponents);
+}
+
+void PhysicsScene::exportComponents(const EntityID p_entityID, PhysicsComponentsConstructionInfo &p_constructionInfo)
+{
+	// Get the world scene required for getting the entity registry
+	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
+
+	// Get the entity registry 
+	auto &entityRegistry = worldScene->getEntityRegistry();
+
+	// Export RigidBodyComponent
+	auto *rigidBodyComponent = entityRegistry.try_get<RigidBodyComponent>(p_entityID);
+	if(rigidBodyComponent != nullptr)
+	{
+		if(p_constructionInfo.m_rigidBodyConstructionInfo == nullptr)
+			p_constructionInfo.m_rigidBodyConstructionInfo = new RigidBodyComponent::RigidBodyComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_rigidBodyConstructionInfo, *rigidBodyComponent);
+	}
+}
+
 SystemObject *PhysicsScene::createComponent(const EntityID &p_entityID, const RigidBodyComponent::RigidBodyComponentConstructionInfo &p_constructionInfo, const bool p_startLoading)
 {
 	// If valid type was not specified, or object creation failed, return a null object instead
@@ -399,7 +441,7 @@ SystemObject *PhysicsScene::createComponent(const EntityID &p_entityID, const Ri
 				groundTransform.setIdentity();
 				groundTransform.setOrigin(Math::toBtVector3(spatialComponent->getSpatialDataChangeManager().getLocalSpaceData().m_spatialData.m_position));
 				groundTransform.setRotation(Math::toBtQuaternion(spatialComponent->getSpatialDataChangeManager().getLocalSpaceData().m_spatialData.m_rotationQuat));
-				//groundTransform.setFromOpenGLMatrix(&spatialComponent->getSpatialDataChangeManager().getLocalSpaceData().m_transformMat[0][0]);
+				//groundTransform.setFromOpenGLMatrix(&spatialComponent->getSpatialDataChangeManager().getLocalSpaceData().m_transformMatNoScale[0][0]);
 				component.m_motionState.setWorldTransform(groundTransform);
 
 				component.m_motionState.updateMotionStateTrans();

+ 38 - 0
Praxis3D/Source/PhysicsScene.h

@@ -76,6 +76,8 @@ public:
 
 	ErrorCode setup(const PropertySet &p_properties);
 
+	void exportSetup(PropertySet &p_propertySet);
+
 	void activate()
 	{
 		s_currentPhysicsScene = this;
@@ -108,18 +110,52 @@ public:
 
 		return components;
 	}
+	
+	void exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo);
+	void exportComponents(const EntityID p_entityID, PhysicsComponentsConstructionInfo &p_constructionInfo);
 
 	SystemObject *createComponent(const EntityID &p_entityID, const RigidBodyComponent::RigidBodyComponentConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
 	void createCollisionEventComponent(const EntityID &p_entityID);
+
+	void exportComponent(RigidBodyComponent::RigidBodyComponentConstructionInfo &p_constructionInfo, const RigidBodyComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+
+		p_constructionInfo.m_friction = p_component.getRigidBody()->getFriction();
+		p_constructionInfo.m_mass = p_component.getRigidBody()->getMass();
+		p_constructionInfo.m_restitution = p_component.getRigidBody()->getRestitution();
+		p_constructionInfo.m_kinematic = p_component.getRigidBody()->isKinematicObject();
+		p_constructionInfo.m_collisionShapeType = p_component.getCollisionShapeType();
+		p_constructionInfo.m_collisionShapeSize = p_component.getCollisionShapeSize();
+		p_constructionInfo.m_linearVelocity = Math::toGlmVec3(p_component.getRigidBody()->getLinearVelocity());
+	}
+
 	ErrorCode destroyObject(SystemObject *p_systemObject);
 
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) { }
 
+	void receiveData(const DataType p_dataType, void *p_data, const bool p_deleteAfterReceiving)
+	{
+		switch(p_dataType)
+		{
+			case DataType_SimulationActive:
+				m_simulationRunning = static_cast<bool>(p_data);
+				break;
+		}
+	}
+
 	SystemTask *getSystemTask() { return m_physicsTask; };
 	Systems::TypeID getSystemType() { return Systems::TypeID::Physics; };
 	BitMask getDesiredSystemChanges() { return Systems::Changes::Generic::CreateObject || Systems::Changes::Generic::DeleteObject; }
 	BitMask getPotentialSystemChanges() { return Systems::Changes::None; }
 
+	// Fluch the collision contacts of a rigid body (used after changing the collision shape dimensions)
+	void cleanProxyFromPairs(btRigidBody &p_rigidBody)
+	{
+		m_collisionBroadphase->getOverlappingPairCache()->cleanProxyFromPairs(p_rigidBody.getBroadphaseProxy(), m_collisionDispatcher);
+	}
+
 private:
 	// Removes an object from a pool, by iterating checking each pool for matched index; returns true if the object was found and removed
 	inline bool removeObjectFromPool(PhysicsObject &p_object)
@@ -161,4 +197,6 @@ private:
 	btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
 
 	static PhysicsScene *s_currentPhysicsScene;
+
+	bool m_simulationRunning;
 };

+ 1 - 1
Praxis3D/Source/PostProcessPass.h

@@ -7,7 +7,7 @@ class PostProcessPass : public RenderPass
 {
 public:
 	PostProcessPass(RendererFrontend &p_renderer) :
-		RenderPass(p_renderer), 
+		RenderPass(p_renderer, RenderPassType::RenderPassType_NumOfTypes),
 		m_lensFlareParamBuffer(BufferType_Uniform, BufferBindTarget_Uniform, BufferUsageHint_DynamicDraw),
 		m_lensFlareGhostGradient(Loaders::texture2D().load(Config::rendererVar().lens_flare_ghost_gradient_texture))
 	{

+ 5 - 1
Praxis3D/Source/PropertySet.h

@@ -148,6 +148,10 @@ public:
 				&& m_variable.m_vec4f.z == 0.0f && m_variable.m_vec4f.w == 0.0f ? false : true;
 			break;
 		case Property::Type_string:
+			if(m_variable.m_string == "true" || "1")
+				return true;
+			if(m_variable.m_string == "false" || "0")
+				return false;
 			return m_variable.m_string == "" ? false : true;
 			break;
 		case Property::Type_propertyID:
@@ -444,7 +448,7 @@ public:
 			return "";
 			break;
 		case Property::Type_bool:
-			return m_variable.m_bool == false ? "0" : "1";
+			return m_variable.m_bool == false ? "false" : "true";
 			break;
 		case Property::Type_int:
 			return Utilities::toString(m_variable.m_int);

+ 1 - 1
Praxis3D/Source/ReflectionPass.h

@@ -5,7 +5,7 @@
 class ReflectionPass : public RenderPass
 {
 public:
-	ReflectionPass(RendererFrontend &p_renderer) : RenderPass(p_renderer) { }
+	ReflectionPass(RendererFrontend &p_renderer) : RenderPass(p_renderer, RenderPassType::RenderPassType_NumOfTypes) { }
 
 	~ReflectionPass() { }
 

+ 3 - 1
Praxis3D/Source/RenderPassBase.h

@@ -83,7 +83,7 @@ struct RenderPassData
 class RenderPass
 {
 public:
-	RenderPass(RendererFrontend &p_renderer) : m_renderer(p_renderer) { }
+	RenderPass(RendererFrontend &p_renderer, RenderPassType p_renderPassType) : m_renderer(p_renderer), m_renderPassType(p_renderPassType), m_ID(0) { }
 	virtual ~RenderPass() { }
 
 	virtual ErrorCode init() = 0;
@@ -96,9 +96,11 @@ public:
 
 	inline const std::string &getName() const { return m_name; }
 	inline unsigned int getID() const { return m_ID; }
+	RenderPassType getRenderPassType() const { return m_renderPassType; }
 
 protected:
 	unsigned int m_ID;
+	RenderPassType m_renderPassType;
 	std::string m_name;
 
 	RendererFrontend &m_renderer;

+ 15 - 0
Praxis3D/Source/RendererFrontend.cpp

@@ -279,6 +279,21 @@ void RendererFrontend::setRenderingPasses(const RenderingPasses &p_renderingPass
 	glViewport(0, 0, m_frameData.m_screenSize.x, m_frameData.m_screenSize.y);
 }
 
+const RenderingPasses RendererFrontend::getRenderingPasses()
+{
+	RenderingPasses renderPasses;
+
+	for(const auto renderPass : m_renderingPasses)
+	{
+		if(renderPass != nullptr)
+		{
+			renderPasses.push_back(renderPass->getRenderPassType());
+		}
+	}
+
+	return renderPasses;
+}
+
 void RendererFrontend::renderFrame(SceneObjects &p_sceneObjects, const float p_deltaTime)
 {
 	// Adjust rendering resolution if the screen size has changed

+ 2 - 0
Praxis3D/Source/RendererFrontend.h

@@ -63,6 +63,8 @@ public:
 	void setRenderToTextureResolution(const glm::ivec2 p_renderToTextureResolution);
 	void setRenderingPasses(const RenderingPasses &p_renderingPasses);
 
+	const RenderingPasses getRenderingPasses();
+
 	// Renders a complete frame
 	void renderFrame(SceneObjects &p_sceneObjects, const float p_deltaTime);
 

+ 84 - 9
Praxis3D/Source/RendererScene.cpp

@@ -7,7 +7,7 @@
 #include "SpatialComponent.h"
 #include "WorldScene.h"
 
-RendererScene::RendererScene(RendererSystem *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader)
+RendererScene::RendererScene(RendererSystem *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader, Properties::PropertyID::Renderer)
 {
 	m_renderTask = new RenderTask(this, p_system->getRenderer());
 	//m_camera = nullptr;
@@ -39,18 +39,38 @@ ErrorCode RendererScene::setup(const PropertySet &p_properties)
 {
 	// Get the world scene required for reserving the component pools
 	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
-	
-	// Reserve every component type that belongs to this scene
-	worldScene->reserve<CameraComponent>(Config::objectPoolVar().camera_component_default_pool_size);
-	worldScene->reserve<GraphicsLoadToMemoryComponent>(Config::objectPoolVar().model_component_default_pool_size + Config::objectPoolVar().shader_component_default_pool_size);
-	worldScene->reserve<GraphicsLoadToVideoMemoryComponent>(Config::objectPoolVar().model_component_default_pool_size + Config::objectPoolVar().shader_component_default_pool_size);
-	worldScene->reserve<LightComponent>(Config::objectPoolVar().light_component_default_pool_size);
-	worldScene->reserve<ModelComponent>(Config::objectPoolVar().model_component_default_pool_size);
-	worldScene->reserve<ShaderComponent>(Config::objectPoolVar().shader_component_default_pool_size);
+
+	// Get the property set containing object pool size
+	auto &objectPoolSizeProperty = p_properties.getPropertySetByID(Properties::ObjectPoolSize);
+
+	// Get model and shader components pool sizes
+	int modelComponentPoolSize = std::max(Config::objectPoolVar().model_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::ModelComponent).getInt());
+	int shaderComponentPoolSize = std::max(Config::objectPoolVar().shader_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::ShaderComponent).getInt());
+
+	// Reserve every component type that belongs to this scene (and set the minimum number of objects based on default config)
+	worldScene->reserve<CameraComponent>(std::max(Config::objectPoolVar().camera_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::CameraComponent).getInt()));
+	worldScene->reserve<LightComponent>(std::max(Config::objectPoolVar().light_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::LightComponent).getInt()));
+	worldScene->reserve<ModelComponent>(modelComponentPoolSize);
+	worldScene->reserve<ShaderComponent>(shaderComponentPoolSize);
+	worldScene->reserve<GraphicsLoadToMemoryComponent>(modelComponentPoolSize + shaderComponentPoolSize);
+	worldScene->reserve<GraphicsLoadToVideoMemoryComponent>(modelComponentPoolSize + shaderComponentPoolSize);
 
 	return ErrorCode::Success;
 }
 
+void RendererScene::exportSetup(PropertySet &p_propertySet)
+{
+	// Get the world scene required for getting the pool sizes
+	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
+
+	// Add object pool sizes
+	auto &objectPoolSizePropertySet = p_propertySet.addPropertySet(Properties::ObjectPoolSize);
+	objectPoolSizePropertySet.addProperty(Properties::CameraComponent, (int)worldScene->getPoolSize<CameraComponent>());
+	objectPoolSizePropertySet.addProperty(Properties::LightComponent, (int)worldScene->getPoolSize<LightComponent>());
+	objectPoolSizePropertySet.addProperty(Properties::ModelComponent, (int)worldScene->getPoolSize<ModelComponent>());
+	objectPoolSizePropertySet.addProperty(Properties::ShaderComponent, (int)worldScene->getPoolSize<ShaderComponent>());
+}
+
 ErrorCode RendererScene::preload()
 {
 	// Get the entity registry 
@@ -338,6 +358,60 @@ std::vector<SystemObject*> RendererScene::createComponents(const EntityID p_enti
 	return createComponents(p_entityID, p_constructionInfo.m_graphicsComponents, p_startLoading);
 }
 
+void RendererScene::exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo)
+{
+	exportComponents(p_entityID, p_constructionInfo.m_graphicsComponents);
+}
+
+void RendererScene::exportComponents(const EntityID p_entityID, GraphicsComponentsConstructionInfo &p_constructionInfo)
+{
+	// Get the world scene required for getting the entity registry
+	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
+
+	// Get the entity registry 
+	auto &entityRegistry = worldScene->getEntityRegistry();
+
+	// Export CameraComponent
+	auto *cameraComponent = entityRegistry.try_get<CameraComponent>(p_entityID);
+	if(cameraComponent != nullptr)
+	{
+		if(p_constructionInfo.m_cameraConstructionInfo == nullptr)
+			p_constructionInfo.m_cameraConstructionInfo = new CameraComponent::CameraComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_cameraConstructionInfo, *cameraComponent);
+	}
+
+	// Export LightComponent
+	auto *lightComponent = entityRegistry.try_get<LightComponent>(p_entityID);
+	if(lightComponent != nullptr)
+	{
+		if(p_constructionInfo.m_lightConstructionInfo == nullptr)
+			p_constructionInfo.m_lightConstructionInfo = new LightComponent::LightComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_lightConstructionInfo, *lightComponent);
+	}
+
+	// Export ModelComponent
+	auto *modelComponent = entityRegistry.try_get<ModelComponent>(p_entityID);
+	if(modelComponent != nullptr)
+	{
+		if(p_constructionInfo.m_modelConstructionInfo == nullptr)
+			p_constructionInfo.m_modelConstructionInfo = new ModelComponent::ModelComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_modelConstructionInfo, *modelComponent);
+	}
+
+	// Export ShaderComponent
+	auto *shaderComponent = entityRegistry.try_get<ShaderComponent>(p_entityID);
+	if(shaderComponent != nullptr)
+	{
+		if(p_constructionInfo.m_shaderConstructionInfo == nullptr)
+			p_constructionInfo.m_shaderConstructionInfo = new ShaderComponent::ShaderComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_shaderConstructionInfo, *shaderComponent);
+	}
+}
+
 SystemObject *RendererScene::createComponent(const EntityID &p_entityID, const CameraComponent::CameraComponentConstructionInfo &p_constructionInfo, const bool p_startLoading)
 {
 	// If valid type was not specified, or object creation failed, return a null object instead
@@ -355,6 +429,7 @@ SystemObject *RendererScene::createComponent(const EntityID &p_entityID, const C
 		component.setActive(p_constructionInfo.m_active);
 		component.setLoadedToMemory(true);
 		component.setLoadedToVideoMemory(true);
+		component.m_fov = p_constructionInfo.m_fov;
 
 		returnObject = &component;
 	}

+ 54 - 0
Praxis3D/Source/RendererScene.h

@@ -110,6 +110,8 @@ public:
 	// Sets up various scene-specific values (should be called before creating objects / updating)
 	ErrorCode setup(const PropertySet &p_properties);
 
+	void exportSetup(PropertySet &p_propertySet);
+
 	// Preloads all the resources in the scene (as opposed to loading them while rendering, in background threads)
 	ErrorCode preload();
 
@@ -139,11 +141,63 @@ public:
 		return components;
 	}
 
+	void exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo);
+	void exportComponents(const EntityID p_entityID, GraphicsComponentsConstructionInfo &p_constructionInfo);
+
 	SystemObject *createComponent(const EntityID &p_entityID, const CameraComponent::CameraComponentConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
 	SystemObject *createComponent(const EntityID &p_entityID, const LightComponent::LightComponentConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
 	SystemObject *createComponent(const EntityID &p_entityID, const ModelComponent::ModelComponentConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
 	SystemObject *createComponent(const EntityID &p_entityID, const ShaderComponent::ShaderComponentConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
 
+	void exportComponent(CameraComponent::CameraComponentConstructionInfo &p_constructionInfo, const CameraComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+		p_constructionInfo.m_fov = p_component.m_fov;
+	}
+	void exportComponent(LightComponent::LightComponentConstructionInfo &p_constructionInfo, const LightComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+
+		p_constructionInfo.m_lightComponentType = p_component.getLightType();
+
+		switch(p_component.getLightType())
+		{
+			case LightComponent::LightComponentType_directional:
+				p_constructionInfo.m_color = p_component.m_lightComponent.m_directional.m_color;
+				p_constructionInfo.m_intensity = p_component.m_lightComponent.m_directional.m_intensity;
+				p_constructionInfo.m_direction = p_component.m_lightComponent.m_directional.m_direction;
+				break;
+			case LightComponent::LightComponentType_point:
+				p_constructionInfo.m_color = p_component.m_lightComponent.m_point.m_color;
+				p_constructionInfo.m_intensity = p_component.m_lightComponent.m_point.m_intensity;
+				break;
+			case LightComponent::LightComponentType_spot:
+				p_constructionInfo.m_color = p_component.m_lightComponent.m_spot.m_color;
+				p_constructionInfo.m_intensity = p_component.m_lightComponent.m_spot.m_intensity;
+				p_constructionInfo.m_cutoffAngle = p_component.m_lightComponent.m_spot.m_cutoffAngle;
+				break;
+		}
+	}
+	void exportComponent(ModelComponent::ModelComponentConstructionInfo &p_constructionInfo, const ModelComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+
+		p_component.getMeshMaterialsProperties(p_constructionInfo.m_materialsFromProperties);
+		p_component.getModelsProperties(p_constructionInfo.m_modelsProperties);
+	}
+	void exportComponent(ShaderComponent::ShaderComponentConstructionInfo &p_constructionInfo, const ShaderComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+
+		p_constructionInfo.m_fragmentShaderFilename = p_component.getShaderData()->m_shader.getShaderFilename(ShaderType::ShaderType_Fragment);
+		p_constructionInfo.m_geometryShaderFilename = p_component.getShaderData()->m_shader.getShaderFilename(ShaderType::ShaderType_Geometry);
+		p_constructionInfo.m_vetexShaderFilename = p_component.getShaderData()->m_shader.getShaderFilename(ShaderType::ShaderType_Vertex);
+	}
+
 	ErrorCode destroyObject(SystemObject *p_systemObject);
 
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType);

+ 43 - 0
Praxis3D/Source/RendererSystem.cpp

@@ -77,6 +77,49 @@ ErrorCode RendererSystem::setup(const PropertySet &p_properties)
 	return ErrorCode::Success;
 }
 
+void RendererSystem::exportSetup(PropertySet &p_propertySet)
+{
+	// Create the render passes Property Set entry
+	auto &RenderPassesPropertySet = p_propertySet.addPropertySet(Properties::RenderPasses);
+
+	// Get the rendering passes from the renderer
+	auto renderingPasses = m_renderer.getRenderingPasses();
+
+	// Go over each rendering pass
+	for(auto renderPassType : renderingPasses)
+	{
+		// Convert RenderPassType to PropertyID
+		Properties::PropertyID renderPassTypeProperty = Properties::Null;
+		switch(renderPassType)
+		{
+			case RenderPassType::RenderPassType_AtmScattering:
+				renderPassTypeProperty = Properties::AtmScatteringRenderPass;
+				break;
+			case RenderPassType::RenderPassType_Bloom:
+				renderPassTypeProperty = Properties::BloomRenderPass;
+				break;
+			case RenderPassType::RenderPassType_Geometry:
+				renderPassTypeProperty = Properties::GeometryRenderPass;
+				break;
+			case RenderPassType::RenderPassType_GUI:
+				renderPassTypeProperty = Properties::GUIRenderPass;
+				break;
+			case RenderPassType::RenderPassType_Lighting:
+				renderPassTypeProperty = Properties::LightingRenderPass;
+				break;
+			case RenderPassType::RenderPassType_Luminance:
+				renderPassTypeProperty = Properties::LuminanceRenderPass;
+				break;
+			case RenderPassType::RenderPassType_Final:
+				renderPassTypeProperty = Properties::FinalRenderPass;
+				break;
+		}
+
+		// Add the rendering pass array entry and rendering pass type
+		RenderPassesPropertySet.addPropertySet(Properties::ArrayEntry).addProperty(Properties::Type, renderPassTypeProperty);
+	}
+}
+
 ErrorCode RendererSystem::preload()
 {
 	if(m_rendererScene != nullptr)

+ 2 - 0
Praxis3D/Source/RendererSystem.h

@@ -17,6 +17,8 @@ public:
 
 	ErrorCode setup(const PropertySet &p_properties);
 
+	void exportSetup(PropertySet &p_propertySet);
+
 	//virtual ErrorCode destroyScene(SystemScene *p_systemScene);
 
 	virtual ErrorCode preload();

+ 156 - 0
Praxis3D/Source/RigidBodyComponent.cpp

@@ -0,0 +1,156 @@
+#include "PhysicsScene.h"
+#include "RigidBodyComponent.h"
+
+void RigidBodyComponent::changeOccurred(ObservedSubject *p_subject, BitMask p_changeType)
+{
+	// Track what data has been modified
+	BitMask newChanges = Systems::Changes::None;
+
+	// Track whether any spatial data was modified, so that the transform matrix can be recreated
+	bool transformModifed = false;
+
+	// Consider ignoring LocalTransform change, as Bullet can only accept a transform matrix that does not have scale applied to it. LocalTransform however includes scaling.
+	// To avoid scaled transform, only the position is retrieved from the LocalTransform, and the rotation is retrieved by getting a LocalRotation quaternion.
+	// This might cause a problem of getting an out-of-date rotation, as it is not certain if the LocalRotation quaternion has been updated.
+	if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalTransform))
+	{
+		m_motionState.setPosition(p_subject->getMat4(this, Systems::Changes::Spatial::LocalTransform));
+		m_motionState.setRotation(p_subject->getQuaternion(this, Systems::Changes::Spatial::LocalRotation));
+
+		transformModifed = true;
+
+		newChanges |= Systems::Changes::Spatial::LocalTransformNoScale;
+	}
+
+	if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalTransformNoScale))
+	{
+		m_motionState.setWorldTransform(p_subject->getMat4(this, Systems::Changes::Spatial::LocalTransformNoScale));
+
+		transformModifed = true;
+
+		newChanges |= Systems::Changes::Spatial::LocalTransformNoScale;
+	}
+
+	if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalPosition))
+	{
+		m_motionState.setPosition(p_subject->getVec3(this, Systems::Changes::Spatial::LocalPosition));
+
+		transformModifed = true;
+
+		newChanges |= Systems::Changes::Spatial::LocalPosition;
+	}
+
+	if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalRotation))
+	{
+		m_motionState.setRotation(p_subject->getQuaternion(this, Systems::Changes::Spatial::LocalRotation));
+
+		transformModifed = true;
+
+		newChanges |= Systems::Changes::Spatial::LocalRotation;
+	}
+
+	if(transformModifed)
+	{
+		btTransform transform;
+		m_motionState.getWorldTransform(transform);
+
+		m_rigidBody->setWorldTransform(transform);
+		m_rigidBody->getMotionState()->setWorldTransform(transform);
+
+		m_rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
+		m_rigidBody->setAngularVelocity(btVector3(0.0f, 0.0f, 0.0f));
+		m_rigidBody->clearForces();
+		m_rigidBody->activate(true);
+	}
+
+	if(CheckBitmask(p_changeType, Systems::Changes::Spatial::Velocity))
+	{
+		m_rigidBody->setLinearVelocity(Math::toBtVector3(p_subject->getVec3(this, Systems::Changes::Spatial::Velocity)));
+
+		newChanges |= Systems::Changes::Spatial::Velocity;
+	}
+
+	if(CheckBitmask(p_changeType, Systems::Changes::Physics::CollisionShapeSize))
+	{
+		switch(m_collisionShapeType)
+		{
+		case CollisionShapeType::CollisionShapeType_Box:
+			m_collisionShape.m_boxShape->setImplicitShapeDimensions(Math::toBtVector3(p_subject->getVec3(this, Systems::Changes::Physics::CollisionShapeSize)));
+			static_cast<PhysicsScene *>(m_systemScene)->cleanProxyFromPairs(*m_rigidBody);
+			break;
+		case CollisionShapeType::CollisionShapeType_Capsule:
+			break;
+		case CollisionShapeType::CollisionShapeType_Cone:
+			break;
+		case CollisionShapeType::CollisionShapeType_ConvexHull:
+			break;
+		case CollisionShapeType::CollisionShapeType_Cylinder:
+			break;
+		case CollisionShapeType::CollisionShapeType_Sphere:
+			m_collisionShape.m_sphereShape->setImplicitShapeDimensions(Math::toBtVector3(p_subject->getVec3(this, Systems::Changes::Physics::CollisionShapeSize)));
+			static_cast<PhysicsScene *>(m_systemScene)->cleanProxyFromPairs(*m_rigidBody);
+			break;
+		}
+	}
+
+	if(CheckBitmask(p_changeType, Systems::Changes::Physics::CollisionShapeType))
+	{
+		auto collisionShapeTypeNumber = p_subject->getUnsignedInt(this, Systems::Changes::Physics::CollisionShapeType);
+		if(collisionShapeTypeNumber >= 0 && collisionShapeTypeNumber < CollisionShapeType::CollisionShapeType_NumOfTypes)
+		{
+			CollisionShapeType collisionShapeType = static_cast<CollisionShapeType>(collisionShapeTypeNumber);
+		}
+	}
+
+	if(CheckBitmask(p_changeType, Systems::Changes::Physics::Friction))
+	{
+		m_rigidBody->setFriction(p_subject->getFloat(this, Systems::Changes::Physics::Friction));
+	}
+
+	if(CheckBitmask(p_changeType, Systems::Changes::Physics::Mass))
+	{
+		m_rigidBody->setMassProps(p_subject->getFloat(this, Systems::Changes::Physics::Mass), btVector3(0, 0, 0));
+	}
+
+	if(CheckBitmask(p_changeType, Systems::Changes::Physics::Restitution))
+	{
+		m_rigidBody->setRestitution(p_subject->getFloat(this, Systems::Changes::Physics::Restitution));
+	}
+
+	if(CheckBitmask(p_changeType, Systems::Changes::Physics::Kinematic))
+	{
+		bool kinematic = p_subject->getBool(this, Systems::Changes::Physics::Kinematic);
+
+		if(kinematic)
+		{
+			m_rigidBody->setCollisionFlags(m_rigidBody->getCollisionFlags() | btCollisionObject::CollisionFlags::CF_KINEMATIC_OBJECT);
+			m_rigidBody->setActivationState(DISABLE_DEACTIVATION);
+
+			//Globals::phyWorld->removeRigidBody(Obj->BodyRigid);
+			//Obj->BodyRigid->setMassProps(0, btVector3(0, 0, 0));
+			//Obj->BodyRigid->setCollisionFlags(Obj->BodyRigid->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE);
+			//Obj->BodyRigid->setLinearVelocity(btVector3(0, 0, 0));
+			//Obj->BodyRigid->setAngularVelocity(btVector3(0, 0, 0));
+			//Obj->BodyRigid->setActivationState(DISABLE_DEACTIVATION);
+			//Globals::phyWorld->addRigidBody(Obj->BodyRigid);
+		}
+		else
+		{
+			m_rigidBody->setCollisionFlags(btCollisionObject::CollisionFlags::CF_DYNAMIC_OBJECT);
+			m_rigidBody->setActivationState(WANTS_DEACTIVATION);
+
+			//Globals::phySoftWorld->removeRigidBody(Obj->BodyRigid);
+			//btVector3 inertia(0, 0, 0);
+			//Obj->BodyShape->calculateLocalInertia(Obj->Behavior.ObjTraits->Mass, inertia);
+			//Obj->BodyRigid->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
+			//Obj->BodyRigid->setMassProps(Obj->Behavior.ObjTraits->Mass, inertia);
+			//Obj->BodyRigid->updateInertiaTensor();
+			//Obj->BodyRigid->setLinearVelocity(btVector3(0, 0, 0));
+			//Obj->BodyRigid->setAngularVelocity(btVector3(0, 0, 0));
+			//Obj->BodyRigid->setActivationState(WANTS_DEACTIVATION);
+			//Globals::phySoftWorld->addRigidBody(Obj->BodyRigid);
+		}
+	}
+
+	postChanges(newChanges);
+}

+ 47 - 54
Praxis3D/Source/RigidBodyComponent.h

@@ -15,7 +15,8 @@ public:
 		CollisionShapeType_Cone,
 		CollisionShapeType_ConvexHull,
 		CollisionShapeType_Cylinder,
-		CollisionShapeType_Sphere
+		CollisionShapeType_Sphere,
+		CollisionShapeType_NumOfTypes
 	};
 
 	struct RigidBodyComponentConstructionInfo : public SystemObject::SystemObjectConstructionInfo
@@ -229,24 +230,24 @@ public:
 
 		switch(m_collisionShapeType)
 		{
-		case CollisionShapeType::CollisionShapeType_Box:
-			collisionShape = m_collisionShape.m_boxShape;
-			break;
-		case CollisionShapeType::CollisionShapeType_Capsule:
-			collisionShape = m_collisionShape.m_capsuleShape;
-			break;
-		case CollisionShapeType::CollisionShapeType_Cone:
-			collisionShape = m_collisionShape.m_coneShape;
-			break;
-		case CollisionShapeType::CollisionShapeType_ConvexHull:
-			collisionShape = m_collisionShape.m_convexHullShape;
-			break;
-		case CollisionShapeType::CollisionShapeType_Cylinder:
-			collisionShape = m_collisionShape.m_cylinderShape;
-			break;
-		case CollisionShapeType::CollisionShapeType_Sphere:
-			collisionShape = m_collisionShape.m_sphereShape;
-			break;
+			case CollisionShapeType::CollisionShapeType_Box:
+				collisionShape = m_collisionShape.m_boxShape;
+				break;
+			case CollisionShapeType::CollisionShapeType_Capsule:
+				collisionShape = m_collisionShape.m_capsuleShape;
+				break;
+			case CollisionShapeType::CollisionShapeType_Cone:
+				collisionShape = m_collisionShape.m_coneShape;
+				break;
+			case CollisionShapeType::CollisionShapeType_ConvexHull:
+				collisionShape = m_collisionShape.m_convexHullShape;
+				break;
+			case CollisionShapeType::CollisionShapeType_Cylinder:
+				collisionShape = m_collisionShape.m_cylinderShape;
+				break;
+			case CollisionShapeType::CollisionShapeType_Sphere:
+				collisionShape = m_collisionShape.m_sphereShape;
+				break;
 		}
 
 		return collisionShape;
@@ -257,47 +258,37 @@ public:
 	inline btConvexHullShape *getCollisionShapeConvexHull() { return m_collisionShapeType == CollisionShapeType::CollisionShapeType_ConvexHull ? m_collisionShape.m_convexHullShape : nullptr; }
 	inline btCylinderShape *getCollisionShapeCylinder()     { return m_collisionShapeType == CollisionShapeType::CollisionShapeType_Cylinder   ? m_collisionShape.m_cylinderShape   : nullptr; }
 	inline btSphereShape *getCollisionShapeSphere()         { return m_collisionShapeType == CollisionShapeType::CollisionShapeType_Sphere     ? m_collisionShape.m_sphereShape     : nullptr; }
-
-	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType)
+	inline const std::vector<const char *> &getCollisionTypeText() const { return m_collisionShapeTypeText; }
+	inline const btRigidBody *getRigidBody() const { return m_rigidBody; }
+	inline const glm::vec3 getCollisionShapeSize() const
 	{
-		// Track what data has been modified
-		BitMask newChanges = Systems::Changes::None;
-
-		// Consider ignoring LocalTransform change, as Bullet can only accept a transform matrix that does not have scale applied to it. LocalTransform however includes scaling.
-		// To avoid scaled transform, only the position is retrieved from the LocalTransform, and the rotation is retrieved by getting a LocalRotation quaternion.
-		// This might cause a problem of getting an out-of-date rotation, as it is not certain if the LocalRotation quaternion has been updated.
-		if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalTransform))
-		{
-			m_motionState.setPosition(p_subject->getMat4(this, Systems::Changes::Spatial::LocalTransform));
-			m_motionState.setRotation(p_subject->getQuaternion(this, Systems::Changes::Spatial::LocalRotation));
-
-			newChanges |= Systems::Changes::Spatial::LocalTransformNoScale;
-		}
-
-		if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalTransformNoScale))
-		{
-			m_motionState.setWorldTransform(p_subject->getMat4(this, Systems::Changes::Spatial::LocalTransformNoScale));
-
-			newChanges |= Systems::Changes::Spatial::LocalTransformNoScale;
-		}
-		
-		if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalPosition))
-		{
-			m_motionState.setPosition(p_subject->getVec3(this, Systems::Changes::Spatial::LocalPosition));
-
-			newChanges |= Systems::Changes::Spatial::LocalPosition;
-		}
-
-		if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalRotation))
+		switch(m_collisionShapeType)
 		{
-			m_motionState.setRotation(p_subject->getQuaternion(this, Systems::Changes::Spatial::LocalRotation));
-
-			newChanges |= Systems::Changes::Spatial::LocalRotation;
+			case CollisionShapeType::CollisionShapeType_Box:
+				return Math::toGlmVec3(m_collisionShape.m_boxShape->getImplicitShapeDimensions());
+				break;
+			case CollisionShapeType::CollisionShapeType_Capsule:
+				return Math::toGlmVec3(m_collisionShape.m_capsuleShape->getImplicitShapeDimensions());
+				break;
+			case CollisionShapeType::CollisionShapeType_Cone:
+				return Math::toGlmVec3(m_collisionShape.m_coneShape->getImplicitShapeDimensions());
+				break;
+			case CollisionShapeType::CollisionShapeType_ConvexHull:
+				return Math::toGlmVec3(m_collisionShape.m_convexHullShape->getImplicitShapeDimensions());
+				break;
+			case CollisionShapeType::CollisionShapeType_Cylinder:
+				return Math::toGlmVec3(m_collisionShape.m_cylinderShape->getImplicitShapeDimensions());
+				break;
+			case CollisionShapeType::CollisionShapeType_Sphere:
+				return Math::toGlmVec3(m_collisionShape.m_sphereShape->getImplicitShapeDimensions());
+				break;
 		}
 
-		postChanges(newChanges);
+		return glm::vec3(0.5f);
 	}
 
+	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType);
+
 	const glm::mat4 &getMat4(const Observer *p_observer, BitMask p_changedBits)								const override { return m_motionState.getWorldTransform(); }
 	const glm::quat &getQuaternion(const Observer *p_observer, BitMask p_changedBits)						const override { return m_motionState.getRotation(); }
 	const glm::vec3 &getVec3(const Observer *p_observer, BitMask p_changedBits)								const override { return m_motionState.getPosition(); }
@@ -315,6 +306,8 @@ private:
 
 	CollisionShapeType m_collisionShapeType;
 
+	std::vector<const char *> m_collisionShapeTypeText { "null", "Box", "Capsule", "Cone", "Convex hull", "Cylinder", "Sphere" };
+
 	btRigidBody *m_rigidBody; 
 	
 	btRigidBody::btRigidBodyConstructionInfo *m_constructionInfo;

+ 505 - 28
Praxis3D/Source/SceneLoader.cpp

@@ -168,34 +168,88 @@ ErrorCode SceneLoader::saveToFile(const std::string p_filename)
 
 	if(!filename.empty())
 	{
-		PropertySet propertySet(Properties::Default);
+		// Get the world scene required for getting the entity registry
+		WorldScene *worldScene = static_cast<WorldScene *>(m_systemScenes[Systems::World]);
+
+		// Get the entity registry 
+		auto &entityRegistry = worldScene->getEntityRegistry();
+
+		// Add root property set for the whole file
+		PropertySet rootPropertySet(Properties::Default);
+
+		// Add root property set game objects
+		auto &gameObjects = rootPropertySet.addPropertySet(Properties::GameObject);
+
+		// An array holding all of the entities
+		std::vector<EntityID> allEntities;
+
+		// Add all entities to the array
+		entityRegistry.each([&](auto entity)
+			{
+				allEntities.push_back(entity);
+			});
+
+		// Sort the entities so they are written to file in order
+		std::sort(allEntities.begin(), allEntities.end());
+
+		// Iterate every entity
+		for(auto &entity : allEntities)
+		{
+			// Create an array entry for the entity
+			auto &gameObjectEntry = gameObjects.addPropertySet(Properties::ArrayEntry);
+
+			// Export the entity to the Construction Info
+			ComponentsConstructionInfo constructionInfo;
+			worldScene->exportEntity(entity, constructionInfo);
+
+			// Export the Construction Info to the Property Set
+			exportToProperties(constructionInfo, gameObjectEntry);
+		}
 
 		// Add scene loaded properties
-		propertySet.addProperty(Properties::LoadInBackground, m_loadInBackground);
-		
+		rootPropertySet.addProperty(Properties::LoadInBackground, m_loadInBackground);
+
 		// Add root property set for systems
-		auto &systems = propertySet.addPropertySet(Properties::Systems);
+		auto &rootSystemsPropertySet = rootPropertySet.addPropertySet(Properties::Systems);
 
 		// Add each system's properties
-		//for(size_t i = 0; i < Systems::NumberOfSystems; i++)
-		//	systems.addPropertySet(m_systemScenes[i]->exportObject());
-
-		// Add root property set for object links
-		auto &objLinksPropertySet = propertySet.addPropertySet(Properties::ObjectLinks);
+		for(size_t systemType = 0; systemType < Systems::NumberOfSystems; systemType++)
+		{
+			// Convert TypeID to PropertyID
+			Properties::PropertyID systemTypeProperty = Properties::Null;
+			switch(systemType)
+			{
+				case Systems::TypeID::Audio:
+					systemTypeProperty = Properties::Audio;
+					break;
+				case Systems::TypeID::Graphics:
+					systemTypeProperty = Properties::Graphics;
+					break;
+				case Systems::TypeID::GUI:
+					systemTypeProperty = Properties::GUI;
+					break;
+				case Systems::TypeID::Physics:
+					systemTypeProperty = Properties::Physics;
+					break;
+				case Systems::TypeID::Script:
+					systemTypeProperty = Properties::Script;
+					break;
+				case Systems::TypeID::World:
+					systemTypeProperty = Properties::World;
+					break;
+			}
 
-		// Get object links from the change controller
-		/*auto &objLinkList = m_changeController->getObjectLinksList();
+			// Add system type entry
+			auto &systemPropertyIDentry = rootSystemsPropertySet.addPropertySet(systemTypeProperty);
 
-		for(UniversalScene::ObjectLinkList::const_iterator it = objLinkList.begin(); it != objLinkList.end(); it++)
-		{
-			auto &objectLinkEntry = objLinksPropertySet.addPropertySet(Properties::ArrayEntry);
-			objectLinkEntry.addProperty(Properties::Subject, it->m_observerName);
-			objectLinkEntry.addProperty(Properties::Observer, it->m_subjectName);
-		}*/
+			// Add scene and system settings
+			m_systemScenes[systemType]->exportSetup(systemPropertyIDentry.addPropertySet(Properties::Scene));
+			m_systemScenes[systemType]->getSystem()->exportSetup(systemPropertyIDentry.addPropertySet(Properties::System));
+		}
 
 		// Save properties to a file
-		PropertyLoader savedProperties(Config::filepathVar().map_path + filename);
-		ErrorCode loaderError = savedProperties.saveToFile(propertySet);
+		PropertyLoader savedProperties(filename);
+		ErrorCode loaderError = savedProperties.saveToFile(rootPropertySet);
 
 		// Check if loading was successful, return an error, if not
 		if(loaderError != ErrorCode::Success)
@@ -300,17 +354,19 @@ void SceneLoader::importFromProperties(ComponentsConstructionInfo &p_constructio
 		switch(p_properties[i].getPropertyID())
 		{
 			case Properties::Parent:
-			{
-				// Get the entity ID if the parent object
-				p_constructionInfo.m_parent = (EntityID)p_properties[i].getInt();
-			}
-			break;
+				{
+					// Get the entity ID if the parent object
+					p_constructionInfo.m_parent = (EntityID)p_properties[i].getInt();
+				}
+				break;
 
 			case Properties::Prefab:
-			{
-				importPrefab(p_constructionInfo, p_properties[i].getString());
-			}
-			break;
+				{
+					std::string prefabName = p_properties[i].getString();
+					importPrefab(p_constructionInfo, prefabName);
+					p_constructionInfo.m_prefab = prefabName;
+				}
+				break;
 		}
 	}
 
@@ -944,3 +1000,424 @@ void SceneLoader::importFromProperties(WorldComponentsConstructionInfo &p_constr
 		}
 	}
 }
+
+void SceneLoader::exportToProperties(const ComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties)
+{
+	p_properties.addProperty(Properties::PropertyID::Name, p_constructionInfo.m_name);
+	p_properties.addProperty(Properties::PropertyID::ID, (int)p_constructionInfo.m_id);
+	p_properties.addProperty(Properties::PropertyID::Parent, (int)p_constructionInfo.m_parent);
+
+	if(!p_constructionInfo.m_prefab.empty())
+		p_properties.addProperty(Properties::PropertyID::Prefab, p_constructionInfo.m_prefab);
+
+	// Export audio components
+	exportToProperties(p_constructionInfo.m_audioComponents, p_properties);
+
+	// Export graphics components
+	exportToProperties(p_constructionInfo.m_graphicsComponents, p_properties);
+
+	// Export GUI components
+	exportToProperties(p_constructionInfo.m_guiComponents, p_properties);
+
+	// Export physics components
+	exportToProperties(p_constructionInfo.m_physicsComponents, p_properties);
+
+	// Export script components
+	exportToProperties(p_constructionInfo.m_scriptComponents, p_properties);
+
+	// Export world components
+	exportToProperties(p_constructionInfo.m_worldComponents, p_properties);
+}
+
+void SceneLoader::exportToProperties(const AudioComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties)
+{
+	if(	p_constructionInfo.m_soundConstructionInfo != nullptr ||
+		p_constructionInfo.m_soundListenerConstructionInfo != nullptr)
+	{
+		auto &propertySet = p_properties.addPropertySet(Properties::PropertyID::Audio);
+
+		// Export SoundComponent
+		if(p_constructionInfo.m_soundConstructionInfo != nullptr)
+		{
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::SoundComponent);
+
+			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_soundConstructionInfo->m_active);
+			componentPropertySet.addProperty(Properties::PropertyID::Filename, p_constructionInfo.m_soundConstructionInfo->m_soundFilename);
+			switch(p_constructionInfo.m_soundConstructionInfo->m_soundType)
+			{
+				case SoundComponent::SoundType::SoundType_Ambient:
+					componentPropertySet.addProperty(Properties::PropertyID::Type, Properties::PropertyID::Ambient);
+					break;
+				case SoundComponent::SoundType::SoundType_Music:
+					componentPropertySet.addProperty(Properties::PropertyID::Type, Properties::PropertyID::Music);
+					break;
+				case SoundComponent::SoundType::SoundType_SoundEffect:
+					componentPropertySet.addProperty(Properties::PropertyID::Type, Properties::PropertyID::SoundEffect);
+					break;
+			}
+			componentPropertySet.addProperty(Properties::PropertyID::Loop, p_constructionInfo.m_soundConstructionInfo->m_loop);
+			componentPropertySet.addProperty(Properties::PropertyID::Spatialized, p_constructionInfo.m_soundConstructionInfo->m_spatialized);
+			componentPropertySet.addProperty(Properties::PropertyID::StartPlaying, p_constructionInfo.m_soundConstructionInfo->m_startPlaying);
+			componentPropertySet.addProperty(Properties::PropertyID::Volume, p_constructionInfo.m_soundConstructionInfo->m_volume);
+		}
+
+		// Export SoundListenerComponent
+		if(p_constructionInfo.m_soundListenerConstructionInfo != nullptr)
+		{
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::SoundListenerComponent);
+
+			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_soundListenerConstructionInfo->m_active);
+			//componentPropertySet.addProperty(Properties::PropertyID::ListenerID, p_constructionInfo.m_soundListenerConstructionInfo->m_listenerID);
+		}
+	}
+}
+
+void SceneLoader::exportToProperties(const GraphicsComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties)
+{
+	if(p_constructionInfo.m_cameraConstructionInfo != nullptr ||
+		p_constructionInfo.m_lightConstructionInfo != nullptr ||
+		p_constructionInfo.m_modelConstructionInfo != nullptr ||
+		p_constructionInfo.m_shaderConstructionInfo != nullptr)
+	{
+		auto &propertySet = p_properties.addPropertySet(Properties::PropertyID::Graphics);
+
+		// Export CameraComponent
+		if(p_constructionInfo.m_cameraConstructionInfo != nullptr)
+		{
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::CameraComponent);
+
+			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_cameraConstructionInfo->m_active);
+			//componentPropertySet.addProperty(Properties::PropertyID::FOV, p_constructionInfo.m_cameraConstructionInfo->m_fov);
+		}
+
+		// Export LightComponent
+		if(p_constructionInfo.m_lightConstructionInfo != nullptr)
+		{
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::LightComponent);
+
+			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_lightConstructionInfo->m_active);
+			switch(p_constructionInfo.m_lightConstructionInfo->m_lightComponentType)
+			{
+				case LightComponent::LightComponentType::LightComponentType_directional:
+					componentPropertySet.addProperty(Properties::PropertyID::Type, Properties::PropertyID::DirectionalLight);
+					componentPropertySet.addProperty(Properties::PropertyID::Color, p_constructionInfo.m_lightConstructionInfo->m_color);
+					componentPropertySet.addProperty(Properties::PropertyID::Intensity, p_constructionInfo.m_lightConstructionInfo->m_intensity);
+					break;
+				case LightComponent::LightComponentType::LightComponentType_point:
+					componentPropertySet.addProperty(Properties::PropertyID::Type, Properties::PropertyID::PointLight);
+					componentPropertySet.addProperty(Properties::PropertyID::Color, p_constructionInfo.m_lightConstructionInfo->m_color);
+					componentPropertySet.addProperty(Properties::PropertyID::Intensity, p_constructionInfo.m_lightConstructionInfo->m_intensity);
+					break;
+				case LightComponent::LightComponentType::LightComponentType_spot:
+					componentPropertySet.addProperty(Properties::PropertyID::Type, Properties::PropertyID::SpotLight);
+					componentPropertySet.addProperty(Properties::PropertyID::Color, p_constructionInfo.m_lightConstructionInfo->m_color);
+					componentPropertySet.addProperty(Properties::PropertyID::Intensity, p_constructionInfo.m_lightConstructionInfo->m_intensity);
+					componentPropertySet.addProperty(Properties::PropertyID::CutoffAngle, p_constructionInfo.m_lightConstructionInfo->m_cutoffAngle);
+					break;
+			}
+
+		}
+
+		// Export ModelComponent
+		if(p_constructionInfo.m_modelConstructionInfo != nullptr)
+		{
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::ModelComponent);
+
+			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_modelConstructionInfo->m_active);
+
+			auto &modelsPropertySet = componentPropertySet.addPropertySet(Properties::PropertyID::Models);
+
+			// Go over each model
+			for(auto &model : p_constructionInfo.m_modelConstructionInfo->m_modelsProperties.m_modelNames)
+			{
+				auto &modelPropertyArrayEntry = modelsPropertySet.addPropertySet(Properties::ArrayEntry);
+
+				// Add model data
+				modelPropertyArrayEntry.addProperty(Properties::PropertyID::Filename, model);
+
+				auto &meshesPropertySet = modelPropertyArrayEntry.addPropertySet(Properties::PropertyID::Meshes);
+
+				// Go over each mesh
+				for(decltype(p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_numOfMeshes) i = 0; i < p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_numOfMeshes; i++)
+				{
+					// Make sure the mesh data is present
+					if(p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_present[i])
+					{
+						auto &meshPropertyArrayEntry = meshesPropertySet.addPropertySet(Properties::ArrayEntry);
+
+						// Add mesh data
+						meshPropertyArrayEntry.addProperty(Properties::PropertyID::Index, (int)i);
+						meshPropertyArrayEntry.addProperty(Properties::PropertyID::AlphaThreshold, p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_alphaThreshold[i]);
+						meshPropertyArrayEntry.addProperty(Properties::PropertyID::HeightScale, p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_heightScale[i]);
+
+						auto &materialsPropertySet = meshPropertyArrayEntry.addPropertySet(Properties::Materials);
+
+						// Go over each material
+						for(unsigned int materialType = 0; materialType < MaterialType::MaterialType_NumOfTypes; materialType++)
+						{
+							// Make sure the material filename is not empty
+							if(!p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_meshMaterials[i][materialType].empty())
+							{
+								Properties::PropertyID materialPropertyID = Properties::Null;
+
+								// Convert MaterialType to PropertyID
+								switch(materialType)
+								{
+									case MaterialType_Diffuse:
+										materialPropertyID = Properties::Diffuse;
+										break;
+									case MaterialType_Normal:
+										materialPropertyID = Properties::Normal;
+										break;
+									case MaterialType_Emissive:
+										materialPropertyID = Properties::Emissive;
+										break;
+									case MaterialType_Combined:
+										materialPropertyID = Properties::RMHAO;
+										break;
+								}
+								auto &materialPropertySet = materialsPropertySet.addPropertySet(materialPropertyID);
+
+								// Add material data
+								materialPropertySet.addProperty(Properties::PropertyID::Filename, p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_meshMaterials[i][materialType]);
+								materialPropertySet.addProperty(Properties::PropertyID::TextureScale, p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_meshMaterialsScale[i][materialType]);
+							}
+						}
+					}
+				}
+
+
+
+			}
+
+			modelsPropertySet.addPropertySet(Properties::ArrayEntry);
+		}
+
+		// Export ShaderComponent
+		if(p_constructionInfo.m_shaderConstructionInfo != nullptr)
+		{
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::ShaderComponent);
+
+			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_shaderConstructionInfo->m_active);
+
+			// Add shader data, making sure isn't not empty before adding it
+			if(!p_constructionInfo.m_shaderConstructionInfo->m_fragmentShaderFilename.empty())
+				componentPropertySet.addProperty(Properties::PropertyID::FragmentShader, p_constructionInfo.m_shaderConstructionInfo->m_fragmentShaderFilename);
+			if(!p_constructionInfo.m_shaderConstructionInfo->m_vetexShaderFilename.empty())
+				componentPropertySet.addProperty(Properties::PropertyID::VertexShader, p_constructionInfo.m_shaderConstructionInfo->m_vetexShaderFilename);
+			if(!p_constructionInfo.m_shaderConstructionInfo->m_geometryShaderFilename.empty())
+				componentPropertySet.addProperty(Properties::PropertyID::GeometryShader, p_constructionInfo.m_shaderConstructionInfo->m_geometryShaderFilename);
+		}
+	}
+}
+
+void SceneLoader::exportToProperties(const GUIComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties)
+{
+	if(p_constructionInfo.m_guiSequenceConstructionInfo != nullptr)
+	{
+		auto &propertySet = p_properties.addPropertySet(Properties::PropertyID::GUI);
+
+		// Export GUISequenceComponent
+		if(p_constructionInfo.m_guiSequenceConstructionInfo != nullptr)
+		{
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::GUISequenceComponent);
+
+			// Add GUI sequence data
+			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_guiSequenceConstructionInfo->m_active);
+			componentPropertySet.addProperty(Properties::PropertyID::Static, p_constructionInfo.m_guiSequenceConstructionInfo->m_staticSequence);
+		}
+	}
+}
+
+void SceneLoader::exportToProperties(const PhysicsComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties)
+{
+	if(p_constructionInfo.m_rigidBodyConstructionInfo != nullptr)
+	{
+		auto &propertySet = p_properties.addPropertySet(Properties::PropertyID::Physics);
+
+		// Export RigidBodyComponent
+		if(p_constructionInfo.m_rigidBodyConstructionInfo != nullptr)
+		{
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::RigidBodyComponent);
+
+			// Add rigid body data
+			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_rigidBodyConstructionInfo->m_active);
+			componentPropertySet.addProperty(Properties::PropertyID::Friction, p_constructionInfo.m_rigidBodyConstructionInfo->m_friction);
+			componentPropertySet.addProperty(Properties::PropertyID::Mass, p_constructionInfo.m_rigidBodyConstructionInfo->m_mass);
+			componentPropertySet.addProperty(Properties::PropertyID::Restitution, p_constructionInfo.m_rigidBodyConstructionInfo->m_restitution);
+			componentPropertySet.addProperty(Properties::PropertyID::Kinematic, p_constructionInfo.m_rigidBodyConstructionInfo->m_kinematic);
+
+			// Convert CollisionShapeType to PropertyID
+			Properties::PropertyID collisionShapeType = Properties::Null;
+			switch(p_constructionInfo.m_rigidBodyConstructionInfo->m_collisionShapeType)
+			{
+				case RigidBodyComponent::CollisionShapeType_Box:
+					collisionShapeType = Properties::Box;
+					break;
+				case RigidBodyComponent::CollisionShapeType_Capsule:
+					collisionShapeType = Properties::Capsule;
+					break;
+				case RigidBodyComponent::CollisionShapeType_Cone:
+					collisionShapeType = Properties::Cone;
+					break;
+				case RigidBodyComponent::CollisionShapeType_ConvexHull:
+					collisionShapeType = Properties::ConvexHull;
+					break;
+				case RigidBodyComponent::CollisionShapeType_Cylinder:
+					collisionShapeType = Properties::Cylinder;
+					break;
+				case RigidBodyComponent::CollisionShapeType_Sphere:
+					collisionShapeType = Properties::Sphere;
+					break;
+			}
+
+			// Add collision shape data, if it's valid
+			if(collisionShapeType != Properties::Null)
+			{
+				auto &collisionShapePropertySet = componentPropertySet.addPropertySet(Properties::PropertyID::CollisionShape);
+				collisionShapePropertySet.addProperty(Properties::PropertyID::Type, collisionShapeType);
+				collisionShapePropertySet.addProperty(Properties::PropertyID::Size, p_constructionInfo.m_rigidBodyConstructionInfo->m_collisionShapeSize);
+			}
+		}
+	}
+}
+
+void SceneLoader::exportToProperties(const ScriptComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties)
+{
+	if(p_constructionInfo.m_luaConstructionInfo != nullptr)
+	{
+		auto &propertySet = p_properties.addPropertySet(Properties::PropertyID::Script);
+
+		// Export LuaComponent
+		if(p_constructionInfo.m_luaConstructionInfo != nullptr)
+		{
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::LuaComponent);
+
+			// Add LUA component data
+			if(!p_constructionInfo.m_luaConstructionInfo->m_luaScriptFilename.empty())
+			{
+				componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_luaConstructionInfo->m_active);
+				componentPropertySet.addProperty(Properties::PropertyID::Filename, p_constructionInfo.m_luaConstructionInfo->m_luaScriptFilename);
+
+				if(!p_constructionInfo.m_luaConstructionInfo->m_variables.empty())
+				{
+					auto &variablesPropertySet = componentPropertySet.addPropertySet(Properties::PropertyID::Variables);
+
+					// Go over each variable
+					for(auto &variable : p_constructionInfo.m_luaConstructionInfo->m_variables)
+					{
+						// Make sure variable type is valid
+						if(variable.second.getVariableType() != Property::PropertyVariableType::Type_null)
+						{
+							auto &variableArrayEntry = variablesPropertySet.addPropertySet(Properties::PropertyID::ArrayEntry);
+
+							// Add variable data
+							variableArrayEntry.addProperty(Properties::PropertyID::Name, variable.first);
+
+							// Add the appropriate data based on the variable's data type
+							switch(variable.second.getVariableType())
+							{
+								case Property::PropertyVariableType::Type_bool:
+									variableArrayEntry.addProperty(Properties::PropertyID::Value, variable.second.getBool());
+									break;
+								case Property::PropertyVariableType::Type_int:
+									variableArrayEntry.addProperty(Properties::PropertyID::Value, variable.second.getInt());
+									break;
+								case Property::PropertyVariableType::Type_float:
+									variableArrayEntry.addProperty(Properties::PropertyID::Value, variable.second.getFloat());
+									break;
+								case Property::PropertyVariableType::Type_double:
+									variableArrayEntry.addProperty(Properties::PropertyID::Value, variable.second.getDouble());
+									break;
+								case Property::PropertyVariableType::Type_vec2i:
+									variableArrayEntry.addProperty(Properties::PropertyID::Value, variable.second.getVec2i());
+									break;
+								case Property::PropertyVariableType::Type_vec2f:
+									variableArrayEntry.addProperty(Properties::PropertyID::Value, variable.second.getVec2f());
+									break;
+								case Property::PropertyVariableType::Type_vec3f:
+									variableArrayEntry.addProperty(Properties::PropertyID::Value, variable.second.getVec3f());
+									break;
+								case Property::PropertyVariableType::Type_vec4f:
+									variableArrayEntry.addProperty(Properties::PropertyID::Value, variable.second.getVec4f());
+									break;
+								case Property::PropertyVariableType::Type_string:
+									variableArrayEntry.addProperty(Properties::PropertyID::Value, variable.second.getString());
+									break;
+								case Property::PropertyVariableType::Type_propertyID:
+									variableArrayEntry.addProperty(Properties::PropertyID::Value, variable.second.getID());
+									break;
+							}
+						}
+					}
+
+				}
+			}
+		}
+	}
+
+	std::string m_luaScriptFilename;
+	std::vector<std::pair<std::string, Property>> m_variables;
+}
+
+void SceneLoader::exportToProperties(const WorldComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties)
+{
+	if(	p_constructionInfo.m_objectMaterialConstructionInfo != nullptr ||
+		p_constructionInfo.m_spatialConstructionInfo != nullptr)
+	{
+		auto &propertySet = p_properties.addPropertySet(Properties::PropertyID::World);
+
+		// Export ObjectMaterialComponent
+		if(p_constructionInfo.m_objectMaterialConstructionInfo != nullptr)
+		{
+			// Convert ObjectMaterialType to PropertyID
+			Properties::PropertyID objectMaterialType = Properties::Null;
+			switch(p_constructionInfo.m_objectMaterialConstructionInfo->m_materialType)
+			{
+				case Concrete:
+					objectMaterialType = Properties::Concrete;
+					break;
+				case Glass:
+					objectMaterialType = Properties::Glass;
+					break;
+				case Metal:
+					objectMaterialType = Properties::Metal;
+					break;
+				case Plastic:
+					objectMaterialType = Properties::Plastic;
+					break;
+				case Rock:
+					objectMaterialType = Properties::Rock;
+					break;
+				case Rubber:
+					objectMaterialType = Properties::Rubber;
+					break;
+				case Wood:
+					objectMaterialType = Properties::Wood;
+					break;
+			}
+
+			// Add object material data, if it's valid
+			if(objectMaterialType != Properties::Null)
+			{
+				auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::ObjectMaterialComponent);
+
+				componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_objectMaterialConstructionInfo->m_active);
+				componentPropertySet.addProperty(Properties::PropertyID::Type, objectMaterialType);
+			}
+		}
+
+		// Export SpatialComponent
+		if(p_constructionInfo.m_spatialConstructionInfo != nullptr)
+		{
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::SpatialComponent);
+
+			// Add spatial data
+			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_spatialConstructionInfo->m_active);
+			componentPropertySet.addProperty(Properties::PropertyID::LocalPosition, p_constructionInfo.m_spatialConstructionInfo->m_localPosition);
+			componentPropertySet.addProperty(Properties::PropertyID::LocalRotation, p_constructionInfo.m_spatialConstructionInfo->m_localRotationEuler);
+			componentPropertySet.addProperty(Properties::PropertyID::LocalRotationQuaternion, Math::toGlmVec4(p_constructionInfo.m_spatialConstructionInfo->m_localRotationQuaternion));
+			componentPropertySet.addProperty(Properties::PropertyID::LocalScale, p_constructionInfo.m_spatialConstructionInfo->m_localScale);
+		}
+	}
+}

+ 19 - 0
Praxis3D/Source/SceneLoader.h

@@ -36,11 +36,21 @@ public:
 	inline SystemScene *getSystemScene(Systems::TypeID p_systemType) const { return m_systemScenes[p_systemType]; }
 	inline UniversalScene *getChangeController() const { return m_changeController; }
 
+	// Load a scene from file, pass it along to every system scene and create every entity
 	ErrorCode loadFromFile(const std::string &p_filename);
+
+	// Export the entire entity registry and system scene settings to file
 	ErrorCode saveToFile(const std::string p_filename = "");
 
+	// Load a single prefab from file
 	ErrorCode importPrefab(ComponentsConstructionInfo &p_constructionInfo, const std::string &p_filename, const bool p_forceReload = false);
 
+	// Returns all prefabs that have been loaded during scene loading
+	const std::map<std::string, ComponentsConstructionInfo> &getPrefabs() { return m_prefabs; }
+
+	// Returns the last loaded scene filename
+	const std::string &getSceneFilename() const { return m_filename; }
+
 private:
 	ErrorCode importFromFile(ComponentsConstructionInfo &p_constructionInfo, const std::string &p_filename);
 	void importFromProperties(ComponentsConstructionInfo &p_constructionInfo, const PropertySet &p_properties);
@@ -51,6 +61,15 @@ private:
 	void importFromProperties(ScriptComponentsConstructionInfo &p_constructionInfo, const PropertySet &p_properties, const std::string &p_name);
 	void importFromProperties(WorldComponentsConstructionInfo &p_constructionInfo, const PropertySet &p_properties, const std::string &p_name);
 
+	void exportToProperties(const ComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties);
+	void exportToProperties(const AudioComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties);
+	void exportToProperties(const GraphicsComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties);
+	void exportToProperties(const GUIComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties);
+	void exportToProperties(const PhysicsComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties);
+	void exportToProperties(const ScriptComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties);
+	void exportToProperties(const WorldComponentsConstructionInfo &p_constructionInfo, PropertySet &p_properties);
+
+
 	// Mutex used to block calls from other threads while import operation is in progress
 	SpinWait m_mutex;
 

+ 1 - 1
Praxis3D/Source/ScriptObject.h

@@ -129,7 +129,7 @@ public:
 
 
 			// Calculate model matrix
-			//m_worldSpace.m_transformMat = Math::createTransformMat(m_worldSpace.m_spatialData.m_position, m_worldSpace.m_spatialData.m_rotationEuler, m_worldSpace.m_spatialData.m_scale);
+			//m_worldSpace.m_transformMatNoScale = Math::createTransformMat(m_worldSpace.m_spatialData.m_position, m_worldSpace.m_spatialData.m_rotationEuler, m_worldSpace.m_spatialData.m_scale);
 
 			// Update components
 			//if(modelComponentPresent())

+ 40 - 16
Praxis3D/Source/ScriptScene.cpp

@@ -8,7 +8,7 @@
 #include "TaskManagerLocator.h"
 #include "WorldScene.h"
 
-ScriptScene::ScriptScene(ScriptSystem *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader)
+ScriptScene::ScriptScene(ScriptSystem *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader, Properties::PropertyID::Script)
 {
 	m_scriptingTask = nullptr;
 	m_luaScriptsEnabled = true;
@@ -29,28 +29,28 @@ ErrorCode ScriptScene::init()
 
 ErrorCode ScriptScene::setup(const PropertySet &p_properties)
 {
-	// Get default object pool size
-	int objectPoolSize = Config::objectPoolVar().object_pool_size;
-
-	for(decltype(p_properties.getNumProperties()) i = 0, size = p_properties.getNumProperties(); i < size; i++)
-	{
-		switch(p_properties[i].getPropertyID())
-		{
-		case Properties::ObjectPoolSize:
-			objectPoolSize = p_properties[i].getInt();
-			break;
-		}
-	}
-
 	// Get the world scene required for reserving the component pools
 	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
 
-	// Reserve every component type that belongs to this scene
-	worldScene->reserve<LuaComponent>(Config::objectPoolVar().lua_component_default_pool_size);
+	// Get the property set containing object pool size
+	auto &objectPoolSizeProperty = p_properties.getPropertySetByID(Properties::ObjectPoolSize);
+
+	// Reserve every component type that belongs to this scene (and set the minimum number of objects based on default config)
+	worldScene->reserve<LuaComponent>(std::max(Config::objectPoolVar().lua_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::LuaComponent).getInt()));
 
 	return ErrorCode::Success;
 }
 
+void ScriptScene::exportSetup(PropertySet &p_propertySet)
+{
+	// Get the world scene required for getting the pool sizes
+	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
+
+	// Add object pool sizes
+	auto &objectPoolSizePropertySet = p_propertySet.addPropertySet(Properties::ObjectPoolSize);
+	objectPoolSizePropertySet.addProperty(Properties::LuaComponent, (int)worldScene->getPoolSize<LuaComponent>());
+}
+
 void ScriptScene::update(const float p_deltaTime)
 {
 	// Get the world scene required for getting components
@@ -134,6 +134,30 @@ std::vector<SystemObject*> ScriptScene::createComponents(const EntityID p_entity
 	return createComponents(p_entityID, p_constructionInfo.m_scriptComponents, p_startLoading);
 }
 
+void ScriptScene::exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo)
+{
+	exportComponents(p_entityID, p_constructionInfo.m_scriptComponents);
+}
+
+void ScriptScene::exportComponents(const EntityID p_entityID, ScriptComponentsConstructionInfo &p_constructionInfo)
+{
+	// Get the world scene required for getting the entity registry
+	WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
+
+	// Get the entity registry 
+	auto &entityRegistry = worldScene->getEntityRegistry();
+
+	// Export LuaComponent
+	auto *luaComponent = entityRegistry.try_get<LuaComponent>(p_entityID);
+	if(luaComponent != nullptr)
+	{
+		if(p_constructionInfo.m_luaConstructionInfo == nullptr)
+			p_constructionInfo.m_luaConstructionInfo = new LuaComponent::LuaComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_luaConstructionInfo, *luaComponent);
+	}
+}
+
 SystemObject *ScriptScene::createComponent(const EntityID &p_entityID, const LuaComponent::LuaComponentConstructionInfo &p_constructionInfo, const bool p_startLoading)
 {	
 	// If valid type was not specified, or object creation failed, return a null object instead

+ 19 - 1
Praxis3D/Source/ScriptScene.h

@@ -46,7 +46,9 @@ public:
 
 	ErrorCode init();
 
-	ErrorCode setup(const PropertySet &p_properties);
+	ErrorCode setup(const PropertySet &p_properties); 
+	
+	void exportSetup(PropertySet &p_propertySet);
 
 	void update(const float p_deltaTime);
 
@@ -65,7 +67,23 @@ public:
 		return components;
 	}
 
+	void exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo);
+	void exportComponents(const EntityID p_entityID, ScriptComponentsConstructionInfo &p_constructionInfo);
+
 	SystemObject *createComponent(const EntityID &p_entityID, const LuaComponent::LuaComponentConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
+
+	void exportComponent(LuaComponent::LuaComponentConstructionInfo &p_constructionInfo, const LuaComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+
+		if(p_component.getLuaScript() != nullptr)
+		{
+			p_constructionInfo.m_luaScriptFilename = Utilities::stripFilename(p_component.getLuaScript()->getLuaScriptFilename());
+			p_constructionInfo.m_variables = p_component.getLuaScript()->getLuaVariables();
+		}
+	}
+
 	ErrorCode destroyObject(SystemObject *p_systemObject);
 
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType);

+ 1 - 1
Praxis3D/Source/SkyPass.h

@@ -7,7 +7,7 @@ class SkyPass : public RenderPass
 {
 public:
 	SkyPass(RendererFrontend &p_renderer) :
-		RenderPass(p_renderer) { }
+		RenderPass(p_renderer, RenderPassType::RenderPassType_NumOfTypes) { }
 
 	~SkyPass() { }
 

+ 3 - 1
Praxis3D/Source/SoundListenerComponent.h

@@ -45,10 +45,12 @@ public:
 
 	BitMask getDesiredSystemChanges() final override { return Systems::Changes::Audio::All; }
 	BitMask getPotentialSystemChanges() final override { return Systems::Changes::None; }
+	const inline int getListenerID() const { return m_listenerID; }
 
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType)
 	{
-
+		if(CheckBitmask(p_changeType, Systems::Changes::Audio::ListenerID))
+			m_listenerID = p_subject->getInt(this, Systems::Changes::Audio::ListenerID);
 	}
 
 private:

+ 87 - 34
Praxis3D/Source/SpatialDataManager.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <atomic>
+#include <iostream>
 
 #include "Containers.h"
 #include "CommonDefinitions.h"
@@ -46,7 +47,9 @@ public:
 		m_worldTransformUpToDate = p_spatialDataManager.m_worldTransformUpToDate;
 		m_localSpace = p_spatialDataManager.m_localSpace;
 		m_parentTransform = p_spatialDataManager.m_parentTransform;
-		m_worldTransform = p_spatialDataManager.m_worldTransform;
+		m_localTransformWithScale = p_spatialDataManager.m_localTransformWithScale;
+		m_worldTransformWithScale = p_spatialDataManager.m_worldTransformWithScale;
+		m_worldTransformNoScale = p_spatialDataManager.m_worldTransformNoScale;
 		m_updateCount = p_spatialDataManager.m_updateCount;
 		m_changes = p_spatialDataManager.m_changes;
 
@@ -60,7 +63,7 @@ public:
 		{
 			if(!m_localPositionUpToDate)
 			{
-				m_localSpace.m_spatialData.m_position = m_localSpace.m_transformMat[3];
+				m_localSpace.m_spatialData.m_position = m_localSpace.m_transformMatNoScale[3];
 				m_localPositionUpToDate = true;
 
 				if(m_trackLocalChanges)
@@ -76,7 +79,14 @@ public:
 			if(!m_localQuaternionUpToDate)
 			{
 				if(m_localTransformUpToDate)
-					m_localSpace.m_spatialData.m_rotationQuat = glm::toQuat(m_localSpace.m_transformMat);
+				{
+					m_localSpace.m_spatialData.m_rotationQuat = glm::toQuat(m_localSpace.m_transformMatNoScale);
+					const glm::mat3 rotMtx(
+						glm::vec3(m_localSpace.m_transformMatNoScale[0]),
+						glm::vec3(m_localSpace.m_transformMatNoScale[1]),
+						glm::vec3(m_localSpace.m_transformMatNoScale[2]));
+					m_localSpace.m_spatialData.m_rotationQuat = glm::quat_cast(rotMtx);
+				}
 				else
 					m_localSpace.m_spatialData.m_rotationQuat = Math::eulerDegreesToQuaterion(m_localSpace.m_spatialData.m_rotationEuler);
 
@@ -95,7 +105,7 @@ public:
 				glm::vec3 skew;
 				glm::vec4 perspective;
 
-				glm::decompose(m_localSpace.m_transformMat, m_localSpace.m_spatialData.m_scale, rotation, translation, skew, perspective);
+				glm::decompose(m_localSpace.m_transformMatNoScale, m_localSpace.m_spatialData.m_scale, rotation, translation, skew, perspective);
 				m_localScaleUpToDate = true;
 
 				if(m_trackLocalChanges)
@@ -104,10 +114,9 @@ public:
 
 			if(!m_localTransformUpToDate)
 			{
-				m_localSpace.m_transformMat = Math::createTransformMat(
+				m_localSpace.m_transformMatNoScale = Math::createTransformMat(
 					m_localSpace.m_spatialData.m_position, 
-					m_localSpace.m_spatialData.m_rotationQuat, 
-					m_localSpace.m_spatialData.m_scale);
+					m_localSpace.m_spatialData.m_rotationQuat);
 
 				m_localTransformUpToDate = true;
 
@@ -121,7 +130,8 @@ public:
 		// Calculate the world transform if it's outdated
 		if(!m_worldTransformUpToDate)
 		{
-			m_worldTransform = m_localSpace.m_transformMat * m_parentTransform;
+			m_worldTransformNoScale = m_localSpace.m_transformMatNoScale * m_parentTransform;
+			m_worldTransformWithScale = glm::scale(m_worldTransformNoScale, m_localSpace.m_spatialData.m_scale);
 
 			m_worldTransformUpToDate = true;
 
@@ -179,14 +189,15 @@ public:
 
 					if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalTransform))
 					{
-						setLocalTransform(p_subject.getMat4(&m_parent, Systems::Changes::Spatial::LocalTransform));
+						setLocalTransformWithScale(p_subject.getMat4(&m_parent, Systems::Changes::Spatial::LocalTransform));
 						localOrWorldTransformChanged = true;
 					}
 
 					if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalTransformNoScale))
 					{
-						// Scale the local transform before assigning it
-						setLocalTransform(glm::scale(p_subject.getMat4(&m_parent, Systems::Changes::Spatial::LocalTransform), m_localSpace.m_spatialData.m_scale));
+						//setLocalTransform(glm::scale(p_subject.getMat4(&m_parent, Systems::Changes::Spatial::LocalTransform), m_localSpace.m_spatialData.m_scale));
+						setLocalTransform(p_subject.getMat4(&m_parent, Systems::Changes::Spatial::LocalTransformNoScale));
+
 						localOrWorldTransformChanged = true;
 					}
 				}
@@ -214,7 +225,8 @@ public:
 		// Update the world-space data if any changes have been made
 		if(localOrWorldTransformChanged)
 		{
-			m_worldTransform = m_localSpace.m_transformMat * m_parentTransform;
+			m_worldTransformNoScale = m_localSpace.m_transformMatNoScale * m_parentTransform;
+			m_worldTransformWithScale = glm::scale(m_worldTransformNoScale, m_localSpace.m_spatialData.m_scale);
 
 			m_worldTransformUpToDate = true;
 
@@ -227,15 +239,19 @@ public:
 
 	// Get local-space spatial data
 	const inline SpatialTransformData &getLocalSpaceData() const { return m_localSpace; }
+	inline SpatialTransformData &getLocalSpaceDataNonConst() { return m_localSpace; }
 
 	// Get local-space transform
-	const inline glm::mat4 &getLocalTransform() const { return m_localSpace.m_transformMat; }
+	const inline glm::mat4 &getLocalTransform() const { return m_localSpace.m_transformMatNoScale; }
 
 	// Get world-space transform of the parent
 	const inline glm::mat4 &getParemtTransform() const { return m_parentTransform; }
 
 	// Get world-space transform (combination of the local-space and the parent objects world-space)
-	const inline glm::mat4 &getWorldTransform() const { return m_worldTransform; }
+	const inline glm::mat4 &getWorldTransform() const { return m_worldTransformNoScale; }
+
+	// Get world-space transform with scale applied (combination of the local-space and the parent objects world-space)
+	const inline glm::mat4 &getWorldTransformWithScale() const { return m_worldTransformWithScale; }
 
 	// Get the current velocity
 	const inline glm::vec3 &getVelocity() const { return m_velocity; }
@@ -270,18 +286,20 @@ public:
 	{
 		switch(p_changedBits)
 		{
+		// Apply scale to the local transform matrix
 		case Systems::Changes::Spatial::LocalTransform:
-			return m_localSpace.m_transformMat;
 
-		// Construct a local transform matrix without scaling it
+			m_localTransformWithScale = glm::scale(m_localSpace.m_transformMatNoScale, m_localSpace.m_spatialData.m_scale);
+			return m_localTransformWithScale;
+
 		case Systems::Changes::Spatial::LocalTransformNoScale:
-			m_localTransformNoScale = Math::createTransformMat(
-				m_localSpace.m_spatialData.m_position,
-				m_localSpace.m_spatialData.m_rotationQuat);
-			return m_localTransformNoScale;
+			return m_localSpace.m_transformMatNoScale;
 		
 		case Systems::Changes::Spatial::WorldTransform:
-			return m_worldTransform;
+			return m_worldTransformNoScale;
+
+		case Systems::Changes::Spatial::WorldTransformNoScale:
+			return m_worldTransformNoScale;
 		}
 
 		return NullObjects::NullMat4f;
@@ -326,7 +344,7 @@ public:
 	{
 		m_localSpace = p_spatialDataManager.m_localSpace;
 		m_parentTransform = p_spatialDataManager.m_parentTransform;
-		m_worldTransform = p_spatialDataManager.m_worldTransform;
+		m_worldTransformNoScale = p_spatialDataManager.m_worldTransformNoScale;
 
 		m_localEverythingUpToDate = p_spatialDataManager.m_localEverythingUpToDate;
 		m_localPositionUpToDate = p_spatialDataManager.m_localPositionUpToDate;
@@ -401,7 +419,7 @@ public:
 	}
 	const inline void setLocalTransform(const glm::mat4 p_transform)
 	{
-		m_localSpace.m_transformMat = p_transform;
+		m_localSpace.m_transformMatNoScale = p_transform;
 
 		// Updated variables
 		m_localTransformUpToDate = true;
@@ -415,7 +433,24 @@ public:
 		m_localScaleUpToDate = false;
 
 		if(m_trackLocalChanges)
-			m_changes |= Systems::Changes::Spatial::LocalTransform;
+			m_changes |= Systems::Changes::Spatial::LocalTransformNoScale;
+	}
+	const inline void setLocalTransformWithScale(const glm::mat4 p_transform)
+	{
+		m_localTransformWithScale = p_transform;
+
+		glm::vec3 scale;
+		glm::quat rotation;
+		glm::vec3 translation;
+		glm::vec3 skew;
+		glm::vec4 perspective;
+		glm::decompose(m_localTransformWithScale, scale, rotation, translation, skew, perspective);
+
+		m_localSpace.m_spatialData.m_position = translation;
+		m_localSpace.m_spatialData.m_rotationQuat = rotation;
+		m_localSpace.m_spatialData.m_scale = scale;
+
+		setLocalTransform(Math::createTransformMat(m_localSpace.m_spatialData.m_position, m_localSpace.m_spatialData.m_rotationQuat));
 	}
 	const inline void setLocalSpatialData(const SpatialData &p_spatialData)
 	{
@@ -466,9 +501,9 @@ public:
 	// Set world transform, that should be the combination of local and parent transforms
 	const inline void setWorldTransform(const glm::mat4 p_transform)		
 	{ 
-		m_worldTransform = p_transform;
+		m_worldTransformNoScale = p_transform;
 
-		m_changes |= Systems::Changes::Spatial::WorldTransform;
+		m_changes |= Systems::Changes::Spatial::WorldTransformNoScale;
 	}
 
 	const inline void calculateLocalTransform() 
@@ -476,8 +511,25 @@ public:
 		updateTransformMatrix(m_localSpace); 
 	}
 
-private:
+	// Manually updates the local rotation Euler angles, as they are not automatically updated
+	const inline void calculateLocalRotationEuler()
+	{
+		if(!m_localQuaternionUpToDate)
+		{
+			if(m_localTransformUpToDate)
+				m_localSpace.m_spatialData.m_rotationQuat = glm::toQuat(m_localSpace.m_transformMatNoScale);
+			else
+				m_localSpace.m_spatialData.m_rotationQuat = Math::eulerDegreesToQuaterion(m_localSpace.m_spatialData.m_rotationEuler);
+
+			m_localQuaternionUpToDate = true;
+		}
 
+		m_localSpace.m_spatialData.m_rotationEuler = glm::degrees(glm::eulerAngles(m_localSpace.m_spatialData.m_rotationQuat));
+
+		m_localEulerUpToDate = true;
+	}
+
+private:
 	const inline void localDataChanged()
 	{
 		m_localTransformUpToDate = false;
@@ -487,9 +539,8 @@ private:
 	// Recalculates the model transform matrix in the world-space
 	void updateTransformMatrix(SpatialTransformData &p_spacialTransformData)
 	{
-		p_spacialTransformData.m_transformMat = Math::createTransformMat(	p_spacialTransformData.m_spatialData.m_position, 
-																			p_spacialTransformData.m_spatialData.m_rotationEuler, 
-																			p_spacialTransformData.m_spatialData.m_scale);
+		p_spacialTransformData.m_transformMatNoScale = Math::createTransformMat(p_spacialTransformData.m_spatialData.m_position, 
+																				p_spacialTransformData.m_spatialData.m_rotationEuler);
 	}
 
 	// Increments the update count; should be called after any data has been changed
@@ -517,10 +568,12 @@ private:
 	SpatialTransformData m_localSpace;
 	// Transform data in world space the parent object
 	glm::mat4 m_parentTransform;
-	// Transform data in world space (local and parent space added together), final transform data used for rendering
-	glm::mat4 m_worldTransform;
-	// A local transform matrix constructed without scaling it
-	mutable glm::mat4 m_localTransformNoScale;
+	// Transform data in world space (local and parent space added together), with scale applied, final transform data used for rendering
+	glm::mat4 m_worldTransformWithScale;
+	// Transform data in world space (local and parent space added together)
+	glm::mat4 m_worldTransformNoScale;
+	// A local transform matrix constructed while scaling it
+	mutable glm::mat4 m_localTransformWithScale;
 	// Current velocity vector
 	glm::vec3 m_velocity;
 

+ 2 - 2
Praxis3D/Source/System.cpp

@@ -3,14 +3,14 @@
 #include "ObjectDirectory.h"
 #include "System.h"
 
-SystemObject::SystemObject() : m_initialized(false), m_active(false), m_updateNeeded(false), m_systemScene(nullptr), m_objectType(Properties::Null), m_objectID(0)
+SystemObject::SystemObject() : Observer(Properties::Null), m_initialized(false), m_active(false), m_updateNeeded(false), m_systemScene(nullptr), m_objectID(0)
 {
 	setName("Null Object");
 	m_entityID = NULL_ENTITY_ID;
 	//m_objectID = ObjectDirectory::registerObject(*this);
 }
 
-SystemObject::SystemObject(SystemScene *p_systemScene, const std::string &p_name, Properties::PropertyID p_objectType, EntityID p_entityID) : m_initialized(false), m_active(false), m_updateNeeded(false), m_systemScene(p_systemScene), m_objectType(p_objectType), m_objectID(0), m_entityID(p_entityID)
+SystemObject::SystemObject(SystemScene *p_systemScene, const std::string &p_name, Properties::PropertyID p_objectType, EntityID p_entityID) : Observer(p_objectType), m_initialized(false), m_active(false), m_updateNeeded(false), m_systemScene(p_systemScene), m_objectID(0), m_entityID(p_entityID)
 {
 	setName(p_name);
 	m_objectID = ObjectDirectory::registerObject(*this);

+ 12 - 7
Praxis3D/Source/System.h

@@ -29,13 +29,16 @@ class SystemBase
 {
 public:
 	SystemBase() : m_initialized(false) { }
-	//~SystemBase();
 
 	virtual ErrorCode init() = 0;
 	//virtual ErrorCode destroyScene(SystemScene *p_systemScene) = 0;
 
+	// Internal system data-driven setup based on passed properties
 	virtual ErrorCode setup(const PropertySet &p_properties) = 0;
 
+	// Exports all the system settings
+	virtual void exportSetup(PropertySet &p_propertySet) { }
+
 	virtual Systems::TypeID getSystemType() = 0;
 	virtual std::string getName() { return m_systemName; }
 
@@ -56,8 +59,8 @@ class SystemScene : public ObservedSubject, public Observer
 {
 	friend SystemBase;
 public:
-	SystemScene(SystemBase *p_system, SceneLoader *p_sceneLoader)
-		: m_initialized(false), m_system(p_system), m_sceneLoader(p_sceneLoader) { }
+	SystemScene(SystemBase *p_system, SceneLoader *p_sceneLoader, Properties::PropertyID p_objectType)
+		: Observer(p_objectType), m_initialized(false), m_system(p_system), m_sceneLoader(p_sceneLoader) { }
 	//~SystemScene();
 
 	// Gets the parent system
@@ -68,6 +71,9 @@ public:
 
 	// Internal scene data-driven setup based on passed properties
 	virtual ErrorCode setup(const PropertySet &p_properties) = 0;
+
+	// Exports all the scene settings
+	virtual void exportSetup(PropertySet &p_propertySet) { }
 	
 	// Activation is called when the engine play state containing this scene is made current (activated)
 	virtual void activate() { }
@@ -87,6 +93,9 @@ public:
 	// Create all the components that belong to this scene, that are contained in ComponentsConstructionInfo; return a vector of all created components
 	virtual std::vector<SystemObject*> createComponents(const EntityID p_entityID, const ComponentsConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
 
+	// Exports all the components that belong to this scene into ComponentsConstructionInfo
+	virtual void exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo) { }
+
 	// Destroy an object that belongs to this system scene
 	virtual ErrorCode destroyObject(SystemObject *p_systemObject) = 0;
 
@@ -157,7 +166,6 @@ public:
 	inline bool isUpdateNeeded() const					{ return m_updateNeeded;				 }
 	const inline std::string &getName() const			{ return m_name;						 }
 	inline SystemScene *getSystemScene() const			{ return m_systemScene;					 }
-	inline Properties::PropertyID getObjectType() const { return m_objectType;					 }
 	const virtual std::string &getString(const Observer *p_observer, BitMask p_changedBits) const
 	{
 		switch(p_changedBits)
@@ -174,7 +182,6 @@ public:
 	inline void setParent(void *p_parent)								 { m_parent = p_parent;				}
 	inline void setName(std::string p_name)								 { m_name = p_name;					}
 	inline void setSystemScene(SystemScene *p_systemScene)				 { m_systemScene = p_systemScene;	}
-	inline void setObjectType(const Properties::PropertyID p_objectType) { m_objectType = p_objectType;		}
 	inline void setActive(const bool p_isActive)						 { m_active = p_isActive;			}
 
 	// Bool operator; returns true if the system object is not null (i.e. valid derived object)
@@ -191,8 +198,6 @@ protected:
 	// Sets the 'update needed' flag to false
 	inline void updatePerformed() { setUpdateNeeded(false); }
 
-	Properties::PropertyID m_objectType;
-
 	void *m_parent;
 	bool m_initialized;
 	bool m_active;

+ 8 - 0
Praxis3D/Source/TextureLoader.h

@@ -352,6 +352,14 @@ public:
 		return Texture2DHandle(returnTexture);
 	}
 
+	inline bool isTextureDefault(const Texture2DHandle &p_textureHandle) const 
+	{ 
+		return p_textureHandle.m_textureData == m_default2DTexture ||
+			p_textureHandle.m_textureData == m_defaultEmissive ||
+			p_textureHandle.m_textureData == m_defaultHeight ||
+			p_textureHandle.m_textureData == m_defaultNormal;
+	}
+
 protected:
 	// Default textures used in place of missing ones when loading textures
 	Texture2D *m_default2DTexture;

+ 2 - 2
Praxis3D/Source/Universal.cpp

@@ -2,6 +2,7 @@
 #include "Universal.h"
 
 UniversalScene::UniversalScene(ChangeController *p_sceneChangeController, ChangeController *p_objectChangeController) : 
+								Observer(Properties::PropertyID::UniversalScene),
 								m_sceneChangeController(p_sceneChangeController), 
 								m_objectChangeController(p_objectChangeController)
 {
@@ -223,8 +224,7 @@ void UniversalScene::changeOccurred(ObservedSubject *p_subject, BitMask p_change
 	}
 }
 
-UniversalObject::UniversalObject(UniversalScene *p_universalScene, std::string p_name)
-	:	m_scene(p_universalScene)
+UniversalObject::UniversalObject(UniversalScene *p_universalScene, std::string p_name) : Observer(Properties::PropertyID::UniversalObject), m_scene(p_universalScene)
 {
 	setName(p_name);
 }

+ 1 - 1
Praxis3D/Source/Universal.h

@@ -35,7 +35,7 @@ public:
 	{
 		// Check if any changes have been done
 		//if(p_changedBits)
-		//	m_objectChangeController->oneTimeChange(p_subject, p_observer, p_changedBits);
+		m_objectChangeController->oneTimeChange(p_subject, p_observer, p_changedBits);
 	}
 
 	// Sends a one-off notification to a system object containing data, without requiring the object linking

+ 84 - 17
Praxis3D/Source/WorldScene.cpp

@@ -6,7 +6,7 @@
 #include "SpatialComponent.h"
 #include "WorldScene.h"
 
-WorldScene::WorldScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader)
+WorldScene::WorldScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader, Properties::PropertyID::World)
 {
 	m_worldTask = new WorldTask(this);
 }
@@ -22,27 +22,26 @@ ErrorCode WorldScene::init()
 
 ErrorCode WorldScene::setup(const PropertySet &p_properties)
 {
-	// Get default object pool size
-	int objectPoolSize = Config::objectPoolVar().object_pool_size;
+	// Get the property set containing object pool size
+	auto &objectPoolSizeProperty = p_properties.getPropertySetByID(Properties::ObjectPoolSize);
 
-	for(decltype(p_properties.getNumProperties()) i = 0, size = p_properties.getNumProperties(); i < size; i++)
-	{
-		switch(p_properties[i].getPropertyID())
-		{
-		case Properties::ObjectPoolSize:
-			objectPoolSize = p_properties[i].getInt();
-			break;
-		}
-	}
-
-	// Reserve every component type that belongs to this scene
-	reserve<MetadataComponent>(Config::objectPoolVar().spatial_component_default_pool_size);
-	reserve<ObjectMaterialComponent>(Config::objectPoolVar().spatial_component_default_pool_size);
-	reserve<SpatialComponent>(Config::objectPoolVar().spatial_component_default_pool_size);
+	// Reserve every component type that belongs to this scene (and set the minimum number of objects based on default config)
+	reserve<MetadataComponent>(std::max(Config::objectPoolVar().spatial_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::MetadataComponent).getInt()));
+	reserve<ObjectMaterialComponent>(std::max(Config::objectPoolVar().spatial_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::ObjectMaterialComponent).getInt()));
+	reserve<SpatialComponent>(std::max(Config::objectPoolVar().spatial_component_default_pool_size, objectPoolSizeProperty.getPropertyByID(Properties::SpatialComponent).getInt()));
 
 	return ErrorCode::Success;
 }
 
+void WorldScene::exportSetup(PropertySet &p_propertySet)
+{
+	// Add object pool sizes
+	auto &objectPoolSizePropertySet = p_propertySet.addPropertySet(Properties::ObjectPoolSize);
+	objectPoolSizePropertySet.addProperty(Properties::MetadataComponent, (int)getPoolSize<MetadataComponent>());
+	objectPoolSizePropertySet.addProperty(Properties::ObjectMaterialComponent, (int)getPoolSize<ObjectMaterialComponent>());
+	objectPoolSizePropertySet.addProperty(Properties::SpatialComponent, (int)getPoolSize<SpatialComponent>());
+}
+
 void WorldScene::update(const float p_deltaTime)
 {
 	//	 ___________________________
@@ -151,6 +150,30 @@ EntityID WorldScene::createEntity(const ComponentsConstructionInfo &p_constructi
 	return newEntity;
 }
 
+void WorldScene::exportEntity(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo)
+{
+	if(m_entityRegistry.valid(p_entityID))
+	{
+		// Export AUDIO components
+		m_sceneLoader->getSystemScene(Systems::Audio)->exportComponents(p_entityID, p_constructionInfo);
+
+		// Export RENDERING components
+		m_sceneLoader->getSystemScene(Systems::Graphics)->exportComponents(p_entityID, p_constructionInfo);
+
+		// Export GUI components
+		m_sceneLoader->getSystemScene(Systems::GUI)->exportComponents(p_entityID, p_constructionInfo);
+
+		// Export PHYSICS components
+		m_sceneLoader->getSystemScene(Systems::Physics)->exportComponents(p_entityID, p_constructionInfo);
+
+		// Export SCRIPTING components
+		m_sceneLoader->getSystemScene(Systems::Script)->exportComponents(p_entityID, p_constructionInfo);
+
+		// Export WORLD components
+		exportComponents(p_entityID, p_constructionInfo);
+	}
+}
+
 std::vector<SystemObject*> WorldScene::createComponents(const EntityID p_entityID, const ComponentsConstructionInfo &p_constructionInfo, const bool p_startLoading)
 {
 	return createComponents(p_entityID, p_constructionInfo.m_worldComponents, p_startLoading);
@@ -169,6 +192,47 @@ std::vector<SystemObject*> WorldScene::createComponents(const EntityID p_entityI
 	return components;
 }
 
+void WorldScene::exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo)
+{
+	p_constructionInfo.m_id = p_entityID;
+
+	// Export MetadataComponent
+	auto *metadataComponent = m_entityRegistry.try_get<MetadataComponent>(p_entityID);
+	if(metadataComponent != nullptr)
+	{
+		p_constructionInfo.m_name = metadataComponent->getName();
+		p_constructionInfo.m_parent = metadataComponent->getParentEntityID();
+
+		if(metadataComponent->getUsesPrefab())
+			p_constructionInfo.m_prefab = metadataComponent->getPrefabName();
+	}
+	else
+	{
+		p_constructionInfo.m_name = GetString(Properties::GameObject) + Utilities::toString(p_entityID);
+		p_constructionInfo.m_parent = 0;
+	}
+
+	// Export SpatialComponent
+	auto *spatialComponent = m_entityRegistry.try_get<SpatialComponent>(p_entityID);
+	if(spatialComponent != nullptr)
+	{
+		if(p_constructionInfo.m_worldComponents.m_spatialConstructionInfo == nullptr)
+			p_constructionInfo.m_worldComponents.m_spatialConstructionInfo = new SpatialComponent::SpatialComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_worldComponents.m_spatialConstructionInfo, *spatialComponent);
+	}
+
+	// Export ObjectMaterialComponent
+	auto *objectMaterialComponent = m_entityRegistry.try_get<ObjectMaterialComponent>(p_entityID);
+	if(objectMaterialComponent != nullptr)
+	{
+		if(p_constructionInfo.m_worldComponents.m_objectMaterialConstructionInfo == nullptr)
+			p_constructionInfo.m_worldComponents.m_objectMaterialConstructionInfo = new ObjectMaterialComponent::ObjectMaterialComponentConstructionInfo();
+
+		exportComponent(*p_constructionInfo.m_worldComponents.m_objectMaterialConstructionInfo, *objectMaterialComponent);
+	}
+}
+
 ErrorCode WorldScene::destroyObject(SystemObject *p_systemObject)
 {
 	ErrorCode returnError = ErrorCode::Success;
@@ -203,6 +267,9 @@ SystemObject *WorldScene::createComponent(const EntityID p_entityID, const Compo
 
 	metadataComponent->setParent(p_constructionInfo.m_parent);
 
+	if(!p_constructionInfo.m_prefab.empty())
+		metadataComponent->setPrefabName(p_constructionInfo.m_prefab);
+	
 	metadataComponent->init();
 
 	return metadataComponent;

+ 38 - 0
Praxis3D/Source/WorldScene.h

@@ -51,6 +51,8 @@ public:
 
 	ErrorCode setup(const PropertySet &p_properties);
 
+	void exportSetup(PropertySet &p_propertySet);
+
 	void update(const float p_deltaTime);
 
 	ErrorCode preload() { return ErrorCode::Success; }
@@ -58,9 +60,13 @@ public:
 	void loadInBackground() { }
 
 	EntityID createEntity(const ComponentsConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
+	void exportEntity(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo);
 
 	std::vector<SystemObject*> createComponents(const EntityID p_entityID, const ComponentsConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
 	std::vector<SystemObject*> createComponents(const EntityID p_entityID, const WorldComponentsConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
+
+	void exportComponents(const EntityID p_entityID, ComponentsConstructionInfo &p_constructionInfo);
+
 	ErrorCode destroyObject(SystemObject *p_systemObject);
 
 	SystemObject *createComponent(const EntityID p_entityID, const ComponentsConstructionInfo &p_constructionInfo, const bool p_startLoading = true);
@@ -71,6 +77,7 @@ public:
 
 		objectMaterialComponent = &addComponent<ObjectMaterialComponent>(p_entityID, this, p_constructionInfo.m_name, p_entityID);
 
+		objectMaterialComponent->setActive(p_constructionInfo.m_active);
 		objectMaterialComponent->m_materialType = p_constructionInfo.m_materialType;
 
 		objectMaterialComponent->init();
@@ -84,6 +91,7 @@ public:
 
 		spatialComponent = &addComponent<SpatialComponent>(p_entityID, this, p_constructionInfo.m_name, p_entityID);
 
+		spatialComponent->setActive(p_constructionInfo.m_active);
 		spatialComponent->m_spatialData.setLocalPosition(p_constructionInfo.m_localPosition);
 		spatialComponent->m_spatialData.setLocalScale(p_constructionInfo.m_localScale);
 
@@ -98,6 +106,29 @@ public:
 		return spatialComponent;
 	}
 
+	void exportComponent(ObjectMaterialComponent::ObjectMaterialComponentConstructionInfo &p_constructionInfo, const ObjectMaterialComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+
+		p_constructionInfo.m_materialType = p_component.getObjectMaterialType();
+	}
+
+	void exportComponent(SpatialComponent::SpatialComponentConstructionInfo &p_constructionInfo, SpatialComponent &p_component)
+	{
+		p_constructionInfo.m_active = p_component.isObjectActive();
+		p_constructionInfo.m_name = p_component.getName();
+
+		// Call update to make sure the spatial data is current
+		p_component.m_spatialData.update();
+		p_component.m_spatialData.calculateLocalRotationEuler();
+
+		p_constructionInfo.m_localPosition = p_component.getSpatialDataChangeManager().getLocalSpaceData().m_spatialData.m_position;
+		p_constructionInfo.m_localRotationEuler = p_component.getSpatialDataChangeManager().getLocalSpaceData().m_spatialData.m_rotationEuler;
+		p_constructionInfo.m_localRotationQuaternion = p_component.getSpatialDataChangeManager().getLocalSpaceData().m_spatialData.m_rotationQuat;
+		p_constructionInfo.m_localScale = p_component.getSpatialDataChangeManager().getLocalSpaceData().m_spatialData.m_scale;
+	}
+
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) { }
 
 	SystemTask *getSystemTask() { return m_worldTask; };
@@ -129,6 +160,13 @@ public:
 		m_entityRegistry.storage<T_Component>().reserve(p_capacity);
 	}
 
+	// Get the internal pool size of a given component
+	template <class T_Component>
+	unsigned int getPoolSize()
+	{
+		return m_entityRegistry.storage<T_Component>().size();
+	}
+
 	inline entt::basic_registry<EntityID> &getEntityRegistry() { return m_entityRegistry; }
 
 private:

+ 187 - 13
Praxis3D/imgui.ini

@@ -1,11 +1,11 @@
 [Window][Debug##Default]
-Pos=521,402
+Pos=364,395
 Size=400,400
 Collapsed=0
 
 [Window][Dear ImGui Demo]
-Pos=1226,163
-Size=548,583
+Pos=66,369
+Size=507,676
 Collapsed=0
 
 [Window][Dear ImGui Stack Tool]
@@ -85,25 +85,25 @@ Collapsed=0
 
 [Window][##LeftWindow]
 Pos=0,69
-Size=292,797
+Size=301,797
 Collapsed=0
 DockId=0x00000001,0
 
 [Window][##RightWindow]
-Pos=1626,69
-Size=294,1011
+Pos=1499,69
+Size=421,1011
 Collapsed=0
 DockId=0x00000008,0
 
 [Window][##BottomWindow]
 Pos=0,868
-Size=1624,212
+Size=1497,212
 Collapsed=0
 DockId=0x00000006,0
 
 [Window][##CenterWindow]
-Pos=294,69
-Size=1330,797
+Pos=303,69
+Size=1194,797
 Collapsed=0
 DockId=0x00000004,0
 
@@ -117,6 +117,56 @@ Pos=60,71
 Size=409,229
 Collapsed=0
 
+[Window][Open LUA script file##LuaScriptFilenameDialog]
+Pos=474,207
+Size=896,564
+Collapsed=0
+
+[Window][Open LUA script file##EditorFileBrowserDialog]
+Pos=549,231
+Size=666,477
+Collapsed=0
+
+[Window][Dear ImGui Metrics/Debugger]
+Pos=335,134
+Size=608,708
+Collapsed=0
+
+[Window][Dear ImGui Debug Log]
+Pos=60,60
+Size=623,156
+Collapsed=0
+
+[Window][Save scene##EditorFileBrowserDialog]
+Pos=511,151
+Size=831,573
+Collapsed=0
+
+[Window][####OpenLuaScriptFileDialog]
+Pos=654,212
+Size=668,440
+Collapsed=0
+
+[Window][####SaveSceneFileDialog]
+Pos=590,204
+Size=826,588
+Collapsed=0
+
+[Window][The file Already Exist !##Save scene##SaveSceneFileDialogOverWriteDialog]
+Pos=883,472
+Size=240,71
+Collapsed=0
+
+[Window][####LoadSceneFileDialog]
+Pos=623,201
+Size=718,546
+Collapsed=0
+
+[Window][####OpenSceneFileDialog]
+Pos=373,134
+Size=1085,711
+Collapsed=0
+
 [Table][0x9A4BDFDE,4]
 RefScale=13
 Column 0  Sort=0v
@@ -297,14 +347,138 @@ Column 0  Sort=0v
 RefScale=13
 Column 0  Sort=0v
 
+[Table][0xEC1161C2,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x242F4E13,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x0C4B34EB,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x90639B51,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x80DBD5DB,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x781035F9,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x821E68A8,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x920F8CFA,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xCD7C42C7,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x686B7325,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xA7A9B5E3,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x180BF5DE,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xA69D6952,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x23059405,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xC49DC663,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xB28796CC,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xA724D5B5,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xD26480BD,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x9A57B4B9,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xBCF550F9,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x2EA74F99,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x1613E6C1,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x14845EB2,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x38EC6FB8,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x023213D4,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xA207CC06,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x2327C7BE,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xA03CAA2D,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x3964C952,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x236E1450,4]
+RefScale=13
+Column 3  Sort=0^
+
+[Table][0x7B9255BE,4]
+RefScale=13
+Column 0  Sort=0v
+
 [Docking][Data]
 DockSpace         ID=0x8B93E3BD Window=0xA787BDB4 Pos=0,69 Size=1920,1011 Split=X
-  DockNode        ID=0x00000007 Parent=0x8B93E3BD SizeRef=1624,1011 Split=Y
+  DockNode        ID=0x00000007 Parent=0x8B93E3BD SizeRef=1497,1011 Split=Y
     DockNode      ID=0x00000005 Parent=0x00000007 SizeRef=1920,725 Split=X
-      DockNode    ID=0x00000001 Parent=0x00000005 SizeRef=292,1011 Selected=0xB1B21E90
-      DockNode    ID=0x00000003 Parent=0x00000005 SizeRef=1330,1011 Split=X
+      DockNode    ID=0x00000001 Parent=0x00000005 SizeRef=301,1011 Selected=0xB1B21E90
+      DockNode    ID=0x00000003 Parent=0x00000005 SizeRef=1194,1011 Split=X
         DockNode  ID=0x00000002 Parent=0x00000003 SizeRef=332,1042 Selected=0xD00C9CD4
         DockNode  ID=0x00000004 Parent=0x00000003 SizeRef=1586,1042 CentralNode=1 Selected=0xFB1B6F35
     DockNode      ID=0x00000006 Parent=0x00000007 SizeRef=1920,212 Selected=0x51C0BD29
-  DockNode        ID=0x00000008 Parent=0x8B93E3BD SizeRef=294,1011 Selected=0x96D2BCA2
+  DockNode        ID=0x00000008 Parent=0x8B93E3BD SizeRef=421,1011 Selected=0x96D2BCA2
 

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików