Browse Source

Added "About" window, font loading, sound event playback

Added an about window showing info about the engine
Added a way to load custom fonts, in CommonDefinitions, GUISystem, GUIHandler
Added a way to completely unload engine states via a message, in Engine
Added an ability to play events from sound banks, in AudioScene, SoundComponent, SceneLoader, EditorWindow
Added a way to check if any scene is currently loading any objects, in EngineState
Added a way for any scene to get the currently active EngineState, in EngineState, SceneLoader
Added a way to send changes to any observer from a Lua script, in LuaComponent, LuaScript
Added a way to pause Lua scripts and for any script to be exempt based on its settings, in ScriptingScene, LuaComponent
Added a way to get the current viewport size from any scene, in RendererScene, Config
Added a way to get an entity ID from its name, in WorldScene
Added Lua scripts for constant rotation of objects
Added Lua script for ambient sound control of day-night cycle
Added Lua script for showing info at the start of the example map
Added default sound bank for ambient sound
Added more user types and function to Lua, in LuaScript
Added more error codes and error strings
Added more Config variables
Fixed a bug of parent object position not being applied to a collision sound position, in AudioScene
Fixed a bug of audio buses not being parsed, in AudioSystem
Fixed a bug of the screen not showing solid black when no-drawing is set, because some rendering passes were still running
Updated LICENSE for an added font
Updated engine version to v0.2.2
Paul A 1 year ago
parent
commit
b1cbdf3ec9
64 changed files with 2553 additions and 724 deletions
  1. 95 0
      LICENSE.md
  2. BIN
      Praxis3D/Data/Fonts/Default/OpenSans-Regular.ttf
  3. 279 49
      Praxis3D/Data/Maps/default.pmap
  4. BIN
      Praxis3D/Data/Materials/Default/GUI/logo2.png
  5. 0 27
      Praxis3D/Data/Scripts/Constant_rotation.lua
  6. 45 0
      Praxis3D/Data/Scripts/Constant_rotation_single_axis.lua
  7. 49 0
      Praxis3D/Data/Scripts/Constant_rotation_two_axes.lua
  8. 48 0
      Praxis3D/Data/Scripts/Day_night_cycle_ambient_sound.lua
  9. 139 0
      Praxis3D/Data/Scripts/Example_map_startup_window.lua
  10. 18 7
      Praxis3D/Data/Scripts/MainMenu_image_buttons.lua
  11. 14 3
      Praxis3D/Data/Scripts/Window_controls.lua
  12. BIN
      Praxis3D/Data/Sounds/Default/Ambient.bank
  13. BIN
      Praxis3D/Data/Sounds/Default/Master.bank
  14. BIN
      Praxis3D/Data/Sounds/Default/Master.strings.bank
  15. 3 0
      Praxis3D/Data/error-strings-eng.data
  16. 1 0
      Praxis3D/Praxis3D.vcxproj
  17. 3 0
      Praxis3D/Praxis3D.vcxproj.filters
  18. 171 0
      Praxis3D/Source/AboutWindow.cpp
  19. 109 13
      Praxis3D/Source/AboutWindow.h
  20. 85 82
      Praxis3D/Source/AmbientOcclusionPass.h
  21. 3 3
      Praxis3D/Source/AtmScatteringPass.h
  22. 366 150
      Praxis3D/Source/AudioScene.cpp
  23. 3 2
      Praxis3D/Source/AudioScene.h
  24. 3 0
      Praxis3D/Source/AudioSystem.cpp
  25. 2 0
      Praxis3D/Source/AudioSystem.h
  26. 13 10
      Praxis3D/Source/BloomCompositePass.h
  27. 52 49
      Praxis3D/Source/BloomPass.h
  28. 8 0
      Praxis3D/Source/CommonDefinitions.h
  29. 8 1
      Praxis3D/Source/Config.cpp
  30. 44 19
      Praxis3D/Source/Config.h
  31. 2 0
      Praxis3D/Source/EditorState.cpp
  32. 60 10
      Praxis3D/Source/EditorWindow.cpp
  33. 18 3
      Praxis3D/Source/EditorWindow.h
  34. 21 6
      Praxis3D/Source/Engine.cpp
  35. 1 1
      Praxis3D/Source/EngineState.cpp
  36. 20 0
      Praxis3D/Source/EngineState.h
  37. 3 0
      Praxis3D/Source/ErrorCodes.h
  38. 3 0
      Praxis3D/Source/ErrorHandler.cpp
  39. 3 0
      Praxis3D/Source/GUIHandler.h
  40. 11 11
      Praxis3D/Source/GUIScene.cpp
  41. 2 1
      Praxis3D/Source/GUIScene.h
  42. 45 0
      Praxis3D/Source/GUISystem.h
  43. 0 5
      Praxis3D/Source/GeometryBuffer.cpp
  44. 1 1
      Praxis3D/Source/LightingPass.h
  45. 81 2
      Praxis3D/Source/LuaComponent.h
  46. 129 42
      Praxis3D/Source/LuaScript.cpp
  47. 39 2
      Praxis3D/Source/LuaScript.h
  48. 24 21
      Praxis3D/Source/LuminancePass.h
  49. 2 0
      Praxis3D/Source/MainMenuState.cpp
  50. 29 73
      Praxis3D/Source/PhysicsScene.cpp
  51. 3 2
      Praxis3D/Source/PhysicsScene.h
  52. 2 0
      Praxis3D/Source/PlayState.cpp
  53. 26 23
      Praxis3D/Source/RendererBackend.cpp
  54. 8 0
      Praxis3D/Source/RendererFrontend.cpp
  55. 6 11
      Praxis3D/Source/RendererScene.cpp
  56. 0 3
      Praxis3D/Source/RendererScene.h
  57. 90 62
      Praxis3D/Source/SceneLoader.cpp
  58. 26 1
      Praxis3D/Source/SceneLoader.h
  59. 4 3
      Praxis3D/Source/ScriptScene.cpp
  60. 1 0
      Praxis3D/Source/ScriptScene.h
  61. 36 7
      Praxis3D/Source/SoundComponent.h
  62. 7 2
      Praxis3D/Source/Version.h
  63. 18 0
      Praxis3D/Source/WorldScene.h
  64. 271 17
      Praxis3D/imgui.ini

+ 95 - 0
LICENSE.md

@@ -41,6 +41,8 @@ DEPENDENCY LICENSES:
 - SDL (Simple DirectMedia Layer)
 - SDL (Simple DirectMedia Layer)
 - Sol3
 - Sol3
 - TBB (Intel® Threading Building Blocks)
 - TBB (Intel® Threading Building Blocks)
+####
+- Open Sans (font)
 
 
 ### Licenses:
 ### Licenses:
 
 
@@ -880,3 +882,96 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    limitations under the License.
    limitations under the License.
 
 
 </code>
 </code>
+
+### [Open Sans:](https://github.com/googlefonts/opensans)
+
+<code>
+
+Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans)
+
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font
+creation efforts of academic and linguistic communities, and to
+provide a free and open framework in which fonts may be shared and
+improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply to
+any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software
+components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to,
+deleting, or substituting -- in part or in whole -- any of the
+components of the Original Version, by changing formats or by porting
+the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed,
+modify, redistribute, and sell modified and unmodified copies of the
+Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in
+Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the
+corresponding Copyright Holder. This restriction only applies to the
+primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created using
+the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+</code>

BIN
Praxis3D/Data/Fonts/Default/OpenSans-Regular.ttf


+ 279 - 49
Praxis3D/Data/Maps/default.pmap

@@ -1,5 +1,5 @@
 {
 {
-	"LoadInBackground": "false",
+	"LoadInBackground": "true",
 	"GameObject": 
 	"GameObject": 
 	[
 	[
 		{
 		{
@@ -10,6 +10,7 @@
 			{
 			{
 				"LuaComponent": 
 				"LuaComponent": 
 				{
 				{
+					"PauseInEditor": "false",
 					"Active": "true",
 					"Active": "true",
 					"Filename": "Window_controls.lua"
 					"Filename": "Window_controls.lua"
 				}
 				}
@@ -828,7 +829,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 1",
 			"Name": "Cube 1",
-			"ID": "11",
+			"ID": "10",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -903,7 +904,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Rubber"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -917,7 +918,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 2",
 			"Name": "Cube 2",
-			"ID": "12",
+			"ID": "11",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -992,7 +993,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Metal"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -1006,7 +1007,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 3",
 			"Name": "Cube 3",
-			"ID": "13",
+			"ID": "12",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -1081,7 +1082,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Metal"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -1095,7 +1096,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 4",
 			"Name": "Cube 4",
-			"ID": "14",
+			"ID": "13",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -1170,7 +1171,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Metal"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -1184,7 +1185,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 5",
 			"Name": "Cube 5",
-			"ID": "15",
+			"ID": "14",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -1259,7 +1260,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Metal"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -1273,7 +1274,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 6",
 			"Name": "Cube 6",
-			"ID": "16",
+			"ID": "15",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -1348,7 +1349,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Metal"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -1362,7 +1363,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 7",
 			"Name": "Cube 7",
-			"ID": "17",
+			"ID": "16",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -1437,7 +1438,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Rubber"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -1451,7 +1452,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 8",
 			"Name": "Cube 8",
-			"ID": "18",
+			"ID": "17",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -1526,7 +1527,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Rubber"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -1540,7 +1541,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 9",
 			"Name": "Cube 9",
-			"ID": "19",
+			"ID": "18",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -1615,7 +1616,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Metal"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -1629,7 +1630,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 10",
 			"Name": "Cube 10",
-			"ID": "20",
+			"ID": "19",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -1704,7 +1705,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Rubber"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -1718,7 +1719,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 11",
 			"Name": "Cube 11",
-			"ID": "21",
+			"ID": "20",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -1793,7 +1794,7 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Metal"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
@@ -1807,7 +1808,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Cube 12",
 			"Name": "Cube 12",
-			"ID": "22",
+			"ID": "21",
 			"Parent": "0",
 			"Parent": "0",
 			"Prefab": "cubeRigidBody.prefab",
 			"Prefab": "cubeRigidBody.prefab",
 			"Graphics": 
 			"Graphics": 
@@ -1882,12 +1883,12 @@
 				"ObjectMaterialComponent": 
 				"ObjectMaterialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"Type": "Metal"
+					"Type": "Rock"
 				},
 				},
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"LocalPosition": "17.5926f, 2.00004f, 31.3525f",
+					"LocalPosition": "17.3766f, 2.00006f, 31.3525f",
 					"LocalRotation": "0.0f, -31.5152f, 0.0f",
 					"LocalRotation": "0.0f, -31.5152f, 0.0f",
 					"LocalRotationQuaternion": "0.962419f, 0.0f, -0.271568f, 0.0f",
 					"LocalRotationQuaternion": "0.962419f, 0.0f, -0.271568f, 0.0f",
 					"LocalScale": "2.0f, 2.0f, 2.0f"
 					"LocalScale": "2.0f, 2.0f, 2.0f"
@@ -1896,7 +1897,7 @@
 		},
 		},
 		{
 		{
 			"Name": "Sphere 1",
 			"Name": "Sphere 1",
-			"ID": "23",
+			"ID": "22",
 			"Parent": "0",
 			"Parent": "0",
 			"Graphics": 
 			"Graphics": 
 			{
 			{
@@ -1977,6 +1978,89 @@
 				}
 				}
 			}
 			}
 		},
 		},
+		{
+			"Name": "Sphere 2",
+			"ID": "23",
+			"Parent": "0",
+			"Graphics": 
+			{
+				"ModelComponent": 
+				{
+					"Active": "true",
+					"Models": 
+					[
+						{
+							"Filename": "Default\sphereHighpoly.fbx",
+							"Meshes": 
+							[
+								{
+									"Index": "0",
+									"Active": "true",
+									"AlphaThreshold": "0.0f",
+									"EmissiveIntensity": "0.0f",
+									"HeightScale": "0.0f",
+									"StochasticSampling": "false",
+									"StochasticSamplingScale": "1.0f",
+									"WrapMode": "Repeat",
+									"Materials": 
+									{
+										"Diffuse": 
+										{
+											"Filename": "Default\grid_yellow_alb.png",
+											"TextureScale": "4.0f, 1.0f"
+										},
+										"Normal": 
+										{
+											"Filename": "Default\default_normal.png",
+											"TextureScale": "1.0f, 1.0f"
+										},
+										"Emissive": 
+										{
+											"Filename": "Default\default_emissive.png",
+											"TextureScale": "1.0f, 1.0f"
+										},
+										"RMHAO": 
+										{
+											"Filename": "Default\grid_2_RMHA.png",
+											"TextureScale": "1.0f, 1.0f"
+										}
+									}
+								}
+							]
+						}
+					]
+				}
+			},
+			"Physics": 
+			{
+				"RigidBodyComponent": 
+				{
+					"Active": "true",
+					"Friction": "0.85f",
+					"Kinematic": "false",
+					"Mass": "2.0f",
+					"Restitution": "1.0f",
+					"RollingFriction": "0.001f",
+					"SpinningFriction": "1.0f",
+					"CollisionShape": 
+					{
+						"Type": "Sphere",
+						"Size": "1.0f, 1.0f, 1.0f"
+					}
+				}
+			},
+			"World": 
+			{
+				"SpatialComponent": 
+				{
+					"Active": "true",
+					"LocalPosition": "-4.95439f, 18.7009f, 27.759f",
+					"LocalRotation": "0.584159f, 65.048f, -179.714f",
+					"LocalRotationQuaternion": "0.000638762f, -0.537655f, 0.00295783f, 0.843159f",
+					"LocalScale": "1.0f, 1.0f, 1.0f"
+				}
+			}
+		},
 		{
 		{
 			"Name": "Light red",
 			"Name": "Light red",
 			"ID": "24",
 			"ID": "24",
@@ -2509,13 +2593,22 @@
 			{
 			{
 				"LuaComponent": 
 				"LuaComponent": 
 				{
 				{
-					"Active": "false",
-					"Filename": "Constant_rotation.lua",
+					"PauseInEditor": "true",
+					"Active": "true",
+					"Filename": "Constant_rotation_single_axis.lua",
 					"Variables": 
 					"Variables": 
 					[
 					[
 						{
 						{
 							"Name": "rotationSpeed",
 							"Name": "rotationSpeed",
 							"Value": "50.0f"
 							"Value": "50.0f"
+						},
+						{
+							"Name": "rotationAxis",
+							"Value": "0.0f, 1.0f, 0.0f"
+						},
+						{
+							"Name": "syncWithPhysicsSimulation",
+							"Value": "true"
 						}
 						}
 					]
 					]
 				}
 				}
@@ -2735,13 +2828,22 @@
 			{
 			{
 				"LuaComponent": 
 				"LuaComponent": 
 				{
 				{
-					"Active": "false",
-					"Filename": "Constant_rotation.lua",
+					"PauseInEditor": "true",
+					"Active": "true",
+					"Filename": "Constant_rotation_single_axis.lua",
 					"Variables": 
 					"Variables": 
 					[
 					[
 						{
 						{
 							"Name": "rotationSpeed",
 							"Name": "rotationSpeed",
 							"Value": "50.0f"
 							"Value": "50.0f"
+						},
+						{
+							"Name": "rotationAxis",
+							"Value": "0.0f, 1.0f, 0.0f"
+						},
+						{
+							"Name": "syncWithPhysicsSimulation",
+							"Value": "true"
 						}
 						}
 					]
 					]
 				}
 				}
@@ -2912,7 +3014,8 @@
 			{
 			{
 				"SoundListenerComponent": 
 				"SoundListenerComponent": 
 				{
 				{
-					"Active": "true"
+					"Active": "true",
+					"ID": "0"
 				}
 				}
 			},
 			},
 			"Graphics": 
 			"Graphics": 
@@ -2930,6 +3033,7 @@
 			{
 			{
 				"LuaComponent": 
 				"LuaComponent": 
 				{
 				{
+					"PauseInEditor": "false",
 					"Active": "true",
 					"Active": "true",
 					"Filename": "Camera_free.lua",
 					"Filename": "Camera_free.lua",
 					"Variables": 
 					"Variables": 
@@ -2950,9 +3054,9 @@
 				"SpatialComponent": 
 				"SpatialComponent": 
 				{
 				{
 					"Active": "true",
 					"Active": "true",
-					"LocalPosition": "0.474485f, 6.47126f, 7.71065f",
-					"LocalRotation": "168.727f, -0.453055f, -179.917f",
-					"LocalRotationQuaternion": "-0.00400652f, -0.000332513f, 0.994943f, 0.0981934f",
+					"LocalPosition": "-1.33628f, 8.73796f, 3.85384f",
+					"LocalRotation": "175.977f, -2.05774f, -179.87f",
+					"LocalRotationQuaternion": "-0.017989f, -0.000506373f, 0.999005f, 0.0350705f",
 					"LocalScale": "1.0f, 1.0f, 1.0f"
 					"LocalScale": "1.0f, 1.0f, 1.0f"
 				}
 				}
 			}
 			}
@@ -2975,8 +3079,28 @@
 			{
 			{
 				"LuaComponent": 
 				"LuaComponent": 
 				{
 				{
+					"PauseInEditor": "true",
 					"Active": "true",
 					"Active": "true",
-					"Filename": "Sun_move.lua"
+					"Filename": "Constant_rotation_two_axes.lua",
+					"Variables": 
+					[
+						{
+							"Name": "rotationSpeed",
+							"Value": "0.5f"
+						},
+						{
+							"Name": "rotationAxis1",
+							"Value": "0.0f, 1.0f, 0.0f"
+						},
+						{
+							"Name": "rotationAxis2",
+							"Value": "1.0f, 0.0f, 0.0f"
+						},
+						{
+							"Name": "syncWithPhysicsSimulation",
+							"Value": "true"
+						}
+					]
 				}
 				}
 			},
 			},
 			"World": 
 			"World": 
@@ -2985,11 +3109,104 @@
 				{
 				{
 					"Active": "true",
 					"Active": "true",
 					"LocalPosition": "0.0f, 0.0f, 0.0f",
 					"LocalPosition": "0.0f, 0.0f, 0.0f",
-					"LocalRotation": "-68.861f, -42.1089f, -0.000119687f",
-					"LocalRotationQuaternion": "0.769747f, -0.527659f, -0.296318f, -0.203126f",
+					"LocalRotation": "-50f, -59.9991f, -0.000375651f",
+					"LocalRotationQuaternion": "0.784888f, -0.366001f, -0.453147f, -0.211309f",
 					"LocalScale": "1.0f, 1.0f, 1.0f"
 					"LocalScale": "1.0f, 1.0f, 1.0f"
 				}
 				}
 			}
 			}
+		},
+		{
+			"Name": "Day-night ambient sound",
+			"ID": "37",
+			"Parent": "0",
+			"Script": 
+			{
+				"LuaComponent": 
+				{
+					"PauseInEditor": "false",
+					"Active": "true",
+					"Filename": "Day_night_cycle_ambient_sound.lua",
+					"Variables": 
+					[
+						{
+							"Name": "entityNameSun",
+							"Value": "Directional sunlight"
+						},
+						{
+							"Name": "entityNameDaySound",
+							"Value": "Ambient sound day"
+						},
+						{
+							"Name": "entityNameNightSound",
+							"Value": "Ambient sound night"
+						},
+						{
+							"Name": "dayNightTransitionRange",
+							"Value": "0.1f"
+						}
+					]
+				}
+			}
+		},
+		{
+			"Name": "Ambient sound day",
+			"ID": "38",
+			"Parent": "37",
+			"Audio": 
+			{
+				"SoundComponent": 
+				{
+					"Active": "true",
+					"Loop": "true",
+					"Name": "Ambient_default_day",
+					"Source": "Event",
+					"Spatialized": "false",
+					"StartPlaying": "true",
+					"Type": "Ambient",
+					"Volume": "1.0f"
+				}
+			}
+		},
+		{
+			"Name": "Ambient sound night",
+			"ID": "39",
+			"Parent": "37",
+			"Audio": 
+			{
+				"SoundComponent": 
+				{
+					"Active": "true",
+					"Loop": "true",
+					"Name": "Ambient_default_night",
+					"Source": "Event",
+					"Spatialized": "false",
+					"StartPlaying": "true",
+					"Type": "Ambient",
+					"Volume": "0.0f"
+				}
+			}
+		},
+		{
+			"Name": "Startup window",
+			"ID": "40",
+			"Parent": "0",
+			"GUI": 
+			{
+				"GUISequenceComponent": 
+				{
+					"Active": "true",
+					"Static": "false"
+				}
+			},
+			"Script": 
+			{
+				"LuaComponent": 
+				{
+					"PauseInEditor": "true",
+					"Active": "true",
+					"Filename": "Example_map_startup_window.lua"
+				}
+			}
 		}
 		}
 	],
 	],
 	"Systems": 
 	"Systems": 
@@ -3000,18 +3217,21 @@
 			{
 			{
 				"ObjectPoolSize": 
 				"ObjectPoolSize": 
 				{
 				{
-					"SoundComponent": "0",
+					"SoundComponent": "2",
 					"SoundListenerComponent": "1"
 					"SoundListenerComponent": "1"
 				},
 				},
 				"Banks": 
 				"Banks": 
 				[
 				[
 					{
 					{
 						"Filename": "Default\Impact.bank"
 						"Filename": "Default\Impact.bank"
+					},
+					{
+						"Filename": "Default\Ambient.bank"
 					}
 					}
 				],
 				],
 				"Volume": 
 				"Volume": 
 				{
 				{
-					"Ambient": "1.0f",
+					"Ambient": "0.2f",
 					"Master": "0.5f",
 					"Master": "0.5f",
 					"Music": "0.1f",
 					"Music": "0.1f",
 					"SoundEffect": "1.0f"
 					"SoundEffect": "1.0f"
@@ -3049,7 +3269,7 @@
 				{
 				{
 					"CameraComponent": "1",
 					"CameraComponent": "1",
 					"LightComponent": "10",
 					"LightComponent": "10",
-					"ModelComponent": "33",
+					"ModelComponent": "34",
 					"ShaderComponent": "0"
 					"ShaderComponent": "0"
 				},
 				},
 				"RenderPasses": 
 				"RenderPasses": 
@@ -3088,7 +3308,7 @@
 				"ShadowMapping": 
 				"ShadowMapping": 
 				{
 				{
 					"PenumbraSize": "0.72f",
 					"PenumbraSize": "0.72f",
-					"PenumbraScaleRange": "1.0f, 2000.0f",
+					"PenumbraScaleRange": "1.0f, 300.0f",
 					"Resolution": "4096",
 					"Resolution": "4096",
 					"ZClipping": "true",
 					"ZClipping": "true",
 					"ZPlaneMultiplier": "10.0f",
 					"ZPlaneMultiplier": "10.0f",
@@ -3108,6 +3328,11 @@
 							"BiasMax": "0.0005f",
 							"BiasMax": "0.0005f",
 							"PenumbraScale": "1.0f"
 							"PenumbraScale": "1.0f"
 						},
 						},
+						{
+							"Distance": "32.0f",
+							"BiasMax": "0.0005f",
+							"PenumbraScale": "1.0f"
+						},
 						{
 						{
 							"Distance": "64.0f",
 							"Distance": "64.0f",
 							"BiasMax": "0.0005f",
 							"BiasMax": "0.0005f",
@@ -3121,12 +3346,17 @@
 						{
 						{
 							"Distance": "256.0f",
 							"Distance": "256.0f",
 							"BiasMax": "0.0005f",
 							"BiasMax": "0.0005f",
+							"PenumbraScale": "2.0f"
+						},
+						{
+							"Distance": "512.0f",
+							"BiasMax": "0.0005f",
 							"PenumbraScale": "1.0f"
 							"PenumbraScale": "1.0f"
 						},
 						},
 						{
 						{
 							"Divider": "1.0f",
 							"Divider": "1.0f",
 							"BiasMax": "0.0005f",
 							"BiasMax": "0.0005f",
-							"PenumbraScale": "2.0f"
+							"PenumbraScale": "1.0f"
 						}
 						}
 					]
 					]
 				}
 				}
@@ -3141,7 +3371,7 @@
 			{
 			{
 				"ObjectPoolSize": 
 				"ObjectPoolSize": 
 				{
 				{
-					"GUISequenceComponent": "0"
+					"GUISequenceComponent": "1"
 				}
 				}
 			},
 			},
 			"System": 
 			"System": 
@@ -3155,8 +3385,8 @@
 				"Gravity": "0.0f, -9.8f, 0.0f",
 				"Gravity": "0.0f, -9.8f, 0.0f",
 				"ObjectPoolSize": 
 				"ObjectPoolSize": 
 				{
 				{
-					"RigidBodyComponent": "27",
-					"CollisionEventComponent": "27"
+					"RigidBodyComponent": "28",
+					"CollisionEventComponent": "28"
 				}
 				}
 			},
 			},
 			"System": 
 			"System": 
@@ -3169,7 +3399,7 @@
 			{
 			{
 				"ObjectPoolSize": 
 				"ObjectPoolSize": 
 				{
 				{
-					"LuaComponent": "5"
+					"LuaComponent": "7"
 				}
 				}
 			},
 			},
 			"System": 
 			"System": 
@@ -3182,9 +3412,9 @@
 			{
 			{
 				"ObjectPoolSize": 
 				"ObjectPoolSize": 
 				{
 				{
-					"MetadataComponent": "36",
+					"MetadataComponent": "41",
 					"ObjectMaterialComponent": "26",
 					"ObjectMaterialComponent": "26",
-					"SpatialComponent": "36"
+					"SpatialComponent": "37"
 				}
 				}
 			},
 			},
 			"System": 
 			"System": 

BIN
Praxis3D/Data/Materials/Default/GUI/logo2.png


+ 0 - 27
Praxis3D/Data/Scripts/Constant_rotation.lua

@@ -1,27 +0,0 @@
-
-function init ()
-	-- Create needed variables
-	create(Types.SpatialDataManager, 'spatialData');
-	
-	speed = rotationSpeed
-	
-	if speed == 0 then
-		speed = 50
-	end
-	
-	ErrHandlerLoc.logErrorCode(ErrorCode.Initialize_success, getLuaFilename())
-end
-	
-function update (p_deltaTime)
-	-- Get current spatial data and its inverse
-	localTransformMat4 = spatialData:getLocalTransform()
-	
-	-- Calculate rotation angle
-	angle = (speed * p_deltaTime)
-	
-	-- Rotate left/right on a fixed Y direction (up/down) to not introduce any roll
-	localTransformMat4 = localTransformMat4:rotate(toRadianF(angle), Vec3.new(0.0, 1.0, 0.0))
-	
-	-- Update spatial data with the new matrix
-	spatialData:setLocalTransform(localTransformMat4)
-end

+ 45 - 0
Praxis3D/Data/Scripts/Constant_rotation_single_axis.lua

@@ -0,0 +1,45 @@
+--[[
+	Rotates an object around a single axis
+	
+	Inputs:
+	rotationSpeed - (float) speed of rotation
+	rotationAxis - (vec3f) axis of rotation
+	syncWithPhysicsSimulation - (bool) stop rotating when the physics simulation is paused
+]]--
+
+function init ()
+	-- Create needed variables
+	create(Types.SpatialDataManager, 'spatialData');
+	
+	doRotation = true
+	
+	speed = rotationSpeed
+	if speed == 0 then
+		speed = 50
+	end
+	
+	ErrHandlerLoc.logErrorCode(ErrorCode.Initialize_success, getLuaFilename())
+end
+	
+function update (p_deltaTime)
+
+	-- If the sync-with-physics-simulation flag is set, perform rotation only when physics simulation is running
+	if syncWithPhysicsSimulation then
+		doRotation = getPhysicsSimulationRunning()
+	end
+	
+	if doRotation then
+		-- Get current spatial data and its inverse
+		localTransformMat4 = spatialData:getLocalTransform()
+		
+		-- Calculate rotation angle
+		angle = (speed * p_deltaTime)
+		
+		-- Rotate on a given axis
+		localTransformMat4 = localTransformMat4:rotate(toRadianF(angle), rotationAxis)
+		
+		-- Update spatial data with the new matrix
+		spatialData:setLocalTransform(localTransformMat4)
+	end
+	
+end

+ 49 - 0
Praxis3D/Data/Scripts/Constant_rotation_two_axes.lua

@@ -0,0 +1,49 @@
+--[[
+	Rotates an object around a two axes
+	
+	Inputs:
+	rotationSpeed - (float) speed of rotation
+	rotationAxis1 - (vec3f) first axis of rotation	
+	rotationAxis2 - (vec3f) second axis of rotation
+	syncWithPhysicsSimulation - (bool) stop rotating when the physics simulation is paused
+]]--
+
+function init ()
+	-- Create needed variables
+	create(Types.SpatialDataManager, 'spatialData');
+	
+	doRotation = true
+	
+	speed = rotationSpeed
+	if speed == 0 then
+		speed = 50
+	end
+	
+	ErrHandlerLoc.logErrorCode(ErrorCode.Initialize_success, getLuaFilename())
+end
+	
+function update (p_deltaTime)
+
+	-- If the sync-with-physics-simulation flag is set, perform rotation only when physics simulation is running
+	if syncWithPhysicsSimulation then
+		doRotation = getPhysicsSimulationRunning()
+	end
+	
+	if doRotation then
+		-- Get current spatial data and its inverse
+		localTransformMat4 = spatialData:getLocalTransform()
+		
+		-- Calculate rotation angle
+		angle = (speed * p_deltaTime)
+		
+		-- Rotate on a given first axis
+		localTransformMat4 = localTransformMat4:rotate(toRadianF(angle), rotationAxis1)
+		
+		-- Rotate on a given second axis
+		localTransformMat4 = localTransformMat4:rotate(toRadianF(angle), rotationAxis2)
+		
+		-- Update spatial data with the new matrix
+		spatialData:setLocalTransform(localTransformMat4)
+	end
+	
+end

+ 48 - 0
Praxis3D/Data/Scripts/Day_night_cycle_ambient_sound.lua

@@ -0,0 +1,48 @@
+--[[
+	Sets the volume of day and night ambient sound components
+	
+	Inputs:
+	sunEntity 				- (string) name of the sun (directional light) component
+	daySoundEntity 			- (string) name of the day time ambient sound component	
+	nightSoundEntity 		- (string) name of the night time ambient sound component
+	dayNightTransitionRange - (float) day-night cycle transition point denoting when the transition happens
+]]--
+
+function init ()
+	-- Create needed variables
+	upVector = Vec3.new(0.0, 1.0, 0.0)
+	
+	-- Get entity IDs of sun and sound objects
+	sunEntity = getEntityID(entityNameSun)
+	daySoundEntity = getEntityID(entityNameDaySound)
+	nightSoundEntity = getEntityID(entityNameNightSound)
+	
+	ErrHandlerLoc.logErrorCode(ErrorCode.Initialize_success, getLuaFilename())
+end
+	
+function update (p_deltaTime)
+	-- Get sun spatial component
+	sunSpatialComponent = getSpatialComponent(sunEntity)
+	if sunSpatialComponent then
+		
+		-- Get sun world transform matrix
+		sunWorldTransform = sunSpatialComponent:getSpatialDataChangeManager():getWorldTransform()
+		
+		-- Calculate day-night transition factor by first getting the dot product of sun's position and a vector pointing up
+		-- and then interpolating it between a set range while clamping the result to [0 1]
+		dayNightTransitionFactor = clamp(linearInterpolation(dot(sunWorldTransform:getRotZVec3(), upVector), -dayNightTransitionRange, dayNightTransitionRange), 0.0, 1.0)
+		
+		-- Get the day sound component and set its volume (day-night factor)
+		daySoundComponent = getSoundComponentSystemObject(daySoundEntity)
+		if daySoundComponent then
+			sendChange(daySoundComponent, Changes.Audio.Volume, dayNightTransitionFactor)
+		end
+		
+		-- Get the night sound component and set its volume (inverse of day-night factor)
+		nightSoundComponent = getSoundComponentSystemObject(nightSoundEntity)
+		if nightSoundComponent then
+			sendChange(nightSoundComponent, Changes.Audio.Volume, 1.0 - dayNightTransitionFactor)
+		end
+		
+	end
+end

+ 139 - 0
Praxis3D/Data/Scripts/Example_map_startup_window.lua

@@ -0,0 +1,139 @@
+--[[
+	Shows a GUI window with info about the default example scene.
+	Pauses physics simulation while the window is showing.
+]]--
+
+function init ()
+	-- Create needed variables
+	create(Types.Conditional, 'continueButtonPressed')
+	create(Types.Conditional, 'continueButtonHovered')
+	showWindow = true
+	simulationActive = false
+	
+	-- CONTINUE button settings
+	continueButtonSizeX = 350.0
+	continueButtonSizeY = 64.0
+	
+	-- Title text shown at the top of the window, with increased font size
+	titleBodyText = {}
+	titleBodyText[1] = 'An example scene made out of simple assets,'
+	titleBodyText[2] = 'showing different types of objects and components'
+	titleBodyTextSize = 2
+	
+	-- Body text shown in the middle of the window
+	mainBodyText = {}
+	mainBodyText[1] = 'Scene contains:'
+	mainBodyText[2] = 'PBR shading using Cook-Torrance BRDF'
+	mainBodyText[3] = 'PBR bloom with lens dirt'
+	mainBodyText[4] = 'Luminance histogram with auto exposure compensation'
+	mainBodyText[5] = 'Cascaded shadow mapping with PCF filtering'
+	mainBodyText[6] = 'Horizon-based ambient occlusion mapping'
+	mainBodyText[7] = 'Dynamic points lights with emissive mapping'
+	mainBodyText[8] = 'Sky and fog using Mie and Rayleigh atmospheric light scattering'
+	mainBodyText[9] = 'HDR rendering with Uchimura tone-mapping'
+	mainBodyText[10] = 'Rigid body objects for collision detection'
+	mainBodyText[11] = 'Ambient sound based on day-night cycle'
+	mainBodyText[12] = ''
+	mainBodyText[13] = 'Controls:'
+	mainBodyText[14] = '[W] - move forward'
+	mainBodyText[15] = '[A] - strafe left'
+	mainBodyText[16] = '[S] - move backward'
+	mainBodyText[17] = '[D] - strafe right'
+	mainBodyText[18] = '[C] - move upward'
+	mainBodyText[19] = '[SPACE] - move downward'
+	mainBodyText[20] = '[F9] - toggle fullscreen'
+	mainBodyText[21] = '[F11] - toggle v-sync'
+	mainBodyText[22] = '[ESC] - go back to main-menu'
+	mainBodyTextSize = 22
+	
+	-- Pause physics simulation while this GUI window is showing
+	sendData(SystemType.Physics, DataType.DataType_SimulationActive, false)
+	
+	-- Make sure the mouse is released, so the buttons can be pressed
+	setMouseCapture(false)
+		
+	ErrHandlerLoc.logErrorCode(ErrorCode.Initialize_success, getLuaFilename())
+end
+	
+function update (p_deltaTime)
+	
+	if showWindow then
+		-- Set font
+		GUI.PushFont(ImGuiFont.AboutWindow)
+		
+		-- Set GUI colors
+		GUI.PushStyleColor(ImGuiCol.WindowBg, 0.102, 0.102, 0.102, 0.9)
+		
+		-- Set the GUI window to be fullscreen
+		GUI.SetNextWindowPos(0, 0)
+		GUI.SetNextWindowSizeFullscreen()
+		
+		-- BEGIN WINDOW
+		GUI.Begin('##ExampleMapInfo', bitwiseOr(ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoCollapse, ImGuiWindowFlags.NoMove))
+		
+		screenSize = GUI.GetScreenSize()
+		
+		-- Increase the font size for the title text
+		GUI.SetWindowFontScale(2.0)
+		
+		-- Draw title text
+		for i = 1, titleBodyTextSize do
+			GUI.TextCenterAligned(titleBodyText[i])
+		end
+		
+		-- Go back to the regular font size
+		GUI.NewLine()
+		GUI.SetWindowFontScale(1.0)
+		
+		-- Draw main body text
+		for i = 1, mainBodyTextSize do
+			GUI.TextCenterAligned(mainBodyText[i])
+		end
+		
+		-- Set the CONTINUE button colors and style
+		if continueButtonHovered:isChecked() then
+			GUI.PushStyleColor(ImGuiCol.Text, 0.102, 0.102, 0.102, 1.0)
+		else
+			GUI.PushStyleColor(ImGuiCol.Text, 0.588, 0.773, 0.29, 1.0)
+		end
+		GUI.PushStyleColor(ImGuiCol.Button, 0.0, 0.0, 0.0, 0.0)
+		GUI.PushStyleColor(ImGuiCol.ButtonHovered, 0.588, 0.773, 0.29, 1.0)
+		GUI.PushStyleVar(ImGuiStyleVar.FrameRounding, 20.0)
+		GUI.PushStyleVar(ImGuiStyleVar.ButtonTextAlign, 0.5, 0.5)
+
+		-- Increase the font size for the CONTINUE button
+		GUI.SetWindowFontScale(2.0)
+		
+		-- Set the CONTINUE button position to be centered at the bottom of the screen
+		GUI.SetCursorPosX((screenSize.x - continueButtonSizeX) * 0.5)
+		GUI.SetCursorPosY(screenSize.y - continueButtonSizeY - 10.0)
+		
+		-- Draw the CONTINUE button
+		GUI.Button('Continue', continueButtonSizeX, continueButtonSizeY, continueButtonPressed)
+		GUI.IsItemHovered(continueButtonHovered)
+		
+		GUI.PopStyleColor(3)	-- Text, Button, ButtonHovered
+		GUI.PopStyleVar(2)		-- FrameRounding, ButtonTextAlign
+		GUI.SetWindowFontScale(1.0)
+		
+		-- END WINDOW
+		GUI.End()
+		
+		-- Return to the previous font
+		GUI.PopFont()
+		
+		GUI.PopStyleColor()	-- WindowBg
+		
+		-- If the CONTINUE button was pressed, stop showing this window
+		if continueButtonPressed:isChecked() then
+			showWindow = false
+			simulationActive = true
+			continueButtonPressed:uncheck()
+			setMouseCapture(true)
+			
+			-- Unpause the physics simulation
+			sendData(SystemType.Physics, DataType.DataType_SimulationActive, true)
+		end
+	end
+	
+end

+ 18 - 7
Praxis3D/Data/Scripts/MainMenu_image_buttons.lua

@@ -1,3 +1,11 @@
+--[[
+	The default main-menu screen of the engine.
+	
+	Contains full-screen engine logo, and the required FMOD logo.
+	Uses textures for buttons.
+	Spawns file-browser-dialog for loading scene files.
+	Scales with any screen size.
+]]--
 
 
 function init ()
 function init ()
 	-- Create needed variables
 	-- Create needed variables
@@ -132,20 +140,23 @@ function update (p_deltaTime)
 	-- Make sure the mouse is released, so the buttons can be pressed
 	-- Make sure the mouse is released, so the buttons can be pressed
 	setMouseCapture(false)
 	setMouseCapture(false)
 	
 	
+	-- Get the current view-port size
+	screenSize = GUI.GetScreenSize()
+	
 	-- Calculate the position of the middle of the screen
 	-- Calculate the position of the middle of the screen
-	halfScreenSizeX = graphicsVariables.current_resolution_x / 2.0
-	halfScreenSizeY = graphicsVariables.current_resolution_y / 2.0
+	halfScreenSizeX = screenSize.x / 2.0
+	halfScreenSizeY = screenSize.y / 2.0
 	
 	
 	-- Calculate the starting position for the buttons (relative to window size, not absolute, so the buttons are always in the right place)
 	-- Calculate the starting position for the buttons (relative to window size, not absolute, so the buttons are always in the right place)
 	buttonPositionX = halfScreenSizeX * buttonOffsetMultX
 	buttonPositionX = halfScreenSizeX * buttonOffsetMultX
 	buttonPositionY = halfScreenSizeY * buttonOffsetMultY
 	buttonPositionY = halfScreenSizeY * buttonOffsetMultY
 	
 	
 	-- Calculate engine logo size based based on texture and window size (try to fit it on screen vertically)
 	-- Calculate engine logo size based based on texture and window size (try to fit it on screen vertically)
-	engineLogoAdjustedSizeX = praxisLogoTexture:getTextureWidth() / (praxisLogoTexture:getTextureWidth() / graphicsVariables.current_resolution_x) * praxisLogoScale
-	engineLogoAdjustedSizeY = praxisLogoTexture:getTextureHeight() / (praxisLogoTexture:getTextureWidth() / graphicsVariables.current_resolution_x) * praxisLogoScale
+	engineLogoAdjustedSizeX = praxisLogoTexture:getTextureWidth() / (praxisLogoTexture:getTextureWidth() / screenSize.x) * praxisLogoScale
+	engineLogoAdjustedSizeY = praxisLogoTexture:getTextureHeight() / (praxisLogoTexture:getTextureWidth() / screenSize.x) * praxisLogoScale
 	
 	
 	-- Calculate fmod logo size based on texture and window size (so it scaled with the screen size)
 	-- Calculate fmod logo size based on texture and window size (so it scaled with the screen size)
-	fmodLogoAdjustedSizeMultAverage = ((fmodLogoTexture:getTextureHeight() / graphicsVariables.current_resolution_y) + (fmodLogoTexture:getTextureWidth() / graphicsVariables.current_resolution_x)) / 2
+	fmodLogoAdjustedSizeMultAverage = ((fmodLogoTexture:getTextureHeight() / screenSize.y) + (fmodLogoTexture:getTextureWidth() / screenSize.x)) / 2
 	fmodLogoAdjustedSizeX = fmodLogoTexture:getTextureWidth() / fmodLogoAdjustedSizeMultAverage * fmodLogoScale
 	fmodLogoAdjustedSizeX = fmodLogoTexture:getTextureWidth() / fmodLogoAdjustedSizeMultAverage * fmodLogoScale
 	fmodLogoAdjustedSizeY = fmodLogoTexture:getTextureHeight() / fmodLogoAdjustedSizeMultAverage * fmodLogoScale
 	fmodLogoAdjustedSizeY = fmodLogoTexture:getTextureHeight() / fmodLogoAdjustedSizeMultAverage * fmodLogoScale
 
 
@@ -156,13 +167,13 @@ function update (p_deltaTime)
 	-- Draw the background color
 	-- Draw the background color
 	GUI.PushStyleColor(ImGuiCol.WindowBg, 0.102, 0.102, 0.102, 255.0)
 	GUI.PushStyleColor(ImGuiCol.WindowBg, 0.102, 0.102, 0.102, 255.0)
 	GUI.SetNextWindowPos(0, 0)
 	GUI.SetNextWindowPos(0, 0)
-	GUI.SetNextWindowSize(graphicsVariables.current_resolution_x, graphicsVariables.current_resolution_y)
+	GUI.SetNextWindowSize(screenSize.x, screenSize.y)
 	GUI.Begin('BACKGROUND', bitwiseOr(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.NoMouseInputs, ImGuiWindowFlags.NoFocusOnAppearing))
 	GUI.Begin('BACKGROUND', bitwiseOr(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.NoMouseInputs, ImGuiWindowFlags.NoFocusOnAppearing))
 	GUI.End()
 	GUI.End()
 	GUI.PopStyleColor()
 	GUI.PopStyleColor()
 	
 	
 	-- Draw the engine logo
 	-- Draw the engine logo
-	GUI.SetNextWindowPos((graphicsVariables.current_resolution_x - engineLogoAdjustedSizeX) / 2, (graphicsVariables.current_resolution_y - engineLogoAdjustedSizeY) / 2)
+	GUI.SetNextWindowPos((screenSize.x - engineLogoAdjustedSizeX) / 2, (screenSize.y - engineLogoAdjustedSizeY) / 2)
 	GUI.SetNextWindowSize(engineLogoAdjustedSizeX, engineLogoAdjustedSizeY)
 	GUI.SetNextWindowSize(engineLogoAdjustedSizeX, engineLogoAdjustedSizeY)
 	GUI.Begin('PRAXIS LOGO', bitwiseOr(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.NoBackground, ImGuiWindowFlags.NoMouseInputs))
 	GUI.Begin('PRAXIS LOGO', bitwiseOr(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.NoBackground, ImGuiWindowFlags.NoMouseInputs))
 	GUI.Image(praxisLogoTexture, engineLogoAdjustedSizeX, engineLogoAdjustedSizeY)
 	GUI.Image(praxisLogoTexture, engineLogoAdjustedSizeX, engineLogoAdjustedSizeY)

+ 14 - 3
Praxis3D/Data/Scripts/Window_controls.lua

@@ -1,3 +1,12 @@
+--[[
+	Basic window controls by hot-keys.
+	
+	Functions:
+	- Go back to main menu
+	- Toggle full-screen mode
+	- Toggle mouse capture mode
+	- Toggle v-sync mode
+]]--
 
 
 function init ()
 function init ()
 	-- Create needed variables
 	-- Create needed variables
@@ -28,9 +37,11 @@ end
 function update (p_deltaTime)
 function update (p_deltaTime)
 		
 		
 	if closeKey:isActivated() then
 	if closeKey:isActivated() then
-		-- Set the engine running state to false, so it is shutdown the next frame
-		--setEngineRunning(false)
-		setEngineState(EngineStateType.MainMenu)
+		-- If the current engine state is PlayState, unload it and return to main menu
+		if getEngineState() == EngineStateType.Play then
+			sendEngineChange(EngineChangeType.StateChange, EngineStateType.MainMenu)
+			sendEngineChange(EngineChangeType.SceneUnload, EngineStateType.Play)
+		end
 	end	
 	end	
 	
 	
 	if fullscreenKey:isActivated() then
 	if fullscreenKey:isActivated() then

BIN
Praxis3D/Data/Sounds/Default/Ambient.bank


BIN
Praxis3D/Data/Sounds/Default/Master.bank


BIN
Praxis3D/Data/Sounds/Default/Master.strings.bank


+ 3 - 0
Praxis3D/Data/error-strings-eng.data

@@ -22,6 +22,7 @@
 		"Framebuffer_failed"								: "Framebuffer has failed to load",
 		"Framebuffer_failed"								: "Framebuffer has failed to load",
 		"Geometrybuffer_failed"							: "Geometry buffer 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",
 		"Editor_path_outside_current_dir"		: "Selected file path is outside of current working directory",
+		"Font_type_missing_construction"		: "Missing data required for loading a font",
 		"GL_context_missing"								: "Failed to get GL context handle",
 		"GL_context_missing"								: "Failed to get GL context handle",
 		"Universal_scene_extend_null"				: "Invalid scene was passed while trying to extend the Universal Scene",
 		"Universal_scene_extend_null"				: "Invalid scene was passed while trying to extend the Universal Scene",
 		"Universal_scene_extend_duplicate"	: "Duplicate scene was passed while trying to extend the Universal Scene",
 		"Universal_scene_extend_duplicate"	: "Duplicate scene was passed while trying to extend the Universal Scene",
@@ -29,6 +30,8 @@
 		"AssimpScene_failed"								: "Assimp scene has failed to load",
 		"AssimpScene_failed"								: "Assimp scene has failed to load",
 		"ObjectPool_full"										: "Object pool overflow",
 		"ObjectPool_full"										: "Object pool overflow",
 		"Collision_invalid"									: "Invalid collision type",
 		"Collision_invalid"									: "Invalid collision type",
+		"Collision_max_dynamic_events"			: "Dynamic collision events have surpassed the maximum supported dynamic event count",
+		"Collision_max_static_events"				: "Static collision events have surpassed the maximum supported static event count",
 		"Collision_missing"									: "Collision shape missing",
 		"Collision_missing"									: "Collision shape missing",
 		"Kinematic_has_mass"								: "Kinematic object has a mass greater than zero",
 		"Kinematic_has_mass"								: "Kinematic object has a mass greater than zero",
 		"Property_missing_size"							: "Missing 'Size' property",
 		"Property_missing_size"							: "Missing 'Size' property",

+ 1 - 0
Praxis3D/Praxis3D.vcxproj

@@ -144,6 +144,7 @@
     <ClCompile Include="..\Dependencies\include\imgui_tex_inspect\imgui_tex_inspect.cpp" />
     <ClCompile Include="..\Dependencies\include\imgui_tex_inspect\imgui_tex_inspect.cpp" />
     <ClCompile Include="..\Dependencies\include\imgui_tex_inspect\tex_inspect_opengl.cpp" />
     <ClCompile Include="..\Dependencies\include\imgui_tex_inspect\tex_inspect_opengl.cpp" />
     <ClCompile Include="main.cpp" />
     <ClCompile Include="main.cpp" />
+    <ClCompile Include="Source\AboutWindow.cpp" />
     <ClCompile Include="Source\AtmScatteringModel.cpp" />
     <ClCompile Include="Source\AtmScatteringModel.cpp" />
     <ClCompile Include="Source\AtmScatteringPass.cpp" />
     <ClCompile Include="Source\AtmScatteringPass.cpp" />
     <ClCompile Include="Source\AudioScene.cpp" />
     <ClCompile Include="Source\AudioScene.cpp" />

+ 3 - 0
Praxis3D/Praxis3D.vcxproj.filters

@@ -462,6 +462,9 @@
     <ClCompile Include="..\Dependencies\include\ImGuiColorTextEdit\LanguageDefinitions.cpp">
     <ClCompile Include="..\Dependencies\include\ImGuiColorTextEdit\LanguageDefinitions.cpp">
       <Filter>3rd Party\ImGuiColorTextEdit</Filter>
       <Filter>3rd Party\ImGuiColorTextEdit</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\AboutWindow.cpp">
+      <Filter>GUI\Objects\Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="Source\ErrorCodes.h">
     <ClInclude Include="Source\ErrorCodes.h">

+ 171 - 0
Praxis3D/Source/AboutWindow.cpp

@@ -0,0 +1,171 @@
+#include "AboutWindow.h"
+#include "GUISystem.h"
+#include "Version.h"
+
+ErrorCode AboutWindow::init()
+{
+	ErrorCode returnError = ErrorCode::Success;
+	
+	// Load the logo texture
+	m_logoTexture.loadToMemory();
+	m_guiSystemScene->getSceneLoader()->getChangeController()->sendData(m_guiSystemScene->getSceneLoader()->getSystemScene(Systems::Graphics), DataType::DataType_LoadTexture2D, (void *)&m_logoTexture);
+
+	// Get the about window font
+	m_font = static_cast<GUISystem *>(m_guiSystemScene->getSystem())->getFont(GuiFontType::GuiFontType_AboutWindow);
+
+	return returnError;
+}
+
+void AboutWindow::update(const float p_deltaTime)
+{
+	auto &imguiIO = ImGui::GetIO();
+
+	// Set window background color and make the child window background transparent
+	ImGui::PushStyleColor(ImGuiCol_WindowBg, m_windowBackgroundColor);
+	ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
+
+	// Center the main window
+	ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f));
+	ImGui::SetNextWindowSize(imguiIO.DisplaySize);
+
+	// Use the about window font
+	ImGui::PushFont(m_font);
+
+	if(ImGui::Begin("##AboutWindow", (bool *)0, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove))
+	{
+		// Calculate window size based on resolution
+		//ImVec2 centerWindowSize = imguiIO.DisplaySize * m_centerWindowScale;
+		ImVec2 centerWindowSize = m_centerWindowSize;
+
+		float test = imguiIO.DisplaySize.y - (m_closeButtonSize.y * 2.0f);
+
+		if(centerWindowSize.x > imguiIO.DisplaySize.x)
+			centerWindowSize.x = imguiIO.DisplaySize.x;
+
+		if(centerWindowSize.y > test)
+			centerWindowSize.y = test;
+
+		// Center the child window
+		ImGui::SetNextWindowPos((imguiIO.DisplaySize - centerWindowSize) / 2.0f);
+		if(ImGui::BeginChild("##AboutWindowCenter", centerWindowSize, false))
+		{
+			const float windowWidth = ImGui::GetContentRegionAvail().x;
+			// Calculate the logo size based on the logo height
+			const float logoAspectRatio = (float)m_logoTexture.getTextureWidth() / (float)m_logoTexture.getTextureHeight();
+			ImVec2 logoSize(m_logoHeight * logoAspectRatio, m_logoHeight);
+
+			// Center the logo horizontally
+			ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - logoSize.x) / 2.0f);
+
+			// Draw the logo
+			ImGui::Image(m_logoTexture.getHandle(), logoSize, ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f));
+
+			ImGui::SameLine();
+			ImGui::BeginGroup();
+
+			drawRightAlignedText("Version: v" + std::string(PRAXIS3D_VERSION_STRING), windowWidth);
+			drawRightAlignedText("Commit date: " + std::string(PRAXIS3D_COMMIT_DATE_STRING), windowWidth);
+
+			//ImGui::EndGroup();
+			ImGui::EndGroup();
+
+			// Draw the main text using a custom font scale
+			ImGui::SetWindowFontScale(m_mainTextFontScale);
+			drawCenteredTextColored(m_greenColor, "Praxis3D game engine");
+			drawCenteredTextColored(m_greenColor, "Created by Paulius Akulavicius");
+			ImGui::SetWindowFontScale(1.0f);
+
+			ImGui::NewLine();
+
+			// Draw project description
+			drawCenteredText("Written in C++20, GLSL, Lua, JSON");
+			drawCenteredText("Using OpenGL as the graphics API");
+
+			ImGui::NewLine();
+
+			// Draw project links
+			drawCenteredText("Find out more about this project at:");
+			ImGui::SetWindowFontScale(m_linksTextFontScale);
+			drawCenteredTextColored(m_greenColor, "pauldev.org");
+			drawCenteredTextColored(m_greenColor, "github.com/paul-akl/Praxis3D");
+			ImGui::SetWindowFontScale(1.0f);
+
+			ImGui::NewLine();
+
+			drawCenteredText("Dependencies used:");
+			ImGui::SetWindowFontScale(0.75f);
+
+			ImGui::NewLine();
+
+			// Calculate the dependencies table width based on the longest text entry in the dependencies array
+			const float dependenciesTableWidth = ImGui::CalcTextSize(m_dependencies[m_dependenciesLongestEntryIndex].c_str()).x * 2.0f;
+			ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - dependenciesTableWidth) / 2.0f);
+
+			// Draw the dependencies table
+			if(ImGui::BeginTable("##DependenciesTable", 2, 0, ImVec2(dependenciesTableWidth, 0.0f)))
+			{
+				for(decltype(m_dependencies.size()) i = 0; i < m_dependenciesHalfSize; i++)
+				{
+					ImGui::TableNextRow();
+
+					ImGui::TableSetColumnIndex(0);
+					ImGui::Text(m_dependencies[i].c_str());
+
+					// Make sure to not go out of bounds if the dependencies array size is odd
+					ImGui::TableSetColumnIndex(1);
+					if(i + m_dependenciesHalfSize < m_dependencies.size())
+						ImGui::Text(m_dependencies[i + m_dependenciesHalfSize].c_str());
+					else
+						ImGui::Text("");
+				}
+				ImGui::EndTable();
+			}
+			ImGui::SetWindowFontScale(1.0f);
+
+			ImGui::NewLine();
+
+			drawCenteredText("Licenses can be found in LICENSE.md");
+		}
+		ImGui::EndChild();
+
+		// Set the close button colors and style
+		ImGui::PushStyleColor(ImGuiCol_Text, m_closeButtonCurrentTextColor);
+		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
+		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, m_greenColor);
+		ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 20.0f);
+		ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.5f, 0.5f));
+
+		// Set the close button font scale
+		ImGui::SetWindowFontScale(m_closeButtonFontScale);
+
+		// Calculate close button height
+		const char *closeButtonText = "Close";
+		m_closeButtonSize.y = ImGui::CalcTextSize(closeButtonText).y + ImGui::GetStyle().FramePadding.y * 2.0f;
+
+		// Center the close button horizontally and offset vertically from the bottom
+		ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - m_closeButtonSize.x) / 2.0f);
+		ImGui::SetCursorPosY(ImGui::GetWindowHeight() - m_closeButtonSize.y - ImGui::GetStyle().WindowPadding.y);
+
+		// Draw the close button
+		if(ImGui::Button(closeButtonText, m_closeButtonSize))
+		{
+			// If the close button was pressed, sent a message to the GUI scene to disable the about window
+			m_guiSystemScene->getSceneLoader()->getChangeController()->sendData(m_guiSystemScene->getSceneLoader()->getSystemScene(Systems::GUI), DataType::DataType_AboutWindow, (void *)false);
+		}
+
+		// Reset the font scale back to normal
+		ImGui::SetWindowFontScale(1.0f);
+
+		// Set the close button text color based on whether the mouse is hovering over the button
+		m_closeButtonCurrentTextColor = ImGui::IsItemHovered() ? m_closeButtonHoveredTextColor : m_closeButtonDefaultTextColor;
+
+		ImGui::PopStyleVar(2);		// ImGuiStyleVar_FrameRounding, ImGuiStyleVar_ButtonTextAlign
+		ImGui::PopStyleColor(3);	// ImGuiCol_Text, ImGuiCol_Button, ImGuiCol_ButtonHovered
+	}
+	ImGui::End();
+
+	// Reset the font
+	ImGui::PopFont();
+
+	ImGui::PopStyleColor(2);	// ImGuiCol_WindowBg, ImGuiCol_ChildBg
+}

+ 109 - 13
Praxis3D/Source/AboutWindow.h

@@ -1,41 +1,114 @@
 #pragma once
 #pragma once
 
 
+#include "EngineDefinitions.h"
 #include "ErrorHandlerLocator.h"
 #include "ErrorHandlerLocator.h"
 #include "GUIHandler.h"
 #include "GUIHandler.h"
+#include "GUIHandlerLocator.h"
+#include "Loaders.h"
+#include "SceneLoader.h"
+#include "System.h"
 
 
 class AboutWindow
 class AboutWindow
 {
 {
 	//friend class GUIScene;
 	//friend class GUIScene;
 public:
 public:
-	AboutWindow(SystemScene *p_guiSystemScene) : m_guiSystemScene(p_guiSystemScene) { }
-	~AboutWindow() { }
-
-	ErrorCode init()
+	AboutWindow(SystemScene *p_guiSystemScene) : m_guiSystemScene(p_guiSystemScene), m_logoTexture(Loaders::texture2D().load(Config::filepathVar().gui_assets_path + Config::GUIVar().about_window_logo_texture))
 	{
 	{
-		ErrorCode returnError = ErrorCode::Success;
+		m_closeButtonDefaultTextColor = ImVec4(0.588f, 0.773f, 0.29f, 1.0f);
+		m_closeButtonHoveredTextColor = ImVec4(0.102f, 0.102f, 0.102f, 1.0f);
+		m_closeButtonCurrentTextColor = m_closeButtonDefaultTextColor;
+
+		m_greenColor = ImVec4(0.588f, 0.773f, 0.29f, 1.0f); 
+		m_windowBackgroundColor = ImVec4(0.102f, 0.102f, 0.102f, 0.95f);
+
+		m_closeButtonSize = ImVec2(300.0f, 50.0f);
+		m_centerWindowScale = ImVec2(0.6f, 0.85f);
+		m_centerWindowSize = ImVec2(1200.0f, 1000.0f);
+
+		m_font = nullptr;
+
+		m_logoHeight = 200.0f; 
+		m_closeButtonOffsetFromBottom = 75.0f;
+		m_closeButtonFontScale = 1.5f;
+		m_mainTextFontScale = 2.0f;
+		m_linksTextFontScale = 1.25f;
+
+		m_dependencies = {
+			"- Assimp (Open Asset Import Library)",
+			"- Bullet3 (Bullet Physics)",
+			"- Dear ImGui",
+			"- EnTT",
+			"- FMOD",
+			"- FreeImage",
+			"- GLEW (OpenGL Extension Wrangler)",
+			"- GLM (OpenGL Mathematics)",
+			"- ImGuiColorTextEdit",
+			"- ImGuiFileDialog",
+			"- ImGuiTexInspect",
+			"- ImGuizmo",
+			"- ImSpinner",
+			"- LuaJIT",
+			"- SDL (Simple DirectMedia Layer)",
+			"- Sol3",
+			"- TBB (Intel Threading Building Blocks)" }; 
+		
+		// Calculate half the size of dependencies array while making sure to round up
+		m_dependenciesHalfSize = m_dependencies.size() / 2;
+		m_dependenciesHalfSize += m_dependencies.size() - (m_dependenciesHalfSize * 2);
 
 
-		return returnError;
+		// Get the longest (text-wise) entry in the dependencies array
+		m_dependenciesLongestEntryIndex = 0;
+		for(decltype(m_dependencies.size()) i = 0, longest = 0, size = m_dependencies.size(); i < size; i++)
+		{
+			if(longest < m_dependencies[i].size())
+			{
+				longest = m_dependencies[i].size();
+				m_dependenciesLongestEntryIndex = i;
+			}
+		}
 	}
 	}
+	~AboutWindow() { }
+
+	ErrorCode init();
 
 
 	void activate()
 	void activate()
 	{
 	{
-		//std::cout << "about window activated" << std::endl;
 	}
 	}
 
 
 	void deactivate()
 	void deactivate()
 	{
 	{
-		//std::cout << "about window deactivated" << std::endl;
 	}
 	}
 
 
-	void update(const float p_deltaTime)
+	void update(const float p_deltaTime);
+
+private:
+	const inline void drawRightAlignedText(const std::string &p_text)
 	{
 	{
-		
+		ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(p_text.c_str()).x);
+
+		ImGui::Text(p_text.c_str());
 	}
 	}
+	const inline void drawRightAlignedText(const std::string &p_text, const float p_windowWidth)
+	{
+		ImGui::SetCursorPosX(p_windowWidth - ImGui::CalcTextSize(p_text.c_str()).x);
 
 
-private:
-	const void drawCenteredTextWrapped(const std::string &p_text)
+		ImGui::Text(p_text.c_str());
+	}
+	const inline void drawCenteredText(const std::string &p_text)
+	{
+		ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(p_text.c_str()).x) / 2.0f);
+
+		ImGui::Text(p_text.c_str());
+	}
+	const inline void drawCenteredTextColored(const ImVec4 &p_color, const std::string &p_text)
 	{
 	{
-		const float windowWidth = ImGui::GetWindowSize().x;
+		ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(p_text.c_str()).x) / 2.0f);
+
+		ImGui::TextColored(p_color, p_text.c_str());
+	}
+	const inline void drawCenteredTextWrapped(const std::string &p_text)
+	{
+		const float windowWidth = ImGui::GetContentRegionAvail().x;
 		const float textWidth = ImGui::CalcTextSize(p_text.c_str()).x;
 		const float textWidth = ImGui::CalcTextSize(p_text.c_str()).x;
 
 
 		// calculate the indentation that centers the text on one line, relative
 		// calculate the indentation that centers the text on one line, relative
@@ -56,5 +129,28 @@ private:
 		ImGui::PopTextWrapPos();
 		ImGui::PopTextWrapPos();
 	}
 	}
 
 
+	// Keep a pointer to the GUI scene for messaging and font retrieval
 	SystemScene *m_guiSystemScene;
 	SystemScene *m_guiSystemScene;
+
+	ImVec4 m_closeButtonCurrentTextColor;
+	ImVec4 m_closeButtonDefaultTextColor;
+	ImVec4 m_closeButtonHoveredTextColor;
+	ImVec4 m_greenColor;
+	ImVec4 m_windowBackgroundColor;
+	ImVec2 m_closeButtonSize; 
+	ImVec2 m_centerWindowScale;
+	ImVec2 m_centerWindowSize;
+	ImFont *m_font;
+
+	float m_logoHeight;
+	float m_closeButtonOffsetFromBottom;
+	float m_closeButtonFontScale;
+	float m_mainTextFontScale;
+	float m_linksTextFontScale;
+
+	TextureLoader2D::Texture2DHandle m_logoTexture;
+
+	std::vector<std::string> m_dependencies; 
+	decltype(m_dependencies.size()) m_dependenciesHalfSize;
+	decltype(m_dependencies.size()) m_dependenciesLongestEntryIndex;
 };
 };

+ 85 - 82
Praxis3D/Source/AmbientOcclusionPass.h

@@ -180,99 +180,102 @@ public:
 			m_renderer.passUpdateCommandsToBackend();
 			m_renderer.passUpdateCommandsToBackend();
 		}
 		}
 
 
-		switch(m_aoData.m_aoType)
+		if(p_sceneObjects.m_processDrawing)
 		{
 		{
-			case AmbientOcclusionType_None:
-				return;
-				break;
-			case AmbientOcclusionType_SSAO:
-				{
-					//	 ____________________________
-					//	|							 |
-					//	|		   AO PASS           |
-					//	|____________________________|
-					//
-
-					// Bind the noise texture
-					m_renderer.m_backend.bindTextureForReadering(MaterialType::MaterialType_Noise, m_ssaoNoiseTexture);
-
-					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
-					m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferPosition, GBufferTextureType::GBufferPosition);
-					m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferNormal, GBufferTextureType::GBufferNormal);
-					m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferMatProperties, GBufferTextureType::GBufferMatProperties);
-
-					m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GBufferTextureType::GBufferFinal);
-
-					// Queue and render a full screen quad using a final pass shader
-					m_renderer.queueForDrawing(m_ssaoPassShader->getShaderHandle(), m_ssaoPassShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
-					m_renderer.passScreenSpaceDrawCommandsToBackend();
-
-					//	 ____________________________
-					//	|							 |
-					//	|		  BLUR PASS          |
-					//	|____________________________|
-					//
-
-					m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferFinal, GBufferTextureType::GBufferFinal);
-					m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GBufferTextureType::GBufferMatProperties);
-
-					// Queue and render a full screen quad using a final pass shader
-					m_renderer.queueForDrawing(m_ssaoBlurShader->getShaderHandle(), m_ssaoBlurShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
-					m_renderer.passScreenSpaceDrawCommandsToBackend();
-				}
-				break;
-			case AmbientOcclusionType_HBAO:
-				{
-					//	 ____________________________
-					//	|							 |
-					//	|		   AO PASS           |
-					//	|____________________________|
-					//
-
-					// Bind the noise texture
-					m_renderer.m_backend.bindTextureForReadering(MaterialType::MaterialType_Noise, m_hbaoNoiseTexture);
-
-					//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-					//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
-					m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferPosition, GBufferTextureType::GBufferPosition);
-					m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferNormal, GBufferTextureType::GBufferNormal);
-
-					m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GBufferTextureType::GBufferFinal);
-
-					// Queue and render a full screen quad using a final pass shader
-					m_renderer.queueForDrawing(m_hbaoPassShader->getShaderHandle(), m_hbaoPassShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
-					m_renderer.passScreenSpaceDrawCommandsToBackend();
-
-					//	 ____________________________
-					//	|							 |
-					//	|		  BLUR PASS          |
-					//	|____________________________|
-					//
-					// Horizontal blur
+			switch(m_aoData.m_aoType)
+			{
+				case AmbientOcclusionType_None:
+					return;
+					break;
+				case AmbientOcclusionType_SSAO:
 					{
 					{
-						m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferFinal, GBufferTextureType::GBufferInputTexture);
-						m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GBufferTextureType::GBufferIntermediate);
+						//	 ____________________________
+						//	|							 |
+						//	|		   AO PASS           |
+						//	|____________________________|
+						//
+
+						// Bind the noise texture
+						m_renderer.m_backend.bindTextureForReadering(MaterialType::MaterialType_Noise, m_ssaoNoiseTexture);
+
+						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+						m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferPosition, GBufferTextureType::GBufferPosition);
+						m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferNormal, GBufferTextureType::GBufferNormal);
+						m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferMatProperties, GBufferTextureType::GBufferMatProperties);
+
+						m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GBufferTextureType::GBufferFinal);
 
 
 						// Queue and render a full screen quad using a final pass shader
 						// Queue and render a full screen quad using a final pass shader
-						m_renderer.queueForDrawing(m_hbaoBlurHorizontalShader->getShaderHandle(), m_hbaoBlurHorizontalShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
+						m_renderer.queueForDrawing(m_ssaoPassShader->getShaderHandle(), m_ssaoPassShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
 						m_renderer.passScreenSpaceDrawCommandsToBackend();
 						m_renderer.passScreenSpaceDrawCommandsToBackend();
-					}
 
 
-					// Vertical blur
-					{
-						m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferIntermediate, GBufferTextureType::GBufferInputTexture);
-						m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferMatProperties, GBufferTextureType::GBufferMatProperties);
+						//	 ____________________________
+						//	|							 |
+						//	|		  BLUR PASS          |
+						//	|____________________________|
+						//
+
+						m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferFinal, GBufferTextureType::GBufferFinal);
 						m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GBufferTextureType::GBufferMatProperties);
 						m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GBufferTextureType::GBufferMatProperties);
 
 
 						// Queue and render a full screen quad using a final pass shader
 						// Queue and render a full screen quad using a final pass shader
-						m_renderer.queueForDrawing(m_hbaoBlurVerticalShader->getShaderHandle(), m_hbaoBlurVerticalShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
+						m_renderer.queueForDrawing(m_ssaoBlurShader->getShaderHandle(), m_ssaoBlurShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
 						m_renderer.passScreenSpaceDrawCommandsToBackend();
 						m_renderer.passScreenSpaceDrawCommandsToBackend();
 					}
 					}
-				}
-				break;
+					break;
+				case AmbientOcclusionType_HBAO:
+					{
+						//	 ____________________________
+						//	|							 |
+						//	|		   AO PASS           |
+						//	|____________________________|
+						//
+
+						// Bind the noise texture
+						m_renderer.m_backend.bindTextureForReadering(MaterialType::MaterialType_Noise, m_hbaoNoiseTexture);
+
+						//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+						//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+						m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferPosition, GBufferTextureType::GBufferPosition);
+						m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferNormal, GBufferTextureType::GBufferNormal);
+
+						m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GBufferTextureType::GBufferFinal);
+
+						// Queue and render a full screen quad using a final pass shader
+						m_renderer.queueForDrawing(m_hbaoPassShader->getShaderHandle(), m_hbaoPassShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
+						m_renderer.passScreenSpaceDrawCommandsToBackend();
+
+						//	 ____________________________
+						//	|							 |
+						//	|		  BLUR PASS          |
+						//	|____________________________|
+						//
+						// Horizontal blur
+						{
+							m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferFinal, GBufferTextureType::GBufferInputTexture);
+							m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GBufferTextureType::GBufferIntermediate);
+
+							// Queue and render a full screen quad using a final pass shader
+							m_renderer.queueForDrawing(m_hbaoBlurHorizontalShader->getShaderHandle(), m_hbaoBlurHorizontalShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
+							m_renderer.passScreenSpaceDrawCommandsToBackend();
+						}
+
+						// Vertical blur
+						{
+							m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferIntermediate, GBufferTextureType::GBufferInputTexture);
+							m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferMatProperties, GBufferTextureType::GBufferMatProperties);
+							m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GBufferTextureType::GBufferMatProperties);
+
+							// Queue and render a full screen quad using a final pass shader
+							m_renderer.queueForDrawing(m_hbaoBlurVerticalShader->getShaderHandle(), m_hbaoBlurVerticalShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
+							m_renderer.passScreenSpaceDrawCommandsToBackend();
+						}
+					}
+					break;
+			}
 		}
 		}
 	}
 	}
 
 

+ 3 - 3
Praxis3D/Source/AtmScatteringPass.h

@@ -207,11 +207,11 @@ public:
 				m_renderer.queueForDrawing(m_groundShader->getShaderHandle(), m_groundShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
 				m_renderer.queueForDrawing(m_groundShader->getShaderHandle(), m_groundShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
 
 
 			}
 			}
+
+			// Pass the draw command so it is executed
+			m_renderer.passScreenSpaceDrawCommandsToBackend();
 		}
 		}
 		
 		
-		// Pass the draw command so it is executed
-		m_renderer.passScreenSpaceDrawCommandsToBackend();
-		
 		p_renderPassData.swapColorInputOutputMaps();
 		p_renderPassData.swapColorInputOutputMaps();
 
 
 		p_renderPassData.m_atmScatDoSkyPass = !p_renderPassData.m_atmScatDoSkyPass;
 		p_renderPassData.m_atmScatDoSkyPass = !p_renderPassData.m_atmScatDoSkyPass;

+ 366 - 150
Praxis3D/Source/AudioScene.cpp

@@ -190,8 +190,21 @@ void AudioScene::deactivate()
 		{
 		{
 			if(component.m_playing)
 			if(component.m_playing)
 			{
 			{
-				component.m_channel->stop();
-				component.m_playing = false;
+				switch(component.m_soundSourceType)
+				{
+					case SoundComponent::SoundSourceType::SoundSourceType_Event:
+						{
+							//component.m_soundEventInstance->stop(FMOD_STUDIO_STOP_MODE::FMOD_STUDIO_STOP_IMMEDIATE);
+							//component.m_playing = false;
+						}
+						break;
+					case SoundComponent::SoundSourceType::SoundSourceType_File:
+						{
+							component.m_channel->stop();
+							component.m_playing = false;
+						}
+						break;
+				}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -262,134 +275,238 @@ void AudioScene::update(const float p_deltaTime)
 		}
 		}
 	}
 	}
 
 
-	//	 ___________________________
-	//	|							|
-	//	|  SOUND COMPONENTS UPDATE	|
-	//	|___________________________|
-	//
-	auto soundComponentView = entityRegistry.view<SoundComponent>();
-	for(auto entity : soundComponentView)
+	if(!(m_sceneLoader->getFirstLoad() && m_sceneLoader->getSceneLoadingStatus()))
 	{
 	{
-		auto &component = soundComponentView.get<SoundComponent>(entity);
-
-		if(component.isObjectActive())
+		//	 ___________________________
+		//	|							|
+		//	|  SOUND COMPONENTS UPDATE	|
+		//	|___________________________|
+		//
+		auto soundComponentView = entityRegistry.view<SoundComponent>();
+		for(auto entity : soundComponentView)
 		{
 		{
-			if(component.m_changePending)
+			auto &component = soundComponentView.get<SoundComponent>(entity);
+
+			switch(component.m_soundSourceType)
 			{
 			{
-				if(component.m_reloadSound)
-				{
-					createSound(component);
-				}
-				else
-				{
-					if(component.m_volumeChanged)
-						component.m_channel->setVolume(component.m_volume);
+				case SoundComponent::SoundSourceType::SoundSourceType_Event:
+					{
+						FMOD_STUDIO_PLAYBACK_STATE playState;
+						component.m_soundEventInstance->getPlaybackState(&playState);
 
 
-					if(component.m_loopChanged)
-						if(component.m_loop)
-							component.m_channel->setMode(FMOD_LOOP_NORMAL);
+						if(playState == FMOD_STUDIO_PLAYBACK_STATE::FMOD_STUDIO_PLAYBACK_PLAYING)
+							component.m_playing = true;
 						else
 						else
-							component.m_channel->setMode(FMOD_LOOP_OFF);
+							component.m_playing = false;
 
 
-					if(component.m_spatializedChanged)
-						if(component.m_spatialized)
-							component.m_channel->setMode(FMOD_3D);
+						if(component.isObjectActive())
+						{
+							if(component.m_changePending)
+							{
+								if(component.m_reloadSound)
+								{
+									createSound(component);
+								}
+								else
+								{
+									if(component.m_volumeChanged)
+										component.m_soundEventInstance->setVolume(component.m_volume);
+								}
+							}
+
+							if(!component.m_playing)
+							{
+								if(component.m_startPlaying && component.m_soundEventInstance != nullptr)
+								{
+									//component.m_playing = true;
+
+									component.m_soundEventInstance->setVolume(component.m_volume);
+									//eventInstance->set3DAttributes(&spatialAttributes);
+									component.m_soundEventInstance->start();
+									component.m_soundEventInstance->setPaused(false);
+
+									//component.m_soundEventInstance->p
+									//AudioSystem::fmodErrorLog(m_coreSystem->playSound(component.m_sound, m_soundTypeChannelGroups[component.m_soundType], true, &component.m_channel), component.m_soundName);
+									//component.m_channel->setVolume(component.m_volume);
+
+									if(component.m_spatialized)
+									{
+										auto spatialComponent = entityRegistry.try_get<SpatialComponent>(entity);
+										if(spatialComponent != nullptr)
+										{
+											FMOD_VECTOR velocity = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getVelocity());
+											FMOD_VECTOR position = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getWorldTransform()[3]);
+
+											//component.m_channel->set3DAttributes(&position, &velocity);
+										}
+									}
+
+									//component.m_channel->setPaused(false);
+								}
+							}
+
+							if(component.m_spatialized)
+							{
+								auto spatialComponent = entityRegistry.try_get<SpatialComponent>(entity);
+								if(spatialComponent != nullptr)
+								{
+									const glm::mat3 translateMatrix = glm::mat3(spatialComponent->getSpatialDataChangeManager().getWorldTransform());
+
+									// Get 3D attributes
+									FMOD_3D_ATTRIBUTES spatialAttributes;
+									spatialAttributes.position = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getWorldTransform()[3]);
+									spatialAttributes.velocity = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getVelocity());
+									spatialAttributes.forward = Math::toFmodVector(glm::vec3(0.0f, 0.0f, -1.0f) * translateMatrix);
+									spatialAttributes.up = Math::toFmodVector(glm::vec3(0.0f, 1.0f, 0.0f) * translateMatrix);
+
+									component.m_soundEventInstance->set3DAttributes(&spatialAttributes);
+								}
+							}
+						}
 						else
 						else
-							component.m_channel->setMode(FMOD_2D);
-				}
-
-				component.resetChanges();
-			}
-
-			if(!component.m_playing)
-			{
-				if(component.m_startPlaying && component.m_sound != nullptr)
-				{
-					component.m_playing = true;
-
-					AudioSystem::fmodErrorLog(m_coreSystem->playSound(component.m_sound, m_soundTypeChannelGroups[component.m_soundType], true, &component.m_channel), component.m_soundFilename);
-					component.m_channel->setVolume(component.m_volume);
+						{
+							if(component.m_playing)
+							{
+								//if(component.m_soundEventInstance != nullptr)
+								component.m_soundEventInstance->stop(FMOD_STUDIO_STOP_ALLOWFADEOUT);
+								component.m_playing = false;
+							}
+						}
+					}
+					break;
 
 
-					if(component.m_spatialized)
+				case SoundComponent::SoundSourceType::SoundSourceType_File:
 					{
 					{
-						auto spatialComponent = entityRegistry.try_get<SpatialComponent>(entity);
-						if(spatialComponent != nullptr)
+						if(component.isObjectActive())
 						{
 						{
-							FMOD_VECTOR velocity = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getVelocity());
-							FMOD_VECTOR position = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getWorldTransform()[3]);
-
-							component.m_channel->set3DAttributes(&position, &velocity);
+							if(component.m_changePending)
+							{
+								if(component.m_reloadSound)
+								{
+									createSound(component);
+								}
+								else
+								{
+									if(component.m_volumeChanged)
+										component.m_channel->setVolume(component.m_volume);
+
+									if(component.m_loopChanged)
+										if(component.m_loop)
+											component.m_channel->setMode(FMOD_LOOP_NORMAL);
+										else
+											component.m_channel->setMode(FMOD_LOOP_OFF);
+
+									if(component.m_spatializedChanged)
+										if(component.m_spatialized)
+											component.m_channel->setMode(FMOD_3D);
+										else
+											component.m_channel->setMode(FMOD_2D);
+								}
+
+								component.resetChanges();
+							}
+
+							if(!component.m_playing)
+							{
+								if(component.m_startPlaying && component.m_sound != nullptr)
+								{
+									component.m_playing = true;
+
+									AudioSystem::fmodErrorLog(m_coreSystem->playSound(component.m_sound, m_soundTypeChannelGroups[component.m_soundType], true, &component.m_channel), component.m_soundName);
+									component.m_channel->setVolume(component.m_volume);
+
+									if(component.m_spatialized)
+									{
+										auto spatialComponent = entityRegistry.try_get<SpatialComponent>(entity);
+										if(spatialComponent != nullptr)
+										{
+											FMOD_VECTOR velocity = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getVelocity());
+											FMOD_VECTOR position = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getWorldTransform()[3]);
+
+											component.m_channel->set3DAttributes(&position, &velocity);
+										}
+									}
+
+									component.m_channel->setPaused(false);
+								}
+							}
+
+							if(component.m_spatialized)
+							{
+								auto spatialComponent = entityRegistry.try_get<SpatialComponent>(entity);
+								if(spatialComponent != nullptr)
+								{
+									FMOD_VECTOR velocity = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getVelocity());
+									FMOD_VECTOR position = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getWorldTransform()[3]);
+
+									component.m_channel->set3DAttributes(&position, &velocity);
+								}
+							}
+						}
+						else
+						{
+							if(component.m_playing)
+							{
+								component.m_channel->stop();
+								component.m_playing = false;
+							}
 						}
 						}
 					}
 					}
-
-					component.m_channel->setPaused(false);
-				}
-			}
-
-			if(component.m_spatialized)
-			{
-				auto spatialComponent = entityRegistry.try_get<SpatialComponent>(entity);
-				if(spatialComponent != nullptr)
-				{
-					FMOD_VECTOR velocity = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getVelocity());
-					FMOD_VECTOR position = Math::toFmodVector(spatialComponent->getSpatialDataChangeManager().getWorldTransform()[3]);
-
-					component.m_channel->set3DAttributes(&position, &velocity);
-				}
-			}
-		}
-		else
-		{
-			if(component.m_playing)
-			{
-				component.m_channel->stop();
-				component.m_playing = false;
+					break;
 			}
 			}
 		}
 		}
-	}	
 
 
-	//	 ___________________________
-	//	|							|
-	//	|  COLLISION EVENTS UPDATE	|
-	//	|___________________________|
-	//
-	auto collisionEventMaterialView = worldScene->getEntityRegistry().view<CollisionEventComponent, ObjectMaterialComponent>();
-	for(auto entity : collisionEventMaterialView)
-	{
-		auto &collisionComponent = collisionEventMaterialView.get<CollisionEventComponent>(entity);
-
-		if(collisionComponent.m_numOfDynamicCollisions[frontIndex] > 0)
+		//	 ___________________________
+		//	|							|
+		//	|  COLLISION EVENTS UPDATE	|
+		//	|___________________________|
+		//
+		const auto collisionEventMaterialSpatialView = worldScene->getEntityRegistry().view<CollisionEventComponent, ObjectMaterialComponent, SpatialComponent>();
+		for(auto entity : collisionEventMaterialSpatialView)
 		{
 		{
-			auto &materialComponent = collisionEventMaterialView.get<ObjectMaterialComponent>(entity);
+			// Get the collision component
+			const auto &collisionComponent = collisionEventMaterialSpatialView.get<CollisionEventComponent>(entity);
 
 
-			for(size_t i = 0, size = collisionComponent.m_numOfDynamicCollisions[frontIndex]; i < size; i++)
+			// Check if there are any collisions
+			if(collisionComponent.m_numOfDynamicCollisions[frontIndex] > 0)
 			{
 			{
-				//if(collisionComponent.m_dynamicCollisions[frontIndex][i].m_firstObjInCollisionPair)
+				// Get parent spatial data
+				const auto &spatialComponent = collisionEventMaterialSpatialView.get<SpatialComponent>(entity);
+				const glm::mat3 parentTranslateMatrix = glm::mat3(spatialComponent.getSpatialDataChangeManager().getParentTransform());
+				const glm::vec4 parentPosition = spatialComponent.getSpatialDataChangeManager().getParentTransform()[3];
+
+				auto &materialComponent = collisionEventMaterialSpatialView.get<ObjectMaterialComponent>(entity);
+
+				// Go over each collision of the entity
+				for(size_t i = 0, size = collisionComponent.m_numOfDynamicCollisions[frontIndex]; i < size; i++)
 				{
 				{
-					// Get the transform matrix
-					glm::mat4 transformMatrix;
-					collisionComponent.m_dynamicCollisions[frontIndex][i].m_worldTransform.getOpenGLMatrix(glm::value_ptr(transformMatrix));
-					const glm::mat3 translateMatrix = glm::mat3(transformMatrix);
-
-					// Get 3D attributes
-					FMOD_3D_ATTRIBUTES spatialAttributes;
-					spatialAttributes.position = Math::toFmodVector(transformMatrix[3]);
-					spatialAttributes.velocity = Math::toFmodVector(collisionComponent.m_dynamicCollisions[frontIndex][i].m_velocity);
-					spatialAttributes.forward = Math::toFmodVector(glm::vec3(0.0f, 0.0f, -1.0f) * translateMatrix);
-					spatialAttributes.up = Math::toFmodVector(glm::vec3(0.0f, 1.0f, 0.0f) * translateMatrix);
-					const float volume = glm::min(collisionComponent.m_dynamicCollisions[frontIndex][i].m_appliedImpulse / Config::audioVar().impact_impulse_volume_divider, Config::audioVar().impact_max_volume_threshold);
-
-					// Create an event (sound) instance
-					FMOD::Studio::EventInstance *eventInstance;
-					m_impactEvents[materialComponent.getObjectMaterialType()]->createInstance(&eventInstance);
-
-					// Set sound parameters and play the sound
-					eventInstance->setParameterByName("Impulse", collisionComponent.m_dynamicCollisions[frontIndex][i].m_appliedImpulse / Config::audioVar().impact_impulse_param_divider);
-					eventInstance->setVolume(volume);
-					eventInstance->set3DAttributes(&spatialAttributes);
-					eventInstance->start();
-					eventInstance->setPaused(false);
-					eventInstance->release();
+					//if(collisionComponent.m_dynamicCollisions[frontIndex][i].m_firstObjInCollisionPair)
+					{
+						// Get the transform matrix
+						glm::mat4 transformMatrix;
+						collisionComponent.m_dynamicCollisions[frontIndex][i].m_worldTransform.getOpenGLMatrix(glm::value_ptr(transformMatrix));
+						const glm::mat3 translateMatrix = glm::mat3(transformMatrix) * parentTranslateMatrix;
+
+						// Get 3D attributes
+						FMOD_3D_ATTRIBUTES spatialAttributes;
+						spatialAttributes.position = Math::toFmodVector(transformMatrix[3] + parentPosition);
+						spatialAttributes.velocity = Math::toFmodVector(collisionComponent.m_dynamicCollisions[frontIndex][i].m_velocity);
+						spatialAttributes.forward = Math::toFmodVector(glm::vec3(0.0f, 0.0f, -1.0f) * translateMatrix);
+						spatialAttributes.up = Math::toFmodVector(glm::vec3(0.0f, 1.0f, 0.0f) * translateMatrix);
+						const float volume = glm::clamp(collisionComponent.m_dynamicCollisions[frontIndex][i].m_appliedImpulse / Config::audioVar().impact_impulse_volume_divider, Config::audioVar().impact_min_volume_threshold, Config::audioVar().impact_max_volume_threshold);
+
+						// Create an event (sound) instance
+						FMOD::Studio::EventInstance *eventInstance;
+						m_impactEvents[materialComponent.getObjectMaterialType()]->createInstance(&eventInstance);
+
+						// Set sound parameters and play the sound
+						eventInstance->setParameterByName("Impulse", collisionComponent.m_dynamicCollisions[frontIndex][i].m_appliedImpulse / Config::audioVar().impact_impulse_param_divider);
+						eventInstance->setVolume(volume);
+						eventInstance->set3DAttributes(&spatialAttributes);
+						eventInstance->start();
+						eventInstance->setPaused(false);
+						eventInstance->release();
+					}
 				}
 				}
 			}
 			}
 		}
 		}
@@ -460,7 +577,7 @@ std::vector<SystemObject *> AudioScene::getComponents(const EntityID p_entityID)
 	return returnVector;
 	return returnVector;
 }
 }
 
 
-std::vector<SystemObject*> AudioScene::createComponents(const EntityID p_entityID, const ComponentsConstructionInfo &p_constructionInfo, const bool p_startLoading)
+std::vector<SystemObject *> AudioScene::createComponents(const EntityID p_entityID, const ComponentsConstructionInfo &p_constructionInfo, const bool p_startLoading)
 {
 {
 	return createComponents(p_entityID, p_constructionInfo.m_audioComponents, p_startLoading);
 	return createComponents(p_entityID, p_constructionInfo.m_audioComponents, p_startLoading);
 }
 }
@@ -513,14 +630,16 @@ SystemObject *AudioScene::createComponent(const EntityID &p_entityID, const Soun
 	auto componentInitError = component.init();
 	auto componentInitError = component.init();
 	if(componentInitError == ErrorCode::Success)
 	if(componentInitError == ErrorCode::Success)
 	{
 	{
-		component.m_soundType = p_constructionInfo.m_soundType;
-		component.m_soundFilename = p_constructionInfo.m_soundFilename;
+		component.setActive(p_constructionInfo.m_active);
 		component.m_loop = p_constructionInfo.m_loop;
 		component.m_loop = p_constructionInfo.m_loop;
+		component.m_soundName = p_constructionInfo.m_soundName;
+		component.m_soundSourceType = p_constructionInfo.m_soundSourceType;
 		component.m_spatialized = p_constructionInfo.m_spatialized;
 		component.m_spatialized = p_constructionInfo.m_spatialized;
 		component.m_startPlaying = p_constructionInfo.m_startPlaying;
 		component.m_startPlaying = p_constructionInfo.m_startPlaying;
+		component.m_soundType = p_constructionInfo.m_soundType;
 		component.m_volume = p_constructionInfo.m_volume;
 		component.m_volume = p_constructionInfo.m_volume;
+
 		component.m_objectType = Properties::PropertyID::SoundComponent;
 		component.m_objectType = Properties::PropertyID::SoundComponent;
-		component.setActive(p_constructionInfo.m_active);
 
 
 		createSound(component);
 		createSound(component);
 
 
@@ -723,61 +842,158 @@ void AudioScene::receiveData(const DataType p_dataType, void *p_data, const bool
 
 
 void AudioScene::createSound(SoundComponent &p_soundComponent)
 void AudioScene::createSound(SoundComponent &p_soundComponent)
 {
 {
-	if(p_soundComponent.m_sound != nullptr)
+	switch(p_soundComponent.m_soundSourceType)
 	{
 	{
-		if(p_soundComponent.m_playing)
-		{
-			p_soundComponent.m_channel->stop();
-			p_soundComponent.m_playing = false;
-		}
+		case SoundComponent::SoundSourceType::SoundSourceType_Event:
+			{
+				if(p_soundComponent.m_soundEventInstance != nullptr)
+				{
+					if(p_soundComponent.m_playing)
+					{
+						p_soundComponent.m_soundEventInstance->stop(FMOD_STUDIO_STOP_MODE::FMOD_STUDIO_STOP_IMMEDIATE);
+						p_soundComponent.m_playing = false;
+					}
 
 
-		p_soundComponent.m_sound->release(); 
-		p_soundComponent.m_sound = nullptr;
-	}
+					p_soundComponent.m_soundEventInstance = nullptr;
+				}
 
 
-	FMOD_MODE mode = 0;
+				p_soundComponent.m_soundEventDescription = m_audioSystem->getEvent(p_soundComponent.m_soundName);
+				p_soundComponent.m_soundEventDescription->createInstance(&p_soundComponent.m_soundEventInstance);
+			}
+			break;
 
 
-	if(p_soundComponent.m_loop)
-		mode |= FMOD_LOOP_NORMAL;
-	else
-		mode |= FMOD_LOOP_OFF;
+		case SoundComponent::SoundSourceType::SoundSourceType_File:
+			{
+				if(p_soundComponent.m_sound != nullptr)
+				{
+					if(p_soundComponent.m_playing)
+					{
+						p_soundComponent.m_channel->stop();
+						p_soundComponent.m_playing = false;
+					}
 
 
-	if(p_soundComponent.m_spatialized)
-		mode |= FMOD_3D | FMOD_3D_WORLDRELATIVE | FMOD_3D_INVERSEROLLOFF;
-	else
-		mode |= FMOD_2D;
+					p_soundComponent.m_sound->release();
+					p_soundComponent.m_sound = nullptr;
+				}
 
 
+				FMOD_MODE mode = 0;
 
 
-	switch(p_soundComponent.m_soundType)
-	{
-		case SoundComponent::SoundType::SoundType_Music:
-			{
-				m_coreSystem->createStream((Config::filepathVar().sound_path + p_soundComponent.m_soundFilename).c_str(), mode, p_soundComponent.m_soundExInfo, &p_soundComponent.m_sound);
+				if(p_soundComponent.m_loop)
+					mode |= FMOD_LOOP_NORMAL;
+				else
+					mode |= FMOD_LOOP_OFF;
+
+				if(p_soundComponent.m_spatialized)
+					mode |= FMOD_3D | FMOD_3D_WORLDRELATIVE | FMOD_3D_INVERSEROLLOFF;
+				else
+					mode |= FMOD_2D;
+
+				switch(p_soundComponent.m_soundType)
+				{
+					case SoundComponent::SoundType::SoundType_Music:
+						{
+							m_coreSystem->createStream((Config::filepathVar().sound_path + p_soundComponent.m_soundName).c_str(), mode, p_soundComponent.m_soundExInfo, &p_soundComponent.m_sound);
+						}
+						break;
+
+					case SoundComponent::SoundType::SoundType_Ambient:
+						{
+							m_coreSystem->createStream((Config::filepathVar().sound_path + p_soundComponent.m_soundName).c_str(), mode, p_soundComponent.m_soundExInfo, &p_soundComponent.m_sound);
+						}
+						break;
+
+					case SoundComponent::SoundType::SoundType_SoundEffect:
+						{
+							m_coreSystem->createSound((Config::filepathVar().sound_path + p_soundComponent.m_soundName).c_str(), mode, p_soundComponent.m_soundExInfo, &p_soundComponent.m_sound);
+						}
+						break;
+
+					case SoundComponent::SoundType::SoundType_Null:
+					default:
+						break;
+				}
 			}
 			}
 			break;
 			break;
+	}
+}
 
 
-		case SoundComponent::SoundType::SoundType_Ambient:
+void AudioScene::playSound(SoundComponent &p_soundComponent)
+{
+	switch(p_soundComponent.m_soundSourceType)
+	{
+		case SoundComponent::SoundSourceType::SoundSourceType_Event:
 			{
 			{
-				m_coreSystem->createStream((Config::filepathVar().sound_path + p_soundComponent.m_soundFilename).c_str(), mode, p_soundComponent.m_soundExInfo, &p_soundComponent.m_sound);
+				if(p_soundComponent.m_soundEventInstance != nullptr)
+				{
+					if(p_soundComponent.m_playing)
+					{
+						p_soundComponent.m_soundEventInstance->stop(FMOD_STUDIO_STOP_MODE::FMOD_STUDIO_STOP_IMMEDIATE);
+						p_soundComponent.m_playing = false;
+					}
+
+					p_soundComponent.m_soundEventInstance = nullptr;
+				}
+
+				p_soundComponent.m_soundEventDescription = m_audioSystem->getEvent(p_soundComponent.m_soundName);
+				p_soundComponent.m_soundEventDescription->createInstance(&p_soundComponent.m_soundEventInstance);
 			}
 			}
 			break;
 			break;
 
 
-		case SoundComponent::SoundType::SoundType_SoundEffect:
+		case SoundComponent::SoundSourceType::SoundSourceType_File:
 			{
 			{
-				m_coreSystem->createSound((Config::filepathVar().sound_path + p_soundComponent.m_soundFilename).c_str(), mode, p_soundComponent.m_soundExInfo, &p_soundComponent.m_sound);
-			}
-			break;
+				if(p_soundComponent.m_sound != nullptr)
+				{
+					if(p_soundComponent.m_playing)
+					{
+						p_soundComponent.m_channel->stop();
+						p_soundComponent.m_playing = false;
+					}
 
 
-		case SoundComponent::SoundType::SoundType_Null:
-		default:
+					p_soundComponent.m_sound->release();
+					p_soundComponent.m_sound = nullptr;
+				}
+
+				FMOD_MODE mode = 0;
+
+				if(p_soundComponent.m_loop)
+					mode |= FMOD_LOOP_NORMAL;
+				else
+					mode |= FMOD_LOOP_OFF;
+
+				if(p_soundComponent.m_spatialized)
+					mode |= FMOD_3D | FMOD_3D_WORLDRELATIVE | FMOD_3D_INVERSEROLLOFF;
+				else
+					mode |= FMOD_2D;
+
+				switch(p_soundComponent.m_soundType)
+				{
+					case SoundComponent::SoundType::SoundType_Music:
+						{
+							m_coreSystem->createStream((Config::filepathVar().sound_path + p_soundComponent.m_soundName).c_str(), mode, p_soundComponent.m_soundExInfo, &p_soundComponent.m_sound);
+						}
+						break;
+
+					case SoundComponent::SoundType::SoundType_Ambient:
+						{
+							m_coreSystem->createStream((Config::filepathVar().sound_path + p_soundComponent.m_soundName).c_str(), mode, p_soundComponent.m_soundExInfo, &p_soundComponent.m_sound);
+						}
+						break;
+
+					case SoundComponent::SoundType::SoundType_SoundEffect:
+						{
+							m_coreSystem->createSound((Config::filepathVar().sound_path + p_soundComponent.m_soundName).c_str(), mode, p_soundComponent.m_soundExInfo, &p_soundComponent.m_sound);
+						}
+						break;
+
+					case SoundComponent::SoundType::SoundType_Null:
+					default:
+						break;
+				}
+			}
 			break;
 			break;
 	}
 	}
 }
 }
 
 
-void AudioScene::playSound(SoundComponent &p_soundComponent)
-{
-}
-
 void AudioScene::loadParameterGUIDs()
 void AudioScene::loadParameterGUIDs()
 {
 {
 	int numOfBanks = 0;
 	int numOfBanks = 0;

+ 3 - 2
Praxis3D/Source/AudioScene.h

@@ -100,10 +100,11 @@ public:
 		p_constructionInfo.m_name = p_component.getName();
 		p_constructionInfo.m_name = p_component.getName();
 
 
 		p_constructionInfo.m_loop = p_component.m_loop;
 		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_soundName = p_component.m_soundName;
+		p_constructionInfo.m_soundSourceType = p_component.m_soundSourceType;
 		p_constructionInfo.m_spatialized = p_component.m_spatialized;
 		p_constructionInfo.m_spatialized = p_component.m_spatialized;
 		p_constructionInfo.m_startPlaying = p_component.m_startPlaying;
 		p_constructionInfo.m_startPlaying = p_component.m_startPlaying;
+		p_constructionInfo.m_soundType = p_component.m_soundType;
 		p_constructionInfo.m_volume = p_component.m_volume;
 		p_constructionInfo.m_volume = p_component.m_volume;
 	}
 	}
 	void exportComponent(SoundListenerComponent::SoundListenerComponentConstructionInfo &p_constructionInfo, const SoundListenerComponent &p_component)
 	void exportComponent(SoundListenerComponent::SoundListenerComponentConstructionInfo &p_constructionInfo, const SoundListenerComponent &p_component)

+ 3 - 0
Praxis3D/Source/AudioSystem.cpp

@@ -58,6 +58,9 @@ ErrorCode AudioSystem::init()
 				}
 				}
 			}
 			}
 
 
+			// Get all audio buses
+			assignBusses();
+
 			// Add all channel groups (other than master) to the master channel group as a nested group
 			// Add all channel groups (other than master) to the master channel group as a nested group
 			for(unsigned int i = 0; i < AudioBusType::AudioBusType_NumOfTypes; i++)
 			for(unsigned int i = 0; i < AudioBusType::AudioBusType_NumOfTypes; i++)
 				if(i != AudioBusType::AudioBusType_Master)
 				if(i != AudioBusType::AudioBusType_Master)

+ 2 - 0
Praxis3D/Source/AudioSystem.h

@@ -167,6 +167,7 @@ protected:
 	void assignBusses()
 	void assignBusses()
 	{
 	{
 		for(unsigned int busType = 0; busType < AudioBusType::AudioBusType_NumOfTypes; busType++)
 		for(unsigned int busType = 0; busType < AudioBusType::AudioBusType_NumOfTypes; busType++)
+		{
 			switch(busType)
 			switch(busType)
 			{
 			{
 				case AudioBusType_Ambient:
 				case AudioBusType_Ambient:
@@ -187,6 +188,7 @@ protected:
 					ErrHandlerLoc::get().log(ErrorCode::Audio_invalid_bus_type, ErrorSource::Source_AudioSystem);
 					ErrHandlerLoc::get().log(ErrorCode::Audio_invalid_bus_type, ErrorSource::Source_AudioSystem);
 					break;
 					break;
 			}
 			}
+		}
 	}
 	}
 
 
 	FMOD::Studio::Bus *getBus(const AudioBusType p_busType) { return m_buses[p_busType]; }
 	FMOD::Studio::Bus *getBus(const AudioBusType p_busType) { return m_buses[p_busType]; }

+ 13 - 10
Praxis3D/Source/BloomCompositePass.h

@@ -46,17 +46,20 @@ public:
 
 
 	void update(RenderPassData &p_renderPassData, const SceneObjects &p_sceneObjects, const float p_deltaTime)
 	void update(RenderPassData &p_renderPassData, const SceneObjects &p_sceneObjects, const float p_deltaTime)
 	{
 	{
-		glDisable(GL_DEPTH_TEST);
-		
-		// Bind input color texture for reading so it can be accessed in the shaders
-		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(p_renderPassData.getColorInputMap(), GBufferTextureType::GBufferInputTexture);
-		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferEmissive, GBufferTextureType::GBufferEmissive);
-		
-		m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(p_renderPassData.getColorOutputMap());
+		if(p_sceneObjects.m_processDrawing)
+		{
+			glDisable(GL_DEPTH_TEST);
+
+			// Bind input color texture for reading so it can be accessed in the shaders
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(p_renderPassData.getColorInputMap(), GBufferTextureType::GBufferInputTexture);
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferEmissive, GBufferTextureType::GBufferEmissive);
+
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(p_renderPassData.getColorOutputMap());
 
 
-		// Perform various visual effects in the post process shader
-		m_renderer.queueForDrawing(m_bloomCompositeShader->getShaderHandle(), m_bloomCompositeShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
-		m_renderer.passScreenSpaceDrawCommandsToBackend();
+			// Perform various visual effects in the post process shader
+			m_renderer.queueForDrawing(m_bloomCompositeShader->getShaderHandle(), m_bloomCompositeShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
+			m_renderer.passScreenSpaceDrawCommandsToBackend();
+		}
 
 
 		p_renderPassData.swapColorInputOutputMaps();
 		p_renderPassData.swapColorInputOutputMaps();
 	}
 	}

+ 52 - 49
Praxis3D/Source/BloomPass.h

@@ -71,66 +71,69 @@ public:
 
 
 	void update(RenderPassData &p_renderPassData, const SceneObjects &p_sceneObjects, const float p_deltaTime)
 	void update(RenderPassData &p_renderPassData, const SceneObjects &p_sceneObjects, const float p_deltaTime)
 	{
 	{
-		// Assign the bloom threshold value so it can be sent to the shader
-		m_renderer.m_frameData.m_bloomTreshold = m_bloomTreshold;
+		if(p_sceneObjects.m_processDrawing)
+		{
+			// Assign the bloom threshold value so it can be sent to the shader
+			m_renderer.m_frameData.m_bloomTreshold = m_bloomTreshold;
 
 
-		// Get the screen image buffer size
-		const unsigned int imageWidth = m_renderer.m_backend.getGeometryBuffer()->getBufferWidth();
-		const unsigned int imageHeight = m_renderer.m_backend.getGeometryBuffer()->getBufferHeight();
+			// Get the screen image buffer size
+			const unsigned int imageWidth = m_renderer.m_backend.getGeometryBuffer()->getBufferWidth();
+			const unsigned int imageHeight = m_renderer.m_backend.getGeometryBuffer()->getBufferHeight();
 
 
-		// Calculate mipmap size and level
-		glm::uvec2 mipmapSize = glm::uvec2(imageWidth / 2, imageHeight / 2);
-		unsigned int mipmapLevels = calculateMipmapLevels(imageWidth, imageHeight, (unsigned int)Config::graphicsVar().bloom_mipmap_limit, (unsigned int)Config::graphicsVar().bloom_downscale_limit);
+			// Calculate mipmap size and level
+			glm::uvec2 mipmapSize = glm::uvec2(imageWidth / 2, imageHeight / 2);
+			unsigned int mipmapLevels = calculateMipmapLevels(imageWidth, imageHeight, (unsigned int)Config::graphicsVar().bloom_mipmap_limit, (unsigned int)Config::graphicsVar().bloom_downscale_limit);
 
 
-		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferFinal, GBufferTextureType::GBufferInputTexture);
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferFinal, GBufferTextureType::GBufferInputTexture);
 
 
-		// Bloom downscaling
-		for(unsigned int i = 0; i < mipmapLevels - 1; i++)
-		{
-			// Assign the texel size and mipmap level so it can be sent to the shader
-			m_renderer.m_frameData.m_texelSize = 1.0f / glm::vec2(mipmapSize);
-			m_renderer.m_frameData.m_mipLevel = i;
-
-			// Bind the corresponding mipmap level of the image buffer
-			m_renderer.m_backend.getGeometryBuffer()->bindBufferToImageUnitForWriting(GBufferTextureType::GBufferFinal, 0, i + 1);
-
-			const unsigned int groupX = (unsigned int)glm::ceil(mipmapSize.x / 8.0);
-			const unsigned int groupY = (unsigned int)glm::ceil(mipmapSize.y / 8.0);
-
-			// Dispatch the compute shader
-			m_renderer.queueForDrawing(m_bloomDownscaleShader->getShaderHandle(), m_bloomDownscaleShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix, groupX, groupY, 1, MemoryBarrierType::MemoryBarrierType_AccessAndFetchBarrier);
-			m_renderer.passComputeDispatchCommandsToBackend();
-			
-			// Half the mipmap size as we go up the mipmap levels
-			mipmapSize = mipmapSize / 2u;
-		}
+			// Bloom downscaling
+			for(unsigned int i = 0; i < mipmapLevels - 1; i++)
+			{
+				// Assign the texel size and mipmap level so it can be sent to the shader
+				m_renderer.m_frameData.m_texelSize = 1.0f / glm::vec2(mipmapSize);
+				m_renderer.m_frameData.m_mipLevel = i;
 
 
-		// Bind lens dirt texture
-		glActiveTexture(GL_TEXTURE0 + LensFlareTextureType::LensFlareTextureType_LenseDirt);
-		glBindTexture(GL_TEXTURE_2D, m_lensDirtTexture.getHandle());
+				// Bind the corresponding mipmap level of the image buffer
+				m_renderer.m_backend.getGeometryBuffer()->bindBufferToImageUnitForWriting(GBufferTextureType::GBufferFinal, 0, i + 1);
 
 
-		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferFinal, GBufferTextureType::GBufferInputTexture);
+				const unsigned int groupX = (unsigned int)glm::ceil(mipmapSize.x / 8.0);
+				const unsigned int groupY = (unsigned int)glm::ceil(mipmapSize.y / 8.0);
 
 
-		// Bloom upscaling
-		for(unsigned int i = mipmapLevels - 1; i >= 1; i--)
-		{
-			// Recalculate the mipmap size as we go down the mipmap levels
-			mipmapSize.x = (unsigned int)glm::max(1.0, glm::floor(imageWidth / glm::pow(2u, i - 1.0)));
-			mipmapSize.y = (unsigned int)glm::max(1.0, glm::floor(imageHeight / glm::pow(2u, i - 1.0)));
+				// Dispatch the compute shader
+				m_renderer.queueForDrawing(m_bloomDownscaleShader->getShaderHandle(), m_bloomDownscaleShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix, groupX, groupY, 1, MemoryBarrierType::MemoryBarrierType_AccessAndFetchBarrier);
+				m_renderer.passComputeDispatchCommandsToBackend();
+
+				// Half the mipmap size as we go up the mipmap levels
+				mipmapSize = mipmapSize / 2u;
+			}
+
+			// Bind lens dirt texture
+			glActiveTexture(GL_TEXTURE0 + LensFlareTextureType::LensFlareTextureType_LenseDirt);
+			glBindTexture(GL_TEXTURE_2D, m_lensDirtTexture.getHandle());
+
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GBufferTextureType::GBufferFinal, GBufferTextureType::GBufferInputTexture);
+
+			// Bloom upscaling
+			for(unsigned int i = mipmapLevels - 1; i >= 1; i--)
+			{
+				// Recalculate the mipmap size as we go down the mipmap levels
+				mipmapSize.x = (unsigned int)glm::max(1.0, glm::floor(imageWidth / glm::pow(2u, i - 1.0)));
+				mipmapSize.y = (unsigned int)glm::max(1.0, glm::floor(imageHeight / glm::pow(2u, i - 1.0)));
 
 
-			// Assign the texel size and mipmap level so it can be sent to the shader
-			m_renderer.m_frameData.m_texelSize = 1.0f / glm::vec2(mipmapSize);
-			m_renderer.m_frameData.m_mipLevel = i;
+				// Assign the texel size and mipmap level so it can be sent to the shader
+				m_renderer.m_frameData.m_texelSize = 1.0f / glm::vec2(mipmapSize);
+				m_renderer.m_frameData.m_mipLevel = i;
 
 
-			// Bind the corresponding mipmap level of the image buffer
-			m_renderer.m_backend.getGeometryBuffer()->bindBufferToImageUnitForWriting(GBufferTextureType::GBufferFinal, 0, i - 1);
+				// Bind the corresponding mipmap level of the image buffer
+				m_renderer.m_backend.getGeometryBuffer()->bindBufferToImageUnitForWriting(GBufferTextureType::GBufferFinal, 0, i - 1);
 
 
-			const unsigned int groupX = (unsigned int)glm::ceil(mipmapSize.x / 8.0);
-			const unsigned int groupY = (unsigned int)glm::ceil(mipmapSize.y / 8.0);
+				const unsigned int groupX = (unsigned int)glm::ceil(mipmapSize.x / 8.0);
+				const unsigned int groupY = (unsigned int)glm::ceil(mipmapSize.y / 8.0);
 
 
-			// Dispatch the compute shader
-			m_renderer.queueForDrawing(m_bloomUpscaleShader->getShaderHandle(), m_bloomUpscaleShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix, groupX, groupY, 1, MemoryBarrierType::MemoryBarrierType_AccessAndFetchBarrier);
-			m_renderer.passComputeDispatchCommandsToBackend();
+				// Dispatch the compute shader
+				m_renderer.queueForDrawing(m_bloomUpscaleShader->getShaderHandle(), m_bloomUpscaleShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix, groupX, groupY, 1, MemoryBarrierType::MemoryBarrierType_AccessAndFetchBarrier);
+				m_renderer.passComputeDispatchCommandsToBackend();
+			}
 		}
 		}
 	}
 	}
 
 

+ 8 - 0
Praxis3D/Source/CommonDefinitions.h

@@ -39,6 +39,7 @@ enum EngineChangeType : unsigned int
 	EngineChangeType_None = 0,
 	EngineChangeType_None = 0,
 	EngineChangeType_SceneFilename,
 	EngineChangeType_SceneFilename,
 	EngineChangeType_SceneLoad,
 	EngineChangeType_SceneLoad,
+	EngineChangeType_SceneUnload,
 	EngineChangeType_SceneReload,
 	EngineChangeType_SceneReload,
 	EngineChangeType_StateChange
 	EngineChangeType_StateChange
 };
 };
@@ -312,6 +313,13 @@ enum AudioBusType : unsigned int
 	AudioBusType_NumOfTypes
 	AudioBusType_NumOfTypes
 };
 };
 
 
+enum GuiFontType : unsigned int
+{
+	GuiFontType_Default = 0,
+	GuiFontType_AboutWindow,
+	GuiFontType_NumOfTypes
+};
+
 #define OBJ_MATERIAL_ID(Code) \
 #define OBJ_MATERIAL_ID(Code) \
 	Code(Concrete, = 0) \
 	Code(Concrete, = 0) \
 	Code(Glass,) \
 	Code(Glass,) \

+ 8 - 1
Praxis3D/Source/Config.cpp

@@ -56,6 +56,7 @@ void Config::init()
 	// Audio Variables
 	// Audio Variables
 	AddVariablePredef(m_audioVar, impact_impulse_param_divider);
 	AddVariablePredef(m_audioVar, impact_impulse_param_divider);
 	AddVariablePredef(m_audioVar, impact_impulse_volume_divider);
 	AddVariablePredef(m_audioVar, impact_impulse_volume_divider);
+	AddVariablePredef(m_audioVar, impact_min_volume_threshold);
 	AddVariablePredef(m_audioVar, impact_max_volume_threshold); 
 	AddVariablePredef(m_audioVar, impact_max_volume_threshold); 
 	AddVariablePredef(m_audioVar, impact_soft_hard_threshold);
 	AddVariablePredef(m_audioVar, impact_soft_hard_threshold);
 	AddVariablePredef(m_audioVar, max_impact_volume);
 	AddVariablePredef(m_audioVar, max_impact_volume);
@@ -221,6 +222,7 @@ void Config::init()
 	AddVariablePredef(m_GUIVar, gui_render);
 	AddVariablePredef(m_GUIVar, gui_render);
 	AddVariablePredef(m_GUIVar, gui_dark_style);
 	AddVariablePredef(m_GUIVar, gui_dark_style);
 	AddVariablePredef(m_GUIVar, gui_sequence_array_reserve_size);
 	AddVariablePredef(m_GUIVar, gui_sequence_array_reserve_size);
+	AddVariablePredef(m_GUIVar, about_window_font_size);
 	AddVariablePredef(m_GUIVar, editor_asset_selection_button_size_multiplier);
 	AddVariablePredef(m_GUIVar, editor_asset_selection_button_size_multiplier);
 	AddVariablePredef(m_GUIVar, editor_asset_texture_button_size_x);
 	AddVariablePredef(m_GUIVar, editor_asset_texture_button_size_x);
 	AddVariablePredef(m_GUIVar, editor_asset_texture_button_size_y);
 	AddVariablePredef(m_GUIVar, editor_asset_texture_button_size_y);
@@ -238,6 +240,8 @@ void Config::init()
 	AddVariablePredef(m_GUIVar, loading_spinner_radius);
 	AddVariablePredef(m_GUIVar, loading_spinner_radius);
 	AddVariablePredef(m_GUIVar, loading_spinner_speed);
 	AddVariablePredef(m_GUIVar, loading_spinner_speed);
 	AddVariablePredef(m_GUIVar, loading_spinner_thickness);
 	AddVariablePredef(m_GUIVar, loading_spinner_thickness);
+	AddVariablePredef(m_GUIVar, about_window_font);
+	AddVariablePredef(m_GUIVar, about_window_logo_texture);
 	AddVariablePredef(m_GUIVar, editor_button_add_texture);
 	AddVariablePredef(m_GUIVar, editor_button_add_texture);
 	AddVariablePredef(m_GUIVar, editor_button_add_list_texture);
 	AddVariablePredef(m_GUIVar, editor_button_add_list_texture);
 	AddVariablePredef(m_GUIVar, editor_button_arrow_down_texture);
 	AddVariablePredef(m_GUIVar, editor_button_arrow_down_texture);
@@ -255,6 +259,8 @@ void Config::init()
 	AddVariablePredef(m_GUIVar, editor_button_scripting_enabled_texture);
 	AddVariablePredef(m_GUIVar, editor_button_scripting_enabled_texture);
 	AddVariablePredef(m_GUIVar, editor_new_entity_name);
 	AddVariablePredef(m_GUIVar, editor_new_entity_name);
 	AddVariablePredef(m_GUIVar, gui_editor_window_name);
 	AddVariablePredef(m_GUIVar, gui_editor_window_name);
+	AddVariablePredef(m_GUIVar, url_github);
+	AddVariablePredef(m_GUIVar, url_pauldev);
 
 
 	// Input variables
 	// Input variables
 	AddVariablePredef(m_inputVar, back_key);
 	AddVariablePredef(m_inputVar, back_key);
@@ -324,7 +330,8 @@ void Config::init()
 
 
 	// File-path variables
 	// File-path variables
 	AddVariablePredef(m_filepathVar, config_path);
 	AddVariablePredef(m_filepathVar, config_path);
-	AddVariablePredef(m_filepathVar, engine_assets_path);
+	AddVariablePredef(m_filepathVar, engine_assets_path); 
+	AddVariablePredef(m_filepathVar, font_path);
 	AddVariablePredef(m_filepathVar, gui_assets_path);
 	AddVariablePredef(m_filepathVar, gui_assets_path);
 	AddVariablePredef(m_filepathVar, map_path);
 	AddVariablePredef(m_filepathVar, map_path);
 	AddVariablePredef(m_filepathVar, model_path);
 	AddVariablePredef(m_filepathVar, model_path);

+ 44 - 19
Praxis3D/Source/Config.h

@@ -12,7 +12,6 @@
 #include "Utilities.h"
 #include "Utilities.h"
 
 
 typedef uint64_t BitMask;
 typedef uint64_t BitMask;
-//typedef uint32_t DataType;
 
 
 // Tests if the given bitmask contains the given flag; returns true if the flag bits are present in the bitmask
 // Tests if the given bitmask contains the given flag; returns true if the flag bits are present in the bitmask
 constexpr bool CheckBitmask(const BitMask p_bitmask, const BitMask p_flag) { return ((p_bitmask & p_flag) == p_flag); }
 constexpr bool CheckBitmask(const BitMask p_bitmask, const BitMask p_flag) { return ((p_bitmask & p_flag) == p_flag); }
@@ -236,23 +235,24 @@ namespace Systems
 		}
 		}
 		namespace Audio
 		namespace Audio
 		{
 		{
-			static constexpr BitMask Filename				= Changes::Type::Audio + Changes::Common::Shared1;
+			static constexpr BitMask SoundName				= Changes::Type::Audio + Changes::Common::Shared1;
 			static constexpr BitMask ListenerID				= Changes::Type::Audio + Changes::Common::Shared2;
 			static constexpr BitMask ListenerID				= Changes::Type::Audio + Changes::Common::Shared2;
 			static constexpr BitMask Loop					= Changes::Type::Audio + Changes::Common::Shared3;
 			static constexpr BitMask Loop					= Changes::Type::Audio + Changes::Common::Shared3;
 			static constexpr BitMask Reload					= Changes::Type::Audio + Changes::Common::Shared4;
 			static constexpr BitMask Reload					= Changes::Type::Audio + Changes::Common::Shared4;
 			static constexpr BitMask SoundType				= Changes::Type::Audio + Changes::Common::Shared5;
 			static constexpr BitMask SoundType				= Changes::Type::Audio + Changes::Common::Shared5;
-			static constexpr BitMask Spatialized			= Changes::Type::Audio + Changes::Common::Shared6;
-			static constexpr BitMask StartPlaying			= Changes::Type::Audio + Changes::Common::Shared7;
-			static constexpr BitMask Volume					= Changes::Type::Audio + Changes::Common::Shared8;
+			static constexpr BitMask SoundSourceType		= Changes::Type::Audio + Changes::Common::Shared6;
+			static constexpr BitMask Spatialized			= Changes::Type::Audio + Changes::Common::Shared7;
+			static constexpr BitMask StartPlaying			= Changes::Type::Audio + Changes::Common::Shared8;
+			static constexpr BitMask Volume					= Changes::Type::Audio + Changes::Common::Shared9;
 			
 			
-			static constexpr BitMask VolumeAmbient			= Changes::Type::Audio + Changes::Common::Shared9;
-			static constexpr BitMask VolumeMaster			= Changes::Type::Audio + Changes::Common::Shared10;
-			static constexpr BitMask VolumeMusic			= Changes::Type::Audio + Changes::Common::Shared11;
-			static constexpr BitMask VolumeSFX				= Changes::Type::Audio + Changes::Common::Shared12;
+			static constexpr BitMask VolumeAmbient			= Changes::Type::Audio + Changes::Common::Shared10;
+			static constexpr BitMask VolumeMaster			= Changes::Type::Audio + Changes::Common::Shared11;
+			static constexpr BitMask VolumeMusic			= Changes::Type::Audio + Changes::Common::Shared12;
+			static constexpr BitMask VolumeSFX				= Changes::Type::Audio + Changes::Common::Shared13;
 			static constexpr BitMask AllVolume				= VolumeAmbient | VolumeMaster | VolumeMusic | VolumeSFX;
 			static constexpr BitMask AllVolume				= VolumeAmbient | VolumeMaster | VolumeMusic | VolumeSFX;
 
 
-			static constexpr BitMask All					= Filename | ListenerID | Loop | Reload | SoundType | Spatialized | StartPlaying | 
-																Volume | AllVolume;
+			static constexpr BitMask All					= SoundName | ListenerID | Loop | Reload | SoundType | SoundSourceType | 
+																Spatialized | StartPlaying | Volume | AllVolume;
 		}
 		}
 		namespace Graphics
 		namespace Graphics
 		{
 		{
@@ -322,9 +322,10 @@ namespace Systems
 		}
 		}
 		namespace Script
 		namespace Script
 		{
 		{
-			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;
+			static constexpr BitMask Filename				= Changes::Type::Script + Changes::Common::Shared1;
+			static constexpr BitMask PauseInEditor			= Changes::Type::Script + Changes::Common::Shared2;
+			static constexpr BitMask Reload					= Changes::Type::Script + Changes::Common::Shared3;
+			static constexpr BitMask All					= Filename | PauseInEditor | Reload;
 		}
 		}
 		namespace World
 		namespace World
 		{
 		{
@@ -348,6 +349,7 @@ namespace Properties
 	Code(ChangeController,) \
 	Code(ChangeController,) \
 	Code(Components,) \
 	Code(Components,) \
 	Code(Default,) \
 	Code(Default,) \
+	Code(File,) \
 	Code(Filename,) \
 	Code(Filename,) \
 	Code(Index,) \
 	Code(Index,) \
 	Code(Keybindings,) \
 	Code(Keybindings,) \
@@ -357,6 +359,7 @@ namespace Properties
 	Code(Objects,) \
 	Code(Objects,) \
 	Code(ObjectPoolSize,) \
 	Code(ObjectPoolSize,) \
 	Code(Scene,) \
 	Code(Scene,) \
+	Code(Source,) \
 	Code(System,) \
 	Code(System,) \
 	Code(Systems,) \
 	Code(Systems,) \
 	Code(Type,) \
 	Code(Type,) \
@@ -368,6 +371,7 @@ namespace Properties
 	Code(Ambient,) \
 	Code(Ambient,) \
 	Code(Audio,) \
 	Code(Audio,) \
 	Code(Banks,) \
 	Code(Banks,) \
+	Code(Event,) \
 	Code(Loop,) \
 	Code(Loop,) \
 	Code(Master,) \
 	Code(Master,) \
 	Code(Music,) \
 	Code(Music,) \
@@ -568,6 +572,7 @@ namespace Properties
 	Code(KeyName,) \
 	Code(KeyName,) \
 	Code(Minutes,) \
 	Code(Minutes,) \
 	Code(Month,) \
 	Code(Month,) \
+	Code(PauseInEditor,) \
 	Code(Radius,) \
 	Code(Radius,) \
 	Code(Script,) \
 	Code(Script,) \
 	Code(ScriptObject,) \
 	Code(ScriptObject,) \
@@ -673,7 +678,8 @@ public:
 		AudioVariables()
 		AudioVariables()
 		{
 		{
 			impact_impulse_param_divider = 1.0f;
 			impact_impulse_param_divider = 1.0f;
-			impact_impulse_volume_divider = 200.0f;
+			impact_impulse_volume_divider = 100.0f;
+			impact_min_volume_threshold = 0.1f;
 			impact_max_volume_threshold = 1.0f;
 			impact_max_volume_threshold = 1.0f;
 			impact_soft_hard_threshold = 30.0f;
 			impact_soft_hard_threshold = 30.0f;
 			max_impact_volume = 2.0f;
 			max_impact_volume = 2.0f;
@@ -696,6 +702,7 @@ public:
 
 
 		float impact_impulse_param_divider;
 		float impact_impulse_param_divider;
 		float impact_impulse_volume_divider;
 		float impact_impulse_volume_divider;
+		float impact_min_volume_threshold;
 		float impact_max_volume_threshold;
 		float impact_max_volume_threshold;
 		float impact_soft_hard_threshold;
 		float impact_soft_hard_threshold;
 		float max_impact_volume;
 		float max_impact_volume;
@@ -1001,8 +1008,6 @@ public:
 		int bloom_mipmap_limit;
 		int bloom_mipmap_limit;
 		int current_resolution_x;
 		int current_resolution_x;
 		int current_resolution_y;
 		int current_resolution_y;
-		//int csm_num_of_levels;
-		//int csm_resolution;
 		int dir_shadow_res_x;
 		int dir_shadow_res_x;
 		int dir_shadow_res_y;
 		int dir_shadow_res_y;
 		int lens_flare_blur_passes;
 		int lens_flare_blur_passes;
@@ -1073,6 +1078,7 @@ public:
 			gui_render = true;
 			gui_render = true;
 			gui_dark_style = true;
 			gui_dark_style = true;
 			gui_sequence_array_reserve_size = 50;
 			gui_sequence_array_reserve_size = 50;
+			about_window_font_size = 30.0f;
 			editor_asset_selection_button_size_multiplier = 2.0f;
 			editor_asset_selection_button_size_multiplier = 2.0f;
 			editor_asset_texture_button_size_x = 60.0f;
 			editor_asset_texture_button_size_x = 60.0f;
 			editor_asset_texture_button_size_y = 60.0f;
 			editor_asset_texture_button_size_y = 60.0f;
@@ -1089,7 +1095,9 @@ public:
 			gui_file_dialog_dir_color_B = 0.314f;
 			gui_file_dialog_dir_color_B = 0.314f;
 			loading_spinner_radius = 24.0f;
 			loading_spinner_radius = 24.0f;
 			loading_spinner_speed = 16.0f;
 			loading_spinner_speed = 16.0f;
-			loading_spinner_thickness = 3.0f;
+			loading_spinner_thickness = 3.0f; 
+			about_window_font = "OpenSans-Regular.ttf";
+			about_window_logo_texture = "logo2.png";
 			editor_button_add_texture = "button_add_3.png";
 			editor_button_add_texture = "button_add_3.png";
 			editor_button_add_list_texture = "button_add_from_list_1.png";
 			editor_button_add_list_texture = "button_add_from_list_1.png";
 			editor_button_arrow_down_texture = "button_arrow_down_1.png";
 			editor_button_arrow_down_texture = "button_arrow_down_1.png";
@@ -1107,11 +1115,14 @@ public:
 			editor_button_scripting_enabled_texture = "button_scripting_3.png";
 			editor_button_scripting_enabled_texture = "button_scripting_3.png";
 			editor_new_entity_name = "New Entity";
 			editor_new_entity_name = "New Entity";
 			gui_editor_window_name = "Editor window";
 			gui_editor_window_name = "Editor window";
+			url_github = "https://github.com/paul-akl/Praxis3D";
+			url_pauldev = "http://www.pauldev.org/project-praxis3d.html";
 		}
 		}
 		bool gui_docking_enabled;
 		bool gui_docking_enabled;
 		bool gui_render;
 		bool gui_render;
 		bool gui_dark_style;
 		bool gui_dark_style;
 		int gui_sequence_array_reserve_size;
 		int gui_sequence_array_reserve_size;
+		float about_window_font_size;
 		float editor_asset_selection_button_size_multiplier;
 		float editor_asset_selection_button_size_multiplier;
 		float editor_asset_texture_button_size_x;
 		float editor_asset_texture_button_size_x;
 		float editor_asset_texture_button_size_y;
 		float editor_asset_texture_button_size_y;
@@ -1129,6 +1140,8 @@ public:
 		float loading_spinner_radius;
 		float loading_spinner_radius;
 		float loading_spinner_speed;
 		float loading_spinner_speed;
 		float loading_spinner_thickness;
 		float loading_spinner_thickness;
+		std::string about_window_font;
+		std::string about_window_logo_texture;
 		std::string editor_button_add_texture;
 		std::string editor_button_add_texture;
 		std::string editor_button_add_list_texture;
 		std::string editor_button_add_list_texture;
 		std::string editor_button_arrow_down_texture;
 		std::string editor_button_arrow_down_texture;
@@ -1146,6 +1159,8 @@ public:
 		std::string editor_button_scripting_enabled_texture;
 		std::string editor_button_scripting_enabled_texture;
 		std::string editor_new_entity_name;
 		std::string editor_new_entity_name;
 		std::string gui_editor_window_name;
 		std::string gui_editor_window_name;
+		std::string url_github;
+		std::string url_pauldev;
 	};
 	};
 	struct InputVariables
 	struct InputVariables
 	{
 	{
@@ -1292,6 +1307,7 @@ public:
 		{
 		{
 			config_path = "Data\\";
 			config_path = "Data\\";
 			engine_assets_path = "Default\\";
 			engine_assets_path = "Default\\";
+			font_path = "Data\\Fonts\\";
 			gui_assets_path = "Default\\GUI\\";
 			gui_assets_path = "Default\\GUI\\";
 			map_path = "Data\\Maps\\";
 			map_path = "Data\\Maps\\";
 			model_path = "Data\\Models\\";
 			model_path = "Data\\Models\\";
@@ -1305,6 +1321,7 @@ public:
 
 
 		std::string config_path;
 		std::string config_path;
 		std::string engine_assets_path;
 		std::string engine_assets_path;
+		std::string font_path;
 		std::string gui_assets_path;
 		std::string gui_assets_path;
 		std::string map_path;
 		std::string map_path;
 		std::string model_path;
 		std::string model_path;
@@ -1319,7 +1336,7 @@ public:
 	{
 	{
 		PhysicsVariables()
 		PhysicsVariables()
 		{
 		{
-			applied_impulse_threshold = 20.0f;
+			applied_impulse_threshold = 1.0f;
 			life_time_threshold = 2;
 			life_time_threshold = 2;
 		}
 		}
 		float applied_impulse_threshold;
 		float applied_impulse_threshold;
@@ -1400,6 +1417,8 @@ public:
 			csm_penumbra_size = 1.42f;
 			csm_penumbra_size = 1.42f;
 			csm_penumbra_size_scale_min = 1.0f;
 			csm_penumbra_size_scale_min = 1.0f;
 			csm_penumbra_size_scale_max = 2000.0f;
 			csm_penumbra_size_scale_max = 2000.0f;
+			current_viewport_position_x = 0.0f;
+			current_viewport_position_y = 0.0f;
 			dir_light_quad_offset_x = 0.0f;
 			dir_light_quad_offset_x = 0.0f;
 			dir_light_quad_offset_y = 0.0f;
 			dir_light_quad_offset_y = 0.0f;
 			dir_light_quad_offset_z = 0.0f;
 			dir_light_quad_offset_z = 0.0f;
@@ -1410,6 +1429,8 @@ public:
 			parallax_mapping_max_steps = 32.0f;
 			parallax_mapping_max_steps = 32.0f;
 			csm_num_of_pcf_samples = 16;
 			csm_num_of_pcf_samples = 16;
 			csm_resolution = 2048;
 			csm_resolution = 2048;
+			current_viewport_size_x = 0;
+			current_viewport_size_y = 0;
 			depth_test_func = GL_LESS;
 			depth_test_func = GL_LESS;
 			face_culling_mode = GL_BACK;
 			face_culling_mode = GL_BACK;
 			heightmap_combine_channel = 3;
 			heightmap_combine_channel = 3;
@@ -1497,6 +1518,8 @@ public:
 		float csm_penumbra_size;
 		float csm_penumbra_size;
 		float csm_penumbra_size_scale_min;
 		float csm_penumbra_size_scale_min;
 		float csm_penumbra_size_scale_max;
 		float csm_penumbra_size_scale_max;
+		float current_viewport_position_x;
+		float current_viewport_position_y;
 		float dir_light_quad_offset_x;
 		float dir_light_quad_offset_x;
 		float dir_light_quad_offset_y;
 		float dir_light_quad_offset_y;
 		float dir_light_quad_offset_z;
 		float dir_light_quad_offset_z;
@@ -1507,6 +1530,8 @@ public:
 		float parallax_mapping_max_steps;
 		float parallax_mapping_max_steps;
 		int csm_num_of_pcf_samples;
 		int csm_num_of_pcf_samples;
 		int csm_resolution;
 		int csm_resolution;
+		int current_viewport_size_x;
+		int current_viewport_size_y;
 		int depth_test_func;
 		int depth_test_func;
 		int face_culling_mode;
 		int face_culling_mode;
 		int heightmap_combine_channel;
 		int heightmap_combine_channel;

+ 2 - 0
Praxis3D/Source/EditorState.cpp

@@ -68,6 +68,8 @@ void EditorState::update(Engine &p_engine)
 
 
 	m_objectChangeController->distributeChanges();
 	m_objectChangeController->distributeChanges();
 	m_sceneChangeController->distributeChanges();
 	m_sceneChangeController->distributeChanges();
+
+	updateSceneLoadingStatus();
 }
 }
 
 
 void EditorState::activate()
 void EditorState::activate()

+ 60 - 10
Praxis3D/Source/EditorWindow.cpp

@@ -1,5 +1,4 @@
 
 
-
 #include <fstream>
 #include <fstream>
 #include <glm/gtc/type_ptr.hpp>
 #include <glm/gtc/type_ptr.hpp>
 #include <ranges>
 #include <ranges>
@@ -314,6 +313,26 @@ void EditorWindow::update(const float p_deltaTime)
             }
             }
             ImGui::EndMenu();
             ImGui::EndMenu();
         }
         }
+        if(ImGui::BeginMenu("Help"))
+        {
+            if(ImGui::MenuItem("Open project page"))
+            {
+                ShellExecuteA(NULL, "open", Config::GUIVar().url_pauldev.c_str(), NULL, NULL, SW_SHOWNORMAL);
+            }
+            if(ImGui::MenuItem("Open Github page"))
+            {
+                ShellExecuteA(NULL, "open", Config::GUIVar().url_github.c_str(), NULL, NULL, SW_SHOWNORMAL);
+            }
+
+            ImGui::Separator();
+
+            if(ImGui::MenuItem("About"))
+            {
+                // Sent a message to the GUI scene to enable the about window
+                m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene->getSceneLoader()->getSystemScene(Systems::GUI), DataType::DataType_AboutWindow, (void *)true);
+            }
+            ImGui::EndMenu();
+        }
 
 
         // Process the pressed main menu button
         // Process the pressed main menu button
         processMainMenuButton(m_activatedMainMenuButton);
         processMainMenuButton(m_activatedMainMenuButton);
@@ -425,6 +444,9 @@ void EditorWindow::update(const float p_deltaTime)
 
 
                 // Tell the Physics scene to run the simulation
                 // Tell the Physics scene to run the simulation
                 m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene->getSceneLoader()->getSystemScene(Systems::Physics), DataType::DataType_SimulationActive, (void *)true);
                 m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene->getSceneLoader()->getSystemScene(Systems::Physics), DataType::DataType_SimulationActive, (void *)true);
+
+                // Tell the Scripting scene to enable LUA components
+                m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene->getSceneLoader()->getSystemScene(Systems::Script), DataType::DataType_EnableLuaScripting, (void *)true);
             }
             }
             ImGui::PopStyleColor();
             ImGui::PopStyleColor();
 
 
@@ -442,6 +464,9 @@ void EditorWindow::update(const float p_deltaTime)
 
 
                 // Tell the Physics scene to pause the simulation
                 // Tell the Physics scene to pause the simulation
                 m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene->getSceneLoader()->getSystemScene(Systems::Physics), DataType::DataType_SimulationActive, (void *)false);
                 m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene->getSceneLoader()->getSystemScene(Systems::Physics), DataType::DataType_SimulationActive, (void *)false);
+
+                // Tell the Scripting scene to either enable or disable LUA components
+                m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene->getSceneLoader()->getSystemScene(Systems::Script), DataType::DataType_EnableLuaScripting, (void *)m_LUAScriptingEnabled);
             }
             }
             ImGui::PopStyleColor();
             ImGui::PopStyleColor();
 
 
@@ -1968,17 +1993,18 @@ void EditorWindow::update(const float p_deltaTime)
                                 m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_spatialized = soundComponent->getSpatialized();
                                 m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_spatialized = soundComponent->getSpatialized();
                                 m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_startPlaying = soundComponent->getStartPlaying();
                                 m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_startPlaying = soundComponent->getStartPlaying();
                                 m_selectedEntity.m_soundType = soundComponent->getSoundType();
                                 m_selectedEntity.m_soundType = soundComponent->getSoundType();
+                                m_selectedEntity.m_soundSourceType = soundComponent->getSoundSourceType();
                                 m_selectedEntity.m_playing = soundComponent->getPlaying();
                                 m_selectedEntity.m_playing = soundComponent->getPlaying();
 
 
                                 // If the sound filename was changed (by file browser), send a notification to the Sound Component
                                 // If the sound filename was changed (by file browser), send a notification to the Sound Component
                                 // Otherwise just get the current sound filename
                                 // Otherwise just get the current sound filename
                                 if(m_selectedEntity.m_soundFilenameModified)
                                 if(m_selectedEntity.m_soundFilenameModified)
                                 {
                                 {
-                                    m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, soundComponent, Systems::Changes::Audio::Filename);
+                                    m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, soundComponent, Systems::Changes::Audio::SoundName);
                                     m_selectedEntity.m_soundFilenameModified = false;
                                     m_selectedEntity.m_soundFilenameModified = false;
                                 }
                                 }
                                 else
                                 else
-                                    m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_soundFilename = soundComponent->getSoundFilename();
+                                    m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_soundName = soundComponent->getSoundName();
 
 
                                 // Draw ACTIVE
                                 // Draw ACTIVE
                                 m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_active = soundComponent->isObjectActive();
                                 m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_active = soundComponent->isObjectActive();
@@ -1991,10 +2017,10 @@ void EditorWindow::update(const float p_deltaTime)
 
 
                                 // Draw SOUND FILENAME
                                 // Draw SOUND FILENAME
                                 drawLeftAlignedLabelText("Filename:", inputWidgetOffset, calcTextSizedButtonOffset(1) - inputWidgetOffset - m_imguiStyle.FramePadding.x);
                                 drawLeftAlignedLabelText("Filename:", inputWidgetOffset, calcTextSizedButtonOffset(1) - inputWidgetOffset - m_imguiStyle.FramePadding.x);
-                                if(ImGui::InputText("##SoundFilenameInput", &m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_soundFilename, ImGuiInputTextFlags_EnterReturnsTrue))
+                                if(ImGui::InputText("##SoundFilenameInput", &m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_soundName, ImGuiInputTextFlags_EnterReturnsTrue))
                                 {
                                 {
                                     // If the sound filename was changed, send a notification to the Sound Component
                                     // If the sound filename was changed, send a notification to the Sound Component
-                                    m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, soundComponent, Systems::Changes::Audio::Filename);
+                                    m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, soundComponent, Systems::Changes::Audio::SoundName);
                                 }
                                 }
 
 
                                 // Draw OPEN button
                                 // Draw OPEN button
@@ -2038,6 +2064,14 @@ void EditorWindow::update(const float p_deltaTime)
                                     m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, soundComponent, Systems::Changes::Audio::SoundType);
                                     m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, soundComponent, Systems::Changes::Audio::SoundType);
                                 }
                                 }
 
 
+                                // Draw SOUND SOURCE TYPE
+                                drawLeftAlignedLabelText("Sound source type:", inputWidgetOffset);
+                                if(ImGui::Combo("##SoundSourceTypePicker", &m_selectedEntity.m_soundSourceType, &(soundComponent->getSoundSourceTypeText()[0]), SoundComponent::SoundSourceType_NumOfTypes))
+                                {
+                                    // If the sound source type was changed, send a notification to the Sound Component
+                                    m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, soundComponent, Systems::Changes::Audio::SoundSourceType);
+                                }
+
                                 // Draw VOLUME
                                 // Draw VOLUME
                                 drawLeftAlignedLabelText("Volume:", inputWidgetOffset);
                                 drawLeftAlignedLabelText("Volume:", inputWidgetOffset);
                                 if(ImGui::DragFloat("##SoundVolumeDrag", &m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_volume, Config::GUIVar().editor_float_slider_speed, 0.0f, 1.0f))
                                 if(ImGui::DragFloat("##SoundVolumeDrag", &m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_volume, Config::GUIVar().editor_float_slider_speed, 0.0f, 1.0f))
@@ -2143,8 +2177,10 @@ void EditorWindow::update(const float p_deltaTime)
                                     else
                                     else
                                         m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_luaScriptFilename = luaScript->getLuaScriptFilename();
                                         m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_luaScriptFilename = luaScript->getLuaScriptFilename();
 
 
-                                    // Draw ACTIVE
                                     m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_active = luaComponent->isObjectActive();
                                     m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_active = luaComponent->isObjectActive();
+                                    m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_pauseInEditor = luaComponent->pauseInEditor();
+
+                                    // Draw ACTIVE
                                     drawLeftAlignedLabelText("Active:", inputWidgetOffset);
                                     drawLeftAlignedLabelText("Active:", inputWidgetOffset);
                                     if(ImGui::Checkbox("##LUAComponentActive", &m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_active))
                                     if(ImGui::Checkbox("##LUAComponentActive", &m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_active))
                                     {
                                     {
@@ -2152,6 +2188,14 @@ void EditorWindow::update(const float p_deltaTime)
                                         m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, luaComponent, Systems::Changes::Generic::Active);
                                         m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, luaComponent, Systems::Changes::Generic::Active);
                                     }
                                     }
 
 
+                                    // Draw PAUSE IN EDITOR
+                                    drawLeftAlignedLabelText("Pause in editor:", inputWidgetOffset);
+                                    if(ImGui::Checkbox("##LUAPauseInEditorCheckbox", &m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_pauseInEditor))
+                                    {
+                                        // If the pause-in-editor flag was changed, send a notification to the LUA Component
+                                        m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, luaComponent, Systems::Changes::Script::PauseInEditor);
+                                    }
+
                                     // Draw LUA FILENAME
                                     // Draw LUA FILENAME
                                     drawLeftAlignedLabelText("Filename:", inputWidgetOffset, calcTextSizedButtonOffset(1) - inputWidgetOffset - m_imguiStyle.FramePadding.x);
                                     drawLeftAlignedLabelText("Filename:", inputWidgetOffset, calcTextSizedButtonOffset(1) - inputWidgetOffset - m_imguiStyle.FramePadding.x);
                                     if(ImGui::InputText("##LuaScriptFilenameInput", &m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_luaScriptFilename, ImGuiInputTextFlags_EnterReturnsTrue))
                                     if(ImGui::InputText("##LuaScriptFilenameInput", &m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_luaScriptFilename, ImGuiInputTextFlags_EnterReturnsTrue))
@@ -3190,8 +3234,6 @@ void EditorWindow::update(const float p_deltaTime)
                             {
                             {
                                 ShellExecuteA(NULL, "explore", (Filesystem::getCurrentDirectory() + "\\" + Config::filepathVar().shader_path + Utilities::stripFilePath(m_selectedProgram->getShaderFilename(m_selectedShaderType))).c_str(), NULL, NULL, SW_SHOWDEFAULT);
                                 ShellExecuteA(NULL, "explore", (Filesystem::getCurrentDirectory() + "\\" + Config::filepathVar().shader_path + Utilities::stripFilePath(m_selectedProgram->getShaderFilename(m_selectedShaderType))).c_str(), NULL, NULL, SW_SHOWDEFAULT);
                             }
                             }
-
-
                         }
                         }
                         ImGui::EndChild();
                         ImGui::EndChild();
 
 
@@ -3413,6 +3455,9 @@ void EditorWindow::update(const float p_deltaTime)
                     m_centerWindowSize.x = (int)m_sceneViewportSize.x;
                     m_centerWindowSize.x = (int)m_sceneViewportSize.x;
                     m_centerWindowSize.y = (int)m_sceneViewportSize.y;
                     m_centerWindowSize.y = (int)m_sceneViewportSize.y;
 
 
+                    Config::m_rendererVar.current_viewport_position_x = m_sceneViewportPosition.x;
+                    Config::m_rendererVar.current_viewport_position_y = m_sceneViewportPosition.y;
+
                     // Tell the renderer the size of available window space as a render to texture resolution, so that the rendered scene fill the whole window
                     // Tell the renderer the size of available window space as a render to texture resolution, so that the rendered scene fill the whole window
                     m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene->getSceneLoader()->getSystemScene(Systems::Graphics), DataType::DataType_RenderToTextureResolution, (void *)&m_centerWindowSize);
                     m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene->getSceneLoader()->getSystemScene(Systems::Graphics), DataType::DataType_RenderToTextureResolution, (void *)&m_centerWindowSize);
 
 
@@ -3847,7 +3892,7 @@ void EditorWindow::update(const float p_deltaTime)
                         if(m_fileBrowserDialog.m_filePathName.rfind(currentDirectory, 0) == 0)
                         if(m_fileBrowserDialog.m_filePathName.rfind(currentDirectory, 0) == 0)
                         {
                         {
                             // Set the selected file path as a relative path from current directory
                             // Set the selected file path as a relative path from current directory
-                            m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_soundFilename = m_fileBrowserDialog.m_filePathName.substr(currentDirectory.size());
+                            m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_soundName = m_fileBrowserDialog.m_filePathName.substr(currentDirectory.size());
 
 
                             // If the Lua script filename was changed, set a flag for it
                             // If the Lua script filename was changed, set a flag for it
                             m_selectedEntity.m_soundFilenameModified = true;
                             m_selectedEntity.m_soundFilenameModified = true;
@@ -4034,6 +4079,7 @@ void EditorWindow::update(const float p_deltaTime)
 void EditorWindow::activate()
 void EditorWindow::activate()
 {
 {
     WindowLocator::get().setWindowTitle(Config::windowVar().name + " - Editor");
     WindowLocator::get().setWindowTitle(Config::windowVar().name + " - Editor");
+    WindowLocator::get().setMouseCapture(false);
 }
 }
 
 
 void EditorWindow::deactivate()
 void EditorWindow::deactivate()
@@ -4821,6 +4867,8 @@ void EditorWindow::processMainMenuButton(MainMenuButtonType &p_mainMenuButtonTyp
         case EditorWindow::MainMenuButtonType_CloseEditor:
         case EditorWindow::MainMenuButtonType_CloseEditor:
             // Send a notification to the engine to change the current engine state back to MainMenu
             // Send a notification to the engine to change the current engine state back to MainMenu
             m_systemScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(EngineChangeType::EngineChangeType_StateChange, EngineStateType::EngineStateType_MainMenu));
             m_systemScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(EngineChangeType::EngineChangeType_StateChange, EngineStateType::EngineStateType_MainMenu));
+            // Unload the editor state
+            m_systemScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(EngineChangeType::EngineChangeType_SceneUnload, EngineStateType::EngineStateType_Editor));
             break;
             break;
         case EditorWindow::MainMenuButtonType_Exit:
         case EditorWindow::MainMenuButtonType_Exit:
             Config::m_engineVar.running = false;
             Config::m_engineVar.running = false;
@@ -5272,7 +5320,9 @@ void EditorWindow::generateNewMap(PropertySet &p_newSceneProperties, SceneData &
     editorCameraObjectEntry.addProperty(Properties::PropertyID::ID, 2000000000);
     editorCameraObjectEntry.addProperty(Properties::PropertyID::ID, 2000000000);
     editorCameraObjectEntry.addProperty(Properties::PropertyID::Parent, 0);
     editorCameraObjectEntry.addProperty(Properties::PropertyID::Parent, 0);
     editorCameraObjectEntry.addPropertySet(Properties::PropertyID::Graphics).addPropertySet(Properties::PropertyID::CameraComponent);
     editorCameraObjectEntry.addPropertySet(Properties::PropertyID::Graphics).addPropertySet(Properties::PropertyID::CameraComponent);
-    editorCameraObjectEntry.addPropertySet(Properties::PropertyID::Script).addPropertySet(Properties::PropertyID::LuaComponent).addProperty(Properties::PropertyID::Filename, std::string("Camera_free_object_spawn.lua"));
+    auto &luaComponentEntry = editorCameraObjectEntry.addPropertySet(Properties::PropertyID::Script).addPropertySet(Properties::PropertyID::LuaComponent);
+    luaComponentEntry.addProperty(Properties::PropertyID::Filename, std::string("Camera_free.lua"));
+    luaComponentEntry.addProperty(Properties::PropertyID::PauseInEditor, false);
     editorCameraObjectEntry.addPropertySet(Properties::PropertyID::World).addPropertySet(Properties::PropertyID::SpatialComponent);
     editorCameraObjectEntry.addPropertySet(Properties::PropertyID::World).addPropertySet(Properties::PropertyID::SpatialComponent);
 
 
     // Add root property set for systems
     // Add root property set for systems

+ 18 - 3
Praxis3D/Source/EditorWindow.h

@@ -26,7 +26,7 @@ public:
 	{
 	{
 		m_renderSceneToTexture = true;
 		m_renderSceneToTexture = true;
 		m_GUISequenceEnabled = false;
 		m_GUISequenceEnabled = false;
-		m_LUAScriptingEnabled = true;
+		m_LUAScriptingEnabled = false;
 		m_translateGuizmoEnabled = true;
 		m_translateGuizmoEnabled = true;
 		m_rotateGuizmoEnabled = false;
 		m_rotateGuizmoEnabled = false;
 		m_showNewMapWindow = false;
 		m_showNewMapWindow = false;
@@ -240,6 +240,12 @@ public:
 					return m_selectedEntity.m_componentData.m_guiComponents.m_guiSequenceConstructionInfo->m_staticSequence;
 					return m_selectedEntity.m_componentData.m_guiComponents.m_guiSequenceConstructionInfo->m_staticSequence;
 				}
 				}
 				break;
 				break;
+
+			case Systems::Changes::Script::PauseInEditor:
+				{
+					return m_selectedEntity.m_componentData.m_scriptComponents.m_luaConstructionInfo->m_pauseInEditor;
+				}
+				break;
 		}
 		}
 
 
 		return NullObjects::NullBool; 
 		return NullObjects::NullBool; 
@@ -288,6 +294,13 @@ public:
 				}
 				}
 				break;
 				break;
 
 
+			case Systems::Changes::Audio::SoundSourceType:
+				{
+					if(m_selectedEntity.m_soundSourceType >= 0 && m_selectedEntity.m_soundSourceType < SoundComponent::SoundSourceType_NumOfTypes)
+						return (unsigned int)m_selectedEntity.m_soundSourceType;
+				}
+				break;
+
 			case Systems::Changes::Graphics::LightType:
 			case Systems::Changes::Graphics::LightType:
 				{
 				{
 					if(m_selectedEntity.m_lightType >= 0 && m_selectedEntity.m_lightType < LightComponent::LightComponentType::LightComponentType_spot + 1)
 					if(m_selectedEntity.m_lightType >= 0 && m_selectedEntity.m_lightType < LightComponent::LightComponentType::LightComponentType_spot + 1)
@@ -427,9 +440,9 @@ public:
 				}
 				}
 				break;
 				break;
 
 
-			case Systems::Changes::Audio::Filename:
+			case Systems::Changes::Audio::SoundName:
 				{
 				{
-					return m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_soundFilename;
+					return m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_soundName;
 				}
 				}
 				break;
 				break;
 
 
@@ -641,6 +654,7 @@ private:
 			setEntity(NULL_ENTITY_ID);
 			setEntity(NULL_ENTITY_ID);
 			m_playing = false;
 			m_playing = false;
 			m_soundType = SoundComponent::SoundType::SoundType_Null;
 			m_soundType = SoundComponent::SoundType::SoundType_Null;
+			m_soundSourceType = 0;
 			m_objectMaterialType = ObjectMaterialType::Concrete;
 			m_objectMaterialType = ObjectMaterialType::Concrete;
 			m_lightType = LightComponent::LightComponentType::LightComponentType_null;
 			m_lightType = LightComponent::LightComponentType::LightComponentType_null;
 			m_collisionShapeType = RigidBodyComponent::CollisionShapeType::CollisionShapeType_Null;
 			m_collisionShapeType = RigidBodyComponent::CollisionShapeType::CollisionShapeType_Null;
@@ -713,6 +727,7 @@ private:
 		// SoundComponent data
 		// SoundComponent data
 		bool m_playing;
 		bool m_playing;
 		int m_soundType;
 		int m_soundType;
+		int m_soundSourceType;
 
 
 		// SpatialComponent data
 		// SpatialComponent data
 		SpatialDataManager m_spatialDataManager;
 		SpatialDataManager m_spatialDataManager;

+ 21 - 6
Praxis3D/Source/Engine.cpp

@@ -148,13 +148,16 @@ void Engine::processEngineChanges()
 	auto changeControllerScene = m_engineStates[m_currentStateType]->getChangeControllerScene();
 	auto changeControllerScene = m_engineStates[m_currentStateType]->getChangeControllerScene();
 	if(changeControllerScene->getEngineChangePending())
 	if(changeControllerScene->getEngineChangePending())
 	{
 	{
+		// Save the current engine state type, in case it gets changed
+		auto previousStateType = m_currentStateType;
+
 		// Go over each engine change
 		// Go over each engine change
 		auto engineChanges = changeControllerScene->getEngineChangeQueue();
 		auto engineChanges = changeControllerScene->getEngineChangeQueue();
 		for(auto const &change : engineChanges)
 		for(auto const &change : engineChanges)
 		{
 		{
 			switch(change.m_changeType)
 			switch(change.m_changeType)
 			{
 			{
-				case EngineChangeType_SceneFilename:
+				case EngineChangeType::EngineChangeType_SceneFilename:
 					{
 					{
 						// Create the state if it hasn't been created already
 						// Create the state if it hasn't been created already
 						if(m_engineStates[change.m_engineStateType] == nullptr)
 						if(m_engineStates[change.m_engineStateType] == nullptr)
@@ -163,12 +166,10 @@ void Engine::processEngineChanges()
 						m_engineStates[change.m_engineStateType]->setSceneFilename(change.m_filename);
 						m_engineStates[change.m_engineStateType]->setSceneFilename(change.m_filename);
 					}
 					}
 					break;
 					break;
-				case EngineChangeType_SceneLoad:
+				case EngineChangeType::EngineChangeType_SceneLoad:
 					{
 					{
 						if(initializeState(change.m_engineStateType))
 						if(initializeState(change.m_engineStateType))
 						{
 						{
-							bool stateLoaded = false;
-
 							if(change.m_sceneProperties)
 							if(change.m_sceneProperties)
 								loadState(change.m_engineStateType, change.m_sceneProperties);
 								loadState(change.m_engineStateType, change.m_sceneProperties);
 							else
 							else
@@ -176,7 +177,21 @@ void Engine::processEngineChanges()
 						}
 						}
 					}
 					}
 					break;
 					break;
-				case EngineChangeType_SceneReload:
+				case EngineChangeType::EngineChangeType_SceneUnload:
+					{
+						if(m_engineStates[change.m_engineStateType] != nullptr)
+						{
+							auto engineStateType = change.m_engineStateType;
+
+							m_engineStates[engineStateType]->shutdown();
+							delete m_engineStates[engineStateType];
+							m_engineStates[engineStateType] = nullptr;
+							if(engineStateType == previousStateType)
+								return;
+						}
+					}
+					break;
+				case EngineChangeType::EngineChangeType_SceneReload:
 					{
 					{
 						std::string filename = change.m_filename;
 						std::string filename = change.m_filename;
 
 
@@ -203,7 +218,7 @@ void Engine::processEngineChanges()
 						return;
 						return;
 					}
 					}
 					break;
 					break;
-				case EngineChangeType_StateChange:
+				case EngineChangeType::EngineChangeType_StateChange:
 					{
 					{
 						if(initializeState(change.m_engineStateType))
 						if(initializeState(change.m_engineStateType))
 						{
 						{

+ 1 - 1
Praxis3D/Source/EngineState.cpp

@@ -8,7 +8,7 @@
 #include "ScriptSystem.h"
 #include "ScriptSystem.h"
 #include "WorldSystem.h"
 #include "WorldSystem.h"
 
 
-EngineState::EngineState(Engine &p_engine, EngineStateType p_engineState) : m_engine(p_engine), m_engineStateType(p_engineState), m_initialized(false), m_loaded(false)
+EngineState::EngineState(Engine &p_engine, EngineStateType p_engineState) : m_engine(p_engine), m_sceneLoader(p_engineState), m_engineStateType(p_engineState), m_initialized(false), m_loaded(false)
 {
 {
 	m_sceneChangeController = nullptr;
 	m_sceneChangeController = nullptr;
 	m_objectChangeController = nullptr;
 	m_objectChangeController = nullptr;

+ 20 - 0
Praxis3D/Source/EngineState.h

@@ -43,6 +43,26 @@ public:
 	inline void setSceneFilename(const std::string &p_filename) { m_sceneFilename = p_filename; }
 	inline void setSceneFilename(const std::string &p_filename) { m_sceneFilename = p_filename; }
 
 
 protected:
 protected:
+	inline void updateSceneLoadingStatus()
+	{
+		bool loadingStatus = false;
+		auto systemScenes = m_sceneLoader.getAllSystemScenes();
+
+		for(unsigned int i = 0; i < Systems::TypeID::NumberOfSystems; i++)
+		{
+			if(systemScenes[i]->getLoadingStatus())
+				loadingStatus = true;
+		}
+
+		if(m_sceneLoader.getFirstLoad())
+		{
+			if(!loadingStatus)
+				m_sceneLoader.setFirstLoad(false);
+		}
+
+		m_sceneLoader.setSceneLoadingStatus(loadingStatus);
+	}
+
 	bool m_initialized;
 	bool m_initialized;
 	bool m_loaded;
 	bool m_loaded;
 	EngineStateType m_engineStateType;
 	EngineStateType m_engineStateType;

+ 3 - 0
Praxis3D/Source/ErrorCodes.h

@@ -60,6 +60,7 @@ DECLARE_ENUM(ErrorType, ERROR_TYPES)
 	Code(Geometrybuffer_failed,) \
 	Code(Geometrybuffer_failed,) \
 	/* GUI errors */ \
 	/* GUI errors */ \
 	Code(Editor_path_outside_current_dir,) \
 	Code(Editor_path_outside_current_dir,) \
+	Code(Font_type_missing_construction,) \
 	Code(GL_context_missing,) \
 	Code(GL_context_missing,) \
 	Code(Universal_scene_extend_null,) \
 	Code(Universal_scene_extend_null,) \
 	Code(Universal_scene_extend_duplicate,) \
 	Code(Universal_scene_extend_duplicate,) \
@@ -70,6 +71,8 @@ DECLARE_ENUM(ErrorType, ERROR_TYPES)
 	Code(ObjectPool_full,) \
 	Code(ObjectPool_full,) \
 	/* Physics system errors */ \
 	/* Physics system errors */ \
 	Code(Collision_invalid,) \
 	Code(Collision_invalid,) \
+	Code(Collision_max_dynamic_events,) \
+	Code(Collision_max_static_events,) \
 	Code(Collision_missing,) \
 	Code(Collision_missing,) \
 	Code(Kinematic_has_mass,) \
 	Code(Kinematic_has_mass,) \
 	/* Property loader errors */ \
 	/* Property loader errors */ \

+ 3 - 0
Praxis3D/Source/ErrorHandler.cpp

@@ -42,6 +42,7 @@ ErrorHandler::ErrorHandler()
 	AssignErrorType(Framebuffer_failed, FatalError);
 	AssignErrorType(Framebuffer_failed, FatalError);
 	AssignErrorType(Geometrybuffer_failed, FatalError);
 	AssignErrorType(Geometrybuffer_failed, FatalError);
 	AssignErrorType(Editor_path_outside_current_dir, Warning);
 	AssignErrorType(Editor_path_outside_current_dir, Warning);
+	AssignErrorType(Font_type_missing_construction, Warning);
 	AssignErrorType(GL_context_missing, Error);
 	AssignErrorType(GL_context_missing, Error);
 	AssignErrorType(Universal_scene_extend_null, Error);
 	AssignErrorType(Universal_scene_extend_null, Error);
 	AssignErrorType(Universal_scene_extend_duplicate, Error);
 	AssignErrorType(Universal_scene_extend_duplicate, Error);
@@ -49,6 +50,8 @@ ErrorHandler::ErrorHandler()
 	AssignErrorType(AssimpScene_failed, Error);
 	AssignErrorType(AssimpScene_failed, Error);
 	AssignErrorType(ObjectPool_full, Warning); 
 	AssignErrorType(ObjectPool_full, Warning); 
 	AssignErrorType(Collision_invalid, Warning);
 	AssignErrorType(Collision_invalid, Warning);
+	AssignErrorType(Collision_max_dynamic_events, Warning);
+	AssignErrorType(Collision_max_static_events, Warning);
 	AssignErrorType(Collision_missing, Warning);
 	AssignErrorType(Collision_missing, Warning);
 	AssignErrorType(Kinematic_has_mass, Warning);
 	AssignErrorType(Kinematic_has_mass, Warning);
 	AssignErrorType(Property_missing_size, Warning);
 	AssignErrorType(Property_missing_size, Warning);

+ 3 - 0
Praxis3D/Source/GUIHandler.h

@@ -152,6 +152,9 @@ protected:
 				ImGui_ImplSDL2_InitForOpenGL(windowHandle, glContextHandle);
 				ImGui_ImplSDL2_InitForOpenGL(windowHandle, glContextHandle);
 				ImGui_ImplOpenGL3_Init(glsl_version);
 				ImGui_ImplOpenGL3_Init(glsl_version);
 
 
+				auto &imguiIO = ImGui::GetIO();
+				auto *m_defaultFont = imguiIO.Fonts->AddFontDefault();
+
 				m_initialized = true;
 				m_initialized = true;
 			}
 			}
 			else
 			else

+ 11 - 11
Praxis3D/Source/GUIScene.cpp

@@ -12,7 +12,7 @@
 #include "NullSystemObjects.h"
 #include "NullSystemObjects.h"
 #include "TaskManagerLocator.h"
 #include "TaskManagerLocator.h"
 
 
-GUIScene::GUIScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader, Properties::PropertyID::GUI)
+GUIScene::GUIScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader, Properties::PropertyID::GUI), m_aboutWindow(this)
 {
 {
 	 m_GUITask = nullptr;
 	 m_GUITask = nullptr;
 	 m_editorWindow = nullptr;
 	 m_editorWindow = nullptr;
@@ -20,7 +20,7 @@ GUIScene::GUIScene(SystemBase *p_system, SceneLoader *p_sceneLoader) : SystemSce
 	 m_showAboutWindow = false;
 	 m_showAboutWindow = false;
 	 m_showSettingsWindow = false;
 	 m_showSettingsWindow = false;
 
 
-	 m_aboutWindow = new AboutWindow(this);
+	 //m_aboutWindow = new AboutWindow(this);
 }
 }
 
 
 GUIScene::~GUIScene()
 GUIScene::~GUIScene()
@@ -28,8 +28,8 @@ GUIScene::~GUIScene()
 	if(m_GUITask != nullptr)
 	if(m_GUITask != nullptr)
 		delete m_GUITask;
 		delete m_GUITask;
 
 
-	if(m_aboutWindow != nullptr)
-		delete m_aboutWindow;
+	//if(m_aboutWindow != nullptr)
+	//	delete m_aboutWindow;
 
 
 	if(m_editorWindow != nullptr)
 	if(m_editorWindow != nullptr)
 		delete m_editorWindow;
 		delete m_editorWindow;
@@ -48,7 +48,7 @@ ErrorCode GUIScene::init()
 	ImVec4(0.808f, 0.498f, 0.306f, 1.0f)*/
 	ImVec4(0.808f, 0.498f, 0.306f, 1.0f)*/
 
 
 	// Initialize the About Window
 	// Initialize the About Window
-	if(ErrorCode aboutWindowError = m_aboutWindow->init(); aboutWindowError != ErrorCode::Success)
+	if(ErrorCode aboutWindowError = m_aboutWindow.init(); aboutWindowError != ErrorCode::Success)
 		ErrHandlerLoc::get().log(aboutWindowError, ErrorSource::Source_GUI);
 		ErrHandlerLoc::get().log(aboutWindowError, ErrorSource::Source_GUI);
 
 
 	return ErrorCode::Success;
 	return ErrorCode::Success;
@@ -106,13 +106,13 @@ void GUIScene::update(const float p_deltaTime)
 		//	|____________________________|
 		//	|____________________________|
 		//
 		//
 		// Check if any of the scenes are currently loading
 		// Check if any of the scenes are currently loading
-		bool loadingStatus = false;
+		/*bool loadingStatus = false;
 		for(unsigned int i = 0; i < Systems::TypeID::NumberOfSystems; i++)
 		for(unsigned int i = 0; i < Systems::TypeID::NumberOfSystems; i++)
 			if(m_sceneLoader->getSystemScene(static_cast<Systems::TypeID>(i))->getLoadingStatus())
 			if(m_sceneLoader->getSystemScene(static_cast<Systems::TypeID>(i))->getLoadingStatus())
-				loadingStatus = true;
+				loadingStatus = true;*/
 
 
 		// If any scenes are currently loading
 		// If any scenes are currently loading
-		if(loadingStatus)
+		if(m_sceneLoader->getSceneLoadingStatus())
 		{
 		{
 			auto &io = ImGui::GetIO();
 			auto &io = ImGui::GetIO();
 			ImVec2 sceneViewportCenter;
 			ImVec2 sceneViewportCenter;
@@ -214,7 +214,7 @@ void GUIScene::update(const float p_deltaTime)
 		//
 		//
 		if(m_showAboutWindow)
 		if(m_showAboutWindow)
 		{
 		{
-			m_aboutWindow->update(p_deltaTime);
+			m_aboutWindow.update(p_deltaTime);
 		}
 		}
 
 
 		//	 ____________________________
 		//	 ____________________________
@@ -396,9 +396,9 @@ void GUIScene::receiveData(const DataType p_dataType, void *p_data, const bool p
 					m_showAboutWindow = newShowAboutWindowFlag;
 					m_showAboutWindow = newShowAboutWindowFlag;
 
 
 					if(m_showAboutWindow)
 					if(m_showAboutWindow)
-						m_aboutWindow->activate();
+						m_aboutWindow.activate();
 					else
 					else
-						m_aboutWindow->deactivate();
+						m_aboutWindow.deactivate();
 				}
 				}
 			}
 			}
 			break;
 			break;

+ 2 - 1
Praxis3D/Source/GUIScene.h

@@ -1,5 +1,6 @@
 #pragma once
 #pragma once
 
 
+#include "AboutWindow.h"
 #include "GUIObject.h"
 #include "GUIObject.h"
 #include "GUITask.h"
 #include "GUITask.h"
 #include "ObjectPool.h"
 #include "ObjectPool.h"
@@ -177,7 +178,7 @@ private:
 
 
 	GUITask *m_GUITask;
 	GUITask *m_GUITask;
 	std::queue<FileBrowserDialog*> m_fileBrowserDialogs;
 	std::queue<FileBrowserDialog*> m_fileBrowserDialogs;
-	AboutWindow *m_aboutWindow;
+	AboutWindow m_aboutWindow;
 	EditorWindow *m_editorWindow;
 	EditorWindow *m_editorWindow;
 	bool m_GUISequenceEnabled;
 	bool m_GUISequenceEnabled;
 
 

+ 45 - 0
Praxis3D/Source/GUISystem.h

@@ -13,6 +13,7 @@ public:
 			m_GUIScenes[i] = nullptr;
 			m_GUIScenes[i] = nullptr;
 
 
 		m_systemName = GetString(Systems::GUI);
 		m_systemName = GetString(Systems::GUI);
+		m_fonts.resize(GuiFontType::GuiFontType_NumOfTypes, nullptr);
 	}
 	}
 	~GUISystem()
 	~GUISystem()
 	{
 	{
@@ -25,6 +26,9 @@ public:
 	{
 	{
 		ErrorCode returnCode = ErrorCode::Success;
 		ErrorCode returnCode = ErrorCode::Success;
 
 
+		// Load fonts
+		loadFonts();
+
 		return returnCode;
 		return returnCode;
 	}
 	}
 
 
@@ -82,6 +86,47 @@ public:
 		}
 		}
 	}
 	}
 
 
+	ImFont *getFont(const GuiFontType p_fontType)
+	{
+		if(p_fontType == GuiFontType::GuiFontType_NumOfTypes)
+			return m_fonts[GuiFontType::GuiFontType_Default];
+
+		return m_fonts[p_fontType];
+	}
+ 
 protected:
 protected:
+	void loadFonts()
+	{
+		for(unsigned int i = 0; i < GuiFontType::GuiFontType_NumOfTypes; i++)
+		{
+			switch(i)
+			{
+				case GuiFontType_Default:
+					{
+						m_fonts[i] = ImGui::GetIO().Fonts->Fonts[0];
+					}
+					break;
+				case GuiFontType_AboutWindow:
+					{
+						ImFontConfig fontConfig;
+						fontConfig.OversampleH = 2;
+						fontConfig.OversampleV = 1;
+						fontConfig.GlyphExtraSpacing.x = 1.0f;
+
+						m_fonts[i] = ImGui::GetIO().Fonts->AddFontFromFileTTF((Config::filepathVar().font_path + Config::filepathVar().engine_assets_path + Config::GUIVar().about_window_font).c_str(), Config::GUIVar().about_window_font_size, &fontConfig);
+					}
+					break;
+				default:
+					{
+						// If default is reached, it means that a case statement is missing for a given font type, so log an error and assign a default font instead
+						ErrHandlerLoc::get().log(ErrorCode::Font_type_missing_construction, ErrorSource::Source_GUI, "Font type: " + Utilities::toString(i));
+						m_fonts[i] = ImGui::GetIO().FontDefault;
+					}
+					break;
+			}
+		}
+	}
+
 	GUIScene *m_GUIScenes[EngineStateType::EngineStateType_NumOfTypes];
 	GUIScene *m_GUIScenes[EngineStateType::EngineStateType_NumOfTypes];
+	std::vector<ImFont *> m_fonts;
 };
 };

+ 0 - 5
Praxis3D/Source/GeometryBuffer.cpp

@@ -129,11 +129,6 @@ ErrorCode GeometryBuffer::init(const UniformFrameData &p_frameData)
 		m_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 		m_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 		if(m_status != GL_FRAMEBUFFER_COMPLETE)
 		if(m_status != GL_FRAMEBUFFER_COMPLETE)
 			returnCode = ErrorCode::Geometrybuffer_failed;
 			returnCode = ErrorCode::Geometrybuffer_failed;
-
-		// Restore the default FBO, so it doesn't get changed from the outside of the class
-		//glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-
-		//glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
 	}
 	}
 	return returnCode;
 	return returnCode;
 }
 }

+ 1 - 1
Praxis3D/Source/LightingPass.h

@@ -223,7 +223,7 @@ public:
 
 
 		ShaderLoader::ShaderProgram *lightPassShader = m_shaderLightCSMPass;
 		ShaderLoader::ShaderProgram *lightPassShader = m_shaderLightCSMPass;
 
 
-		if(shadowMappingData.m_shadowMappingEnabled && !shadowMappingData.m_shadowCascadePlaneDistances.empty())
+		if(p_sceneObjects.m_processDrawing && shadowMappingData.m_shadowMappingEnabled && !shadowMappingData.m_shadowCascadePlaneDistances.empty())
 		{
 		{
 			// If the number of shadow cascades has changed, set the new define inside the shader source and recompile the shader
 			// If the number of shadow cascades has changed, set the new define inside the shader source and recompile the shader
 			if(m_numOfCascades != (unsigned int)shadowMappingData.m_shadowCascadePlaneDistances.size() || m_numOfPCFSamples != shadowMappingData.m_numOfPCFSamples)
 			if(m_numOfCascades != (unsigned int)shadowMappingData.m_shadowCascadePlaneDistances.size() || m_numOfPCFSamples != shadowMappingData.m_numOfPCFSamples)

+ 81 - 2
Praxis3D/Source/LuaComponent.h

@@ -17,17 +17,19 @@ public:
 	{
 	{
 		LuaComponentConstructionInfo()
 		LuaComponentConstructionInfo()
 		{
 		{
-
+			m_pauseInEditor = true;
 		}
 		}
 
 
 		std::string m_luaScriptFilename;
 		std::string m_luaScriptFilename;
 		std::vector<std::pair<std::string, Property>> m_variables;
 		std::vector<std::pair<std::string, Property>> m_variables;
+		bool m_pauseInEditor;
 	};
 	};
 
 
 	LuaComponent(SystemScene *p_systemScene, const std::string &p_name, const EntityID p_entityID) : SystemObject(p_systemScene, p_name, Properties::PropertyID::LuaComponent, p_entityID), m_luaSpatialData(*this), m_GUIData(*this)
 	LuaComponent(SystemScene *p_systemScene, const std::string &p_name, const EntityID p_entityID) : SystemObject(p_systemScene, p_name, Properties::PropertyID::LuaComponent, p_entityID), m_luaSpatialData(*this), m_GUIData(*this)
 	{
 	{
-		m_luaScript = new LuaScript(m_systemScene, m_luaSpatialData, m_GUIData);
+		m_luaScript = new LuaScript(m_systemScene, this, m_luaSpatialData, m_GUIData);
 		m_luaScriptLoaded = false;
 		m_luaScriptLoaded = false;
+		m_pauseInEditor = true;
 		m_luaSpatialData.setTrackLocalChanges(true);
 		m_luaSpatialData.setTrackLocalChanges(true);
 	}
 	}
 	~LuaComponent() 
 	~LuaComponent() 
@@ -81,6 +83,15 @@ public:
 
 
 	inline void update(const float p_deltaTime, const SpatialComponent &p_spatialComponent)
 	inline void update(const float p_deltaTime, const SpatialComponent &p_spatialComponent)
 	{
 	{
+		// Clear the string changes of previous frame
+		if(!m_stringChanges.empty())
+		{
+			for(auto *change : m_stringChanges)
+				delete change;
+
+			m_stringChanges.clear();
+		}
+
 		// Get the current spatial data
 		// Get the current spatial data
 		m_luaSpatialData.setSpatialData(p_spatialComponent.getSpatialDataChangeManager());
 		m_luaSpatialData.setSpatialData(p_spatialComponent.getSpatialDataChangeManager());
 
 
@@ -157,6 +168,59 @@ public:
 	BitMask getDesiredSystemChanges() final override { return Systems::Changes::None; }
 	BitMask getDesiredSystemChanges() final override { return Systems::Changes::None; }
 	BitMask getPotentialSystemChanges() final override { return Systems::Changes::All; }
 	BitMask getPotentialSystemChanges() final override { return Systems::Changes::All; }
 
 
+	const bool getBool(const Observer *p_observer, BitMask p_changedBits) const
+	{
+		if(m_luaScript != nullptr && m_luaScriptLoaded)
+		{
+			if(auto *changeValue = m_luaScript->getQueuedChange(p_observer, p_changedBits); changeValue != nullptr)
+				return changeValue->getBool();
+		}
+
+		return NullObjects::NullBool;
+	}	
+	const int getInt(const Observer *p_observer, BitMask p_changedBits) const
+	{
+		if(m_luaScript != nullptr && m_luaScriptLoaded)
+		{
+			if(auto *changeValue = m_luaScript->getQueuedChange(p_observer, p_changedBits); changeValue != nullptr)
+				return changeValue->getInt();
+		}
+
+		return NullObjects::NullInt;
+	}
+	const unsigned int getUnsignedInt(const Observer *p_observer, BitMask p_changedBits) const
+	{
+		if(m_luaScript != nullptr && m_luaScriptLoaded)
+		{
+			if(auto *changeValue = m_luaScript->getQueuedChange(p_observer, p_changedBits); changeValue != nullptr)
+				return (unsigned int)changeValue->getInt();
+		}
+
+		return NullObjects::NullUnsignedInt;
+	}
+	const float getFloat(const Observer *p_observer, BitMask p_changedBits) const
+	{
+		if(m_luaScript != nullptr && m_luaScriptLoaded)
+		{
+			if(auto *changeValue = m_luaScript->getQueuedChange(p_observer, p_changedBits); changeValue != nullptr)
+				return changeValue->getFloat();
+		}
+
+		return NullObjects::NullFloat;
+	}
+	const std::string &getString(const Observer *p_observer, BitMask p_changedBits)	const
+	{
+		if(m_luaScript != nullptr && m_luaScriptLoaded)
+		{
+			if(auto *changeValue = m_luaScript->getQueuedChange(p_observer, p_changedBits); changeValue != nullptr)
+			{
+				m_stringChanges.push_back(new std::string(changeValue->getString()));
+				return *m_stringChanges.back();
+			}
+		}
+
+		return NullObjects::NullString;
+	}
 	const glm::quat &getQuaternion(const Observer *p_observer, BitMask p_changedBits) const
 	const glm::quat &getQuaternion(const Observer *p_observer, BitMask p_changedBits) const
 	{
 	{
 		return m_luaSpatialData.getQuaternion(p_observer, p_changedBits);
 		return m_luaSpatialData.getQuaternion(p_observer, p_changedBits);
@@ -196,8 +260,11 @@ public:
 
 
 		return NullObjects::NullFunctors;
 		return NullObjects::NullFunctors;
 	}
 	}
+
 	const inline LuaScript *getLuaScript() const { return m_luaScript; }
 	const inline LuaScript *getLuaScript() const { return m_luaScript; }
 
 
+	const bool pauseInEditor() const { return m_pauseInEditor; }
+
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) 
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) 
 	{
 	{
 		if(CheckBitmask(p_changeType, Systems::Changes::Generic::Active))
 		if(CheckBitmask(p_changeType, Systems::Changes::Generic::Active))
@@ -223,6 +290,12 @@ public:
 			}
 			}
 		}
 		}
 
 
+		if(CheckBitmask(p_changeType, Systems::Changes::Script::PauseInEditor))
+		{
+			// Get the pause in editor flag value from the observed subject
+			m_pauseInEditor = p_subject->getBool(this, Systems::Changes::Script::PauseInEditor);
+		}
+
 		if(CheckBitmask(p_changeType, Systems::Changes::Script::Reload))
 		if(CheckBitmask(p_changeType, Systems::Changes::Script::Reload))
 		{
 		{
 			// Check if the lua script exists
 			// Check if the lua script exists
@@ -271,7 +344,13 @@ public:
 private:
 private:
 	LuaScript *m_luaScript;
 	LuaScript *m_luaScript;
 	bool m_luaScriptLoaded;
 	bool m_luaScriptLoaded;
+	bool m_pauseInEditor;
 
 
 	SpatialDataManager m_luaSpatialData;
 	SpatialDataManager m_luaSpatialData;
 	GUIDataManager m_GUIData;
 	GUIDataManager m_GUIData;
+
+	// Contains string changes that are retrieved by an observer. These changes need to be contained, because the strings are constructed during the change retrieval
+	// Mutable because the change retrieval function is const
+	// Needs to be made out of pointers, to maintain pointer stability if the vector is resized
+	mutable std::vector<std::string*> m_stringChanges;
 };
 };

+ 129 - 42
Praxis3D/Source/LuaScript.cpp

@@ -2,6 +2,7 @@
 #include <ImGuiFileDialog/ImGuiFileDialog.h>
 #include <ImGuiFileDialog/ImGuiFileDialog.h>
 
 
 #include "ComponentConstructorInfo.h"
 #include "ComponentConstructorInfo.h"
+#include "GUISystem.h"
 #include "LuaScript.h"
 #include "LuaScript.h"
 #include "Loaders.h"
 #include "Loaders.h"
 
 
@@ -191,6 +192,12 @@ void LuaScript::setDefinitions()
 	imGuiStyleFlag[sol::update_if_empty]["ButtonTextAlign"] = ImGuiStyleVar_::ImGuiStyleVar_ButtonTextAlign;
 	imGuiStyleFlag[sol::update_if_empty]["ButtonTextAlign"] = ImGuiStyleVar_::ImGuiStyleVar_ButtonTextAlign;
 	imGuiStyleFlag[sol::update_if_empty]["SelectableTextAlign"] = ImGuiStyleVar_::ImGuiStyleVar_SelectableTextAlign;
 	imGuiStyleFlag[sol::update_if_empty]["SelectableTextAlign"] = ImGuiStyleVar_::ImGuiStyleVar_SelectableTextAlign;
 
 
+	// Create a table for ImGui fonts
+	sol::table imGuiFont = m_luaState["ImGuiFont"].get_or_create<sol::table>();
+
+	imGuiFont[sol::update_if_empty]["Default"] = GuiFontType::GuiFontType_Default;
+	imGuiFont[sol::update_if_empty]["AboutWindow"] = GuiFontType::GuiFontType_AboutWindow;
+
 	// Add each object type to the user type table
 	// Add each object type to the user type table
 	for(int i = 0; i < LuaDefinitions::UserTypes::NumOfTypes; i++)
 	for(int i = 0; i < LuaDefinitions::UserTypes::NumOfTypes; i++)
 		m_userTypesTable[sol::update_if_empty][GetString(static_cast<LuaDefinitions::UserTypes>(i))] = i;
 		m_userTypesTable[sol::update_if_empty][GetString(static_cast<LuaDefinitions::UserTypes>(i))] = i;
@@ -198,6 +205,9 @@ void LuaScript::setDefinitions()
 	// Create a table for different types of changes
 	// Create a table for different types of changes
 	m_changeTypesTable = m_luaState["Changes"].get_or_create<sol::table>();
 	m_changeTypesTable = m_luaState["Changes"].get_or_create<sol::table>();
 
 
+	// Create entries for AUDIO changes
+	m_changeTypesTable[sol::update_if_empty]["Audio"]["Volume"] = Int64Packer(Systems::Changes::Audio::Volume);
+
 	// Create entries for GUI changes
 	// Create entries for GUI changes
 	m_changeTypesTable[sol::update_if_empty]["GUI"]["Sequence"] = Int64Packer(Systems::Changes::GUI::Sequence);
 	m_changeTypesTable[sol::update_if_empty]["GUI"]["Sequence"] = Int64Packer(Systems::Changes::GUI::Sequence);
 }
 }
@@ -205,7 +215,35 @@ void LuaScript::setDefinitions()
 void LuaScript::setFunctions()
 void LuaScript::setFunctions()
 {
 {
 	// Change controller functions
 	// Change controller functions
-	m_luaState.set_function("sendData", [this](const Systems::TypeID p_v1, const DataType p_v2, bool p_v3) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendData(m_scriptScene->getSceneLoader()->getSystemScene(p_v1), p_v2, (void *)&p_v3, false); });
+	m_luaState.set_function("sendData", [this](const Systems::TypeID p_v1, const DataType p_v2, bool p_v3) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendData(m_scriptScene->getSceneLoader()->getSystemScene(p_v1), p_v2, (void *)p_v3, false); });
+	m_luaState.set_function("sendChange", sol::overload(
+		[this](SystemObject *p_observer, const Int64Packer &p_changeType, const bool p_v1) -> const void { this->queueChange(p_observer, p_changeType.get(), p_v1); },
+		[this](SystemObject *p_observer, const Int64Packer &p_changeType, const int p_v1) -> const void { this->queueChange(p_observer, p_changeType.get(), p_v1); },
+		[this](SystemObject *p_observer, const Int64Packer &p_changeType, const float p_v1) -> const void { this->queueChange(p_observer, p_changeType.get(), p_v1); },
+		[this](SystemObject *p_observer, const Int64Packer &p_changeType, const std::string &p_v1) -> const void { this->queueChange(p_observer, p_changeType.get(), p_v1); }));
+
+	// Entity functions
+	m_luaState.set_function("getEntityID", [this](const std::string &p_filename) -> EntityID { return static_cast<WorldScene *>(m_scriptScene->getSceneLoader()->getSystemScene(Systems::World))->getEntity(p_filename); });
+	m_luaState.set_function("isEntityIDValid", [](const EntityID p_entityID) -> bool { return p_entityID != NULL_ENTITY_ID; });
+	m_luaState.set_function("createEntity", [this](const ComponentsConstructionInfo &p_constructionInfo) -> EntityID { return static_cast<WorldScene *>(m_scriptScene->getSceneLoader()->getSystemScene(Systems::World))->createEntity(p_constructionInfo); });
+	m_luaState.set_function("importPrefab", [this](ComponentsConstructionInfo &p_constructionInfo, const std::string &p_filename) -> bool { return m_scriptScene->getSceneLoader()->importPrefab(p_constructionInfo, p_filename) == ErrorCode::Success; });
+
+	// Entity component functions
+	m_luaState.set_function("getSoundComponent", [this](const EntityID p_entityID) -> SoundComponent *{ return static_cast<WorldScene *>(m_scriptScene->getSceneLoader()->getSystemScene(Systems::World))->getEntityRegistry().try_get<SoundComponent>(p_entityID); });
+	m_luaState.set_function("getSpatialComponent", [this](const EntityID p_entityID) -> SpatialComponent *{ return static_cast<WorldScene *>(m_scriptScene->getSceneLoader()->getSystemScene(Systems::World))->getEntityRegistry().try_get<SpatialComponent>(p_entityID); });
+
+	// Entity component system object functions
+	m_luaState.set_function("getSoundComponentSystemObject", [this](const EntityID p_entityID) -> SystemObject * { return static_cast<WorldScene *>(m_scriptScene->getSceneLoader()->getSystemScene(Systems::World))->getEntityRegistry().try_get<SoundComponent>(p_entityID); });
+	m_luaState.set_function("getSpatialComponentSystemObject", [this](const EntityID p_entityID) -> SystemObject *{ return static_cast<WorldScene *>(m_scriptScene->getSceneLoader()->getSystemScene(Systems::World))->getEntityRegistry().try_get<SpatialComponent>(p_entityID); });
+
+	// Engine functions
+	m_luaState.set_function("setEngineRunning", [](const bool p_v1) -> const void {Config::m_engineVar.running = p_v1; });
+	m_luaState.set_function("setEngineState", [this](const EngineStateType p_v1) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(EngineChangeType::EngineChangeType_StateChange, p_v1)); });
+	m_luaState.set_function("getEngineState", [this]() -> EngineStateType { return m_scriptScene->getSceneLoader()->getEngineState(); });
+
+	m_luaState.set_function("sendEngineChange", sol::overload([this](const EngineChangeType p_v1) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(p_v1)); },
+		[this](const EngineChangeType p_v1, const EngineStateType p_v2) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(p_v1, p_v2)); },
+		[this](const EngineChangeType p_v1, const EngineStateType p_v2, const std::string p_v3) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(p_v1, p_v2, p_v3)); }));
 
 
 	// Error handler functions
 	// Error handler functions
 	auto errorTable = m_luaState.create_table("ErrHandlerLoc");
 	auto errorTable = m_luaState.create_table("ErrHandlerLoc");
@@ -220,40 +258,6 @@ void LuaScript::setFunctions()
 		[this](const ErrorCode p_v1, const std::string p_v2) -> const void { ErrHandlerLoc::get().log(p_v1, ErrorSource::Source_LuaScript, p_v2); },
 		[this](const ErrorCode p_v1, const std::string p_v2) -> const void { ErrHandlerLoc::get().log(p_v1, ErrorSource::Source_LuaScript, p_v2); },
 		[this](const ErrorCode p_v1, const ErrorSource p_v2, const std::string p_v3) -> const void { ErrHandlerLoc::get().log(p_v1, p_v2, p_v3); }));
 		[this](const ErrorCode p_v1, const ErrorSource p_v2, const std::string p_v3) -> const void { ErrHandlerLoc::get().log(p_v1, p_v2, p_v3); }));
 
 
-	// Math functions
-	m_luaState.set_function("toRadianF", sol::resolve<float(const float)>(&glm::radians));
-	m_luaState.set_function("toRadianVec3", sol::resolve<glm::vec3(const glm::vec3 &)>(&glm::radians));
-	m_luaState.set_function("toRadianVec4", sol::resolve<glm::vec4(const glm::vec4 &)>(&glm::radians));
-	m_luaState.set_function("toDegreesF", sol::resolve<float(const float)>(&glm::degrees));
-	m_luaState.set_function("toDegreesVec3", sol::resolve<glm::vec3(const glm::vec3 &)>(&glm::degrees));
-	m_luaState.set_function("toDegreesVec4", sol::resolve<glm::vec4(const glm::vec4 &)>(&glm::degrees));
-	m_luaState.set_function("angleAxisQuat", sol::resolve<glm::quat(const float &, const glm::vec3 &)>(&glm::angleAxis));
-	m_luaState.set_function("bitwiseOr", sol::overload([this](const int p_v1, const int p_v2) -> const int { return p_v1 | p_v2; },
-		[this](const int p_v1, const int p_v2, const int p_v3) -> const int { return p_v1 | p_v2 | p_v3; },
-		[this](const int p_v1, const int p_v2, const int p_v3, const int p_v4) -> const int { return p_v1 | p_v2 | p_v3 | p_v4; },
-		[this](const int p_v1, const int p_v2, const int p_v3, const int p_v4, const int p_v5) -> const int { return p_v1 | p_v2 | p_v3 | p_v4 | p_v5; }));
-
-	// Input / Window functions
-	m_luaState.set_function("getMouseInfo", []() -> const Window::MouseInfo { return WindowLocator::get().getMouseInfo(); });
-	m_luaState.set_function("getMouseCapture", []() -> const bool { return Config::windowVar().mouse_captured; });
-	m_luaState.set_function("setFullscreen", [](const bool p_v1) -> const void { WindowLocator::get().setFullscreen(p_v1); });
-	m_luaState.set_function("setMouseCapture", [](const bool p_v1) -> const void { WindowLocator::get().setMouseCapture(p_v1); });
-	m_luaState.set_function("setVerticalSync", [](const bool p_v1) -> const void { WindowLocator::get().setVerticalSync(p_v1); });
-	m_luaState.set_function("setWindowTitle", [](const std::string &p_v1) -> const void { WindowLocator::get().setWindowTitle(p_v1); });
-
-	// Entity component functions
-	m_luaState.set_function("createEntity", [this](const ComponentsConstructionInfo &p_constructionInfo) -> EntityID { return static_cast<WorldScene *>(m_scriptScene->getSceneLoader()->getSystemScene(Systems::World))->createEntity(p_constructionInfo); });
-	m_luaState.set_function("importPrefab", [this](ComponentsConstructionInfo &p_constructionInfo, const std::string &p_filename) -> bool { return m_scriptScene->getSceneLoader()->importPrefab(p_constructionInfo, p_filename) == ErrorCode::Success; });
-
-	// Engine functions
-	m_luaState.set_function("setEngineRunning", [](const bool p_v1) -> const void {Config::m_engineVar.running = p_v1; });
-	m_luaState.set_function("setEngineState", [this](const EngineStateType p_v1) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(EngineChangeType::EngineChangeType_StateChange, p_v1)); });
-	m_luaState.set_function("getEngineState", [this]() -> EngineStateType { return Config::engineVar().engineState; });
-
-	m_luaState.set_function("sendEngineChange", sol::overload([this](const EngineChangeType p_v1) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(p_v1)); },
-		[this](const EngineChangeType p_v1, const EngineStateType p_v2) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(p_v1, p_v2)); },
-		[this](const EngineChangeType p_v1, const EngineStateType p_v2, const std::string p_v3) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(p_v1, p_v2, p_v3)); }));
-
 	// GUI functions
 	// GUI functions
 	auto GUITable = m_luaState.create_table("GUI");
 	auto GUITable = m_luaState.create_table("GUI");
 	GUITable.set_function("Begin", sol::overload([this](const std::string &p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::Begin(p_v1.c_str()); }); },
 	GUITable.set_function("Begin", sol::overload([this](const std::string &p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::Begin(p_v1.c_str()); }); },
@@ -263,6 +267,7 @@ void LuaScript::setFunctions()
 	GUITable.set_function("BeginMenu", [this](const std::string &p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::BeginMenu(p_v1.c_str()); }); });
 	GUITable.set_function("BeginMenu", [this](const std::string &p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::BeginMenu(p_v1.c_str()); }); });
 	GUITable.set_function("Button", sol::overload([this](const std::string &p_v1, Conditional *p_v2) -> void { m_GUIData.addFunctor([=] { p_v2->m_flag = ImGui::Button(p_v1.c_str()); }); },
 	GUITable.set_function("Button", sol::overload([this](const std::string &p_v1, Conditional *p_v2) -> void { m_GUIData.addFunctor([=] { p_v2->m_flag = ImGui::Button(p_v1.c_str()); }); },
 		[this](const std::string &p_v1, const float p_v2, const float p_v3, Conditional *p_v4) -> void { m_GUIData.addFunctor([=] { p_v4->m_flag = ImGui::Button(p_v1.c_str(), ImVec2(p_v2, p_v3)); }); }));
 		[this](const std::string &p_v1, const float p_v2, const float p_v3, Conditional *p_v4) -> void { m_GUIData.addFunctor([=] { p_v4->m_flag = ImGui::Button(p_v1.c_str(), ImVec2(p_v2, p_v3)); }); }));
+	GUITable.set_function("CalcTextSize", [this](const std::string &p_v1) -> const glm::vec2 { const auto textSize = ImGui::CalcTextSize(p_v1.c_str()); return glm::vec2(textSize.x, textSize.y); });
 	GUITable.set_function("Checkbox", [this](const std::string &p_v1, Conditional *p_v2) -> void { m_GUIData.addFunctor([=] { ImGui::Checkbox(p_v1.c_str(), &p_v2->m_flag); }); });
 	GUITable.set_function("Checkbox", [this](const std::string &p_v1, Conditional *p_v2) -> void { m_GUIData.addFunctor([=] { ImGui::Checkbox(p_v1.c_str(), &p_v2->m_flag); }); });
 	GUITable.set_function("ColorEdit3", [this](const std::string &p_v1, glm::vec3 *p_v2) -> void { m_GUIData.addFunctor([=] { ImGui::ColorEdit3(p_v1.c_str(), &(p_v2->x)); }); });
 	GUITable.set_function("ColorEdit3", [this](const std::string &p_v1, glm::vec3 *p_v2) -> void { m_GUIData.addFunctor([=] { ImGui::ColorEdit3(p_v1.c_str(), &(p_v2->x)); }); });
 	GUITable.set_function("ColorEdit4", [this](const std::string &p_v1, glm::vec4 *p_v2) -> void { m_GUIData.addFunctor([=] { ImGui::ColorEdit4(p_v1.c_str(), &(p_v2->x)); }); });
 	GUITable.set_function("ColorEdit4", [this](const std::string &p_v1, glm::vec4 *p_v2) -> void { m_GUIData.addFunctor([=] { ImGui::ColorEdit4(p_v1.c_str(), &(p_v2->x)); }); });
@@ -271,35 +276,56 @@ void LuaScript::setFunctions()
 	GUITable.set_function("EndMenu", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::EndMenu(); }); });
 	GUITable.set_function("EndMenu", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::EndMenu(); }); });
 	GUITable.set_function("EndMenuBar", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::EndMenuBar(); }); });
 	GUITable.set_function("EndMenuBar", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::EndMenuBar(); }); });
 	GUITable.set_function("FileDialog", [this](FileBrowserDialog *p_v1) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendData(m_scriptScene->getSceneLoader()->getSystemScene(Systems::GUI), DataType::DataType_FileBrowserDialog, (void *)p_v1); });
 	GUITable.set_function("FileDialog", [this](FileBrowserDialog *p_v1) -> const void { m_scriptScene->getSceneLoader()->getChangeController()->sendData(m_scriptScene->getSceneLoader()->getSystemScene(Systems::GUI), DataType::DataType_FileBrowserDialog, (void *)p_v1); });
-	GUITable.set_function("Image", sol::overload([this](TextureLoader2D::Texture2DHandle &p_v1) -> void { m_GUIData.addFunctor([=] { ImGui::Image((ImTextureID)(uint64_t)p_v1.getHandle(), ImVec2((float)p_v1.getTextureWidth(), (float)p_v1.getTextureHeight()), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f)); }); },
-		[this](TextureLoader2D::Texture2DHandle &p_v1, const float p_v2, const float p_v3) -> void { m_GUIData.addFunctor([=] { ImGui::Image((ImTextureID)(uint64_t)p_v1.getHandle(), ImVec2(p_v2, p_v3), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f)); }); },
-		[this](TextureLoader2D::Texture2DHandle &p_v1, const float p_v2, const float p_v3, const float p_v4, const float p_v5, const float p_v6, const float p_v7) -> void { m_GUIData.addFunctor([=] { ImGui::Image((ImTextureID)(uint64_t)p_v1.getHandle(), ImVec2(p_v2, p_v3), ImVec2(p_v4, p_v5), ImVec2(p_v6, p_v7)); }); }));
-	GUITable.set_function("ImageButton", sol::overload([this](TextureLoader2D::Texture2DHandle &p_v1, Conditional *p_v2) -> void { m_GUIData.addFunctor([=] { p_v2->m_flag = ImGui::ImageButton((ImTextureID)(uint64_t)p_v1.getHandle(), ImVec2((float)p_v1.getTextureWidth(), (float)p_v1.getTextureHeight()), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f), 0, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); }); },
-		[this](TextureLoader2D::Texture2DHandle &p_v1, const float p_v2, const float p_v3, Conditional *p_v4) -> void { m_GUIData.addFunctor([=] { p_v4->m_flag = ImGui::ImageButton((ImTextureID)(uint64_t)p_v1.getHandle(), ImVec2(p_v2, p_v3), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f)); }); },
-		[this](TextureLoader2D::Texture2DHandle &p_v1, const float p_v2, const float p_v3, const float p_v4, const float p_v5, const float p_v6, const float p_v7, Conditional *p_v8) -> void { m_GUIData.addFunctor([=] { p_v8->m_flag = ImGui::ImageButton((ImTextureID)(uint64_t)p_v1.getHandle(), ImVec2(p_v2, p_v3), ImVec2(p_v4, p_v5), ImVec2(p_v6, p_v7)); }); }));
+	GUITable.set_function("GetContentRegionAvail", [this]() -> const glm::vec2 { const auto regionSize = ImGui::GetContentRegionAvail(); return glm::vec2(regionSize.x, regionSize.y); });
+	GUITable.set_function("GetContentRegionAvailX", [this]() -> const float { return ImGui::GetContentRegionAvail().x; });
+	GUITable.set_function("GetContentRegionAvailY", [this]() -> const float { return ImGui::GetContentRegionAvail().y; });
+	GUITable.set_function("GetScreenSize", [this]() -> const glm::vec2 { return glm::vec2(Config::rendererVar().current_viewport_size_x, Config::rendererVar().current_viewport_size_y); });
+	GUITable.set_function("Image", sol::overload([this](TextureLoader2D::Texture2DHandle *p_v1) -> void { m_GUIData.addFunctor([=] { ImGui::Image((ImTextureID)(uint64_t)p_v1->getHandle(), ImVec2((float)p_v1->getTextureWidth(), (float)p_v1->getTextureHeight()), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f)); }); },
+		[this](TextureLoader2D::Texture2DHandle *p_v1, const float p_v2, const float p_v3) -> void { m_GUIData.addFunctor([=] { ImGui::Image((ImTextureID)(uint64_t)p_v1->getHandle(), ImVec2(p_v2, p_v3), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f)); }); },
+		[this](TextureLoader2D::Texture2DHandle *p_v1, const float p_v2, const float p_v3, const float p_v4, const float p_v5, const float p_v6, const float p_v7) -> void { m_GUIData.addFunctor([=] { ImGui::Image((ImTextureID)(uint64_t)p_v1->getHandle(), ImVec2(p_v2, p_v3), ImVec2(p_v4, p_v5), ImVec2(p_v6, p_v7)); }); }));
+	GUITable.set_function("ImageButton", sol::overload([this](TextureLoader2D::Texture2DHandle *p_v1, Conditional *p_v2) -> void { m_GUIData.addFunctor([=] { p_v2->m_flag = ImGui::ImageButton((ImTextureID)(uint64_t)p_v1->getHandle(), ImVec2((float)p_v1->getTextureWidth(), (float)p_v1->getTextureHeight()), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f), 0, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); }); },
+		[this](TextureLoader2D::Texture2DHandle *p_v1, const float p_v2, const float p_v3, Conditional *p_v4) -> void { m_GUIData.addFunctor([=] { p_v4->m_flag = ImGui::ImageButton((ImTextureID)(uint64_t)p_v1->getHandle(), ImVec2(p_v2, p_v3), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f)); }); },
+		[this](TextureLoader2D::Texture2DHandle *p_v1, const float p_v2, const float p_v3, const float p_v4, const float p_v5, const float p_v6, const float p_v7, Conditional *p_v8) -> void { m_GUIData.addFunctor([=] { p_v8->m_flag = ImGui::ImageButton((ImTextureID)(uint64_t)p_v1->getHandle(), ImVec2(p_v2, p_v3), ImVec2(p_v4, p_v5), ImVec2(p_v6, p_v7)); }); }));
 	GUITable.set_function("IsItemHovered", [this](Conditional *p_v1) -> const void { m_GUIData.addFunctor([=] { p_v1->m_flag = ImGui::IsItemHovered(); }); });
 	GUITable.set_function("IsItemHovered", [this](Conditional *p_v1) -> const void { m_GUIData.addFunctor([=] { p_v1->m_flag = ImGui::IsItemHovered(); }); });
 	GUITable.set_function("MenuItem", [this](const std::string &p_v1, const std::string &p_v2, Conditional *p_v3) -> void { m_GUIData.addFunctor([=] { p_v3->m_flag = ImGui::MenuItem(p_v1.c_str(), p_v2.c_str()); }); });
 	GUITable.set_function("MenuItem", [this](const std::string &p_v1, const std::string &p_v2, Conditional *p_v3) -> void { m_GUIData.addFunctor([=] { p_v3->m_flag = ImGui::MenuItem(p_v1.c_str(), p_v2.c_str()); }); });
+	GUITable.set_function("NewLine", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::NewLine(); }); });
 	GUITable.set_function("PlotLines", [this](const std::string &p_v1, const float *p_v2, int p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::PlotLines(p_v1.c_str(), p_v2, p_v3); }); });
 	GUITable.set_function("PlotLines", [this](const std::string &p_v1, const float *p_v2, int p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::PlotLines(p_v1.c_str(), p_v2, p_v3); }); });
+	GUITable.set_function("PopFont", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::PopFont(); }); });
 	GUITable.set_function("PopStyleColor", sol::overload([this](const int p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::PopStyleColor(p_v1); }); },
 	GUITable.set_function("PopStyleColor", sol::overload([this](const int p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::PopStyleColor(p_v1); }); },
 		[this]() -> const void { m_GUIData.addFunctor([=] { ImGui::PopStyleColor(1); }); }));
 		[this]() -> const void { m_GUIData.addFunctor([=] { ImGui::PopStyleColor(1); }); }));
 	GUITable.set_function("PopStyleVar", sol::overload([this](const int p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::PopStyleVar(p_v1); }); },
 	GUITable.set_function("PopStyleVar", sol::overload([this](const int p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::PopStyleVar(p_v1); }); },
 		[this]() -> const void { m_GUIData.addFunctor([=] { ImGui::PopStyleVar(1); }); }));
 		[this]() -> const void { m_GUIData.addFunctor([=] { ImGui::PopStyleVar(1); }); }));
+	GUITable.set_function("PushFont", [this](const GuiFontType p_fontType) -> const void { auto *font = static_cast<GUISystem *>(m_scriptScene->getSceneLoader()->getSystemScene(Systems::GUI)->getSystem())->getFont(p_fontType); m_GUIData.addFunctor([=] { ImGui::PushFont(font); }); });
 	GUITable.set_function("PushStyleColor", [this](const int p_v1, const float p_v2, const float p_v3, const float p_v4, const float p_v5) -> const void { m_GUIData.addFunctor([=] { ImGui::PushStyleColor(p_v1, ImVec4(p_v2, p_v3, p_v4, p_v5)); }); });
 	GUITable.set_function("PushStyleColor", [this](const int p_v1, const float p_v2, const float p_v3, const float p_v4, const float p_v5) -> const void { m_GUIData.addFunctor([=] { ImGui::PushStyleColor(p_v1, ImVec4(p_v2, p_v3, p_v4, p_v5)); }); });
 	GUITable.set_function("PushStyleVar", sol::overload([this](const int p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::PushStyleVar(p_v1, p_v2); }); },
 	GUITable.set_function("PushStyleVar", sol::overload([this](const int p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::PushStyleVar(p_v1, p_v2); }); },
 		[this](const int p_v1, const float p_v2, const float p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::PushStyleVar(p_v1, ImVec2(p_v2, p_v3)); }); }));
 		[this](const int p_v1, const float p_v2, const float p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::PushStyleVar(p_v1, ImVec2(p_v2, p_v3)); }); }));
-	GUITable.set_function("SetNextWindowPos", [this](const float p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::SetNextWindowPos(ImVec2(p_v1, p_v2)); }); });
+	GUITable.set_function("SetCursorPosX", [this](const float p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::SetCursorPosX(p_v1); }); });
+	GUITable.set_function("SetCursorPosY", [this](const float p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::SetCursorPosY(p_v1); }); });
+	GUITable.set_function("SetNextWindowPos", [this](const float p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::SetNextWindowPos(ImVec2(Config::rendererVar().current_viewport_position_x + p_v1, Config::rendererVar().current_viewport_position_y + p_v2)); }); });
 	GUITable.set_function("SetNextWindowContentSize", [this](const float p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::SetNextWindowContentSize(ImVec2(p_v1, p_v2)); }); });
 	GUITable.set_function("SetNextWindowContentSize", [this](const float p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::SetNextWindowContentSize(ImVec2(p_v1, p_v2)); }); });
 	GUITable.set_function("SetNextWindowSize", [this](const float p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::SetNextWindowSize(ImVec2(p_v1, p_v2)); }); });
 	GUITable.set_function("SetNextWindowSize", [this](const float p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::SetNextWindowSize(ImVec2(p_v1, p_v2)); }); });
+	GUITable.set_function("SetNextWindowSizeFullscreen", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::SetNextWindowSize(ImVec2((float)Config::rendererVar().current_viewport_size_x, (float)Config::rendererVar().current_viewport_size_y)); }); });
+	GUITable.set_function("SetWindowFontScale", [this](const float p_fontScale) -> const void { m_GUIData.addFunctor([=] { ImGui::SetWindowFontScale(p_fontScale); }); });
 	GUITable.set_function("ShowMetricsWindow", [this](bool p_v1) -> void { m_GUIData.addFunctor([=] { bool open = p_v1; ImGui::ShowMetricsWindow(&open); }); });
 	GUITable.set_function("ShowMetricsWindow", [this](bool p_v1) -> void { m_GUIData.addFunctor([=] { bool open = p_v1; ImGui::ShowMetricsWindow(&open); }); });
 	GUITable.set_function("SliderFloat", [this](const std::string &p_v1, float *p_v2, const float p_v3, const float p_v4) -> const void { m_GUIData.addFunctor([=] { ImGui::SliderFloat(p_v1.c_str(), p_v2, p_v3, p_v4); }); });
 	GUITable.set_function("SliderFloat", [this](const std::string &p_v1, float *p_v2, const float p_v3, const float p_v4) -> const void { m_GUIData.addFunctor([=] { ImGui::SliderFloat(p_v1.c_str(), p_v2, p_v3, p_v4); }); });
 	GUITable.set_function("SameLine", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::SameLine(); }); });
 	GUITable.set_function("SameLine", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::SameLine(); }); });
 	GUITable.set_function("Text", sol::overload([this](const std::string &p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::Text(p_v1.c_str()); }); },
 	GUITable.set_function("Text", sol::overload([this](const std::string &p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::Text(p_v1.c_str()); }); },
 		[this](const std::string &p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::Text(p_v1.c_str(), p_v2); }); },
 		[this](const std::string &p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::Text(p_v1.c_str(), p_v2); }); },
 		[this](const std::string &p_v1, const float p_v2, const float p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::Text(p_v1.c_str(), p_v2, p_v3); }); }));
 		[this](const std::string &p_v1, const float p_v2, const float p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::Text(p_v1.c_str(), p_v2, p_v3); }); }));
+	GUITable.set_function("TextCenterAligned", sol::overload([this](const std::string &p_text) -> const void { m_GUIData.addFunctor([=] { ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(p_text.c_str()).x) / 2.0f); ImGui::Text(p_text.c_str()); }); },
+		[this](const std::string &p_text, const float p_screenSizeX) -> const void { m_GUIData.addFunctor([=] { ImGui::SetCursorPosX((p_screenSizeX - ImGui::CalcTextSize(p_text.c_str()).x) - 2.0f); ImGui::Text(p_text.c_str()); }); }));
 	GUITable.set_function("TextColored", sol::overload([this](const glm::vec4 p_v1, const std::string &p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::TextColored(ImVec4(p_v1.x, p_v1.y, p_v1.z, p_v1.w), p_v2.c_str()); }); },
 	GUITable.set_function("TextColored", sol::overload([this](const glm::vec4 p_v1, const std::string &p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::TextColored(ImVec4(p_v1.x, p_v1.y, p_v1.z, p_v1.w), p_v2.c_str()); }); },
 		[this](const glm::vec4 p_v1, const std::string &p_v2, const float p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::TextColored(ImVec4(p_v1.x, p_v1.y, p_v1.z, p_v1.w), p_v2.c_str(), p_v3); }); },
 		[this](const glm::vec4 p_v1, const std::string &p_v2, const float p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::TextColored(ImVec4(p_v1.x, p_v1.y, p_v1.z, p_v1.w), p_v2.c_str(), p_v3); }); },
 		[this](const glm::vec4 p_v1, const std::string &p_v2, const float p_v3, const float p_v4) -> const void { m_GUIData.addFunctor([=] { ImGui::TextColored(ImVec4(p_v1.x, p_v1.y, p_v1.z, p_v1.w), p_v2.c_str(), p_v3, p_v4); }); }));
 		[this](const glm::vec4 p_v1, const std::string &p_v2, const float p_v3, const float p_v4) -> const void { m_GUIData.addFunctor([=] { ImGui::TextColored(ImVec4(p_v1.x, p_v1.y, p_v1.z, p_v1.w), p_v2.c_str(), p_v3, p_v4); }); }));
 
 
+	// Input / Window functions
+	m_luaState.set_function("getMouseInfo", []() -> const Window::MouseInfo { return WindowLocator::get().getMouseInfo(); });
+	m_luaState.set_function("getMouseCapture", []() -> const bool { return Config::windowVar().mouse_captured; });
+	m_luaState.set_function("setFullscreen", [](const bool p_v1) -> const void { WindowLocator::get().setFullscreen(p_v1); });
+	m_luaState.set_function("setMouseCapture", [](const bool p_v1) -> const void { WindowLocator::get().setMouseCapture(p_v1); });
+	m_luaState.set_function("setVerticalSync", [](const bool p_v1) -> const void { WindowLocator::get().setVerticalSync(p_v1); });
+	m_luaState.set_function("setWindowTitle", [](const std::string &p_v1) -> const void { WindowLocator::get().setWindowTitle(p_v1); });
+
 	// Loader functions
 	// Loader functions
 	m_luaState.set_function("loadTexture2D", [](const std::string &p_v1) -> TextureLoader2D::Texture2DHandle { return Loaders::texture2D().load(p_v1); });
 	m_luaState.set_function("loadTexture2D", [](const std::string &p_v1) -> TextureLoader2D::Texture2DHandle { return Loaders::texture2D().load(p_v1); });
 
 
@@ -307,6 +333,27 @@ void LuaScript::setFunctions()
 	m_luaState.set_function("getLuaFilename", &LuaScript::getLuaScriptFilename, this);
 	m_luaState.set_function("getLuaFilename", &LuaScript::getLuaScriptFilename, this);
 	m_luaState.set_function("postChanges", &LuaScript::registerChange, this);
 	m_luaState.set_function("postChanges", &LuaScript::registerChange, this);
 	m_luaState.set_function(Config::scriptVar().createObjectFunctionName, &LuaScript::createObjectInLua, this);
 	m_luaState.set_function(Config::scriptVar().createObjectFunctionName, &LuaScript::createObjectInLua, this);
+
+	// Math functions
+	m_luaState.set_function("angleAxisQuat", sol::resolve<glm::quat(const float &, const glm::vec3 &)>(&glm::angleAxis));
+	m_luaState.set_function("bitwiseOr", sol::overload([](const int p_v1, const int p_v2) -> const int { return p_v1 | p_v2; },
+		[](const int p_v1, const int p_v2, const int p_v3) -> const int { return p_v1 | p_v2 | p_v3; },
+		[](const int p_v1, const int p_v2, const int p_v3, const int p_v4) -> const int { return p_v1 | p_v2 | p_v3 | p_v4; },
+		[](const int p_v1, const int p_v2, const int p_v3, const int p_v4, const int p_v5) -> const int { return p_v1 | p_v2 | p_v3 | p_v4 | p_v5; }));
+	m_luaState.set_function("clamp", [](const float p_value, const float p_min, const float p_max) -> float { return glm::clamp(p_value, p_min, p_max); });
+	m_luaState.set_function("dot", sol::overload([this](const glm::vec3 &p_v1, const glm::vec3 &p_v2) -> float { return glm::dot(p_v1, p_v2); },
+		[this](const glm::vec4 &p_v1, const glm::vec4 &p_v2) -> float { return glm::dot(p_v1, p_v2); }));
+	m_luaState.set_function("linearInterpolation", sol::overload([](const float p_value, const float p_domainMin, const float p_domainMax) -> const float { return (p_value - p_domainMin) / (p_domainMax - p_domainMin); },
+		[this](const float p_value, const float p_domainMin, const float p_domainMax, const float p_rangeMin, const float p_rangeMax) -> const float { return glm::mix(p_rangeMin, p_rangeMax, (p_value - p_domainMin) / (p_domainMax - p_domainMin)); }));
+	m_luaState.set_function("toRadianF", sol::resolve<float(const float)>(&glm::radians));
+	m_luaState.set_function("toRadianVec3", sol::resolve<glm::vec3(const glm::vec3 &)>(&glm::radians));
+	m_luaState.set_function("toRadianVec4", sol::resolve<glm::vec4(const glm::vec4 &)>(&glm::radians));
+	m_luaState.set_function("toDegreesF", sol::resolve<float(const float)>(&glm::degrees));
+	m_luaState.set_function("toDegreesVec3", sol::resolve<glm::vec3(const glm::vec3 &)>(&glm::degrees));
+	m_luaState.set_function("toDegreesVec4", sol::resolve<glm::vec4(const glm::vec4 &)>(&glm::degrees));
+
+	// Physics functions
+	m_luaState.set_function("getPhysicsSimulationRunning", [this]() -> const bool { return static_cast<PhysicsScene *>(m_scriptScene->getSceneLoader()->getSystemScene(Systems::Physics))->getSimulationRunning(); });
 }
 }
 
 
 void LuaScript::setUsertypes()
 void LuaScript::setUsertypes()
@@ -328,6 +375,7 @@ void LuaScript::setUsertypes()
 		"None", EngineChangeType::EngineChangeType_None,
 		"None", EngineChangeType::EngineChangeType_None,
 		"SceneFilename", EngineChangeType::EngineChangeType_SceneFilename,
 		"SceneFilename", EngineChangeType::EngineChangeType_SceneFilename,
 		"SceneLoad", EngineChangeType::EngineChangeType_SceneLoad,
 		"SceneLoad", EngineChangeType::EngineChangeType_SceneLoad,
+		"SceneUnload", EngineChangeType::EngineChangeType_SceneUnload,
 		"SceneReload", EngineChangeType::EngineChangeType_SceneReload,
 		"SceneReload", EngineChangeType::EngineChangeType_SceneReload,
 		"StateChange", EngineChangeType::EngineChangeType_StateChange);
 		"StateChange", EngineChangeType::EngineChangeType_StateChange);
 
 
@@ -340,6 +388,10 @@ void LuaScript::setUsertypes()
 		GetString(Systems::TypeID::Script), Systems::TypeID::Script,
 		GetString(Systems::TypeID::Script), Systems::TypeID::Script,
 		GetString(Systems::TypeID::World), Systems::TypeID::World);
 		GetString(Systems::TypeID::World), Systems::TypeID::World);
 
 
+	// Components
+	m_luaState.new_usertype<SpatialComponent>("SpatialComponent",
+		"getSpatialDataChangeManager", &SpatialComponent::getSpatialDataChangeManager);
+
 	// Config variables
 	// Config variables
 	m_luaState.new_usertype<Config::EngineVariables>("EngineVariables",
 	m_luaState.new_usertype<Config::EngineVariables>("EngineVariables",
 		"change_ctrl_cml_notify_list_reserv", &Config::EngineVariables::change_ctrl_cml_notify_list_reserv,
 		"change_ctrl_cml_notify_list_reserv", &Config::EngineVariables::change_ctrl_cml_notify_list_reserv,
@@ -431,6 +483,40 @@ void LuaScript::setUsertypes()
 	// Math types
 	// Math types
 	m_luaState.new_usertype<Int64Packer>("Int64");
 	m_luaState.new_usertype<Int64Packer>("Int64");
 
 
+	m_luaState.new_usertype<glm::ivec2>("Ivec2",
+		sol::constructors<glm::ivec2(), glm::ivec2(int), glm::ivec2(int, int), glm::ivec2(glm::vec2)>(),
+		"x", &glm::ivec2::x,
+		"y", &glm::ivec2::y,
+		"addF", [](const glm::ivec2 &v1, const int f) -> glm::ivec2 { return v1 + f; },
+		"subF", [](const glm::ivec2 &v1, const int f) -> glm::ivec2 { return v1 - f; },
+		"mulF", [](const glm::ivec2 &v1, const int f) -> glm::ivec2 { return v1 * f; },
+		"divF", [](const glm::ivec2 &v1, const int f) -> glm::ivec2 { return v1 / f; },
+		"addIvec2", [](const glm::ivec2 &v1, const glm::ivec2 &v2) -> glm::ivec2 { return v1 + v2; },
+		"subIvec2", [](const glm::ivec2 &v1, const glm::ivec2 &v2) -> glm::ivec2 { return v1 - v2; },
+		"mulIvec2", [](const glm::ivec2 &v1, const glm::ivec2 &v2) -> glm::ivec2 { return v1 * v2; },
+		"divIvec2", [](const glm::ivec2 &v1, const glm::ivec2 &v2) -> glm::ivec2 { return v1 / v2; },
+		sol::meta_function::addition, [](const glm::ivec2 &v1, glm::ivec2 &v2) -> glm::ivec2 { return v1 + v2; },
+		sol::meta_function::subtraction, [](const glm::ivec2 &v1, glm::ivec2 &v2) -> glm::ivec2 { return v1 - v2; },
+		sol::meta_function::multiplication, [](const glm::ivec2 &v1, glm::ivec2 &v2) -> glm::ivec2 { return v1 * v2; },
+		sol::meta_function::division, [](const glm::ivec2 &v1, glm::ivec2 &v2) -> glm::ivec2 { return v1 / v2; });
+
+	m_luaState.new_usertype<glm::vec2>("Vec2",
+		sol::constructors<glm::vec2(), glm::vec2(float), glm::vec2(float, float), glm::vec2(glm::vec3), glm::vec2(glm::ivec2)>(),
+		"x", &glm::vec2::x,
+		"y", &glm::vec2::y,
+		"addF", [](const glm::vec2 &v1, const float f) -> glm::vec2 { return v1 + f; },
+		"subF", [](const glm::vec2 &v1, const float f) -> glm::vec2 { return v1 - f; },
+		"mulF", [](const glm::vec2 &v1, const float f) -> glm::vec2 { return v1 * f; },
+		"divF", [](const glm::vec2 &v1, const float f) -> glm::vec2 { return v1 / f; },
+		"addVec2", [](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 + v2; },
+		"subVec2", [](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 - v2; },
+		"mulVec2", [](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 * v2; },
+		"divVec2", [](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 / v2; },
+		sol::meta_function::addition, [](const glm::vec2 &v1, glm::vec2 &v2) -> glm::vec2 { return v1 + v2; },
+		sol::meta_function::subtraction, [](const glm::vec2 &v1, glm::vec2 &v2) -> glm::vec2 { return v1 - v2; },
+		sol::meta_function::multiplication, [](const glm::vec2 &v1, glm::vec2 &v2) -> glm::vec2 { return v1 * v2; },
+		sol::meta_function::division, [](const glm::vec2 &v1, glm::vec2 &v2) -> glm::vec2 { return v1 / v2; });
+
 	m_luaState.new_usertype<glm::vec3>("Vec3",
 	m_luaState.new_usertype<glm::vec3>("Vec3",
 		sol::constructors<glm::vec3(), glm::vec3(float), glm::vec3(float, float, float), glm::vec3(glm::vec4)>(),
 		sol::constructors<glm::vec3(), glm::vec3(float), glm::vec3(float, float, float), glm::vec3(glm::vec4)>(),
 		"x", &glm::vec3::x,
 		"x", &glm::vec3::x,
@@ -444,6 +530,7 @@ void LuaScript::setUsertypes()
 		"subVec3", [](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 - v2; },
 		"subVec3", [](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 - v2; },
 		"mulVec3", [](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 * v2; },
 		"mulVec3", [](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 * v2; },
 		"divVec3", [](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 / v2; },
 		"divVec3", [](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 / v2; },
+		"dot", [](const glm::vec3 &v1, const glm::vec3 &v2) -> float { return glm::dot(v1, v2); },
 		"normalize", [](const glm::vec3 &v1) -> glm::vec3 { return glm::normalize(v1); },
 		"normalize", [](const glm::vec3 &v1) -> glm::vec3 { return glm::normalize(v1); },
 		sol::meta_function::addition, [](const glm::vec3 &v1, glm::vec3 &v2) -> glm::vec3 { return v1 + v2; },
 		sol::meta_function::addition, [](const glm::vec3 &v1, glm::vec3 &v2) -> glm::vec3 { return v1 + v2; },
 		sol::meta_function::subtraction, [](const glm::vec3 &v1, glm::vec3 &v2) -> glm::vec3 { return v1 - v2; },
 		sol::meta_function::subtraction, [](const glm::vec3 &v1, glm::vec3 &v2) -> glm::vec3 { return v1 - v2; },

+ 39 - 2
Praxis3D/Source/LuaScript.h

@@ -67,17 +67,28 @@ struct Conditional
 	bool m_flag;
 	bool m_flag;
 };
 };
 
 
+struct SingleChange
+{
+	SingleChange(const Observer *p_observer, const BitMask p_changeType, const Property &p_changeValue) : m_observer(p_observer), m_changeType(p_changeType), m_changeData(p_changeValue) { }
+
+	const Observer *m_observer;
+	BitMask m_changeType;
+	Property m_changeData;
+};
+
 class LuaScript
 class LuaScript
 {
 {
 	friend class LuaComponent;
 	friend class LuaComponent;
 public:
 public:
-	LuaScript(SystemScene *p_scriptScene, SpatialDataManager &p_spatialData, GUIDataManager &p_GUIData) : m_scriptScene(p_scriptScene), m_spatialData(p_spatialData), m_GUIData(p_GUIData)
+	LuaScript(SystemScene *p_scriptScene, SystemObject *p_luaComponent, SpatialDataManager &p_spatialData, GUIDataManager &p_GUIData) : 
+		m_scriptScene(p_scriptScene), m_luaComponent(p_luaComponent), m_spatialData(p_spatialData), m_GUIData(p_GUIData)
 	{ 
 	{ 
 		m_keyCommands.reserve(10);
 		m_keyCommands.reserve(10);
 		m_conditionals.reserve(10);
 		m_conditionals.reserve(10);
 		m_currentChanges = Systems::Changes::None;
 		m_currentChanges = Systems::Changes::None;
 	}
 	}
-	LuaScript(SystemScene *p_scriptScene, SpatialDataManager &p_spatialData, GUIDataManager &p_GUIData, std::string &p_scriptFilename) : m_scriptScene(p_scriptScene), m_spatialData(p_spatialData), m_GUIData(p_GUIData), m_luaScriptFilename(p_scriptFilename)
+	LuaScript(SystemScene *p_scriptScene, SystemObject *p_luaComponent, SpatialDataManager &p_spatialData, GUIDataManager &p_GUIData, std::string &p_scriptFilename) : 
+		m_scriptScene(p_scriptScene), m_luaComponent(p_luaComponent), m_spatialData(p_spatialData), m_GUIData(p_GUIData), m_luaScriptFilename(p_scriptFilename)
 	{
 	{
 		m_keyCommands.reserve(10);
 		m_keyCommands.reserve(10);
 		m_conditionals.reserve(10);
 		m_conditionals.reserve(10);
@@ -113,6 +124,7 @@ public:
 	{
 	{
 		// Clear changes from the last update
 		// Clear changes from the last update
 		clearChanges();
 		clearChanges();
+		m_queuedChanges.clear();
 
 
 		// Clear all the GUI functors from the last update
 		// Clear all the GUI functors from the last update
 		m_GUIData.clearFunctors();
 		m_GUIData.clearFunctors();
@@ -189,6 +201,25 @@ private:
 	// Sets the defined variables inside the lua script
 	// Sets the defined variables inside the lua script
 	void setLuaVariables();
 	void setLuaVariables();
 
 
+	template <class T_Variable>
+	inline void queueChange(SystemObject *p_observer, const BitMask p_changeType, const T_Variable p_changeValue)
+	{
+		m_queuedChanges.emplace_back(p_observer, p_changeType, Property(Properties::PropertyID::Null, p_changeValue));
+
+		m_scriptScene->getSceneLoader()->getChangeController()->sendChange(m_luaComponent, p_observer, p_changeType);
+	}
+
+	// Returns the change value matching the change type bitmask
+	// Returns nullptr if no match was found
+	inline const Property *getQueuedChange(const Observer *p_observer, const BitMask p_changeType)
+	{
+		for(decltype(m_queuedChanges.size()) i = 0, size = m_queuedChanges.size(); i < size; i++)
+			if(m_queuedChanges[i].m_changeType == p_changeType && m_queuedChanges[i].m_observer == p_observer)
+				return &m_queuedChanges[i].m_changeData;
+
+		return nullptr;
+	}
+
 	// Creates and assigns objects to be used in the lua script
 	// Creates and assigns objects to be used in the lua script
 	// Should only be called from the lua script
 	// Should only be called from the lua script
 	void createObjectInLua(const unsigned int p_objectType, const std::string p_variableName);
 	void createObjectInLua(const unsigned int p_objectType, const std::string p_variableName);
@@ -212,12 +243,18 @@ private:
 	sol::table m_userTypesTable;
 	sol::table m_userTypesTable;
 	sol::table m_changeTypesTable;
 	sol::table m_changeTypesTable;
 
 
+	// An array of queued changes, that get saved when a change is sent from a lua script
+	std::vector<SingleChange> m_queuedChanges;
+
 	// An array of variable names and their value, that get additionally defined in the lua script
 	// An array of variable names and their value, that get additionally defined in the lua script
 	std::vector<std::pair<std::string, Property>> m_variables;
 	std::vector<std::pair<std::string, Property>> m_variables;
 
 
 	// Pointer to the scripting scene that owns this instance; required for getting things like scene loader for entity/component creation
 	// Pointer to the scripting scene that owns this instance; required for getting things like scene loader for entity/component creation
 	SystemScene *m_scriptScene;
 	SystemScene *m_scriptScene;
 
 
+	// Pointer to the Lua component that owns this instance; required for sending changes
+	SystemObject *m_luaComponent;
+
 	// Contains all spatial data
 	// Contains all spatial data
 	SpatialDataManager &m_spatialData;
 	SpatialDataManager &m_spatialData;
 
 

+ 24 - 21
Praxis3D/Source/LuminancePass.h

@@ -85,37 +85,40 @@ public:
 
 
 	void update(RenderPassData &p_renderPassData, const SceneObjects &p_sceneObjects, const float p_deltaTime)
 	void update(RenderPassData &p_renderPassData, const SceneObjects &p_sceneObjects, const float p_deltaTime)
 	{
 	{
-		// Get the screen image buffer size
-		const unsigned int imageWidth = m_renderer.m_backend.getGeometryBuffer()->getBufferWidth();
-		const unsigned int imageHeight = m_renderer.m_backend.getGeometryBuffer()->getBufferHeight();
+		if(p_sceneObjects.m_processDrawing)
+		{
+			// Get the screen image buffer size
+			const unsigned int imageWidth = m_renderer.m_backend.getGeometryBuffer()->getBufferWidth();
+			const unsigned int imageHeight = m_renderer.m_backend.getGeometryBuffer()->getBufferHeight();
 
 
-		// Calculate the number of groups that the compute shader should execute
-		unsigned int groupsX = static_cast<uint32_t>(glm::ceil(imageWidth / 16.0f));
-		unsigned int groupsY = static_cast<uint32_t>(glm::ceil(imageHeight / 16.0f));
+			// Calculate the number of groups that the compute shader should execute
+			unsigned int groupsX = static_cast<uint32_t>(glm::ceil(imageWidth / 16.0f));
+			unsigned int groupsY = static_cast<uint32_t>(glm::ceil(imageHeight / 16.0f));
 
 
-		m_renderer.m_backend.getGeometryBuffer()->bindBufferToImageUnitForReading(GBufferTextureType::GBufferFinal, GBufferTextureType::GBufferInputTexture, 0);
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferToImageUnitForReading(GBufferTextureType::GBufferFinal, GBufferTextureType::GBufferInputTexture, 0);
 
 
-		m_renderer.queueForDrawing(m_luminanceHistogramShader->getShaderHandle(), m_luminanceHistogramShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix, groupsX, groupsY, 1, MemoryBarrierType::MemoryBarrierType_ShaderStorageBarrier);
-		m_renderer.passComputeDispatchCommandsToBackend();
+			m_renderer.queueForDrawing(m_luminanceHistogramShader->getShaderHandle(), m_luminanceHistogramShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix, groupsX, groupsY, 1, MemoryBarrierType::MemoryBarrierType_ShaderStorageBarrier);
+			m_renderer.passComputeDispatchCommandsToBackend();
 
 
-		glBindImageTexture(0, m_luminanceAverageTexture.getHandle(), 0, GL_FALSE, 0, GL_READ_WRITE, GL_R16F);
+			glBindImageTexture(0, m_luminanceAverageTexture.getHandle(), 0, GL_FALSE, 0, GL_READ_WRITE, GL_R16F);
 
 
-		m_renderer.queueForDrawing(m_luminanceAverageShader->getShaderHandle(), m_luminanceAverageShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix, 1, 1, 1, MemoryBarrierType::MemoryBarrierType_ShaderStorageBarrier);
-		m_renderer.passComputeDispatchCommandsToBackend();
+			m_renderer.queueForDrawing(m_luminanceAverageShader->getShaderHandle(), m_luminanceAverageShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix, 1, 1, 1, MemoryBarrierType::MemoryBarrierType_ShaderStorageBarrier);
+			m_renderer.passComputeDispatchCommandsToBackend();
 
 
-		glDisable(GL_DEPTH_TEST);
+			glDisable(GL_DEPTH_TEST);
 
 
-		glActiveTexture(GL_TEXTURE0 + LuminanceTextureType::LensFlareTextureType_AverageLuminance);
-		glBindTexture(GL_TEXTURE_2D, m_luminanceAverageTexture.getHandle());
+			glActiveTexture(GL_TEXTURE0 + LuminanceTextureType::LensFlareTextureType_AverageLuminance);
+			glBindTexture(GL_TEXTURE_2D, m_luminanceAverageTexture.getHandle());
 
 
-		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(p_renderPassData.getColorInputMap(), GBufferTextureType::GBufferInputTexture);
-		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(p_renderPassData.getColorInputMap(), GBufferTextureType::GBufferInputTexture);
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(p_renderPassData.getColorInputMap(), GBufferTextureType::GBufferInputTexture);
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(p_renderPassData.getColorInputMap(), GBufferTextureType::GBufferInputTexture);
 
 
-		m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(p_renderPassData.getColorOutputMap());
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(p_renderPassData.getColorOutputMap());
 
 
-		// Queue and render a full screen quad using a final pass shader
-		m_renderer.queueForDrawing(m_tonemappingShader->getShaderHandle(), m_tonemappingShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
-		m_renderer.passScreenSpaceDrawCommandsToBackend();
+			// Queue and render a full screen quad using a final pass shader
+			m_renderer.queueForDrawing(m_tonemappingShader->getShaderHandle(), m_tonemappingShader->getUniformUpdater(), p_sceneObjects.m_cameraViewMatrix);
+			m_renderer.passScreenSpaceDrawCommandsToBackend();
+		}
 
 
 		p_renderPassData.swapColorInputOutputMaps();
 		p_renderPassData.swapColorInputOutputMaps();
 	}
 	}

+ 2 - 0
Praxis3D/Source/MainMenuState.cpp

@@ -24,4 +24,6 @@ void MainMenuState::update(Engine &p_engine)
 
 
 	m_objectChangeController->distributeChanges();
 	m_objectChangeController->distributeChanges();
 	m_sceneChangeController->distributeChanges();
 	m_sceneChangeController->distributeChanges();
+
+	updateSceneLoadingStatus();
 }
 }

+ 29 - 73
Praxis3D/Source/PhysicsScene.cpp

@@ -129,7 +129,7 @@ void PhysicsScene::exportSetup(PropertySet &p_propertySet)
 void PhysicsScene::update(const float p_deltaTime)
 void PhysicsScene::update(const float p_deltaTime)
 {
 {
 	// Get double buffering index
 	// Get double buffering index
-	auto dbIndex = ClockLocator::get().getDoubleBufferingIndexBack();
+	const auto dbIndex = ClockLocator::get().getDoubleBufferingIndexBack();
 
 
 	// Get the world scene required for getting the entity registry
 	// Get the world scene required for getting the entity registry
 	WorldScene *worldScene = static_cast<WorldScene*>(m_sceneLoader->getSystemScene(Systems::World));
 	WorldScene *worldScene = static_cast<WorldScene*>(m_sceneLoader->getSystemScene(Systems::World));
@@ -147,7 +147,7 @@ void PhysicsScene::update(const float p_deltaTime)
 		component.m_numOfStaticCollisions[dbIndex] = 0;
 		component.m_numOfStaticCollisions[dbIndex] = 0;
 	}
 	}
 
 
-	if(m_simulationRunning)
+	if(m_simulationRunning && !(m_sceneLoader->getFirstLoad() && m_sceneLoader->getSceneLoadingStatus()))
 	{
 	{
 		// Perform the physics simulation for the time step of the last frame
 		// Perform the physics simulation for the time step of the last frame
 		m_dynamicsWorld->stepSimulation(p_deltaTime);
 		m_dynamicsWorld->stepSimulation(p_deltaTime);
@@ -172,35 +172,39 @@ void PhysicsScene::internalTickCallback(btDynamicsWorld *p_world, btScalar p_tim
 	auto &entityRegistry = worldScene->getEntityRegistry();
 	auto &entityRegistry = worldScene->getEntityRegistry();
 
 
 	// Get double buffering index
 	// Get double buffering index
-	auto dbIndex = ClockLocator::get().getDoubleBufferingIndexBack();
+	const auto dbIndex = ClockLocator::get().getDoubleBufferingIndexBack();
 
 
+	// Go over each manifold
 	for(decltype(p_world->getDispatcher()->getNumManifolds()) manifoldIndex = 0, manifoldSize = p_world->getDispatcher()->getNumManifolds(); manifoldIndex < manifoldSize; manifoldIndex++)
 	for(decltype(p_world->getDispatcher()->getNumManifolds()) manifoldIndex = 0, manifoldSize = p_world->getDispatcher()->getNumManifolds(); manifoldIndex < manifoldSize; manifoldIndex++)
 	{
 	{
-		btPersistentManifold *contactManifold = p_world->getDispatcher()->getManifoldByIndexInternal(manifoldIndex);
+		// Get contact manifold
+		const btPersistentManifold *contactManifold = p_world->getDispatcher()->getManifoldByIndexInternal(manifoldIndex);
 
 
+		// Get collision objects that are in contact
 		const btCollisionObject *objectA = static_cast<const btCollisionObject *>(contactManifold->getBody0());
 		const btCollisionObject *objectA = static_cast<const btCollisionObject *>(contactManifold->getBody0());
 		const btCollisionObject *objectB = static_cast<const btCollisionObject *>(contactManifold->getBody1());
 		const btCollisionObject *objectB = static_cast<const btCollisionObject *>(contactManifold->getBody1());
 
 
-		EntityID entityA = *static_cast<EntityID *>(objectA->getUserPointer());
-		EntityID entityB = *static_cast<EntityID *>(objectB->getUserPointer());
-
-		bool processCollision = false;
+		// Get entity IDs of objects that are in contact
+		const EntityID entityA = *static_cast<EntityID *>(objectA->getUserPointer());
+		const EntityID entityB = *static_cast<EntityID *>(objectB->getUserPointer());
 
 
+		// Go over each contact
 		for(decltype(contactManifold->getNumContacts()) contactIndex = 0, contactSize = contactManifold->getNumContacts(); contactIndex < contactSize; contactIndex++)
 		for(decltype(contactManifold->getNumContacts()) contactIndex = 0, contactSize = contactManifold->getNumContacts(); contactIndex < contactSize; contactIndex++)
 		{
 		{
+			// Get collision event components that will contain the contact information
 			auto *collisionEventComponentObjectA = entityRegistry.try_get<CollisionEventComponent>(entityA);
 			auto *collisionEventComponentObjectA = entityRegistry.try_get<CollisionEventComponent>(entityA);
 			auto *collisionEventComponentObjectB = entityRegistry.try_get<CollisionEventComponent>(entityB);
 			auto *collisionEventComponentObjectB = entityRegistry.try_get<CollisionEventComponent>(entityB);
 
 
-			btManifoldPoint &manifoldPoint = contactManifold->getContactPoint(contactIndex);
+			// Get the contact point
+			const btManifoldPoint &manifoldPoint = contactManifold->getContactPoint(contactIndex);
+
+			// Check if the contact distance isn't negative and if the lifetime of the contact hasn't passed a set threshold
 			if(manifoldPoint.getDistance() < 0.0f && manifoldPoint.m_lifeTime < Config::physicsVar().life_time_threshold)
 			if(manifoldPoint.getDistance() < 0.0f && manifoldPoint.m_lifeTime < Config::physicsVar().life_time_threshold)
 			{
 			{
-				//std::cout << manifoldPoint.m_contactMotion1 << " | ";
-				//std::cout << manifoldPoint.m_contactMotion2 << std::endl;
-
-				//if(manifoldPoint.m_appliedImpulseLateral1 > )
-
+				// Determine whether the collision is static or dynamic based on whether the applied impulse of the collision is above a set threshold
 				if(manifoldPoint.m_appliedImpulse > Config::physicsVar().applied_impulse_threshold)
 				if(manifoldPoint.m_appliedImpulse > Config::physicsVar().applied_impulse_threshold)
 				{
 				{
+					// Process the dynamic collision event on the first object
 					if(collisionEventComponentObjectA->m_numOfDynamicCollisions[dbIndex] < NUM_DYNAMIC_COLLISION_EVENTS)
 					if(collisionEventComponentObjectA->m_numOfDynamicCollisions[dbIndex] < NUM_DYNAMIC_COLLISION_EVENTS)
 					{
 					{
 						collisionEventComponentObjectA->m_dynamicCollisions[dbIndex][collisionEventComponentObjectA->m_numOfDynamicCollisions[dbIndex]].m_firstObjInCollisionPair = true;
 						collisionEventComponentObjectA->m_dynamicCollisions[dbIndex][collisionEventComponentObjectA->m_numOfDynamicCollisions[dbIndex]].m_firstObjInCollisionPair = true;
@@ -214,9 +218,11 @@ void PhysicsScene::internalTickCallback(btDynamicsWorld *p_world, btScalar p_tim
 					}
 					}
 					else
 					else
 					{
 					{
-						std::cout << entityA << " : max DYNAMIC collision events" << std::endl;
+						// Log an error if the dynamic collision event count exceeds the maximum number of supported dynamic events
+						ErrHandlerLoc::get().log(ErrorCode::Collision_max_dynamic_events, ErrorSource::Source_Physics);
 					}
 					}
 
 
+					// Process the dynamic collision event on the second object
 					if(collisionEventComponentObjectB->m_numOfDynamicCollisions[dbIndex] < NUM_DYNAMIC_COLLISION_EVENTS)
 					if(collisionEventComponentObjectB->m_numOfDynamicCollisions[dbIndex] < NUM_DYNAMIC_COLLISION_EVENTS)
 					{
 					{
 						collisionEventComponentObjectB->m_dynamicCollisions[dbIndex][collisionEventComponentObjectB->m_numOfDynamicCollisions[dbIndex]].m_firstObjInCollisionPair = false;
 						collisionEventComponentObjectB->m_dynamicCollisions[dbIndex][collisionEventComponentObjectB->m_numOfDynamicCollisions[dbIndex]].m_firstObjInCollisionPair = false;
@@ -230,12 +236,13 @@ void PhysicsScene::internalTickCallback(btDynamicsWorld *p_world, btScalar p_tim
 					}
 					}
 					else
 					else
 					{
 					{
-						std::cout << entityB << " : max DYNAMIC collision events" << std::endl;
+						// Log an error if the dynamic collision event count exceeds the maximum number of supported dynamic events
+						ErrHandlerLoc::get().log(ErrorCode::Collision_max_dynamic_events, ErrorSource::Source_Physics);
 					}
 					}
-
 				}
 				}
 				else
 				else
 				{
 				{
+					// Process the static collision event on the first object
 					if(collisionEventComponentObjectA->m_numOfStaticCollisions[dbIndex] < NUM_STATIC_COLLISION_EVENTS)
 					if(collisionEventComponentObjectA->m_numOfStaticCollisions[dbIndex] < NUM_STATIC_COLLISION_EVENTS)
 					{
 					{
 						collisionEventComponentObjectA->m_staticCollisions[dbIndex][collisionEventComponentObjectA->m_numOfStaticCollisions[dbIndex]].m_firstObjInCollisionPair = true;
 						collisionEventComponentObjectA->m_staticCollisions[dbIndex][collisionEventComponentObjectA->m_numOfStaticCollisions[dbIndex]].m_firstObjInCollisionPair = true;
@@ -249,9 +256,11 @@ void PhysicsScene::internalTickCallback(btDynamicsWorld *p_world, btScalar p_tim
 					}
 					}
 					else
 					else
 					{
 					{
-						std::cout << entityA << " : max STATIC collision events" << std::endl;
+						// Log an error if the static collision event count exceeds the maximum number of supported static events
+						ErrHandlerLoc::get().log(ErrorCode::Collision_max_static_events, ErrorSource::Source_Physics);
 					}
 					}
 
 
+					// Process the static collision event on the second object
 					if(collisionEventComponentObjectB->m_numOfStaticCollisions[dbIndex] < NUM_STATIC_COLLISION_EVENTS)
 					if(collisionEventComponentObjectB->m_numOfStaticCollisions[dbIndex] < NUM_STATIC_COLLISION_EVENTS)
 					{
 					{
 						collisionEventComponentObjectB->m_staticCollisions[dbIndex][collisionEventComponentObjectB->m_numOfStaticCollisions[dbIndex]].m_firstObjInCollisionPair = false;
 						collisionEventComponentObjectB->m_staticCollisions[dbIndex][collisionEventComponentObjectB->m_numOfStaticCollisions[dbIndex]].m_firstObjInCollisionPair = false;
@@ -265,64 +274,11 @@ void PhysicsScene::internalTickCallback(btDynamicsWorld *p_world, btScalar p_tim
 					}
 					}
 					else
 					else
 					{
 					{
-						std::cout << entityB << " : max STATIC collision events" << std::endl;
+						// Log an error if the static collision event count exceeds the maximum number of supported static events
+						ErrHandlerLoc::get().log(ErrorCode::Collision_max_static_events, ErrorSource::Source_Physics);
 					}
 					}
 				}
 				}
 			}
 			}
-			//if(pt.getDistance() < 0.f)
-			//{
-			//	const btVector3 &ptA = pt.getPositionWorldOnA();
-			//	const btVector3 &ptB = pt.getPositionWorldOnB();
-			//	const btVector3 &normalOnB = pt.m_normalWorldOnB;
-			//}
-		}
-
-		if(processCollision)
-		{
-			//const btCollisionObject *obA = static_cast<const btCollisionObject *>(contactManifold->getBody0());
-			//const btCollisionObject *obB = static_cast<const btCollisionObject *>(contactManifold->getBody1());
-
-			//EntityID entityA = *static_cast<EntityID *>(obA->getUserPointer());
-			//EntityID entityB = *static_cast<EntityID *>(obB->getUserPointer());
-
-			std::string materialTypeEntityA;
-			std::string materialTypeEntityB;
-
-			auto objectMaterialComponentA = entityRegistry.try_get<ObjectMaterialComponent>(entityA);
-			if(objectMaterialComponentA != nullptr)
-			{
-				switch(objectMaterialComponentA->getObjectMaterialType())
-				{
-				case ObjectMaterialType::Metal:
-					materialTypeEntityA = "metal";
-					break;
-				case ObjectMaterialType::Rock:
-					materialTypeEntityA = "rock";
-					break;
-				case ObjectMaterialType::Wood:
-					materialTypeEntityA = "wood";
-					break;
-				}
-			}
-
-			auto objectMaterialComponentB = entityRegistry.try_get<ObjectMaterialComponent>(entityB);
-			if(objectMaterialComponentB != nullptr)
-			{
-				switch(objectMaterialComponentB->getObjectMaterialType())
-				{
-				case ObjectMaterialType::Metal:
-					materialTypeEntityB = "metal";
-					break;
-				case ObjectMaterialType::Rock:
-					materialTypeEntityB = "rock";
-					break;
-				case ObjectMaterialType::Wood:
-					materialTypeEntityB = "wood";
-					break;
-				}
-			}
-
-			std::cout << materialTypeEntityA << " <-> " << materialTypeEntityB << std::endl;
 		}
 		}
 	}
 	}
 }
 }

+ 3 - 2
Praxis3D/Source/PhysicsScene.h

@@ -148,9 +148,10 @@ public:
 	BitMask getDesiredSystemChanges() { return Systems::Changes::Generic::CreateObject || Systems::Changes::Generic::DeleteObject; }
 	BitMask getDesiredSystemChanges() { return Systems::Changes::Generic::CreateObject || Systems::Changes::Generic::DeleteObject; }
 	BitMask getPotentialSystemChanges() { return Systems::Changes::None; }
 	BitMask getPotentialSystemChanges() { return Systems::Changes::None; }
 
 
-	const glm::vec3 getGravity() const { return Math::toGlmVec3(m_dynamicsWorld->getGravity()); }
+	const inline glm::vec3 getGravity() const { return Math::toGlmVec3(m_dynamicsWorld->getGravity()); }
+	const inline bool getSimulationRunning() const { return m_simulationRunning; }
 
 
-	// Fluch the collision contacts of a rigid body (used after changing the collision shape dimensions)
+	// Flush the collision contacts of a rigid body (used after changing the collision shape dimensions)
 	void cleanProxyFromPairs(btRigidBody &p_rigidBody)
 	void cleanProxyFromPairs(btRigidBody &p_rigidBody)
 	{
 	{
 		m_collisionBroadphase->getOverlappingPairCache()->cleanProxyFromPairs(p_rigidBody.getBroadphaseProxy(), m_collisionDispatcher);
 		m_collisionBroadphase->getOverlappingPairCache()->cleanProxyFromPairs(p_rigidBody.getBroadphaseProxy(), m_collisionDispatcher);

+ 2 - 0
Praxis3D/Source/PlayState.cpp

@@ -23,4 +23,6 @@ void PlayState::update(Engine &p_engine)
 	
 	
 	m_objectChangeController->distributeChanges();
 	m_objectChangeController->distributeChanges();
 	m_sceneChangeController->distributeChanges();
 	m_sceneChangeController->distributeChanges();
+
+	updateSceneLoadingStatus();
 }
 }

+ 26 - 23
Praxis3D/Source/RendererBackend.cpp

@@ -20,6 +20,10 @@ ErrorCode RendererBackend::init(const UniformFrameData &p_frameData)
 {
 {
 	ErrorCode returnCode = ErrorCode::Success;
 	ErrorCode returnCode = ErrorCode::Success;
 
 
+	// Clear the default framebuffer
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
 	// Initialize gbuffer and check if the gbuffer initialization was successful
 	// Initialize gbuffer and check if the gbuffer initialization was successful
 	if(ErrHandlerLoc::get().ifSuccessful(createFramebuffer(FramebufferType::FramebufferType_GBuffer, p_frameData), returnCode))
 	if(ErrHandlerLoc::get().ifSuccessful(createFramebuffer(FramebufferType::FramebufferType_GBuffer, p_frameData), returnCode))
 	{
 	{
@@ -38,8 +42,6 @@ ErrorCode RendererBackend::init(const UniformFrameData &p_frameData)
 		else
 		else
 			glDisable(GL_DEPTH_TEST);
 			glDisable(GL_DEPTH_TEST);
 
 
-		//glDepthFunc(GL_LESS);
-
 		// Set depth test function
 		// Set depth test function
 		glDepthFunc(Config::rendererVar().depth_test_func);
 		glDepthFunc(Config::rendererVar().depth_test_func);
 	}
 	}
@@ -53,31 +55,32 @@ ErrorCode RendererBackend::createFramebuffer(const FramebufferType p_frambufferT
 	switch(p_frambufferType)
 	switch(p_frambufferType)
 	{
 	{
 		case FramebufferType_GBuffer:
 		case FramebufferType_GBuffer:
-		{
-			if(m_gbuffer != nullptr)
-				delete m_gbuffer;
+			{
+				// Make sure there is only one gbuffer
+				if(m_gbuffer != nullptr)
+					delete m_gbuffer;
 
 
-			// Initialize gbuffer (and also pass the screen size to be used as the buffer size)
-			m_gbuffer = new GeometryBuffer(p_frameData);
+				// Initialize the gbuffer
+				m_gbuffer = new GeometryBuffer(p_frameData);
 
 
-			// Check if the gbuffer initialization was successful
-			returnError = m_gbuffer->init(p_frameData);
-			//if(ErrHandlerLoc::get().ifSuccessful(m_gbuffer->init(), returnError))
-		}
-		break;
+				// Check if the gbuffer initialization was successful
+				returnError = m_gbuffer->init(p_frameData);
+			}
+			break;
 
 
 		case FramebufferType_CSMBuffer:
 		case FramebufferType_CSMBuffer:
-		{
-			if(m_csmBuffer != nullptr)
-				delete m_csmBuffer;
-
-			m_csmBuffer = new CSMFramebuffer(p_frameData);
-
-			returnError = m_csmBuffer->init(p_frameData);
-
-		}
-		break;
-
+			{
+				// Make sure there is only one csm buffer
+				if(m_csmBuffer != nullptr)
+					delete m_csmBuffer;
+
+				// Initialize the csm buffer
+				m_csmBuffer = new CSMFramebuffer(p_frameData);
+
+				// Check if the csm buffer initialization was successful
+				returnError = m_csmBuffer->init(p_frameData);
+			}
+			break;
 	}
 	}
 
 
 	return returnError;
 	return returnError;

+ 8 - 0
Praxis3D/Source/RendererFrontend.cpp

@@ -252,6 +252,10 @@ void RendererFrontend::renderFrame(SceneObjects &p_sceneObjects, const float p_d
 	}
 	}
 	else
 	else
 	{
 	{
+		// Set the gobal variables for the viewport position
+		Config::m_rendererVar.current_viewport_position_x = 0.0f;
+		Config::m_rendererVar.current_viewport_position_y = 0.0f;
+
 		if(m_frameData.m_screenSize.x != Config::graphicsVar().current_resolution_x ||
 		if(m_frameData.m_screenSize.x != Config::graphicsVar().current_resolution_x ||
 			m_frameData.m_screenSize.y != Config::graphicsVar().current_resolution_y)
 			m_frameData.m_screenSize.y != Config::graphicsVar().current_resolution_y)
 		{
 		{
@@ -267,6 +271,10 @@ void RendererFrontend::renderFrame(SceneObjects &p_sceneObjects, const float p_d
 		}
 		}
 	}
 	}
 
 
+	// Set the global variables for the current viewport size
+	Config::m_rendererVar.current_viewport_size_x = m_frameData.m_screenSize.x;
+	Config::m_rendererVar.current_viewport_size_y = m_frameData.m_screenSize.y;
+
 	// If Z-buffer near or far or FOV values have changed, flag projection matrix for updating
 	// If Z-buffer near or far or FOV values have changed, flag projection matrix for updating
 	if(m_frameData.m_zFar != p_sceneObjects.m_zFar || m_frameData.m_zNear != p_sceneObjects.m_zNear || m_frameData.m_fov != p_sceneObjects.m_fov)
 	if(m_frameData.m_zFar != p_sceneObjects.m_zFar || m_frameData.m_zNear != p_sceneObjects.m_zNear || m_frameData.m_fov != p_sceneObjects.m_fov)
 	{
 	{

+ 6 - 11
Praxis3D/Source/RendererScene.cpp

@@ -10,7 +10,6 @@
 RendererScene::RendererScene(RendererSystem *p_system, SceneLoader *p_sceneLoader) : SystemScene(p_system, p_sceneLoader, Properties::PropertyID::Renderer)
 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_renderTask = new RenderTask(this, p_system->getRenderer());
-	m_firstLoadingDone = false;
 
 
 	m_sceneAOData.setDefaultValues();
 	m_sceneAOData.setDefaultValues();
 
 
@@ -572,6 +571,9 @@ void RendererScene::update(const float p_deltaTime)
 					for(decltype(loadableObjectsFromModel.size()) size = loadableObjectsFromModel.size(), i = 0; i < size; i++)
 					for(decltype(loadableObjectsFromModel.size()) size = loadableObjectsFromModel.size(), i = 0; i < size; i++)
 						if(!loadableObjectsFromModel[i].isLoadedToVideoMemory())
 						if(!loadableObjectsFromModel[i].isLoadedToVideoMemory())
 							loadToVideoMemoryComponent.m_objectsToLoad.emplace(loadableObjectsFromModel[i]);
 							loadToVideoMemoryComponent.m_objectsToLoad.emplace(loadableObjectsFromModel[i]);
+
+					// Set the loading status flag to true
+					loadingStatus = true;
 				}
 				}
 			}
 			}
 			else
 			else
@@ -643,20 +645,13 @@ void RendererScene::update(const float p_deltaTime)
 	}
 	}
 
 
 	m_loadingStatus = loadingStatus;
 	m_loadingStatus = loadingStatus;
+	m_sceneObjects.m_processDrawing = true;
 
 
 	// If the render-to-texture is not set (i.e. no scene editor), do not process drawing while there are objects being loaded
 	// If the render-to-texture is not set (i.e. no scene editor), do not process drawing while there are objects being loaded
 	// Perform only during the first initial scene loading
 	// Perform only during the first initial scene loading
-	if(!m_firstLoadingDone && !m_renderTask->m_renderer.getRenderFinalToTexture())
+	if(m_sceneLoader->getFirstLoad() && !m_renderTask->m_renderer.getRenderFinalToTexture())
 	{
 	{
-		if(m_loadingStatus)
-		{
-			m_sceneObjects.m_processDrawing = false;
-		}
-		else
-		{
-			m_sceneObjects.m_processDrawing = true;
-			m_firstLoadingDone = true;
-		}
+		m_sceneObjects.m_processDrawing = !m_loadingStatus;
 	}
 	}
 
 
 	//	 ___________________________
 	//	 ___________________________

+ 0 - 3
Praxis3D/Source/RendererScene.h

@@ -322,7 +322,4 @@ private:
 	// Render-to-texture data
 	// Render-to-texture data
 	bool m_renderToTexture;
 	bool m_renderToTexture;
 	glm::ivec2 m_renderToTextureResolution;
 	glm::ivec2 m_renderToTextureResolution;
-
-	// A flag tracking whether the first scene loading is done (to not trigger actions during loading after the scene was created)
-	bool m_firstLoadingDone;
 };
 };

+ 90 - 62
Praxis3D/Source/SceneLoader.cpp

@@ -6,10 +6,12 @@
 #include "PropertyLoader.h"
 #include "PropertyLoader.h"
 #include "SceneLoader.h"
 #include "SceneLoader.h"
 
 
-SceneLoader::SceneLoader()
+SceneLoader::SceneLoader(const EngineStateType p_engineStateType) : m_engineStateType(p_engineStateType)
 {
 {
 	m_changeController = nullptr;
 	m_changeController = nullptr;
 	m_loadInBackground = false;
 	m_loadInBackground = false;
+	m_loadingStatus = true;
+	m_firstLoad = true;
 
 
 	for(int i = 0; i < Systems::NumberOfSystems; i++)
 	for(int i = 0; i < Systems::NumberOfSystems; i++)
 		m_systemScenes[i] = g_nullSystemBase.createScene(this, EngineStateType::EngineStateType_Default);
 		m_systemScenes[i] = g_nullSystemBase.createScene(this, EngineStateType::EngineStateType_Default);
@@ -442,65 +444,63 @@ void SceneLoader::importFromProperties(AudioComponentsConstructionInfo &p_constr
 					p_constructionInfo.m_soundConstructionInfo = new SoundComponent::SoundComponentConstructionInfo();
 					p_constructionInfo.m_soundConstructionInfo = new SoundComponent::SoundComponentConstructionInfo();
 
 
 				p_constructionInfo.m_soundConstructionInfo->m_name = p_name + Config::componentVar().component_name_separator + GetString(Properties::PropertyID::SoundComponent);
 				p_constructionInfo.m_soundConstructionInfo->m_name = p_name + Config::componentVar().component_name_separator + GetString(Properties::PropertyID::SoundComponent);
-				p_properties.getValueByID(Properties::Active, p_constructionInfo.m_soundConstructionInfo->m_active);
 
 
-				// Get the sound filename
-				auto const &filename = p_properties.getPropertyByID(Properties::Filename).getString();
-
-				if(!filename.empty())
+				// Load property data
+				for(decltype(p_properties.getNumProperties()) i = 0, size = p_properties.getNumProperties(); i < size; i++)
 				{
 				{
-					// Get the sound type
-					auto const &type = p_properties.getPropertyByID(Properties::Type).getID();
-
-					// Load values based on the type of sound
-					switch(type)
+					switch(p_properties[i].getPropertyID())
 					{
 					{
-					case Properties::Ambient:
-
-						p_constructionInfo.m_soundConstructionInfo->m_soundType = SoundComponent::SoundType::SoundType_Ambient;
-
-						p_properties.getValueByID(Properties::Loop, p_constructionInfo.m_soundConstructionInfo->m_loop);
-						p_properties.getValueByID(Properties::Spatialized, p_constructionInfo.m_soundConstructionInfo->m_spatialized);
-						p_properties.getValueByID(Properties::StartPlaying, p_constructionInfo.m_soundConstructionInfo->m_startPlaying);
-						p_properties.getValueByID(Properties::Volume, p_constructionInfo.m_soundConstructionInfo->m_volume);
-						p_constructionInfo.m_soundConstructionInfo->m_soundFilename = filename;
-
-						break;
-
-					case Properties::Music:
-
-						p_constructionInfo.m_soundConstructionInfo->m_soundType = SoundComponent::SoundType::SoundType_Music;
-
-						p_properties.getValueByID(Properties::Loop, p_constructionInfo.m_soundConstructionInfo->m_loop);
-						p_properties.getValueByID(Properties::Spatialized, p_constructionInfo.m_soundConstructionInfo->m_spatialized);
-						p_properties.getValueByID(Properties::StartPlaying, p_constructionInfo.m_soundConstructionInfo->m_startPlaying);
-						p_properties.getValueByID(Properties::Volume, p_constructionInfo.m_soundConstructionInfo->m_volume);
-						p_constructionInfo.m_soundConstructionInfo->m_soundFilename = filename;
-
-						break;
-
-					case Properties::SoundEffect:
-
-						p_constructionInfo.m_soundConstructionInfo->m_soundType = SoundComponent::SoundType::SoundType_SoundEffect;
-
-						p_properties.getValueByID(Properties::Loop, p_constructionInfo.m_soundConstructionInfo->m_loop);
-						p_properties.getValueByID(Properties::Spatialized, p_constructionInfo.m_soundConstructionInfo->m_spatialized);
-						p_properties.getValueByID(Properties::StartPlaying, p_constructionInfo.m_soundConstructionInfo->m_startPlaying);
-						p_properties.getValueByID(Properties::Volume, p_constructionInfo.m_soundConstructionInfo->m_volume);
-						p_constructionInfo.m_soundConstructionInfo->m_soundFilename = filename;
-
-						break;
-
-					default:
-
-						ErrHandlerLoc().get().log(ErrorCode::Property_missing_type, p_name, ErrorSource::Source_SoundComponent);
-						delete p_constructionInfo.m_soundConstructionInfo;
-						p_constructionInfo.m_soundConstructionInfo = nullptr;
-
-						break;
+						case Properties::Active:
+							p_constructionInfo.m_soundConstructionInfo->m_active = p_properties[i].getBool();
+							break;
+						case Properties::Loop:
+							p_constructionInfo.m_soundConstructionInfo->m_loop = p_properties[i].getBool();
+							break;
+						case Properties::Name:
+							p_constructionInfo.m_soundConstructionInfo->m_soundName = p_properties[i].getString();
+							break;
+						case Properties::Source:
+							switch(p_properties[i].getID())
+							{
+								case Properties::Event:
+									p_constructionInfo.m_soundConstructionInfo->m_soundSourceType = SoundComponent::SoundSourceType::SoundSourceType_Event;
+									break;
+								case Properties::File:
+									p_constructionInfo.m_soundConstructionInfo->m_soundSourceType = SoundComponent::SoundSourceType::SoundSourceType_File;
+									break;
+							}
+							break;
+						case Properties::Spatialized:
+							p_constructionInfo.m_soundConstructionInfo->m_spatialized = p_properties[i].getBool();
+							break;
+						case Properties::StartPlaying:
+							p_constructionInfo.m_soundConstructionInfo->m_startPlaying = p_properties[i].getBool();
+							break;
+						case Properties::Type:
+							switch(p_properties[i].getID())
+							{
+								case Properties::Ambient:
+									p_constructionInfo.m_soundConstructionInfo->m_soundType = SoundComponent::SoundType::SoundType_Ambient;
+									break;
+								case Properties::Music:
+									p_constructionInfo.m_soundConstructionInfo->m_soundType = SoundComponent::SoundType::SoundType_Music;
+									break;
+								case Properties::SoundEffect:
+									p_constructionInfo.m_soundConstructionInfo->m_soundType = SoundComponent::SoundType::SoundType_SoundEffect;
+									break;
+								default:
+									ErrHandlerLoc().get().log(ErrorCode::Property_missing_type, p_name, ErrorSource::Source_SoundComponent);
+									break;
+								}
+							break;
+						case Properties::Volume:
+							p_constructionInfo.m_soundConstructionInfo->m_volume = p_properties[i].getFloat();
+							break;
 					}
 					}
 				}
 				}
-				else
+
+				// Make sure the sound name was set
+				if(p_constructionInfo.m_soundConstructionInfo->m_soundName.empty())
 				{
 				{
 					ErrHandlerLoc().get().log(ErrorCode::Property_no_filename, p_name, ErrorSource::Source_SoundComponent);
 					ErrHandlerLoc().get().log(ErrorCode::Property_no_filename, p_name, ErrorSource::Source_SoundComponent);
 					delete p_constructionInfo.m_soundConstructionInfo;
 					delete p_constructionInfo.m_soundConstructionInfo;
@@ -944,6 +944,9 @@ void SceneLoader::importFromProperties(ScriptComponentsConstructionInfo &p_const
 				p_constructionInfo.m_luaConstructionInfo->m_name = p_name + Config::componentVar().component_name_separator + GetString(Properties::PropertyID::LuaComponent);
 				p_constructionInfo.m_luaConstructionInfo->m_name = p_name + Config::componentVar().component_name_separator + GetString(Properties::PropertyID::LuaComponent);
 				p_properties.getValueByID(Properties::Active, p_constructionInfo.m_luaConstructionInfo->m_active);
 				p_properties.getValueByID(Properties::Active, p_constructionInfo.m_luaConstructionInfo->m_active);
 
 
+				if(auto const &pauseInEditorProperty = p_properties.getPropertyByID(Properties::PauseInEditor); pauseInEditorProperty)
+					p_constructionInfo.m_luaConstructionInfo->m_pauseInEditor = pauseInEditorProperty.getBool();
+
 				auto const &luaFilenameProperty = p_properties.getPropertyByID(Properties::Filename);
 				auto const &luaFilenameProperty = p_properties.getPropertyByID(Properties::Filename);
 				auto const &luaVariablesProperty = p_properties.getPropertySetByID(Properties::Variables);
 				auto const &luaVariablesProperty = p_properties.getPropertySetByID(Properties::Variables);
 
 
@@ -1113,40 +1116,62 @@ void SceneLoader::exportToProperties(const AudioComponentsConstructionInfo &p_co
 	if(	p_constructionInfo.m_soundConstructionInfo != nullptr ||
 	if(	p_constructionInfo.m_soundConstructionInfo != nullptr ||
 		p_constructionInfo.m_soundListenerConstructionInfo != nullptr)
 		p_constructionInfo.m_soundListenerConstructionInfo != nullptr)
 	{
 	{
+		// Add Audio entry
 		auto &propertySet = p_properties.addPropertySet(Properties::PropertyID::Audio);
 		auto &propertySet = p_properties.addPropertySet(Properties::PropertyID::Audio);
 
 
 		// Export SoundComponent
 		// Export SoundComponent
 		if(p_constructionInfo.m_soundConstructionInfo != nullptr)
 		if(p_constructionInfo.m_soundConstructionInfo != nullptr)
 		{
 		{
-			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::SoundComponent);
+			// Convert SoundSourceType to PropertyID
+			Properties::PropertyID soundSourceType = Properties::PropertyID::File;
+			switch(p_constructionInfo.m_soundConstructionInfo->m_soundSourceType)
+			{
+				case SoundComponent::SoundSourceType::SoundSourceType_Event:
+					soundSourceType = Properties::PropertyID::Event;
+					break;
+				case SoundComponent::SoundSourceType::SoundSourceType_File:
+					soundSourceType = Properties::PropertyID::File;
+					break;
+			}
 
 
-			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_soundConstructionInfo->m_active);
-			componentPropertySet.addProperty(Properties::PropertyID::Filename, p_constructionInfo.m_soundConstructionInfo->m_soundFilename);
+			// Convert SoundType to PropertyID
+			Properties::PropertyID soundType = Properties::PropertyID::SoundEffect;
 			switch(p_constructionInfo.m_soundConstructionInfo->m_soundType)
 			switch(p_constructionInfo.m_soundConstructionInfo->m_soundType)
 			{
 			{
 				case SoundComponent::SoundType::SoundType_Ambient:
 				case SoundComponent::SoundType::SoundType_Ambient:
-					componentPropertySet.addProperty(Properties::PropertyID::Type, Properties::PropertyID::Ambient);
+					soundType = Properties::PropertyID::Ambient;
 					break;
 					break;
 				case SoundComponent::SoundType::SoundType_Music:
 				case SoundComponent::SoundType::SoundType_Music:
-					componentPropertySet.addProperty(Properties::PropertyID::Type, Properties::PropertyID::Music);
+					soundType = Properties::PropertyID::Music;
 					break;
 					break;
 				case SoundComponent::SoundType::SoundType_SoundEffect:
 				case SoundComponent::SoundType::SoundType_SoundEffect:
-					componentPropertySet.addProperty(Properties::PropertyID::Type, Properties::PropertyID::SoundEffect);
+					soundType = Properties::PropertyID::SoundEffect;
 					break;
 					break;
 			}
 			}
+
+			// Add SoundComponent entry
+			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::SoundComponent);
+
+			// Add SoundComponent properties
+			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_soundConstructionInfo->m_active);
 			componentPropertySet.addProperty(Properties::PropertyID::Loop, p_constructionInfo.m_soundConstructionInfo->m_loop);
 			componentPropertySet.addProperty(Properties::PropertyID::Loop, p_constructionInfo.m_soundConstructionInfo->m_loop);
+			componentPropertySet.addProperty(Properties::PropertyID::Name, p_constructionInfo.m_soundConstructionInfo->m_soundName);
+			componentPropertySet.addProperty(Properties::PropertyID::Source, soundSourceType);
 			componentPropertySet.addProperty(Properties::PropertyID::Spatialized, p_constructionInfo.m_soundConstructionInfo->m_spatialized);
 			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::StartPlaying, p_constructionInfo.m_soundConstructionInfo->m_startPlaying);
+			componentPropertySet.addProperty(Properties::PropertyID::Type, soundType);
 			componentPropertySet.addProperty(Properties::PropertyID::Volume, p_constructionInfo.m_soundConstructionInfo->m_volume);
 			componentPropertySet.addProperty(Properties::PropertyID::Volume, p_constructionInfo.m_soundConstructionInfo->m_volume);
 		}
 		}
 
 
 		// Export SoundListenerComponent
 		// Export SoundListenerComponent
 		if(p_constructionInfo.m_soundListenerConstructionInfo != nullptr)
 		if(p_constructionInfo.m_soundListenerConstructionInfo != nullptr)
 		{
 		{
+			// Add SoundListenerComponent entry
 			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::SoundListenerComponent);
 			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::SoundListenerComponent);
 
 
+			// Add SoundListenerComponent properties
 			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_soundListenerConstructionInfo->m_active);
 			componentPropertySet.addProperty(Properties::PropertyID::Active, p_constructionInfo.m_soundListenerConstructionInfo->m_active);
-			//componentPropertySet.addProperty(Properties::PropertyID::ListenerID, p_constructionInfo.m_soundListenerConstructionInfo->m_listenerID);
+			componentPropertySet.addProperty(Properties::PropertyID::ID, p_constructionInfo.m_soundListenerConstructionInfo->m_listenerID);
 		}
 		}
 	}
 	}
 }
 }
@@ -1399,6 +1424,9 @@ void SceneLoader::exportToProperties(const ScriptComponentsConstructionInfo &p_c
 		{
 		{
 			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::LuaComponent);
 			auto &componentPropertySet = propertySet.addPropertySet(Properties::PropertyID::LuaComponent);
 
 
+			// Add pause-in-editor flag
+			componentPropertySet.addProperty(Properties::PropertyID::PauseInEditor, p_constructionInfo.m_luaConstructionInfo->m_pauseInEditor);
+
 			// Add LUA component data
 			// Add LUA component data
 			if(!p_constructionInfo.m_luaConstructionInfo->m_luaScriptFilename.empty())
 			if(!p_constructionInfo.m_luaConstructionInfo->m_luaScriptFilename.empty())
 			{
 			{

+ 26 - 1
Praxis3D/Source/SceneLoader.h

@@ -18,7 +18,7 @@ struct WorldComponentsConstructionInfo;
 class SceneLoader
 class SceneLoader
 {
 {
 public:
 public:
-	SceneLoader();
+	SceneLoader(const EngineStateType p_engineStateType);
 	~SceneLoader();
 	~SceneLoader();
 
 
 	inline void registerSystemScene(SystemScene *p_scene)
 	inline void registerSystemScene(SystemScene *p_scene)
@@ -33,6 +33,7 @@ public:
 			m_changeController = p_changeCtrl;
 			m_changeController = p_changeCtrl;
 	}
 	}
 
 
+	inline SystemScene **getAllSystemScenes() { return m_systemScenes; }
 	inline SystemScene *getSystemScene(Systems::TypeID p_systemType) const { return m_systemScenes[p_systemType]; }
 	inline SystemScene *getSystemScene(Systems::TypeID p_systemType) const { return m_systemScenes[p_systemType]; }
 	inline UniversalScene *getChangeController() const { return m_changeController; }
 	inline UniversalScene *getChangeController() const { return m_changeController; }
 
 
@@ -63,6 +64,21 @@ public:
 	// Set the load-in-background flag
 	// Set the load-in-background flag
 	inline void setLoadInBackground(const bool p_loadInBackground) { m_loadInBackground = p_loadInBackground; }
 	inline void setLoadInBackground(const bool p_loadInBackground) { m_loadInBackground = p_loadInBackground; }
 
 
+	// Set the current loading status of all scenes
+	inline void setSceneLoadingStatus(const bool p_loadingStatus) { m_loadingStatus = p_loadingStatus; }
+
+	// Get the current loading status of all scenes
+	inline bool getSceneLoadingStatus() const { return m_loadingStatus; }
+	
+	// Set the first (initial) load flag
+	inline void setFirstLoad(const bool p_firstLoad) { m_firstLoad = p_firstLoad; }
+
+	// Is this the first (initial) load
+	inline bool getFirstLoad() const { return m_firstLoad; }
+
+	// Get the engine state type that this scene loader belongs to
+	inline EngineStateType getEngineState() const { return m_engineStateType; }
+
 private:
 private:
 	ErrorCode importFromFile(ComponentsConstructionInfo &p_constructionInfo, const std::string &p_filename);
 	ErrorCode importFromFile(ComponentsConstructionInfo &p_constructionInfo, const std::string &p_filename);
 	void importFromProperties(ComponentsConstructionInfo &p_constructionInfo, const PropertySet &p_properties);
 	void importFromProperties(ComponentsConstructionInfo &p_constructionInfo, const PropertySet &p_properties);
@@ -93,10 +109,19 @@ private:
 	// Change controller, used for storing and distributing messages between subjects and observers
 	// Change controller, used for storing and distributing messages between subjects and observers
 	UniversalScene *m_changeController;
 	UniversalScene *m_changeController;
 
 
+	// The engine state type that this scene loader belongs to
+	const EngineStateType m_engineStateType;
+
 	// Should the imported objects be called to start loading in the background
 	// Should the imported objects be called to start loading in the background
 	bool m_loadInBackground;
 	bool m_loadInBackground;
 
 
 	// Holds the last loaded scene filename, used for exporting the scene back to file
 	// Holds the last loaded scene filename, used for exporting the scene back to file
 	std::string m_filename;
 	std::string m_filename;
+
+	// Denotes whether any of the scenes currently loading
+	bool m_loadingStatus;
+
+	// Denotes whether this is the first time that scenes are loading
+	bool m_firstLoad;
 };
 };
 
 

+ 4 - 3
Praxis3D/Source/ScriptScene.cpp

@@ -56,7 +56,7 @@ void ScriptScene::update(const float p_deltaTime)
 	// Get the world scene required for getting components
 	// Get the world scene required for getting components
 	WorldScene *worldScene = static_cast<WorldScene*>(m_sceneLoader->getSystemScene(Systems::World));
 	WorldScene *worldScene = static_cast<WorldScene*>(m_sceneLoader->getSystemScene(Systems::World));
 
 
-	if(m_luaScriptsEnabled)
+	if(!m_sceneLoader->getFirstLoad() && !m_sceneLoader->getSceneLoadingStatus())
 	{
 	{
 		//	 ____________________________
 		//	 ____________________________
 		//	|							 |
 		//	|							 |
@@ -70,7 +70,7 @@ void ScriptScene::update(const float p_deltaTime)
 			SpatialComponent &spatialComponent = luaAndSpatialView.get<SpatialComponent>(entity);
 			SpatialComponent &spatialComponent = luaAndSpatialView.get<SpatialComponent>(entity);
 
 
 			// Check if the script object is enabled
 			// Check if the script object is enabled
-			if(luaComponent.isObjectActive())
+			if(luaComponent.isObjectActive() && (!luaComponent.pauseInEditor() || m_luaScriptsEnabled))
 			{
 			{
 				// Update the object
 				// Update the object
 				luaComponent.update(p_deltaTime, spatialComponent);
 				luaComponent.update(p_deltaTime, spatialComponent);
@@ -88,7 +88,7 @@ void ScriptScene::update(const float p_deltaTime)
 			LuaComponent &luaComponent = luaOnlyView.get<LuaComponent>(entity);
 			LuaComponent &luaComponent = luaOnlyView.get<LuaComponent>(entity);
 
 
 			// Check if the script object is enabled
 			// Check if the script object is enabled
-			if(luaComponent.isObjectActive())
+			if(luaComponent.isObjectActive() && (!luaComponent.pauseInEditor() || m_luaScriptsEnabled))
 			{
 			{
 				// Update the object
 				// Update the object
 				luaComponent.update(p_deltaTime);
 				luaComponent.update(p_deltaTime);
@@ -197,6 +197,7 @@ SystemObject *ScriptScene::createComponent(const EntityID &p_entityID, const Lua
 
 
 				component.m_objectType = Properties::PropertyID::LuaComponent;
 				component.m_objectType = Properties::PropertyID::LuaComponent;
 				component.m_setActiveAfterLoading = p_constructionInfo.m_active;
 				component.m_setActiveAfterLoading = p_constructionInfo.m_active;
+				component.m_pauseInEditor = p_constructionInfo.m_pauseInEditor;
 				component.setActive(false);
 				component.setActive(false);
 				component.setLoadedToMemory(false);
 				component.setLoadedToMemory(false);
 
 

+ 1 - 0
Praxis3D/Source/ScriptScene.h

@@ -79,6 +79,7 @@ public:
 	{
 	{
 		p_constructionInfo.m_active = p_component.isObjectActive();
 		p_constructionInfo.m_active = p_component.isObjectActive();
 		p_constructionInfo.m_name = p_component.getName();
 		p_constructionInfo.m_name = p_component.getName();
+		p_constructionInfo.m_pauseInEditor = p_component.pauseInEditor();
 
 
 		if(p_component.getLuaScript() != nullptr)
 		if(p_component.getLuaScript() != nullptr)
 		{
 		{

+ 36 - 7
Praxis3D/Source/SoundComponent.h

@@ -19,19 +19,29 @@ public:
 	};
 	};
 	constexpr static unsigned int SoundType_NumOfTypes = 4;
 	constexpr static unsigned int SoundType_NumOfTypes = 4;
 
 
+	enum SoundSourceType : unsigned int
+	{
+		SoundSourceType_File = 0,
+		SoundSourceType_Event
+	};
+	constexpr static unsigned int SoundSourceType_NumOfTypes = 2;
+
 	struct SoundComponentConstructionInfo : public SystemObject::SystemObjectConstructionInfo
 	struct SoundComponentConstructionInfo : public SystemObject::SystemObjectConstructionInfo
 	{
 	{
 		SoundComponentConstructionInfo()
 		SoundComponentConstructionInfo()
 		{
 		{
-			m_soundType = SoundType::SoundType_Music;
+			m_soundType = SoundType::SoundType_SoundEffect;
+			m_soundSourceType = SoundSourceType::SoundSourceType_File;
 			m_volume = 1.0f;
 			m_volume = 1.0f;
 			m_loop = false;
 			m_loop = false;
 			m_spatialized = false;
 			m_spatialized = false;
 			m_startPlaying = false;
 			m_startPlaying = false;
 		}
 		}
 
 
-		std::string m_soundFilename;
+		// Either a filename or an event name
+		std::string m_soundName;
 		SoundType m_soundType;
 		SoundType m_soundType;
+		SoundSourceType m_soundSourceType;
 		float m_volume;
 		float m_volume;
 		bool m_loop,
 		bool m_loop,
 			 m_spatialized,
 			 m_spatialized,
@@ -42,7 +52,10 @@ public:
 	{
 	{
 		m_sound = nullptr;
 		m_sound = nullptr;
 		m_channel = nullptr;
 		m_channel = nullptr;
+		m_soundEventDescription = nullptr;
+		m_soundEventInstance = nullptr;
 		m_soundType = SoundType::SoundType_Null;
 		m_soundType = SoundType::SoundType_Null;
+		m_soundSourceType = SoundSourceType::SoundSourceType_File;
 		m_volume = 1.0f;
 		m_volume = 1.0f;
 		m_loop = false;
 		m_loop = false;
 		m_spatialized = false;
 		m_spatialized = false;
@@ -95,12 +108,11 @@ public:
 			setActive(p_subject->getBool(this, Systems::Changes::Generic::Active));
 			setActive(p_subject->getBool(this, Systems::Changes::Generic::Active));
 		}
 		}
 
 
-		if(CheckBitmask(p_changeType, Systems::Changes::Audio::Filename))
+		if(CheckBitmask(p_changeType, Systems::Changes::Audio::SoundName))
 		{
 		{
-			m_soundFilename = p_subject->getString(this, Systems::Changes::Audio::Filename);
+			m_soundName = p_subject->getString(this, Systems::Changes::Audio::SoundName);
 			m_changePending = true;
 			m_changePending = true;
 			m_reloadSound = true;
 			m_reloadSound = true;
-			std::cout << m_soundFilename << std::endl;
 		}
 		}
 
 
 		if(CheckBitmask(p_changeType, Systems::Changes::Audio::Loop))
 		if(CheckBitmask(p_changeType, Systems::Changes::Audio::Loop))
@@ -123,6 +135,13 @@ public:
 			m_reloadSound = true;
 			m_reloadSound = true;
 		}
 		}
 
 
+		if(CheckBitmask(p_changeType, Systems::Changes::Audio::SoundSourceType))
+		{
+			m_soundSourceType = static_cast<SoundSourceType>(p_subject->getUnsignedInt(this, Systems::Changes::Audio::SoundSourceType));
+			m_changePending = true;
+			m_reloadSound = true;
+		}
+
 		if(CheckBitmask(p_changeType, Systems::Changes::Audio::Spatialized))
 		if(CheckBitmask(p_changeType, Systems::Changes::Audio::Spatialized))
 		{
 		{
 			m_spatialized = p_subject->getBool(this, Systems::Changes::Audio::Spatialized);
 			m_spatialized = p_subject->getBool(this, Systems::Changes::Audio::Spatialized);
@@ -145,21 +164,30 @@ public:
 	}
 	}
 
 
 	const inline SoundType getSoundType() const { return m_soundType; }
 	const inline SoundType getSoundType() const { return m_soundType; }
-	const inline std::string &getSoundFilename() const { return m_soundFilename; }
+	const inline SoundSourceType getSoundSourceType() const { return m_soundSourceType; }
+	const inline std::string &getSoundName() const { return m_soundName; }
 	const inline float getVolume() const { return m_volume; }
 	const inline float getVolume() const { return m_volume; }
 	const inline bool getLoop() const { return m_loop; }
 	const inline bool getLoop() const { return m_loop; }
 	const inline bool getSpatialized() const { return m_spatialized; }
 	const inline bool getSpatialized() const { return m_spatialized; }
 	const inline bool getStartPlaying() const { return m_startPlaying; }
 	const inline bool getStartPlaying() const { return m_startPlaying; }
 	const inline bool getPlaying() const { return m_playing; }
 	const inline bool getPlaying() const { return m_playing; }
 	const inline std::vector<const char *> &getSoundTypeText() const { return m_soundTypeText; }
 	const inline std::vector<const char *> &getSoundTypeText() const { return m_soundTypeText; }
+	const inline std::vector<const char *> &getSoundSourceTypeText() const { return m_soundSourceTypeText; }
 
 
 private:
 private:
 	FMOD::Sound *m_sound;
 	FMOD::Sound *m_sound;
 	FMOD::Channel *m_channel;
 	FMOD::Channel *m_channel;
 	FMOD_CREATESOUNDEXINFO *m_soundExInfo;
 	FMOD_CREATESOUNDEXINFO *m_soundExInfo;
 
 
+	FMOD::Studio::EventDescription *m_soundEventDescription; 
+	FMOD::Studio::EventInstance *m_soundEventInstance;
+
 	SoundType m_soundType;
 	SoundType m_soundType;
-	std::string m_soundFilename;
+	SoundSourceType m_soundSourceType;
+
+	// Either a filename or an event name
+	std::string m_soundName;
+
 	float m_volume;
 	float m_volume;
 	bool m_loop,
 	bool m_loop,
 		 m_spatialized,
 		 m_spatialized,
@@ -173,4 +201,5 @@ private:
 			m_volumeChanged;
 			m_volumeChanged;
 
 
 	std::vector<const char *> m_soundTypeText{ "null", "Music", "Ambient", "Sound effect" };
 	std::vector<const char *> m_soundTypeText{ "null", "Music", "Ambient", "Sound effect" };
+	std::vector<const char *> m_soundSourceTypeText{ "File", "Event" };
 };
 };

+ 7 - 2
Praxis3D/Source/Version.h

@@ -3,11 +3,16 @@
 #define VERSION_TO_STRING_HELPER(v) #v
 #define VERSION_TO_STRING_HELPER(v) #v
 #define VERSION_TO_STRING(v) VERSION_TO_STRING_HELPER(v)
 #define VERSION_TO_STRING(v) VERSION_TO_STRING_HELPER(v)
 
 
-#define PRAXIS3D_COMMIT_DATE 2024-01-19
+#define PRAXIS3D_COMMIT_DATE_YEAR 2024
+#define PRAXIS3D_COMMIT_DATE_MONTH 01
+#define PRAXIS3D_COMMIT_DATE_DAY 27
 
 
 #define PRAXIS3D_VERSION_MAJOR 0
 #define PRAXIS3D_VERSION_MAJOR 0
 #define PRAXIS3D_VERSION_MINOR 2
 #define PRAXIS3D_VERSION_MINOR 2
-#define PRAXIS3D_VERSION_PATCH 1
+#define PRAXIS3D_VERSION_PATCH 2
+
+#define PRAXIS3D_COMMIT_DATE ((PRAXIS3D_COMMIT_DATE_YEAR << 16) | (PRAXIS3D_COMMIT_DATE_MONTH << 8) | PRAXIS3D_COMMIT_DATE_DAY)
+#define PRAXIS3D_COMMIT_DATE_STRING VERSION_TO_STRING(PRAXIS3D_COMMIT_DATE_YEAR) "-" VERSION_TO_STRING(PRAXIS3D_COMMIT_DATE_MONTH) "-" VERSION_TO_STRING(PRAXIS3D_COMMIT_DATE_DAY)
 
 
 #define PRAXIS3D_VERSION ((PRAXIS3D_VERSION_MAJOR << 16) | (PRAXIS3D_VERSION_MINOR << 8) | PRAXIS3D_VERSION_PATCH)
 #define PRAXIS3D_VERSION ((PRAXIS3D_VERSION_MAJOR << 16) | (PRAXIS3D_VERSION_MINOR << 8) | PRAXIS3D_VERSION_PATCH)
 #define PRAXIS3D_VERSION_STRING VERSION_TO_STRING(PRAXIS3D_VERSION_MAJOR) "." VERSION_TO_STRING(PRAXIS3D_VERSION_MINOR) "." VERSION_TO_STRING(PRAXIS3D_VERSION_PATCH)
 #define PRAXIS3D_VERSION_STRING VERSION_TO_STRING(PRAXIS3D_VERSION_MAJOR) "." VERSION_TO_STRING(PRAXIS3D_VERSION_MINOR) "." VERSION_TO_STRING(PRAXIS3D_VERSION_PATCH)

+ 18 - 0
Praxis3D/Source/WorldScene.h

@@ -150,6 +150,24 @@ public:
 	BitMask getDesiredSystemChanges() { return Systems::Changes::Generic::CreateObject || Systems::Changes::Generic::DeleteObject; }
 	BitMask getDesiredSystemChanges() { return Systems::Changes::Generic::CreateObject || Systems::Changes::Generic::DeleteObject; }
 	BitMask getPotentialSystemChanges() { return Systems::Changes::None; }
 	BitMask getPotentialSystemChanges() { return Systems::Changes::None; }
 
 
+	// Find and return an entity ID of an entity matching the given name
+	// Returns NULL_ENTITY_ID if no entity was found
+	inline EntityID getEntity(const std::string &p_name) const
+	{
+		// Iterate every entity and add its entity ID and name to the list
+		for(auto entity : m_entityRegistry.view<EntityID>())
+		{
+			// Try to get the metadata component
+			if(auto metadataComponent = m_entityRegistry.try_get<MetadataComponent>(entity); metadataComponent != nullptr)
+			{
+				if(metadataComponent->m_name == p_name)
+					return entity;
+			}
+		}
+
+		return NULL_ENTITY_ID;
+	}
+
 	// Adds a component with the given parameters and returns a reference to it
 	// Adds a component with the given parameters and returns a reference to it
 	template <class T_Component, class... T_Args>
 	template <class T_Component, class... T_Args>
 	T_Component &addComponent(EntityID p_entity, T_Args&&... p_args)
 	T_Component &addComponent(EntityID p_entity, T_Args&&... p_args)

+ 271 - 17
Praxis3D/imgui.ini

@@ -1,5 +1,5 @@
 [Window][Debug##Default]
 [Window][Debug##Default]
-Pos=101,395
+Pos=101,162
 Size=400,400
 Size=400,400
 Collapsed=0
 Collapsed=0
 
 
@@ -80,30 +80,30 @@ DockId=0x00000002,0
 
 
 [Window][DockSpaceViewport_11111111]
 [Window][DockSpaceViewport_11111111]
 Pos=0,69
 Pos=0,69
-Size=5120,1318
+Size=2335,1309
 Collapsed=0
 Collapsed=0
 
 
 [Window][##LeftWindow]
 [Window][##LeftWindow]
 Pos=0,69
 Pos=0,69
-Size=301,1066
+Size=301,1057
 Collapsed=0
 Collapsed=0
 DockId=0x00000001,0
 DockId=0x00000001,0
 
 
 [Window][##RightWindow]
 [Window][##RightWindow]
-Pos=4611,69
-Size=509,1318
+Pos=1865,69
+Size=470,1309
 Collapsed=0
 Collapsed=0
 DockId=0x00000008,0
 DockId=0x00000008,0
 
 
 [Window][##BottomWindow]
 [Window][##BottomWindow]
-Pos=0,1137
-Size=4609,250
+Pos=0,1128
+Size=1863,250
 Collapsed=0
 Collapsed=0
 DockId=0x00000006,0
 DockId=0x00000006,0
 
 
 [Window][##CenterWindow]
 [Window][##CenterWindow]
 Pos=303,69
 Pos=303,69
-Size=4306,1066
+Size=1560,1057
 Collapsed=0
 Collapsed=0
 DockId=0x00000004,0
 DockId=0x00000004,0
 
 
@@ -213,7 +213,7 @@ Size=855,618
 Collapsed=0
 Collapsed=0
 
 
 [Window][##AddEntityPopup]
 [Window][##AddEntityPopup]
-Pos=273,118
+Pos=224,784
 Size=400,135
 Size=400,135
 Collapsed=0
 Collapsed=0
 
 
@@ -223,8 +223,8 @@ Size=801,605
 Collapsed=0
 Collapsed=0
 
 
 [Window][##LoadingStatusWindow]
 [Window][##LoadingStatusWindow]
-Pos=2424,578
-Size=64,70
+Pos=1135,477
+Size=65,104
 Collapsed=0
 Collapsed=0
 
 
 [Window][Open a shader file##OpenShaderFileFileDialog]
 [Window][Open a shader file##OpenShaderFileFileDialog]
@@ -233,12 +233,22 @@ Size=920,703
 Collapsed=0
 Collapsed=0
 
 
 [Window][Edit Map File##fileBrowserEditMap]
 [Window][Edit Map File##fileBrowserEditMap]
-Pos=488,325
+Pos=522,320
 Size=1007,705
 Size=1007,705
 Collapsed=0
 Collapsed=0
 
 
 [Window][##AboutWindow]
 [Window][##AboutWindow]
-Size=224,1378
+Size=2335,1378
+Collapsed=0
+
+[Window][ExampleMapInfo]
+Pos=756,390
+Size=80,71
+Collapsed=0
+
+[Window][##ExampleMapInfo]
+Pos=0,0
+Size=2335,1055
 Collapsed=0
 Collapsed=0
 
 
 [Table][0x9A4BDFDE,4]
 [Table][0x9A4BDFDE,4]
@@ -2101,14 +2111,258 @@ Column 0  Sort=0v
 RefScale=13
 RefScale=13
 Column 0  Sort=0v
 Column 0  Sort=0v
 
 
+[Table][0x3485E889,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xE9D446AA,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x5F513C80,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x5A320BEA,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x6733A4BE,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x7F8A3A5E,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xF90F2636,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x466BD8B8,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xD86BBC2A,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x4F7DA16E,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xE59B1B75,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x41C43FC0,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x9677DEEB,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xD261BBEF,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x8E2F1435,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xF323FA89,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x6F280316,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x1EF50B11,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xE72B9EB5,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x73820DAA,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x7F01FBFE,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x51104697,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x6FA58406,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xC09C96BC,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x61552CD2,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x0238EADE,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x8EA7C133,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xE3655034,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x9011C310,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x513AD0AF,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x152CB5AB,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xF09D1D12,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xFE89CFE6,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xDDEE4BDD,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xA9CE080F,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xC9C32DB2,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xECD38B13,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x69FFD002,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xC1489D81,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x17071916,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x3989AF40,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xAC6EC196,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x9047599B,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x5268786D,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xEF4E5C79,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x8C8554AB,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xA87D31B3,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x26556975,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x62430C71,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xCCB44065,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xBC148B33,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xE011E7F8,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xF49BD66F,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x06B21235,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xFDB46828,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x478A642D,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x17C5A6F8,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x293D2995,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x962538DF,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x0831B9DA,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xD2D5664F,4]
+RefScale=13
+Column 0  Sort=0v
+
 [Docking][Data]
 [Docking][Data]
-DockSpace         ID=0x8B93E3BD Window=0xA787BDB4 Pos=0,69 Size=5120,1318 Split=X
-  DockNode        ID=0x00000007 Parent=0x8B93E3BD SizeRef=1409,1011 Split=Y
+DockSpace         ID=0x8B93E3BD Pos=0,69 Size=2335,1309 Split=X
+  DockNode        ID=0x00000007 Parent=0x8B93E3BD SizeRef=1863,1011 Split=Y
     DockNode      ID=0x00000005 Parent=0x00000007 SizeRef=1920,1057 Split=X
     DockNode      ID=0x00000005 Parent=0x00000007 SizeRef=1920,1057 Split=X
       DockNode    ID=0x00000001 Parent=0x00000005 SizeRef=301,1011 Selected=0xB1B21E90
       DockNode    ID=0x00000001 Parent=0x00000005 SizeRef=301,1011 Selected=0xB1B21E90
-      DockNode    ID=0x00000003 Parent=0x00000005 SizeRef=1106,1011 Split=X
+      DockNode    ID=0x00000003 Parent=0x00000005 SizeRef=1560,1011 Split=X
         DockNode  ID=0x00000002 Parent=0x00000003 SizeRef=332,1042 Selected=0xD00C9CD4
         DockNode  ID=0x00000002 Parent=0x00000003 SizeRef=332,1042 Selected=0xD00C9CD4
         DockNode  ID=0x00000004 Parent=0x00000003 SizeRef=1586,1042 CentralNode=1 Selected=0xFB1B6F35
         DockNode  ID=0x00000004 Parent=0x00000003 SizeRef=1586,1042 CentralNode=1 Selected=0xFB1B6F35
     DockNode      ID=0x00000006 Parent=0x00000007 SizeRef=1920,250 Selected=0x51C0BD29
     DockNode      ID=0x00000006 Parent=0x00000007 SizeRef=1920,250 Selected=0x51C0BD29
-  DockNode        ID=0x00000008 Parent=0x8B93E3BD SizeRef=509,1011 Selected=0x96D2BCA2
+  DockNode        ID=0x00000008 Parent=0x8B93E3BD SizeRef=470,1011 Selected=0x96D2BCA2