Răsfoiți Sursa

Added SpatialData and SpatialTransformData containers
Added conversion from Quaterion to Vec4f in Math library
Added InheritanceObjects containing general classes used to add specific functionality through inheritance
Added SpatialDataManager to handle all space related data and changes, offloading work from game objects
Added SpatialDataManagerObject and SpatialDataObject classes that adds a way to track spatial-data changes via update counters (when inherited)
Added type definition of ObjectID and standardised the data type in various objects
Added NullObjects which contains static empty containers to be used all around (for example in objects when they fail to get an actual populated container)
Moved null objects from ObserverBase to NullObjects
Refactored the GameObject to use component system
Refactored BitMask definitions for data change tracking
Refactored LightComponent to work with GraphicsObject
Progressed on refactoring the GraphicsObject to use component system
Fixed a bug in TaskScheduler, initializing too many entries in tasksToExecute array
Fixed a bug of potential data loss in assigning mismatched data types for SystemObject IDs and data changes BitMask
Fixed a bug in ObjectDirectory of comparing pointer value instead of assigning it
Upgraded project to work on Visual Studio 2022

Paul A 4 ani în urmă
părinte
comite
eeec9a5627
35 a modificat fișierele cu 838 adăugiri și 433 ștergeri
  1. BIN
      .vs/Praxis3D/v16/.suo
  2. 14 8
      Praxis3D/Praxis3D.vcxproj
  3. 18 0
      Praxis3D/Praxis3D.vcxproj.filters
  4. 6 6
      Praxis3D/Source/BaseGraphicsObjects.h
  5. 4 4
      Praxis3D/Source/CameraScript.h
  6. 5 5
      Praxis3D/Source/ChangeController.cpp
  7. 2 0
      Praxis3D/Source/CommonDefinitions.h
  8. 79 42
      Praxis3D/Source/Config.h
  9. 36 4
      Praxis3D/Source/Containers.h
  10. 5 5
      Praxis3D/Source/DebugRotateScript.h
  11. 63 84
      Praxis3D/Source/GameObject.h
  12. 1 1
      Praxis3D/Source/GraphicsDataSets.h
  13. 69 94
      Praxis3D/Source/GraphicsObject.h
  14. 69 0
      Praxis3D/Source/InheritanceObjects.h
  15. 1 17
      Praxis3D/Source/LightComponent.cpp
  16. 14 89
      Praxis3D/Source/LightComponent.h
  17. 2 2
      Praxis3D/Source/LightingGraphicsObjects.h
  18. 1 0
      Praxis3D/Source/Math.h
  19. 0 1
      Praxis3D/Source/ModelGraphicsObjects.h
  20. 0 0
      Praxis3D/Source/NullObject.cpp
  21. 27 0
      Praxis3D/Source/NullObjects.cpp
  22. 31 0
      Praxis3D/Source/NullObjects.h
  23. 1 1
      Praxis3D/Source/ObjectDirectory.h
  24. 17 15
      Praxis3D/Source/ObjectRegister.h
  25. 3 13
      Praxis3D/Source/ObserverBase.cpp
  26. 23 30
      Praxis3D/Source/ObserverBase.h
  27. 2 2
      Praxis3D/Source/RendererFrontend.cpp
  28. 3 3
      Praxis3D/Source/RendererScene.cpp
  29. 4 0
      Praxis3D/Source/RendererScene.h
  30. 1 1
      Praxis3D/Source/ShaderGraphicsObjects.h
  31. 1 0
      Praxis3D/Source/SpatialDataChangeManager.cpp
  32. 327 0
      Praxis3D/Source/SpatialDataManager.h
  33. 3 0
      Praxis3D/Source/System.h
  34. 1 1
      Praxis3D/Source/TaskScheduler.cpp
  35. 5 5
      Praxis3D/Source/WorldEditObject.h

BIN
.vs/Praxis3D/v16/.suo


+ 14 - 8
Praxis3D/Praxis3D.vcxproj

@@ -43,52 +43,52 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 64bit|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 64bit|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 64bit|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 64bit|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
@@ -309,6 +309,8 @@
     <ClCompile Include="Source\Loaders.cpp" />
     <ClCompile Include="Source\Math.cpp" />
     <ClCompile Include="Source\ModelLoader.cpp" />
+    <ClCompile Include="Source\NullObject.cpp" />
+    <ClCompile Include="Source\NullObjects.cpp" />
     <ClCompile Include="Source\NullSystemObjects.cpp" />
     <ClCompile Include="Source\ObjectDirectory.cpp" />
     <ClCompile Include="Source\ObserverBase.cpp" />
@@ -329,6 +331,7 @@
     <ClCompile Include="Source\ScriptingTask.cpp" />
     <ClCompile Include="Source\ShaderLoader.cpp" />
     <ClCompile Include="Source\ShaderUniformUpdater.cpp" />
+    <ClCompile Include="Source\SpatialDataChangeManager.cpp" />
     <ClCompile Include="Source\SpinWait.cpp" />
     <ClCompile Include="Source\System.cpp" />
     <ClCompile Include="Source\TaskManager.cpp" />
@@ -389,6 +392,7 @@
     <ClInclude Include="Source\GraphicsDataSets.h" />
     <ClInclude Include="Source\GraphicsObject.h" />
     <ClInclude Include="Source\HdrMappingPass.h" />
+    <ClInclude Include="Source\InheritanceObjects.h" />
     <ClInclude Include="Source\Input.h" />
     <ClInclude Include="Source\KeyCommand.h" />
     <ClInclude Include="Source\LenseFlareCompositePass.h" />
@@ -402,6 +406,7 @@
     <ClInclude Include="Source\ModelComponent.h" />
     <ClInclude Include="Source\ModelLoader.h" />
     <ClInclude Include="Source\ModelGraphicsObjects.h" />
+    <ClInclude Include="Source\NullObjects.h" />
     <ClInclude Include="Source\NullSystemObjects.h" />
     <ClInclude Include="Source\ObjectDirectory.h" />
     <ClInclude Include="Source\ObjectPool.h" />
@@ -432,6 +437,7 @@
     <ClInclude Include="Source\ShaderUniformUpdater.h" />
     <ClInclude Include="Source\SkyPass.h" />
     <ClInclude Include="Source\SolarTimeScript.h" />
+    <ClInclude Include="Source\SpatialDataManager.h" />
     <ClInclude Include="Source\SpinWait.h" />
     <ClInclude Include="Source\SunScript.h" />
     <ClInclude Include="Source\System.h" />

+ 18 - 0
Praxis3D/Praxis3D.vcxproj.filters

@@ -288,6 +288,15 @@
     <ClCompile Include="Source\LightComponent.cpp">
       <Filter>Renderer\Objects\Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\SpatialDataChangeManager.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\NullObject.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\NullObjects.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Source\ErrorCodes.h">
@@ -608,6 +617,15 @@
     <ClInclude Include="Source\GameLogicObject.h">
       <Filter>Scripting\Objects\Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Source\SpatialDataManager.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\InheritanceObjects.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\NullObjects.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="Data\config.ini" />

+ 6 - 6
Praxis3D/Source/BaseGraphicsObjects.h

@@ -27,7 +27,7 @@ public:
 	// Processes any spacial changes
 	virtual void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType)
 	{
-		if(p_changeType & Systems::Changes::Spatial::WorldPosition)
+		/*if(p_changeType & Systems::Changes::Spatial::WorldPosition)
 		{
 			m_baseObjectData.m_position = 
 				p_subject->getVec3(this, Systems::Changes::Spatial::WorldPosition) + m_baseObjectData.m_offsetPosition;
@@ -56,7 +56,7 @@ public:
 		if(p_changeType & Systems::Changes::Graphics::Lighting)
 		{
 			m_affectedByLighting = p_subject->getBool(this, Systems::Changes::Graphics::Lighting);
-		}
+		}*/
 	}
 
 	// Has the object been already loaded to memory (RAM)?
@@ -71,7 +71,7 @@ public:
 	// Getters
 	const virtual Math::Vec3f &getVec3(const Observer *p_observer, BitMask p_changedBits) const
 	{
-		switch(p_changedBits)
+		/*switch(p_changedBits)
 		{
 		case Systems::Changes::Spatial::Position:
 			return m_baseObjectData.m_position;
@@ -82,18 +82,18 @@ public:
 		case Systems::Changes::Spatial::Scale:
 			return m_baseObjectData.m_scale;
 			break;
-		}
+		}*/
 
 		return ObservedSubject::getVec3(p_observer, p_changedBits);
 	}
 	const virtual bool getBool(const Observer *p_observer, BitMask p_changedBits) const
 	{
-		switch(p_changedBits)
+		/*switch(p_changedBits)
 		{
 		case Systems::Changes::Graphics::Lighting:
 			return m_affectedByLighting;
 			break;
-		}
+		}*/
 
 		return ObservedSubject::getBool(p_observer, p_changedBits);
 	}

+ 4 - 4
Praxis3D/Source/CameraScript.h

@@ -19,7 +19,7 @@ public:
 
 	const virtual Math::Vec3f &getVec3(const Observer *p_observer, BitMask p_changedBits) const
 	{
-		switch(p_changedBits)
+		/*switch (p_changedBits)
 		{
 		case Systems::Changes::Spatial::Position:
 			return m_positionVec;
@@ -27,19 +27,19 @@ public:
 		case Systems::Changes::Spatial::Rotation:
 			return m_targetVec;
 			break;
-		}
+		}*/
 
 		return ObservedSubject::getVec3(p_observer, p_changedBits);
 	}
 
 	const virtual Math::Mat4f &getMat4(const Observer *p_observer, BitMask p_changedBits) const
 	{
-		switch(p_changedBits)
+		/*switch (p_changedBits)
 		{
 		case Systems::Changes::Spatial::ModelMatrix:
 			return m_modelMatrix;
 			break;
-		}
+		}*/
 
 		return ObservedSubject::getMat4(p_observer, p_changedBits);
 	}

+ 5 - 5
Praxis3D/Source/ChangeController.cpp

@@ -71,7 +71,7 @@ ChangeController::~ChangeController()
 
 ErrorCode ChangeController::registerSubject(ObservedSubject *p_subject, BitMask p_interestedBits, Observer *p_observer, BitMask p_observerBits)
 {
-	// Current return error is "failed" untill the registering has been completed
+	// Current return error is "failed" until the registering has been completed
 	ErrorCode returnError = ErrorCode::Failure;
 
 	if(p_subject && p_observer)
@@ -79,7 +79,7 @@ ErrorCode ChangeController::registerSubject(ObservedSubject *p_subject, BitMask
 		// Stop the updates and lock, during the subject registration
 		SpinWait::Lock lock(m_spinWaitUpdate);
 
-		unsigned int ID = p_subject->getID(this);
+		SystemObjectID ID = p_subject->getID(this);
 
 		// If subject has already been registered
 		if(ID != ObservedSubject::g_invalidID)
@@ -135,7 +135,7 @@ ErrorCode ChangeController::unregisterSubject(ObservedSubject *p_subject, Observ
 		// Stop the updates and lock, during the subject registration
 		SpinWait::Lock lock(m_spinWaitUpdate);
 
-		const unsigned int ID = p_subject->getID(this);
+		const auto ID = p_subject->getID(this);
 
 		if(m_subjectsList.size() <= ID || m_subjectsList[ID].m_subject != p_subject)
 		{
@@ -205,7 +205,7 @@ ErrorCode ChangeController::distributeChanges(BitMask p_systemsToNotify, BitMask
 				Notification &notification = currentList->at(i);
 
 				// Get subject's ID
-				unsigned int ID = notification.m_subject->getID(this);
+				const auto ID = notification.m_subject->getID(this);
 
 				// TODO ASSERT ERROR
 				_ASSERT(ID != ObservedSubject::g_invalidID);
@@ -499,7 +499,7 @@ ErrorCode ChangeController::removeSubject(ObservedSubject *p_subject)
 	{
 		SpinWait::Lock lock(m_spinWaitUpdate);
 
-		unsigned int ID = p_subject->getID(this);
+		const auto ID = p_subject->getID(this);
 		_ASSERT(ID != unsigned int(-1));
 		_ASSERT(m_subjectsList[ID].m_subject == p_subject);
 

+ 2 - 0
Praxis3D/Source/CommonDefinitions.h

@@ -2,6 +2,8 @@
 
 #include <GL\glew.h>
 
+typedef unsigned int UpdateCount;
+
 enum BindCommandType : unsigned int
 {
 	BindCommandType_Texture,

+ 79 - 42
Praxis3D/Source/Config.h

@@ -1,5 +1,6 @@
 #pragma once
 
+#include <climits>
 #include <GL\glew.h>
 #include <string>
 #include <unordered_map>
@@ -11,6 +12,9 @@
 
 typedef unsigned __int64 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); }
+
 //#define ever ;;
 
 //#define GL_LINEAR_MIPMAP_LINEAR 0x2703
@@ -38,50 +42,84 @@ namespace Systems
 	namespace Types
 	{
 		static constexpr BitMask All = static_cast<BitMask>(-1);
-		static constexpr BitMask Max = 32;
+		static constexpr BitMask Max = 32;// (BitMask)1 << ((CHAR_BIT * sizeof(BitMask) - 1));
+	}
+	namespace GameObjectComponents
+	{
+		static constexpr BitMask None		= (BitMask)1 << 0;
+		static constexpr BitMask Graphics	= (BitMask)1 << 1;
+		static constexpr BitMask Scripting	= (BitMask)1 << 2;
+	}	
+	namespace GraphicsObjectComponents
+	{
+		static constexpr BitMask None		= (BitMask)1 << 0;
+		static constexpr BitMask Lighting	= (BitMask)1 << 1;
+		static constexpr BitMask Model		= (BitMask)1 << 2;
+		static constexpr BitMask Shader		= (BitMask)1 << 3;
 	}
-
 	namespace Changes
 	{
 		namespace Common
 		{
-			/*static constexpr BitMask Shared0	= (BitMask)1 << 0;
 			static constexpr BitMask Shared1	= (BitMask)1 << 1;
-			static constexpr BitMask Shared2	= (BitMask)1 << 3;
-			static constexpr BitMask Shared3	= (BitMask)1 << 4;
-			static constexpr BitMask Shared4	= (BitMask)1 << 5;
-			static constexpr BitMask Shared5	= (BitMask)1 << 6;
-			static constexpr BitMask Shared6	= (BitMask)1 << 7;
-			static constexpr BitMask Shared7	= (BitMask)1 << 8;
-			static constexpr BitMask Shared8	= (BitMask)1 << 9;
-			static constexpr BitMask Shared9	= (BitMask)1 << 10;*/
+			static constexpr BitMask Shared2	= (BitMask)1 << 2;
+			static constexpr BitMask Shared3	= (BitMask)1 << 3;
+			static constexpr BitMask Shared4	= (BitMask)1 << 4;
+			static constexpr BitMask Shared5	= (BitMask)1 << 5;
+			static constexpr BitMask Shared6	= (BitMask)1 << 6;
+			static constexpr BitMask Shared7	= (BitMask)1 << 7;
+			static constexpr BitMask Shared8	= (BitMask)1 << 8;
+			static constexpr BitMask Shared9	= (BitMask)1 << 9;
+			static constexpr BitMask Shared10	= (BitMask)1 << 10;
+			static constexpr BitMask Shared11	= (BitMask)1 << 11;
+			static constexpr BitMask Shared12	= (BitMask)1 << 12;
+			static constexpr BitMask Shared13	= (BitMask)1 << 13;
+			static constexpr BitMask Shared14	= (BitMask)1 << 14;
+			static constexpr BitMask Shared15	= (BitMask)1 << 15;
+			static constexpr BitMask Shared16	= (BitMask)1 << 16;
+			static constexpr BitMask Shared17	= (BitMask)1 << 17;
+			static constexpr BitMask Shared18	= (BitMask)1 << 18;
+			static constexpr BitMask Shared19	= (BitMask)1 << 19;
+			static constexpr BitMask Shared20	= (BitMask)1 << 20;
+			static constexpr BitMask Shared21	= (BitMask)1 << 21;
 		}
+		namespace Type
+		{
+			static constexpr BitMask Generic	= (BitMask)1 << 63;
+			static constexpr BitMask Spatial	= (BitMask)1 << 62;
+			static constexpr BitMask Graphics	= (BitMask)1 << 61;
+			static constexpr BitMask Physics	= (BitMask)1 << 60;
+			static constexpr BitMask Audio		= (BitMask)1 << 59;
+			static constexpr BitMask Scripting	= (BitMask)1 << 58;
+		}
+
 		namespace Generic
 		{
-			static constexpr BitMask CreateObject		= (BitMask)1 << 0;
-			static constexpr BitMask DeleteObject		= (BitMask)1 << 1;
-			static constexpr BitMask ExtendObject		= (BitMask)1 << 2;
-			static constexpr BitMask UnextendObject		= (BitMask)1 << 3;
-			static constexpr BitMask Name				= (BitMask)1 << 4;
+			static constexpr BitMask CreateObject		= Changes::Type::Generic + Changes::Common::Shared1;
+			static constexpr BitMask DeleteObject		= Changes::Type::Generic + Changes::Common::Shared2;
+			static constexpr BitMask ExtendObject		= Changes::Type::Generic + Changes::Common::Shared3;
+			static constexpr BitMask UnextendObject		= Changes::Type::Generic + Changes::Common::Shared4;
+			static constexpr BitMask Name				= Changes::Type::Generic + Changes::Common::Shared5;
 			static constexpr BitMask All				= CreateObject | DeleteObject | ExtendObject | Name;
 		}
 		namespace Spatial
 		{
-			static constexpr BitMask LocalModifier			= (BitMask)1 << 5;
-			static constexpr BitMask WorldModifier			= (BitMask)1 << 6;
-			static constexpr BitMask Position				= (BitMask)1 << 7;
-			static constexpr BitMask Rotation				= (BitMask)1 << 8;
-			static constexpr BitMask Scale					= (BitMask)1 << 9;
-			static constexpr BitMask Transform				= (BitMask)1 << 10;
-
-			static constexpr BitMask LocalPosition			= LocalModifier | Position;
-			static constexpr BitMask LocalRotation			= LocalModifier | Rotation;
-			static constexpr BitMask LocalScale				= LocalModifier | Scale;
-			static constexpr BitMask LocalTransform			= LocalModifier | Transform;
-			static constexpr BitMask WorldPosition			= WorldModifier | Position;
-			static constexpr BitMask WorldRotation			= WorldModifier | Rotation;
-			static constexpr BitMask WorldScale				= WorldModifier | Scale;
-			static constexpr BitMask WorldTransform			= WorldModifier | Transform;
+			/*static constexpr BitMask LocalModifier = Changes::Common::Shared0;
+			static constexpr BitMask WorldModifier			= Changes::Common::Shared1;
+			static constexpr BitMask Position				= Changes::Common::Shared2;
+			static constexpr BitMask Rotation				= Changes::Common::Shared3;
+			static constexpr BitMask Scale					= Changes::Common::Shared4;
+			static constexpr BitMask Transform				= Changes::Common::Shared5;*/
+
+			static constexpr BitMask LocalPosition			= Changes::Type::Spatial + Changes::Common::Shared1;
+			static constexpr BitMask LocalRotation			= Changes::Type::Spatial + Changes::Common::Shared2;
+			static constexpr BitMask LocalScale				= Changes::Type::Spatial + Changes::Common::Shared3;
+			static constexpr BitMask LocalTransform			= Changes::Type::Spatial + Changes::Common::Shared4;
+
+			static constexpr BitMask WorldPosition			= Changes::Type::Spatial + Changes::Common::Shared5;
+			static constexpr BitMask WorldRotation			= Changes::Type::Spatial + Changes::Common::Shared6;
+			static constexpr BitMask WorldScale				= Changes::Type::Spatial + Changes::Common::Shared7;
+			static constexpr BitMask WorldTransform			= Changes::Type::Spatial + Changes::Common::Shared8;
 
 			static constexpr BitMask AllLocalNoTransform	= LocalPosition | LocalRotation | LocalScale;
 			static constexpr BitMask AllWorldNoTransform	= WorldPosition | WorldRotation | WorldScale;
@@ -91,19 +129,18 @@ namespace Systems
 		}
 		namespace Graphics
 		{
-			static constexpr BitMask Lighting				= (BitMask)1 << 11;
-
-			static constexpr BitMask Target					= (BitMask)1 << 12;
-			static constexpr BitMask UpVector				= (BitMask)1 << 13;
+			static constexpr BitMask Target					= Changes::Type::Graphics + Changes::Common::Shared1;
+			static constexpr BitMask UpVector				= Changes::Type::Graphics + Changes::Common::Shared2;
 			static constexpr BitMask AllCamera				= Target | UpVector;
 
-			static constexpr BitMask Color					= (BitMask)1 << 14;
-			static constexpr BitMask CutoffAngle			= (BitMask)1 << 15;
-			static constexpr BitMask Direction				= (BitMask)1 << 16;
-			static constexpr BitMask Intensity				= (BitMask)1 << 17;
-			static constexpr BitMask AllLightig				= Color | CutoffAngle | Direction | Intensity;
+			static constexpr BitMask Lighting				= Changes::Type::Graphics + Changes::Common::Shared3;
+			static constexpr BitMask Color					= Changes::Type::Graphics + Changes::Common::Shared4;
+			static constexpr BitMask CutoffAngle			= Changes::Type::Graphics + Changes::Common::Shared5;
+			static constexpr BitMask Direction				= Changes::Type::Graphics + Changes::Common::Shared6;
+			static constexpr BitMask Intensity				= Changes::Type::Graphics + Changes::Common::Shared7;
+			static constexpr BitMask AllLighting			= Lighting | Color | CutoffAngle | Direction | Intensity;
 
-			static constexpr BitMask All					= AllCamera | AllLightig;
+			static constexpr BitMask All					= AllCamera | AllLighting;
 		}
 		namespace Physics
 		{
@@ -118,7 +155,7 @@ namespace Systems
 
 		}
 
-		static constexpr BitMask Link = (BitMask)1 << 29;
+		//static constexpr BitMask Link = (BitMask)1 << 29;
 
 		static constexpr BitMask None = 0;
 		static constexpr BitMask All = static_cast<BitMask>(-1);

+ 36 - 4
Praxis3D/Source/Containers.h

@@ -5,24 +5,56 @@
 // Stores all spatial data (position, rotation, scale)
 struct SpatialData
 {	
+	SpatialData() { }
+	SpatialData(const Math::Vec3f &p_position, const Math::Vec3f &p_rotationEuler, const Math::Vec3f &p_scale, const Math::Quaternion &p_rotationQuat)
+		: m_position(p_position), m_scale(p_scale), m_rotationEuler(p_rotationEuler), m_rotationQuat(p_rotationQuat) { }
+
+	friend const inline SpatialData operator+(const SpatialData &p_left, const SpatialData &p_right)
+	{
+		return SpatialData(	p_left.m_position + p_right.m_position, 
+							p_left.m_rotationEuler + p_right.m_rotationEuler, 
+							p_left.m_scale + p_right.m_scale, 
+							p_left.m_rotationQuat * p_right.m_rotationQuat);
+	}
+
+	const inline SpatialData operator+=(const SpatialData &p_data)
+	{
+		return SpatialData(	m_position + p_data.m_position,
+							m_rotationEuler + p_data.m_rotationEuler,
+							m_scale + p_data.m_scale,
+							m_rotationQuat * p_data.m_rotationQuat);
+	}
+
 	// Set all data to default
 	void clear()
 	{
 		m_position = Math::Vec3f();
-		m_scale = Math::Vec3f();
 		m_rotationEuler = Math::Vec3f();
+		m_scale = Math::Vec3f();
 		m_rotationQuat = Math::Quaternion();
 	}
 
 	Math::Vec3f m_position,
-				m_scale,
-				m_rotationEuler;
+				m_rotationEuler,
+				m_scale;
 	Math::Quaternion m_rotationQuat;
 };
 
-// Stores all spatial data (position, rotation, scale) plus transform matrix
+// Stores all spatial data (position, rotation, scale) plus the transform matrix
 struct SpatialTransformData
 {
+	SpatialTransformData() { }
+	SpatialTransformData(const SpatialData &p_spatialData, const Math::Mat4f &p_transformMat) : m_spatialData(p_spatialData), m_transformMat(p_transformMat) { }
+
+	friend const inline SpatialTransformData operator+(const SpatialTransformData &p_left, const SpatialTransformData &p_right)
+	{
+		return SpatialTransformData(p_left.m_spatialData + p_right.m_spatialData, p_left.m_transformMat * p_right.m_transformMat);
+	}
+	const inline SpatialTransformData operator+=(const SpatialTransformData &p_data)
+	{ 
+		return SpatialTransformData(m_spatialData + p_data.m_spatialData, m_transformMat * p_data.m_transformMat);
+	}
+
 	// Set all data to default
 	void clear()
 	{

+ 5 - 5
Praxis3D/Source/DebugRotateScript.h

@@ -37,7 +37,7 @@ public:
 		propertySet.addProperty(Properties::Type, Properties::DebugRotateScript);
 		propertySet.addProperty(Properties::Name, m_name);
 		propertySet.addProperty(Properties::Axis, m_axis);
-		propertySet.addProperty(Properties::Rotation, m_rotation);
+		propertySet.addProperty(Properties::LocalRotationQuaternion, m_rotation);
 		propertySet.addProperty(Properties::Speed, m_speed);
 
 		return propertySet;
@@ -48,17 +48,17 @@ public:
 		m_rotation.rotate(m_speed * p_deltaTime, m_axis);
 		m_rotation.normalize();
 		
-		postChanges(Systems::Changes::Spacial::Rotation);
+		//postChanges(Systems::Changes::Spatial::Rotation);
 	}
 
 	const virtual Math::Vec3f &getVec3(const Observer *p_observer, BitMask p_changedBits) const
 	{
-		switch (p_changedBits)
+		/*switch (p_changedBits)
 		{
-		case Systems::Changes::Spacial::Rotation:
+		case Systems::Changes::Spatial::Rotation:
 			return m_rotation;
 			break;
-		}
+		}*/
 
 		return ObservedSubject::getVec3(p_observer, p_changedBits);
 	}

+ 63 - 84
Praxis3D/Source/GameObject.h

@@ -2,7 +2,9 @@
 
 #include "Containers.h"
 #include "GraphicsObject.h"
+#include "ObjectRegister.h"
 #include "SceneLoader.h"
+#include "SpatialDataManager.h"
 #include "System.h"
 
 // The main object type that glues all other system objects together, forming a component system.
@@ -11,10 +13,19 @@ class GameObject : public SystemObject
 {
 	friend class WorldScene;
 public:
-	GameObject(SystemScene *p_systemScene, std::string p_name, SceneLoader &p_sceneLoader, std::size_t p_id = 0) : SystemObject(p_systemScene, p_name, Properties::GameObject), m_sceneLoader(p_sceneLoader), m_id(p_id)
+	GameObject(SystemScene *p_systemScene, std::string p_name, SceneLoader &p_sceneLoader, ObjectID p_id = 0) : SystemObject(p_systemScene, p_name, Properties::GameObject), m_sceneLoader(p_sceneLoader), m_id(p_id), m_spatialData(*this)
 	{
 		m_parent = nullptr;
 		m_graphicsComponent = nullptr;
+		m_componentsFlag = 0;
+	}
+	~GameObject()
+	{
+		// Remove all components
+		for(int i = 0; i < Systems::TypeID::NumberOfSystems; i++)
+		{
+			removeComponent(static_cast<Systems::TypeID>(i));
+		}
 	}
 	
 	BitMask getSystemType() override final { return Systems::World; }
@@ -42,20 +53,18 @@ public:
 	// Notify this object of the data that has been changed
 	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) override 
 	{
-		BitMask newChanges = Systems::Changes::None;
+		assert(p_subject == nullptr);
 
-		if(p_changeType & Systems::Changes::Spatial::AllLocal)
-		{
-			m_localSpace = p_subject->getSpatialData(this, Systems::Changes::Spatial::AllLocalNoTransform);
-			newChanges = newChanges | Systems::Changes::Spatial::AllLocalNoTransform;
-		}
+		// Process the spatial changes and record the world-space changes to be passed to the children objects
+		BitMask newChanges = m_spatialData.changeOccurred(*p_subject, p_changeType);
 
-		if(p_changeType & Systems::Changes::Spatial::AllWorld)
-		{
-			m_worldSpace = p_subject->getSpatialData(this, Systems::Changes::Spatial::AllWorldNoTransform);
-			newChanges = newChanges | Systems::Changes::Spatial::AllWorldNoTransform;
-		}
+		//if(CheckBitmask(p_changeType, Systems::Changes::Type::Spatial))
+		//	newChanges |= m_spatialData.changeOccurred(*p_subject, p_changeType);
 		
+		//if(CheckBitmask(p_changeType, Systems::Changes::Type::Graphics) && CheckBitmask(m_componentsFlag, Systems::GameObjectComponents::Graphics))
+		//	m_graphicsComponent->changeOccurred(p_subject, p_changeType);
+
+		// Post the world-space changes
 		if(newChanges != Systems::Changes::None)
 			postChanges(newChanges);
 
@@ -95,47 +104,6 @@ public:
 		}*/
 	}
 
-	const Math::Vec3f &getVec3(const Observer *p_observer, BitMask p_changedBits) const override final
-	{
-		switch(p_changedBits)
-		{
-		case Systems::Changes::Spatial::LocalPosition:
-			return m_localSpace.m_position;
-			break;
-		case Systems::Changes::Spatial::LocalRotation:
-			return m_localSpace.m_rotationEuler;
-			break;
-		case Systems::Changes::Spatial::LocalScale:
-			return m_localSpace.m_scale;
-			break;
-		case Systems::Changes::Spatial::WorldPosition:
-			return m_worldSpace.m_position;
-			break;
-		case Systems::Changes::Spatial::WorldRotation:
-			return m_worldSpace.m_rotationEuler;
-			break;
-		case Systems::Changes::Spatial::WorldScale:
-			return m_worldSpace.m_scale;
-			break;
-		}
-
-		return ObservedSubject::getVec3(p_observer, p_changedBits);
-	}
-	const Math::Vec4f &getVec4(const Observer *p_observer, BitMask p_changedBits) const override final
-	{ 
-		switch(p_changedBits)
-		{
-		case Systems::Changes::Spatial::LocalRotation:
-			return m_localSpace.m_rotationQuat;
-			break;
-		case Systems::Changes::Spatial::WorldRotation:
-			return m_worldSpace.m_rotationQuat;
-			break;
-		}
-
-		return ObservedSubject::getVec4(p_observer, p_changedBits);
-	}
-
 	// Set the parent of this object. The object can have only one parent, thus if the parent was set already, it will be overridden
 	void setParent(GameObject *p_parent) { m_parent = p_parent; }
 
@@ -169,29 +137,22 @@ public:
 	const std::vector<GameObject&> &getChildren() const { return m_children; }
 
 	// Component functions
-	void addComponent(GraphicsObject *p_graphicsComponent) { m_graphicsComponent = p_graphicsComponent; }
-	void addComponent(SystemObject *p_component, Systems::TypeID p_componentType)
-	{
-		switch(p_componentType)
-		{
-			case Systems::TypeID::Graphics:
-			{
-				// Remove the old component if it existed
-				removeComponent(p_componentType);
+	void addComponent(GraphicsObject *p_graphicsComponent) 
+	{ 
+		// Remove the old component if it exists
+		removeComponent(Systems::TypeID::Graphics);
 
-				// Assign the new graphics component
-				m_graphicsComponent = p_component;
+		// Assign the new graphics component
+		m_graphicsComponent = p_graphicsComponent;
 
-				// Set the graphics component as an observer of this game object
-				m_sceneLoader.getChangeController()->createObjectLink(this, m_graphicsComponent);
-				break;
-			}
-			case Systems::TypeID::Scripting:
-			{
-				
-				break;
-			}
-		}
+		// Share the GameObjects spatial data with the component
+		m_graphicsComponent->setSpatialDataManagerReference(m_spatialData);
+
+		// Set the flag for the graphics component, so it is known from the flag that there is one currently present
+		m_componentsFlag |= Systems::GameObjectComponents::Graphics;
+
+		// Set the graphics component as an observer of this game object
+		m_sceneLoader.getChangeController()->createObjectLink(this, m_graphicsComponent);
 	}
 	void removeComponent(Systems::TypeID p_componentType) 
 	{
@@ -199,7 +160,17 @@ public:
 		{
 			case Systems::TypeID::Graphics:
 			{
-				removeComponent(m_graphicsComponent);
+				unlinkComponent(m_graphicsComponent);
+
+				// Stop sharing the spatial data with the component
+				m_graphicsComponent->removeSpatialDataManagerReference();
+
+				// Assign the component pointer as nullptr to denote that it has been removed
+				m_graphicsComponent = nullptr;
+
+				// Remove the bit corresponding to graphics component from the componentsFlag bitmask
+				m_componentsFlag &= ~Systems::GameObjectComponents::Graphics;
+
 				break;
 			}
 			case Systems::TypeID::Scripting:
@@ -210,21 +181,25 @@ public:
 		}
 	}
 
+	const SpatialDataManager &getSpatialDataChangeManager() const { return m_spatialData; }
+	const Math::Quaternion &getQuaternion(const Observer *p_observer, BitMask p_changedBits)				const override { return m_spatialData.getQuaternion(p_observer, p_changedBits); }
+	const Math::Vec3f &getVec3(const Observer *p_observer, BitMask p_changedBits)							const override { return m_spatialData.getVec3(p_observer, p_changedBits); }
+	const Math::Mat4f &getMat4(const Observer *p_observer, BitMask p_changedBits)							const override { return m_spatialData.getMat4(p_observer, p_changedBits); }
+	const SpatialData &getSpatialData(const Observer *p_observer, BitMask p_changedBits)					const override { return m_spatialData.getSpatialData(p_observer, p_changedBits); }
+	const SpatialTransformData &getSpatialTransformData(const Observer *p_observer, BitMask p_changedBits)	const override { return m_spatialData.getSpatialTransformData(p_observer, p_changedBits); }
+
 private:
 	// Set the ID of the object. The ID must be unique
 	void setID(std::size_t p_id) { m_id = p_id; }
 
-	// Remove the given component
-	void removeComponent(SystemObject *p_component)
+	// Unlinks the given component, so that it is removed from observers/listeners
+	void unlinkComponent(SystemObject *p_component)
 	{
 		// If the component exists
 		if(p_component != nullptr)
 		{
 			// Remove the component from the observers
 			m_sceneLoader.getChangeController()->removeObjectLink(this, p_component);
-
-			// Assign the component pointer as nullptr to denote that it has been removed
-			p_component = nullptr;
 		}
 	}
 
@@ -235,13 +210,17 @@ private:
 	GameObject *m_parent;
 
 	//Components
-	SystemObject *m_graphicsComponent;
+	GraphicsObject *m_graphicsComponent;
 	SystemObject *m_scriptingComponent;
 
+	// Stores a separate flag for each component currently present
+	BitMask m_componentsFlag;
+
 	// Position data
-	SpatialData m_localSpace,
-				m_worldSpace;
+	SpatialDataManager m_spatialData;
+	//SpatialData m_localSpace,
+	//			m_worldSpace;
 
 	// ID of a GameObject; separate from m_objectID of a SystemObject
-	std::size_t m_id;
+	ObjectID m_id;
 };

+ 1 - 1
Praxis3D/Source/GraphicsDataSets.h

@@ -46,7 +46,7 @@ struct ModelData
 	std::vector<MeshData>  m_meshes;
 };
 
-// Contains data multiple of multiple models, comprising a model component
+// Contains data of multiple models, comprising a model component
 struct ModelComponentData
 {
 	std::vector<ModelData> m_modelData;

+ 69 - 94
Praxis3D/Source/GraphicsObject.h

@@ -2,10 +2,12 @@
 
 #include "Containers.h"
 #include "GraphicsDataSets.h"
+#include "InheritanceObjects.h"
 #include "LightComponent.h"
 #include "Loaders.h"
 #include "Math.h"
 #include "NullSystemObjects.h"
+#include "SpatialDataManager.h"
 #include "System.h"
 
 enum GraphicsComponentType : std::size_t
@@ -16,16 +18,18 @@ enum GraphicsComponentType : std::size_t
 	GraphicsComponentType_NumOfComponents
 };
 
-class GraphicsObject : public SystemObject
+class GraphicsObject : public SystemObject, public SpatialDataManagerObject
 {
 public:
 	GraphicsObject(SystemScene *p_systemScene, const std::string &p_name)
-		: SystemObject(p_systemScene, p_name, Properties::Graphics) 
+		: SystemObject(p_systemScene, p_name, Properties::Graphics)
 	{
 		m_modelComponent = nullptr;
 		m_shaderComponent = nullptr;
 		m_lightComponent = nullptr;
 		m_updateQuaternion = false;
+		m_componentsFlag = 0;
+
 	}
 	virtual ~GraphicsObject() 
 	{
@@ -39,6 +43,11 @@ public:
 		
 	void update(const float p_deltaTime)
 	{
+		if(hasSpatialDataUpdated())
+		{
+
+		}
+
 		if(isUpdateNeeded())
 		{
 			if(m_updateQuaternion)
@@ -48,107 +57,31 @@ public:
 			}
 
 			// Calculate model matrix
-			m_worldSpace.m_transformMat = Math::createTransformMat(m_worldSpace.m_spatialData.m_position, m_worldSpace.m_spatialData.m_rotationEuler, m_worldSpace.m_spatialData.m_scale);
+			//m_worldSpace.m_transformMat = Math::createTransformMat(m_worldSpace.m_spatialData.m_position, m_worldSpace.m_spatialData.m_rotationEuler, m_worldSpace.m_spatialData.m_scale);
 
 			// Mark as updated
 			updatePerformed();
 		}
 	}
 
-	virtual BitMask getDesiredSystemChanges()	{ return Systems::Changes::Spatial::AllWorld | Systems::Changes::Graphics::All;		}
-	virtual BitMask getPotentialSystemChanges() { return Systems::Changes::Spatial::WorldTransform;	}
+	virtual BitMask getDesiredSystemChanges()	{ return Systems::Changes::Graphics::All; }
+	virtual BitMask getPotentialSystemChanges() { return Systems::Changes::None; }
 	
 	virtual void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType)
 	{
 		// Track what data has been modified
 		BitMask newChanges = Systems::Changes::None;
 		
-		// Get all of the world spatial data, include the transform matrix; add up the bit-mask of changed data;
-		if(p_changeType & Systems::Changes::Spatial::AllWorld)
-		{
-			m_worldSpace.m_spatialData = p_subject->getSpatialData(this, Systems::Changes::Spatial::AllWorldNoTransform);
-			m_worldSpace.m_transformMat = p_subject->getMat4(this, Systems::Changes::Spatial::WorldTransform);
 
-			newChanges = newChanges | Systems::Changes::Spatial::AllWorld;
-		}
-		else
-		{
-			// Get world spatial data without transform matrix; add up the bit-mask of changed data; flag object to need updating
-			if(p_changeType & Systems::Changes::Spatial::AllWorldNoTransform)
-			{
-				m_worldSpace.m_spatialData = p_subject->getSpatialData(this, Systems::Changes::Spatial::AllWorldNoTransform);
-
-				newChanges = newChanges | Systems::Changes::Spatial::AllWorldNoTransform;
 
-				setUpdateNeeded(true);
-			}
-			else
-			{
-				// Get world position vector; add up the bit-mask of changed data; flag object to need updating
-				if(p_changeType & Systems::Changes::Spatial::WorldPosition)
-				{
-					m_worldSpace.m_spatialData.m_position = p_subject->getVec3(this, Systems::Changes::Spatial::WorldPosition);
-
-					newChanges = newChanges | Systems::Changes::Spatial::WorldPosition;
-				
-					setUpdateNeeded(true);
-				}
-
-				// Get world rotation vector; add up the bit-mask of changed data; flag object to need updating; flag rotation quaternion to need updating
-				if(p_changeType & Systems::Changes::Spatial::WorldRotation)
-				{
-					m_worldSpace.m_spatialData.m_rotationEuler = p_subject->getVec3(this, Systems::Changes::Spatial::WorldRotation);
-
-					newChanges = newChanges | Systems::Changes::Spatial::WorldRotation;
-				
-					setUpdateNeeded(true);
-					m_updateQuaternion = true;
-				}
-
-				// Get world scale vector; add up the bit-mask of changed data; flag object to need updating
-				if(p_changeType & Systems::Changes::Spatial::WorldScale)
-				{
-					m_worldSpace.m_spatialData.m_scale = p_subject->getVec3(this, Systems::Changes::Spatial::WorldScale);
-
-					newChanges = newChanges | Systems::Changes::Spatial::WorldScale;
-
-					setUpdateNeeded(true);
-				}
-			}
-		}
-
-		// If any new data has been left, pass it to the components
+		// If any data has been updated, post the changes to listeners
 		if(newChanges != Systems::Changes::None)
 		{
-
-		}
-			//postChanges(newChanges);
-	}
-		
-	const Math::Mat4f &getMat4(const Observer *p_observer, BitMask p_changedBits) const
-	{ 		
-		switch(p_changedBits)
-		{
-		case Systems::Changes::Spatial::WorldTransform:
-			return m_worldSpace.m_transformMat;
-			break;
-		}
-
-		return ObservedSubject::getMat4(p_observer, p_changedBits);
-	}
-	const SpatialData &getSpatialData(const Observer *p_observer, BitMask p_changedBits) const
-	{ 		
-		switch(p_changedBits)
-		{
-		case Systems::Changes::Spatial::AllWorld:
-			return m_worldSpace.m_spatialData;
-			break;
+			postChanges(newChanges);
 		}
-
-		return ObservedSubject::getSpatialData(p_observer, p_changedBits);
 	}
-		
-	// Get the world spatial data (without transform matrix)
+			
+	/*/ Get the world spatial data (without transform matrix)
 	const inline SpatialData &getWorldSpatialData()	const					{ return m_worldSpace.m_spatialData;					}
 	// Get the world spatial transform data
 	const inline SpatialTransformData &getWorldSpatialTransformData() const	{ return m_worldSpace;									}
@@ -173,7 +106,7 @@ public:
 	inline void setWorldRotation(const Math::Quaternion &p_rotationQuat)				{ setUpdateNeeded(true); m_worldSpace.m_spatialData.m_rotationQuat = p_rotationQuat;								}
 	// Set the world scale
 	inline void setWorldScale(const Math::Vec3f &p_scale)								{ setUpdateNeeded(true); m_worldSpace.m_spatialData.m_scale = p_scale;												}
-	
+	*/
 	// Component functions
 	/*void addComponent(DirectionalLightDataSet &p_lightDataSet)
 	{
@@ -198,18 +131,30 @@ public:
 		// Make sure that this component isn't assigned already
 		removeComponent(GraphicsComponentType::GraphicsComponentType_Light);
 		m_lightComponent = p_component;
+
+		// Share the GraphicsObjects spatial data with the component
+		m_lightComponent->setSpatialDataManagerReference(*m_spatialData);
+
+		// Set the flag for the lighting component, so it is known from the flag that there is one currently present
+		m_componentsFlag |= Systems::GraphicsObjectComponents::Lighting;
 	}
 	void addComponent(ModelComponentData *p_component) 
 	{
 		// Make sure that this component isn't assigned already
 		removeComponent(GraphicsComponentType::GraphicsComponentType_Model);
-		m_modelComponent = p_component; 
+		m_modelComponent = p_component;
+
+		// Set the flag for the model component, so it is known from the flag that there is one currently present
+		m_componentsFlag |= Systems::GraphicsObjectComponents::Model;
 	}
 	void addComponent(ShaderData *p_component) 
 	{ 
 		// Make sure that this component isn't assigned already
 		removeComponent(GraphicsComponentType::GraphicsComponentType_Shader);
-		m_shaderComponent = p_component; 
+		m_shaderComponent = p_component;
+
+		// Set the flag for the shader component, so it is known from the flag that there is one currently present
+		m_componentsFlag |= Systems::GraphicsObjectComponents::Shader;
 	}
 	void removeComponent(const GraphicsComponentType p_compType)
 	{
@@ -218,19 +163,46 @@ public:
 		case GraphicsComponentType_Light:
 		{
 			if(m_lightComponent != nullptr)
-				delete m_lightComponent;
+			{
+				// Delete the actual component
+				//delete m_lightComponent;
+
+				// Assign the component pointer as nullptr to denote that it has been removed
+				m_lightComponent = nullptr;
+
+				// Remove the bit corresponding to lighting component from the componentsFlag bitmask
+				m_componentsFlag &= ~Systems::GraphicsObjectComponents::Lighting;
+			}
 			break;
 		}
 		case GraphicsComponentType_Model:
 		{
 			if(m_modelComponent != nullptr)
-				delete m_modelComponent;
+			{
+				// Delete the actual component
+				//delete m_modelComponent;
+
+				// Assign the component pointer as nullptr to denote that it has been removed
+				m_modelComponent = nullptr;
+
+				// Remove the bit corresponding to model component from the componentsFlag bitmask
+				m_componentsFlag &= ~Systems::GraphicsObjectComponents::Model;
+			}
 			break;
 		}
 		case GraphicsComponentType_Shader:
 		{
 			if(m_shaderComponent != nullptr)
-				delete m_shaderComponent;
+			{
+				// Delete the actual component
+				//delete m_shaderComponent;
+
+				// Assign the component pointer as nullptr to denote that it has been removed
+				m_shaderComponent = nullptr;
+
+				// Remove the bit corresponding to shader component from the componentsFlag bitmask
+				m_componentsFlag &= ~Systems::GraphicsObjectComponents::Shader;
+			}
 			break;
 		}
 		}
@@ -273,14 +245,17 @@ private:
 	ProxyValues m_proxyValues;
 	//std::vector<BaseGraphicsComponent&> m_components;
 
-	std::vector<MeshData> m_meshData;
-	SpatialTransformData m_worldSpace;
+	//std::vector<MeshData> m_meshData;
+	//SpatialTransformData m_worldSpace;
 
 	// Components
 	ModelComponentData *m_modelComponent;
 	ShaderData *m_shaderComponent;
 	LightComponent *m_lightComponent;
-	
+
+	// Stores a separate flag for each component currently present
+	BitMask m_componentsFlag;
+
 	// Flag data that needs to be updated
 	bool m_updateQuaternion;
 };

+ 69 - 0
Praxis3D/Source/InheritanceObjects.h

@@ -0,0 +1,69 @@
+#pragma once
+
+#include "CommonDefinitions.h"
+#include "NullObjects.h"
+#include "SpatialDataManager.h"
+
+// Contains a pointer to a const SpatialDataManager
+// Used for objects that do not have their own SpatialDataManager, but uses another objects SpatialDataManager to get spatial data
+// Always has a valid pointer to SpatialDataManager (assigns a static empty SpatialDataManager upon construction) and only accepts valid references to SpatialDataManager (UNLESS THE DATA THAT THE POINTER IS ADDRESSING IS DELETED!)
+class SpatialDataManagerObject
+{
+public:
+	SpatialDataManagerObject() : m_spatialData(&NullObjects::NullSpatialDataManager)
+	{
+		m_updateCount = 0;
+	}
+	~SpatialDataManagerObject() { }
+
+	// Assign a pointer to a const SpatialDataChangeManager, so the object can use it for its spatial data
+	void setSpatialDataManagerReference(const SpatialDataManager &p_spatialData) { m_spatialData = &p_spatialData; }
+
+	const SpatialDataManager &getSpatialDataManagerReference() { return *m_spatialData; }
+
+	// Replaces the pointer to the SpatialDataChangeManager with an empty one, so that this object cannot use the spatial data from the current pointer anymore
+	void removeSpatialDataManagerReference() { m_spatialData = &NullObjects::NullSpatialDataManager; }
+
+protected:
+	// Returns true if the spatial data has changed since the last check; resets the update counter, so the function will not return true until the spatial data changes again
+	inline bool hasSpatialDataUpdated() 
+	{ 
+		auto spatialDataUpdateCount = m_spatialData->getUpdateCount();
+
+		if(spatialDataUpdateCount != m_updateCount)
+		{
+			m_updateCount = spatialDataUpdateCount;
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	const SpatialDataManager *m_spatialData;
+
+private:
+	UpdateCount m_updateCount;
+};
+
+// Contains a pointer to a const SpatialData struct
+// Used for objects that do not have their own SpatialData, but uses another objects SpatialData to get required data
+// Always has a valid pointer to SpatialData (assigns a static empty SpatialData upon construction) and only accepts valid references to SpatialData (UNLESS THE DATA THAT THE POINTER IS ADDRESSING IS DELETED!)
+class SpatialDataObject
+{
+public:
+	SpatialDataObject() : m_spatialData(&NullObjects::NullSpacialData){ }
+	~SpatialDataObject() { }
+
+	// Assign a pointer to a const SpatialData, so the object can use it for its spatial data
+	void setSpatialDataReference(const SpatialData &p_spatialData) { m_spatialData = &p_spatialData; }
+
+	const SpatialData &getSpatialDataReference() { return *m_spatialData; }
+
+	// Replaces the pointer to the SpatialData with an empty one, so that this object cannot use the spatial data from the current pointer anymore
+	void removeSpatialDataReference() { m_spatialData = &NullObjects::NullSpacialData; }
+
+protected:
+	const SpatialData *m_spatialData;
+};

+ 1 - 17
Praxis3D/Source/LightComponent.cpp

@@ -1,18 +1,2 @@
-
 #include "GraphicsObject.h"
-#include "LightComponent.h"
-
-void DirectionalLightComponent::update(GraphicsObject &p_parentObject)
-{
-
-}
-
-void PointLightComponent::update(GraphicsObject &p_parentObject)
-{
-
-}
-
-void SpotLightComponent::update(GraphicsObject &p_parentObject)
-{
-
-}
+#include "LightComponent.h"

+ 14 - 89
Praxis3D/Source/LightComponent.h

@@ -2,10 +2,11 @@
 
 #include "BaseGraphicsComponent.h"
 #include "GraphicsDataSets.h"
+#include "InheritanceObjects.h"
 #include "ObserverBase.h"
 #include "System.h"
 
-class LightComponent : public SystemObject
+class LightComponent : public SystemObject, public SpatialDataManagerObject
 {
 public:
 	enum LightComponentType
@@ -43,6 +44,13 @@ public:
 
 	void update(const float p_deltaTime)
 	{
+		// If the spatial data has changed, update the spatial data in light datasets
+		if(hasSpatialDataUpdated())
+		{
+			updatePosition(m_spatialData->getWorldSpaceData().m_spatialData.m_position);
+			updateRotation(m_spatialData->getWorldSpaceData().m_spatialData.m_rotationEuler);
+		}
+
 		if(isUpdateNeeded())
 		{
 			// Mark as updated
@@ -50,8 +58,8 @@ public:
 		}
 	}
 
-	BitMask getDesiredSystemChanges()	{ return Systems::Changes::Spatial::AllWorld | Systems::Changes::Graphics::All; }
-	BitMask getPotentialSystemChanges() { return Systems::Changes::Spatial::WorldTransform;								}
+	BitMask getDesiredSystemChanges()	{ return Systems::Changes::Graphics::AllLighting; }
+	BitMask getPotentialSystemChanges() { return Systems::Changes::None; }
 
 	~LightComponent() 
 	{
@@ -73,91 +81,9 @@ public:
 		BitMask newChanges = Systems::Changes::None;
 		BitMask processedChange = 0;
 
-		// Deal with each change until there are no changes left
-		while(p_changeType)
-		{
-			switch(p_changeType)
-			{
-			case Systems::Changes::Spatial::AllWorld:
-				processedChange = Systems::Changes::Spatial::AllWorld; 
-				updateSpatialData(p_subject->getSpatialData(this, processedChange));
-				newChanges |= processedChange;
-				break;
-			case Systems::Changes::Spatial::AllWorldNoTransform:
-				processedChange = Systems::Changes::Spatial::AllWorldNoTransform;
-				updateSpatialData(p_subject->getSpatialData(this, processedChange));
-				newChanges |= processedChange;
-				break;
-			case Systems::Changes::Spatial::LocalPosition:
-				processedChange = Systems::Changes::Spatial::LocalPosition;
-				newChanges |= processedChange;
-				break;
-			case (Systems::Changes::Spatial::LocalRotation | Systems::Changes::Graphics::Direction):
-				processedChange = (Systems::Changes::Spatial::LocalRotation | Systems::Changes::Graphics::Direction);
-				newChanges |= processedChange;
-				break;
-			case Systems::Changes::Spatial::WorldPosition:
-				processedChange = Systems::Changes::Spatial::WorldPosition;
-				newChanges |= processedChange;
-				break;
-			case Systems::Changes::Spatial::WorldRotation:
-				processedChange = Systems::Changes::Spatial::WorldRotation;
-				newChanges |= processedChange;
-				break;
-			case Systems::Changes::Graphics::Color:
-				processedChange = Systems::Changes::Graphics::Color;
-				newChanges |= processedChange;
-				break;
-			case Systems::Changes::Graphics::CutoffAngle:
-				processedChange = Systems::Changes::Graphics::CutoffAngle;
-				newChanges |= processedChange;
-				break;
-			case Systems::Changes::Graphics::Intensity:
-				processedChange = Systems::Changes::Graphics::Intensity;
-				newChanges |= processedChange;
-				break;
-			}
-
-			// Remove the processed change mask from the bit mask value, and reset the processed change value
-			p_changeType &= ~processedChange;
-			processedChange = 0;
-		}
-
-		// Get all of the world spatial data, include the transform matrix; add up the bit-mask of changed data;
-		if(p_changeType & Systems::Changes::Spatial::AllWorld)
-		{
-			updateSpatialData(p_subject->getSpatialData(this, Systems::Changes::Spatial::AllWorldNoTransform));
-			newChanges = newChanges | Systems::Changes::Spatial::AllWorld;
-		}
-		else
-		{
-			// Get world spatial data without transform matrix; add up the bit-mask of changed data; flag object to need updating
-			if(p_changeType & Systems::Changes::Spatial::AllWorldNoTransform)
-			{
-				setUpdateNeeded(true);
-				newChanges = newChanges | Systems::Changes::Spatial::AllWorldNoTransform;
-			}
-			else
-			{
-				// Get world position vector; add up the bit-mask of changed data; flag object to need updating
-				if(p_changeType & Systems::Changes::Spatial::WorldPosition)
-				{
-					updatePosition(p_subject->getVec3(this, Systems::Changes::Spatial::WorldPosition));
-					newChanges = newChanges | Systems::Changes::Spatial::WorldPosition;
-
-					setUpdateNeeded(true);
-				}
-
-				// Get world rotation vector; add up the bit-mask of changed data; flag object to need updating; flag rotation quaternion to need updating
-				if(p_changeType & Systems::Changes::Spatial::WorldRotation)
-				{
-					updateRotation(p_subject->getVec3(this, Systems::Changes::Spatial::WorldRotation));
-					newChanges = newChanges | Systems::Changes::Spatial::WorldRotation;
-
-					setUpdateNeeded(true);
-				}
-			}
-		}
+		// Remove the processed change mask from the bit mask value, and reset the processed change value
+		p_changeType &= ~processedChange;
+		processedChange = 0;
 	}
 
 	LightComponentType getLightType() { return m_lightComponentType; }
@@ -180,7 +106,6 @@ private:
 		SpotLightDataSet m_spot;
 	} m_lightComponent;
 
-
 	void updateColor(const Math::Vec3f &p_color)
 	{
 		// Update each type of light individually

+ 2 - 2
Praxis3D/Source/LightingGraphicsObjects.h

@@ -130,8 +130,8 @@ public:
 
 	BitMask getSystemType() { return Systems::Graphics; }
 
-	BitMask getDesiredSystemChanges() { return Systems::Changes::Spatial::Position; }
-	BitMask getPotentialSystemChanges() { return Systems::Changes::Spatial::Position; }
+	BitMask getDesiredSystemChanges() { return Systems::Changes::Spatial::LocalPosition | Systems::Changes::Spatial::WorldPosition; }
+	BitMask getPotentialSystemChanges() { return Systems::Changes::Spatial::LocalPosition | Systems::Changes::Spatial::WorldPosition; }
 
 	// Processes any spacial changes
 	virtual void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType)

+ 1 - 0
Praxis3D/Source/Math.h

@@ -429,6 +429,7 @@ namespace Math
 			v.z = atan2 (2.0f * q.x * q.y + 2.0f * q.z * q.w, 1 - 2.0f * (q.y * q.y + q.z * q.z));	// Roll
 			return clamp(v * (float)RAD2DEG, 180.0f);
 		}
+		inline Vec4f getVec4f() { return Math::Vec4f(x, y, z, w); }
 
 		const inline Quaternion operator*(const Quaternion& p_quat)
 		{

+ 0 - 1
Praxis3D/Source/ModelGraphicsObjects.h

@@ -2,7 +2,6 @@
 
 #include <functional>
 
-#include <assert.h>
 #include "BaseGraphicsObjects.h"
 #include "Loaders.h"
 #include "Renderer.h"

+ 0 - 0
Praxis3D/Source/NullObject.cpp


+ 27 - 0
Praxis3D/Source/NullObjects.cpp

@@ -0,0 +1,27 @@
+
+#include "NullObjects.h"
+#include "Math.h"
+#include "ObserverBase.h"
+#include "SpatialDataManager.h"
+
+// An empty observer class, used only to construct the SpatialDataManager
+class NullObserver : public Observer
+{
+public:
+	virtual void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) { }
+};
+
+constexpr NullObserver nullObserver;
+
+const Math::Quaternion		NullObjects::NullQuaterion = Math::Quaternion();
+const Math::Vec3f			NullObjects::NullVec3f = Math::Vec3f(1.0f);
+const Math::Vec4f			NullObjects::NullVec4f = Math::Vec4f(1.0f);
+const Math::Mat4f			NullObjects::NullMat4f = Math::Mat4f();
+const bool					NullObjects::NullBool = false;
+const int					NullObjects::NullInt = 0;
+const float					NullObjects::NullFloat = 0.0f;
+const double				NullObjects::NullDouble = 0.0;
+const std::string			NullObjects::NullString;
+const SpatialData			NullObjects::NullSpacialData;
+const SpatialTransformData	NullObjects::NullSpacialTransformData;
+const SpatialDataManager	NullObjects::NullSpatialDataManager = SpatialDataManager(nullObserver);

+ 31 - 0
Praxis3D/Source/NullObjects.h

@@ -0,0 +1,31 @@
+#pragma once
+
+#include <string>
+
+namespace Math
+{
+	struct Quaternion;
+	struct Vec3f;
+	struct Vec4f;
+	class Mat4f;
+}
+
+struct SpatialData;
+struct SpatialTransformData;
+class SpatialDataManager;
+
+namespace NullObjects
+{
+	const extern Math::Quaternion		NullQuaterion;
+	const extern Math::Vec3f			NullVec3f;
+	const extern Math::Vec4f			NullVec4f;
+	const extern Math::Mat4f			NullMat4f;
+	const extern bool					NullBool;
+	const extern int					NullInt;
+	const extern float					NullFloat;
+	const extern double					NullDouble;
+	const extern std::string			NullString;
+	const extern SpatialData			NullSpacialData;
+	const extern SpatialTransformData	NullSpacialTransformData;
+	const extern SpatialDataManager		NullSpatialDataManager;
+}

+ 1 - 1
Praxis3D/Source/ObjectDirectory.h

@@ -59,7 +59,7 @@ public:
 			if(m_systemObjectPool[p_objectID] != nullptr)
 			{
 				// Make the slot empty
-				m_systemObjectPool[p_objectID] == nullptr;
+				m_systemObjectPool[p_objectID] = nullptr;
 
 				// Add the slot to the empty element pool, so it can be used for a new object
 				m_emptyObjectListElements.push(p_objectID);

+ 17 - 15
Praxis3D/Source/ObjectRegister.h

@@ -7,8 +7,10 @@ constexpr auto OBJECT_REGISTER_RESIZE_ADDED_OVERHEAD_MULTIPLIER = 1.5;
 #include <tbb/concurrent_vector.h>
 #include <vector>
 
+typedef std::size_t ObjectID;
+
 // An object directory, used for getting unique IDs to all registered objects.
-// Also contains a list of registered object pointers, an object can be retrieved based on its ID.
+// Also contains a list of registered object pointers, thus an object can be retrieved based on its ID.
 // Implementation is NOT thread-safe.
 template <class T_Object>
 class ObjectRegister
@@ -25,9 +27,9 @@ public:
 	}
 
 	// Returns a unique ID
-	inline std::size_t registerObject(T_Object p_object)
+	inline ObjectID registerObject(T_Object p_object)
 	{
-		std::size_t objectID = 0;
+		ObjectID objectID = 0;
 		
 		// Check if there is an index of an unregistered element in the object pool
 		if(!m_emptyObjectIDPool.empty())
@@ -62,9 +64,9 @@ public:
 
 	// Tries to register an object with the given ID
 	// Returns the ID object gets registered at. If ID is different than the given one, it was taken already
-	inline std::size_t registerObject(T_Object p_object, std::size_t p_id)
+	inline ObjectID registerObject(T_Object p_object, ObjectID p_id)
 	{
-		std::size_t objectID = 0;
+		ObjectID objectID = 0;
 
 		// Check if ID is within object pool bounds
 		if(p_id >= m_objectPool.size())
@@ -109,7 +111,7 @@ public:
 	}
 
 	// Removes object from directory, freeing up its ID
-	inline void unregisterObject(const std::size_t p_ID)
+	inline void unregisterObject(const ObjectID p_ID)
 	{
 		// Check if the object ID is within bounds
 		if(p_ID < m_objectPool.size())
@@ -127,7 +129,7 @@ public:
 	}
 
 	// Returns object based on its ID. Returns 'nullptr' if object wasn't found
-	inline T_Object getObject(const std::size_t p_ID) const
+	inline T_Object getObject(const ObjectID p_ID) const
 	{		
 		// Default the return object to nullptr
 		T_Object *returnObject;
@@ -166,7 +168,7 @@ public:
 private:
 	// Finds and removes the element of empty object ID pool that contains the given ID
 	// Slow, as it compares each element and uses std::vector erase
-	void removeIDfromEmptyObjectPool(std::size_t p_id)
+	void removeIDfromEmptyObjectPool(ObjectID p_id)
 	{
 		// Iterate over each element in empty object ID pool
 		for(decltype(m_emptyObjectIDPool.size()) i = 0, size = m_emptyObjectIDPool.size(); i < size; i++)
@@ -192,7 +194,7 @@ private:
 };
 
 // An object directory, used for getting unique IDs to all registered objects.
-// Also contains a list of registered object pointers, an object can be retrieved based on its ID.
+// Also contains a list of registered object pointers, thus an object can be retrieved based on its ID.
 // Implementation is thread-safe.
 template <class T_Object>
 class ObjectRegisterConcurrent 
@@ -208,7 +210,7 @@ public:
 	}
 
 	// Returns a unique ID
-	inline std::size_t registerObject(T_Object p_object)
+	inline ObjectID registerObject(T_Object p_object)
 	{
 		ObjectPoolIndexType objectID = 0;
 		
@@ -236,14 +238,14 @@ public:
 		}
 		
 		// Cast the object index (int) to size_t (unsigned int)
-		return static_cast<std::size_t>(objectID);
+		return static_cast<ObjectID>(objectID);
 	}
 	
 	// Tries to register an object with the given ID
 	// Returns the ID object gets registered at. If ID is different than the given one, it was taken already
-	inline std::size_t registerObject(T_Object p_object, std::size_t p_id)
+	inline ObjectID registerObject(T_Object p_object, ObjectID p_id)
 	{
-		std::size_t objectID = 0;
+		ObjectID objectID = 0;
 
 		// Check if ID is within object pool bounds
 		if(p_id >= m_objectPool.size())
@@ -288,7 +290,7 @@ public:
 	}
 
 	// Removes object from directory, freeing up its ID
-	inline void unregisterObject(const std::size_t p_ID)
+	inline void unregisterObject(const ObjectID p_ID)
 	{
 		// Check if the object ID is within bounds
 		if(p_ID < m_objectPool.size())
@@ -306,7 +308,7 @@ public:
 	}
 
 	// Returns object based on its ID. Returns 'nullptr' if object wasn't found
-	inline T_Object getObject(const std::size_t p_ID) const
+	inline T_Object getObject(const ObjectID p_ID) const
 	{	
 		// Default the return object to nullptr
 		T_Object *returnObject = nullptr;

+ 3 - 13
Praxis3D/Source/ObserverBase.cpp

@@ -1,15 +1,5 @@
 #include "ObserverBase.h"
 
-const Math::Vec3f ObservedSubject::m_nullVec3 = Math::Vec3f(1.0f);
-const Math::Vec4f ObservedSubject::m_nullVec4 = Math::Vec4f(1.0f);
-const Math::Mat4f ObservedSubject::m_nullMat4 = Math::Mat4f();
-const bool ObservedSubject::m_nullBool = false;
-const int ObservedSubject::m_nullInt = 0;
-const float ObservedSubject::m_nullFloat = 0.0f;
-const double ObservedSubject::m_nullDouble = 0.0;
-const std::string ObservedSubject::m_nullString;
-const SpatialData m_nullSpacialData;
-
 ObservedSubject::ObservedSubject()
 {
 
@@ -20,7 +10,7 @@ ObservedSubject::~ObservedSubject()
 }
 
 // Attach an observer for this subject
-ErrorCode ObservedSubject::attach(Observer *p_observer, unsigned int p_interestedBits, unsigned int p_ID, unsigned int p_shiftBits)
+ErrorCode ObservedSubject::attach(Observer *p_observer, BitMask p_interestedBits, SystemObjectID p_ID, unsigned int p_shiftBits)
 {
 	// If the concurrency is enabled, lock the current subject and wait for it to be free
 	#if ENABLE_CONCURRENT_SUBJECT_OPERATIONS
@@ -62,7 +52,7 @@ ErrorCode ObservedSubject::detach(Observer *p_observer)
 	return returnError;
 }
 
-ErrorCode ObservedSubject::updateInterestBits(Observer *p_observer, unsigned int p_interestedBits)
+ErrorCode ObservedSubject::updateInterestBits(Observer *p_observer, BitMask p_interestedBits)
 {
 	ErrorCode returnError = ErrorCode::Failure;
 
@@ -95,7 +85,7 @@ ErrorCode ObservedSubject::updateInterestBits(Observer *p_observer, unsigned int
 
 	return returnError;
 }
-BitMask ObservedSubject::getID(Observer *p_observer) const
+SystemObjectID ObservedSubject::getID(Observer *p_observer) const
 {
 	// Iterate through all the observers
 	for(ObserverDataList::const_iterator it = m_observerList.begin(); it != m_observerList.end(); it++)

+ 23 - 30
Praxis3D/Source/ObserverBase.h

@@ -26,15 +26,18 @@
 
 #include "Config.h"
 #include "Containers.h"
+#include "NullObjects.h"
 #include "Math.h"
 #include "SpinWait.h"
 
+typedef unsigned int SystemObjectID;
+
 class ObservedSubject;
 
 class Observer
 {
 public:
-	virtual ~Observer() = 0;
+	//virtual ~Observer() = 0;
 
 	// This method gets called when data that we are interested changed in observed subject
 	virtual void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) = 0;
@@ -46,43 +49,44 @@ public:
 	ObservedSubject();
 	virtual ~ObservedSubject();
 
-	virtual ErrorCode attach(Observer *p_observer, unsigned int p_interestedBits, unsigned int p_ID, unsigned int p_shiftBits = 0);
+	virtual ErrorCode attach(Observer *p_observer, BitMask p_interestedBits, SystemObjectID p_ID, unsigned int p_shiftBits = 0);
 	virtual ErrorCode detach(Observer *p_observer);
 
-	virtual ErrorCode updateInterestBits(Observer *p_observer, unsigned int p_interestedBits);
-	virtual BitMask getID(Observer *p_observer) const;
+	virtual ErrorCode updateInterestBits(Observer *p_observer, BitMask p_interestedBits);
+	virtual SystemObjectID getID(Observer *p_observer) const;
 	virtual BitMask getPotentialSystemChanges() = 0;
 
 	virtual void postChanges(BitMask p_changedBits);
 	virtual void preDestruct();
 
-	const static unsigned int g_invalidID = static_cast<unsigned int>(-1);
+	const static SystemObjectID g_invalidID = static_cast<unsigned int>(-1);
 
-	const virtual Math::Vec3f &getVec3(const Observer *p_observer, BitMask p_changedBits) const	{ return m_nullVec3; }
-	const virtual Math::Vec4f &getVec4(const Observer *p_observer, BitMask p_changedBits) const { return m_nullVec4; }
-	const virtual Math::Mat4f &getMat4(const Observer *p_observer, BitMask p_changedBits) const	{ return m_nullMat4; }
+	const virtual Math::Quaternion	&getQuaternion(const Observer *p_observer, BitMask p_changedBits)	const { return NullObjects::NullQuaterion;	}
+	const virtual Math::Vec3f		&getVec3(const Observer *p_observer, BitMask p_changedBits)			const { return NullObjects::NullVec3f;		}
+	const virtual Math::Vec4f		&getVec4(const Observer *p_observer, BitMask p_changedBits)			const { return NullObjects::NullVec4f;		}
+	const virtual Math::Mat4f		&getMat4(const Observer *p_observer, BitMask p_changedBits)			const { return NullObjects::NullMat4f;		}
 
-	const virtual bool					getBool(const Observer *p_observer, BitMask p_changedBits) const					{ return m_nullBool;					}
-	const virtual int					getInt(const Observer *p_observer, BitMask p_changedBits) const						{ return m_nullInt;						}
-	const virtual float					getFloat(const Observer *p_observer, BitMask p_changedBits) const					{ return m_nullFloat;					}
-	const virtual double				&getDouble(const Observer *p_observer, BitMask p_changedBits) const					{ return m_nullDouble;					}
-	const virtual std::string			&getString(const Observer *p_observer, BitMask p_changedBits) const					{ return m_nullString;					}
-	const virtual SpatialData			&getSpatialData(const Observer *p_observer, BitMask p_changedBits) const			{ return m_nullSpacialData;				}
-	const virtual SpatialTransformData	&getSpatialTransformData(const Observer *p_observer, BitMask p_changedBits) const	{ return m_nullSpacialTransformData;	}
+	const virtual bool					getBool(const Observer *p_observer, BitMask p_changedBits) const					{ return NullObjects::NullBool;					}
+	const virtual int					getInt(const Observer *p_observer, BitMask p_changedBits) const						{ return NullObjects::NullInt;					}
+	const virtual float					getFloat(const Observer *p_observer, BitMask p_changedBits) const					{ return NullObjects::NullFloat;				}
+	const virtual double				&getDouble(const Observer *p_observer, BitMask p_changedBits) const					{ return NullObjects::NullDouble;				}
+	const virtual std::string			&getString(const Observer *p_observer, BitMask p_changedBits) const					{ return NullObjects::NullString;				}
+	const virtual SpatialData			&getSpatialData(const Observer *p_observer, BitMask p_changedBits) const			{ return NullObjects::NullSpacialData;			}
+	const virtual SpatialTransformData	&getSpatialTransformData(const Observer *p_observer, BitMask p_changedBits) const	{ return NullObjects::NullSpacialTransformData;	}
 
 	// Stores observer information required for postChanges messages
 	struct ObserverData
 	{
-		ObserverData(Observer *p_observer = nullptr, BitMask p_interestedBits = 0, BitMask p_ID = 0)
+		ObserverData(Observer *p_observer = nullptr, BitMask p_interestedBits = 0, SystemObjectID p_ID = 0)
 			:	m_observer(p_observer),
 				m_interestedBits(p_interestedBits),
 				m_ID(p_ID) { }
 
 		bool operator == (Observer *p_observer) const { return m_observer == p_observer; }
 
-		Observer	*m_observer;
-		BitMask		m_ID;
-		BitMask		m_interestedBits;
+		Observer		*m_observer;
+		SystemObjectID	m_ID;
+		BitMask			m_interestedBits;
 	};
 
 private:
@@ -98,15 +102,4 @@ private:
 	#if ENABLE_CONCURRENT_SUBJECT_OPERATIONS
 		SpinWait m_observerListMutex;
 	#endif
-
-	const static Math::Vec3f			m_nullVec3;
-	const static Math::Vec4f			m_nullVec4;
-	const static Math::Mat4f			m_nullMat4;
-	const static bool					m_nullBool;
-	const static int					m_nullInt;
-	const static float					m_nullFloat;
-	const static double					m_nullDouble;
-	const static std::string			m_nullString;
-	const static SpatialData			m_nullSpacialData;
-	const static SpatialTransformData	m_nullSpacialTransformData;
 };

+ 2 - 2
Praxis3D/Source/RendererFrontend.cpp

@@ -214,10 +214,10 @@ void RendererFrontend::renderFrame(const SceneObjects &p_sceneObjects, const flo
 	std::cout << m_frameData.m_viewMatrix.m[12] << " : " << m_frameData.m_viewMatrix.m[13] << " : " << m_frameData.m_viewMatrix.m[14] << " : " << m_frameData.m_viewMatrix.m[15] << std::endl;
 	*/
 	// Set the camera position
-	m_frameData.m_cameraPosition = p_sceneObjects.m_camera->getVec3(nullptr, Systems::Changes::Spatial::Position);
+	m_frameData.m_cameraPosition = p_sceneObjects.m_camera->getVec3(nullptr, Systems::Changes::Spatial::WorldPosition);
 	
 	// Set the camera target vector
-	m_frameData.m_cameraTarget = p_sceneObjects.m_camera->getVec3(nullptr, Systems::Changes::Spatial::Rotation);
+	m_frameData.m_cameraTarget = p_sceneObjects.m_camera->getVec3(nullptr, Systems::Changes::Spatial::WorldRotation);
 
 	// Assign directional light values and also normalize its direction, so it's not neccessary to do it in a shader
 	m_frameData.m_dirLightColor = p_sceneObjects.m_directionalLight->m_color;

+ 3 - 3
Praxis3D/Source/RendererScene.cpp

@@ -936,9 +936,9 @@ EnvironmentMapObject *RendererScene::loadEnvironmentMap(const PropertySet &p_pro
 	{
 		switch(p_properties[i].getPropertyID())
 		{
-		case Properties::Position:
-			newObject->setPosition(p_properties[i].getVec3f());
-			break;
+		//case Properties::Position:
+		//	newObject->setPosition(p_properties[i].getVec3f());
+		//	break;
 		}
 	}
 

+ 4 - 0
Praxis3D/Source/RendererScene.h

@@ -142,12 +142,16 @@ private:
 	SpotLightObject *loadSpotLight(const PropertySet &p_properties);
 		
 	// Object pools
+	// OLD
 	ObjectPool<ModelObject> m_modelObjPool;
 	ObjectPool<ModelObject> m_shaderObjPool;
 	ObjectPool<PointLightObject> m_pointLightPool;
 	ObjectPool<SpotLightObject> m_spotLightPool;
 	ObjectPool<EnvironmentMapObject> m_envMapPool;
 	
+	//NEW
+
+
 	// Stores objects that are currently being loaded to memory in background thread
 	std::vector<LoadableGraphicsObject> m_objectsBeingLoaded;
 	

+ 1 - 1
Praxis3D/Source/ShaderGraphicsObjects.h

@@ -41,7 +41,7 @@ public:
 
 	virtual ErrorCode loadToVideoMemory()
 	{
-		ErrorCode error;
+		//ErrorCode error;
 
 		// Load shader, check if it loaded successfully
 		//if(!ErrHandlerLoc::get().ifSuccessful(m_shader->loadToVideoMemory(), error))

+ 1 - 0
Praxis3D/Source/SpatialDataChangeManager.cpp

@@ -0,0 +1 @@
+#include "SpatialDataChangeManager.h"

+ 327 - 0
Praxis3D/Source/SpatialDataManager.h

@@ -0,0 +1,327 @@
+#pragma once
+
+#include <atomic>
+
+#include "Containers.h"
+#include "CommonDefinitions.h"
+#include "ObserverBase.h"
+#include "NullObjects.h"
+
+// Manages spatial data updates. Contains:
+// *Local-space data		- local data that is every object has individually 
+// *Parent world-space data - world data of the parent object, stored separately from the world data of this objects, in case the local data is changed and new world data needs to be calculated
+// *World-space data		- spatial data comprising of local and parent data, used for rendering
+class SpatialDataManager
+{
+public:
+	SpatialDataManager(const Observer &p_parent) : m_parent(p_parent)
+	{
+		m_updateCount = 0;
+		worldSpaceNeedsUpdate = false;
+	}
+	~SpatialDataManager()
+	{
+
+	}
+
+	// Process spatial changes from the given subject and change type
+	// Returns the changes that have been made; RETURNS ONLY WORLD-SPACE CHANGES!
+	BitMask changeOccurred(const ObservedSubject &p_subject, const BitMask p_changeType)
+	{
+		BitMask newChanges = Systems::Changes::None;
+
+		// Process the "All" changes first, as their bitmask is a combination of multiple changes, so it's faster to process the changes all at once, instead of individually
+		// Checks are laid out in hierarchical sequence, starting with combinations of multiple changes and ending with each individual change
+		if(CheckBitmask(p_changeType, Systems::Changes::Spatial::All))
+		{
+			// Update both the local-space and parent world-space data
+			updateLocalSpatialTransformData(p_subject.getSpatialTransformData(&m_parent, Systems::Changes::Spatial::AllLocal));
+			updateParentSpatialTransformData(p_subject.getSpatialTransformData(&m_parent, Systems::Changes::Spatial::AllWorld));
+			newChanges |= Systems::Changes::Spatial::AllWorld;
+		}
+		else // If the "All" flag wasn't set, check each local and world (parent) change
+		{
+			// Check if everything in local-space has changed
+			if(CheckBitmask(p_changeType, Systems::Changes::Spatial::AllLocal))
+			{
+				updateLocalSpatialTransformData(p_subject.getSpatialTransformData(&m_parent, Systems::Changes::Spatial::AllLocal));
+			}
+			else
+			{
+				// Check if everything in local-space, except the transform matrix has changed
+				if(CheckBitmask(p_changeType, Systems::Changes::Spatial::AllLocalNoTransform))
+				{
+					updateLocalSpatialData(p_subject.getSpatialData(&m_parent, Systems::Changes::Spatial::AllLocalNoTransform));
+				}
+				else // If this is reached, check each individual piece of data has changed
+				{
+					if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalPosition))
+					{
+						updateLocalPosition(p_subject.getVec3(&m_parent, Systems::Changes::Spatial::LocalPosition));
+					}
+
+					if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalRotation))
+					{
+						updateLocalRotation(p_subject.getVec3(&m_parent, Systems::Changes::Spatial::LocalRotation));
+					}
+
+					if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalScale))
+					{
+						updateLocalScale(p_subject.getVec3(&m_parent, Systems::Changes::Spatial::LocalScale));
+					}
+
+					if(CheckBitmask(p_changeType, Systems::Changes::Spatial::LocalTransform))
+					{
+						updateLocalTransform(p_subject.getMat4(&m_parent, Systems::Changes::Spatial::LocalTransform));
+					}
+				}
+			}
+
+			// Check if everything in world-space of the parent object has changed
+			if(CheckBitmask(p_changeType, Systems::Changes::Spatial::AllWorld))
+			{
+				updateParentSpatialTransformData(p_subject.getSpatialTransformData(&m_parent, Systems::Changes::Spatial::AllWorld));
+				newChanges |= Systems::Changes::Spatial::AllWorld;
+			}
+			else
+			{
+				// Check if everything in world-space except the transform matrix, of the parent object, has changed
+				if(CheckBitmask(p_changeType, Systems::Changes::Spatial::AllWorldNoTransform))
+				{
+					updateParentSpatialData(p_subject.getSpatialData(&m_parent, Systems::Changes::Spatial::AllWorldNoTransform));
+					newChanges |= Systems::Changes::Spatial::AllWorldNoTransform;
+				}
+				else // If this is reached, check each individual piece of data has changed
+				{
+					if(CheckBitmask(p_changeType, Systems::Changes::Spatial::WorldPosition))
+					{
+						updateParentPosition(p_subject.getVec3(&m_parent, Systems::Changes::Spatial::WorldPosition));
+						newChanges |= Systems::Changes::Spatial::WorldPosition;
+					}
+
+					if(CheckBitmask(p_changeType, Systems::Changes::Spatial::WorldRotation))
+					{
+						updateParentRotation(p_subject.getVec3(&m_parent, Systems::Changes::Spatial::WorldRotation));
+						newChanges |= Systems::Changes::Spatial::WorldRotation;
+					}
+
+					if(CheckBitmask(p_changeType, Systems::Changes::Spatial::WorldScale))
+					{
+						updateParentScale(p_subject.getVec3(&m_parent, Systems::Changes::Spatial::WorldScale));
+						newChanges |= Systems::Changes::Spatial::WorldScale;
+					}
+
+					if(CheckBitmask(p_changeType, Systems::Changes::Spatial::WorldTransform))
+					{
+						updateParentTransform(p_subject.getMat4(&m_parent, Systems::Changes::Spatial::WorldTransform));
+						newChanges |= Systems::Changes::Spatial::WorldTransform;
+					}
+				}
+			}
+		}
+		
+		// Update the world-space data if any changes have been made
+		if(worldSpaceNeedsUpdate)
+		{
+			updateWorldSpace();
+			newChanges |= Systems::Changes::Spatial::WorldTransform;
+			incrementUpdateCount();
+		}
+
+		return newChanges;
+	}
+
+	// Get local-space spatial data
+	const inline SpatialTransformData &getLocalSpaceData() const { return m_localSpace; }
+
+	// Get world-space spatial data (combination of the local-space and the parent objects world-space data)
+	const inline SpatialTransformData &getWorldSpaceData() const { return m_worldSpace; }
+
+	const inline Math::Quaternion &getQuaternion(const Observer *p_observer, BitMask p_changedBits) const
+	{
+		switch(p_changedBits)
+		{
+		case Systems::Changes::Spatial::LocalRotation:
+			return m_localSpace.m_spatialData.m_rotationQuat;
+
+		case Systems::Changes::Spatial::WorldRotation:
+			return m_worldSpace.m_spatialData.m_rotationQuat;
+		}
+
+		return NullObjects::NullQuaterion;
+	}
+	const inline Math::Vec3f &getVec3(const Observer *p_observer, BitMask p_changedBits) const
+	{
+		switch(p_changedBits)
+		{
+		case Systems::Changes::Spatial::LocalPosition:
+			return m_localSpace.m_spatialData.m_position;
+
+		case Systems::Changes::Spatial::LocalRotation:
+			return m_localSpace.m_spatialData.m_rotationEuler;
+
+		case Systems::Changes::Spatial::LocalScale:
+			return m_localSpace.m_spatialData.m_scale;
+
+		case Systems::Changes::Spatial::WorldPosition:
+			return m_worldSpace.m_spatialData.m_position;
+
+		case Systems::Changes::Spatial::WorldRotation:
+			return m_worldSpace.m_spatialData.m_rotationEuler;
+
+		case Systems::Changes::Spatial::WorldScale:
+			return m_worldSpace.m_spatialData.m_scale;
+		}
+
+		return NullObjects::NullVec3f;
+	}
+	const inline Math::Mat4f &getMat4(const Observer *p_observer, BitMask p_changedBits) const
+	{
+		switch(p_changedBits)
+		{
+		case Systems::Changes::Spatial::LocalTransform:
+			return m_localSpace.m_transformMat;
+
+		case Systems::Changes::Spatial::WorldTransform:
+			return m_worldSpace.m_transformMat;
+		}
+
+		return NullObjects::NullMat4f;
+	}
+	const inline SpatialData &getSpatialData(const Observer *p_observer, BitMask p_changedBits) const
+	{ 
+		switch(p_changedBits)
+		{
+		case Systems::Changes::Spatial::AllLocalNoTransform:
+			return m_localSpace.m_spatialData;
+
+		case Systems::Changes::Spatial::AllWorldNoTransform:
+			return m_worldSpace.m_spatialData;
+		}
+
+		return NullObjects::NullSpacialData;
+	}
+	const inline SpatialTransformData &getSpatialTransformData(const Observer *p_observer, BitMask p_changedBits) const 
+	{ 
+		switch(p_changedBits)
+		{
+		case Systems::Changes::Spatial::AllLocal:
+			return m_localSpace;
+
+		case Systems::Changes::Spatial::AllWorld:
+			return m_worldSpace;
+		}
+
+		return NullObjects::NullSpacialTransformData;
+	}
+
+	// Returns the current update count; each time data is changed, update count is incremented
+	const inline UpdateCount getUpdateCount() const { return m_updateCount; }
+
+private:
+	// Recalculates the model transform matrix in the world-space
+	void updateTransformMatrix(SpatialTransformData &p_spacialTransformData)
+	{
+		p_spacialTransformData.m_transformMat = Math::createTransformMat(	p_spacialTransformData.m_spatialData.m_position, 
+																			p_spacialTransformData.m_spatialData.m_rotationEuler, 
+																			p_spacialTransformData.m_spatialData.m_scale);
+	}
+
+	// Functions of local spatial data
+	void updateLocalSpatialTransformData(const SpatialTransformData &p_spatialTransformData)
+	{
+		m_localSpace = p_spatialTransformData;
+		worldSpaceNeedsUpdate = true;
+	}
+	void updateLocalSpatialData(const SpatialData &p_spatialData)
+	{
+		m_localSpace.m_spatialData = p_spatialData;
+		updateTransformMatrix(m_localSpace);
+		worldSpaceNeedsUpdate = true;
+	}
+	void updateLocalTransform(const Math::Mat4f &p_transform)
+	{
+		m_localSpace.m_transformMat = p_transform;
+		worldSpaceNeedsUpdate = true;
+	}
+	void updateLocalPosition(const Math::Vec3f &p_position)
+	{
+		m_localSpace.m_spatialData.m_position = p_position;
+		updateTransformMatrix(m_localSpace);
+		worldSpaceNeedsUpdate = true;
+	}
+	void updateLocalRotation(const Math::Vec3f &p_rotation)
+	{
+		m_localSpace.m_spatialData.m_rotationEuler = p_rotation;
+		updateTransformMatrix(m_localSpace);
+		worldSpaceNeedsUpdate = true;
+	}
+	void updateLocalScale(const Math::Vec3f &p_scale)
+	{
+		m_localSpace.m_spatialData.m_scale = p_scale;
+		updateTransformMatrix(m_localSpace);
+		worldSpaceNeedsUpdate = true;
+	}
+
+	// Functions of world spatial data of the parent object
+	void updateParentSpatialTransformData(const SpatialTransformData &p_spatialTransformData)
+	{
+		m_parentSpace = p_spatialTransformData;
+		worldSpaceNeedsUpdate = true;
+	}
+	void updateParentSpatialData(const SpatialData &p_spatialData)
+	{
+		m_parentSpace.m_spatialData = p_spatialData;
+		updateTransformMatrix(m_parentSpace);
+		worldSpaceNeedsUpdate = true;
+	}
+	void updateParentTransform(const Math::Mat4f &p_transform)
+	{
+		m_parentSpace.m_transformMat = p_transform;
+		worldSpaceNeedsUpdate = true;
+	}
+	void updateParentPosition(const Math::Vec3f &p_position)
+	{
+		m_parentSpace.m_spatialData.m_position = p_position;
+		updateTransformMatrix(m_parentSpace);
+		worldSpaceNeedsUpdate = true;
+	}
+	void updateParentRotation(const Math::Vec3f &p_rotation)
+	{
+		m_parentSpace.m_spatialData.m_rotationEuler = p_rotation;
+		updateTransformMatrix(m_parentSpace);
+		worldSpaceNeedsUpdate = true;
+	}
+	void updateParentScale(const Math::Vec3f &p_scale)
+	{
+		m_parentSpace.m_spatialData.m_scale = p_scale;
+		updateTransformMatrix(m_parentSpace);
+		worldSpaceNeedsUpdate = true;
+	}
+
+	// Make up the world-space data from local and parent data
+	void updateWorldSpace()
+	{
+		m_worldSpace = m_parentSpace + m_localSpace;
+		worldSpaceNeedsUpdate = false;
+	}
+
+	// Increments the update count; should be called after any data has been changed
+	inline void incrementUpdateCount() { m_updateCount++; }
+
+	// A reference to the parent (which is the observer of all the received changes); required to retrieve the changed data from the observed subject
+	const Observer &m_parent;
+
+	// A flag to determine if the world space needs to be updated
+	bool worldSpaceNeedsUpdate;
+
+	// Transform data in local space
+	SpatialTransformData m_localSpace;
+	// Transform data in world space the parent object
+	SpatialTransformData m_parentSpace;
+	// Transform data in world space (local and parent space added together), final transform data used for rendering
+	SpatialTransformData m_worldSpace;
+
+	// Used for update tracking; each time data is change, update count is incremented
+	UpdateCount m_updateCount;
+};

+ 3 - 0
Praxis3D/Source/System.h

@@ -1,5 +1,8 @@
 #pragma once
 
+// uncomment to disable assert()
+// #define NDEBUG
+#include <assert.h>
 #include <string>
 
 #include "Config.h"

+ 1 - 1
Praxis3D/Source/TaskScheduler.cpp

@@ -61,7 +61,7 @@ void TaskScheduler::execute(float p_deltaTime)
 	if(m_multithreadingEnabled)
 	{
 		// Create temp containers to hold current tasks (to execute in this time-step)
-		SystemTask *tasksToExecute[Systems::Types::Max];
+		SystemTask *tasksToExecute[Systems::TypeID::NumberOfSystems];
 		unsigned int numTasksToExecute = 0;
 
 		// Iterate over all the system scenes and get their tasks

+ 5 - 5
Praxis3D/Source/WorldEditObject.h

@@ -192,8 +192,8 @@ public:
 
 	virtual void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType)
 	{
-		if(p_changeType & Systems::Changes::Spacial::Position)
-			m_objectPosition = p_subject->getVec3(this, Systems::Changes::Spacial::Position);
+		//if(p_changeType & Systems::Changes::Spacial::Position)
+		//	m_objectPosition = p_subject->getVec3(this, Systems::Changes::Spacial::Position);
 
 		if(p_changeType & Systems::Changes::Generic::Name)
 			m_objectName = p_subject->getString(this, Systems::Changes::Generic::Name);
@@ -210,9 +210,9 @@ public:
 	{
 		switch(p_changedBits)
 		{
-		case Systems::Changes::Spacial::Position:
-			return m_objectPosition;
-			break;
+		//case Systems::Changes::Spacial::Position:
+		//	return m_objectPosition;
+		//	break;
 		}
 
 		return ObservedSubject::getVec3(p_observer, p_changedBits);