Browse Source

Renderer completely redesigned and rewritten

Paul A 8 years ago
parent
commit
dac25c98c9
100 changed files with 7949 additions and 3501 deletions
  1. BIN
      Debug/Assimp32.dll
  2. BIN
      Debug/FreeImage.dll
  3. BIN
      Debug/SDL2.dll
  4. BIN
      Debug/glew32.dll
  5. BIN
      Debug/tbb.dll
  6. BIN
      Debug/tbb_debug.dll
  7. 201 217
      Praxis3D/Data/Maps/default_lite.pmap
  8. 925 0
      Praxis3D/Data/Maps/default_lite2.pmap
  9. BIN
      Praxis3D/Data/Materials/Bricks1_DISP.tif
  10. BIN
      Praxis3D/Data/Materials/Bricks1_NRM.tif
  11. 513 0
      Praxis3D/Data/Models/Nanosuit.dae
  12. 23 4
      Praxis3D/Data/Shaders/finalPass.frag
  13. 1 1
      Praxis3D/Data/Shaders/finalPass.vert
  14. 217 656
      Praxis3D/Data/Shaders/geometryPass.frag
  15. 22 7
      Praxis3D/Data/Shaders/geometryPass.vert
  16. 11 8
      Praxis3D/Data/Shaders/geometryPassInf.frag
  17. 1 1
      Praxis3D/Data/Shaders/geometryPassInf.vert
  18. 904 0
      Praxis3D/Data/Shaders/lightPass 3.frag
  19. 99 311
      Praxis3D/Data/Shaders/lightPass.frag
  20. 5 5
      Praxis3D/Data/Shaders/lightPass.vert
  21. 190 0
      Praxis3D/Data/Shaders/reflectionPass.frag
  22. 10 0
      Praxis3D/Data/Shaders/reflectionPass.vert
  23. 11 6
      Praxis3D/Data/Shaders/skybox.frag
  24. 5 5
      Praxis3D/Data/Shaders/skybox.vert
  25. 11 10
      Praxis3D/Data/config.ini
  26. 4 0
      Praxis3D/Data/error-strings-eng.data
  27. 14 1
      Praxis3D/Praxis3D.vcxproj
  28. 48 3
      Praxis3D/Praxis3D.vcxproj.filters
  29. 14 0
      Praxis3D/Source/BaseGraphicsObjects.h
  30. 2 2
      Praxis3D/Source/CameraGraphicsObject.h
  31. 34 1
      Praxis3D/Source/CameraScript.h
  32. 55 20
      Praxis3D/Source/ChangeController.cpp
  33. 26 3
      Praxis3D/Source/ChangeController.h
  34. 177 0
      Praxis3D/Source/CommandBuffer.h
  35. 98 0
      Praxis3D/Source/CommonDefinitions.h
  36. 23 5
      Praxis3D/Source/Config.cpp
  37. 88 14
      Praxis3D/Source/Config.h
  38. 33 3
      Praxis3D/Source/DebugUIScript.h
  39. 385 198
      Praxis3D/Source/DeferredRenderer.cpp
  40. 29 16
      Praxis3D/Source/DeferredRenderer.h
  41. 7 2
      Praxis3D/Source/Engine.cpp
  42. 4 1
      Praxis3D/Source/EngineDefinitions.h
  43. 2 2
      Praxis3D/Source/EnvironmentMapObjects.h
  44. 24 1
      Praxis3D/Source/ErrorCodes.h
  45. 6 2
      Praxis3D/Source/ErrorHandler.cpp
  46. 1 1
      Praxis3D/Source/ErrorHandler.h
  47. 74 0
      Praxis3D/Source/FinalPass.h
  48. 25 5
      Praxis3D/Source/GeometryBuffer.cpp
  49. 92 4
      Praxis3D/Source/GeometryBuffer.h
  50. 84 0
      Praxis3D/Source/GeometryPass.h
  51. 7 6
      Praxis3D/Source/GraphicsDataSets.h
  52. 26 7
      Praxis3D/Source/LightingGraphicsObjects.h
  53. 95 0
      Praxis3D/Source/LightingPass.h
  54. 1 3
      Praxis3D/Source/LoaderBase.h
  55. 2 1
      Praxis3D/Source/Loaders.cpp
  56. 5 2
      Praxis3D/Source/Loaders.h
  57. 9 9
      Praxis3D/Source/Math.cpp
  58. 127 15
      Praxis3D/Source/Math.h
  59. 37 29
      Praxis3D/Source/ModelGraphicsObjects.h
  60. 83 81
      Praxis3D/Source/ModelLoader.cpp
  61. 44 142
      Praxis3D/Source/ModelLoader.h
  62. 1 1
      Praxis3D/Source/ObjectPool.h
  63. 43 0
      Praxis3D/Source/ReflectionPass.h
  64. 29 0
      Praxis3D/Source/RenderPassBase.h
  65. 4 4
      Praxis3D/Source/RenderTask.cpp
  66. 4 3
      Praxis3D/Source/RenderTask.h
  67. 23 14
      Praxis3D/Source/Renderer.h
  68. 135 2
      Praxis3D/Source/RendererBackend.cpp
  69. 839 144
      Praxis3D/Source/RendererBackend.h
  70. 68 72
      Praxis3D/Source/RendererFrontend.cpp
  71. 228 3
      Praxis3D/Source/RendererFrontend.h
  72. 132 138
      Praxis3D/Source/RendererScene.cpp
  73. 39 8
      Praxis3D/Source/RendererScene.h
  74. 3 15
      Praxis3D/Source/RendererSystem.cpp
  75. 3 3
      Praxis3D/Source/RendererSystem.h
  76. 72 89
      Praxis3D/Source/SceneLoader.cpp
  77. 6 0
      Praxis3D/Source/ScriptingScene.cpp
  78. 3 3
      Praxis3D/Source/ShaderGraphicsObjects.h
  79. 14 533
      Praxis3D/Source/ShaderLoader.cpp
  80. 73 95
      Praxis3D/Source/ShaderLoader.h
  81. 45 13
      Praxis3D/Source/ShaderUniformUpdater.cpp
  82. 45 20
      Praxis3D/Source/ShaderUniformUpdater.h
  83. 292 234
      Praxis3D/Source/ShaderUniforms.h
  84. 1 1
      Praxis3D/Source/SolarTimeScript.h
  85. 28 26
      Praxis3D/Source/TaskManager.cpp
  86. 98 97
      Praxis3D/Source/TaskManager.h
  87. 4 4
      Praxis3D/Source/TaskScheduler.cpp
  88. 156 19
      Praxis3D/Source/TextureLoader.cpp
  89. 497 114
      Praxis3D/Source/TextureLoader.h
  90. 81 0
      Praxis3D/Source/UniformData.h
  91. 2 2
      Praxis3D/Source/Universal.h
  92. 23 10
      Praxis3D/Source/Utilities.h
  93. 17 17
      Praxis3D/Source/Window.cpp
  94. 6 6
      Praxis3D/Source/WorldEditObject.h
  95. BIN
      Praxis3D/x64/Debug 64bit/Praxis3D.tlog/CL.command.1.tlog
  96. BIN
      Praxis3D/x64/Debug 64bit/Praxis3D.tlog/CL.read.1.tlog
  97. BIN
      Praxis3D/x64/Debug 64bit/Praxis3D.tlog/CL.write.1.tlog
  98. 1 1
      Praxis3D/x64/Debug 64bit/Praxis3D.tlog/Praxis3D.lastbuildstate
  99. BIN
      Praxis3D/x64/Debug 64bit/Praxis3D.tlog/link.command.1.tlog
  100. BIN
      Praxis3D/x64/Debug 64bit/Praxis3D.tlog/link.read.1.tlog

BIN
Debug/Assimp32.dll


BIN
Debug/FreeImage.dll


BIN
Debug/SDL2.dll


BIN
Debug/glew32.dll


BIN
Debug/tbb.dll


BIN
Debug/tbb_debug.dll


+ 201 - 217
Praxis3D/Data/Maps/default_lite.pmap

@@ -6,9 +6,9 @@
 		{
 			"Scene": 
 			{
-				"ModelPoolSize": "15",
-				"PointLightPoolSize": "10",
-				"SpotLightPoolSize": "10"
+				"ModelPoolSize": "30",
+				"PointLightPoolSize": "20",
+				"SpotLightPoolSize": "20"
 			},
 			"Objects": 
 			[
@@ -20,19 +20,45 @@
 					"Type": "DirectionalLight",
 					"Name": "DirectionalLight 1",
 					"Color": "1.0f, 1.0f, 1.0f",
-					"Direction": "0.0340488f, -0.706697f, -0.706697f",
+					"Direction": "0.006461f, -0.707092f, -0.707092f",
 					"Intensity": "0.1f"
 				},
+				{
+					"Type": "EnvironmentMapStatic",
+					"Position": "0.0f, 0.0f, 0.0f",
+					"Materials": 
+					[
+						{
+							"Filename": "posx.jpg"
+						},
+						{
+							"Filename": "negx.jpg"
+						},
+						{
+							"Filename": "posy.jpg"
+						},
+						{
+							"Filename": "negy.jpg"
+						},
+						{
+							"Filename": "posz.jpg"
+						},
+						{
+							"Filename": "negz.jpg"
+						}
+					]
+				},
 				{
 					"Type": "ModelObject",
-					"Name": "Terrain1",
-					"Position": "100.0f, 1.0f, 0.0f",
+					"Name": "Terrain2",
+					"Position": "-100.0f, 0.0f, 0.0f",
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "100.0f, 100.0f, 100.0f",
-					"Lighting": "1",
+					"Scale": "5.0f, 5.0f, 5.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "20.0f",
 					"Models": 
 					{
@@ -43,38 +69,24 @@
 						"Diffuse": 
 						[
 							{
-								"Filename": "Ground_SmoothRocks_2k_alb.tga",
+								"Filename": "Metal_CleanPaintedWithChips_2k_alb.tga",
 								"Index": "0"
 							}
 						],
 						"Normal": 
 						[
 							{
-								"Filename": "Ground_SmoothRocks_2k_n.tga",
+								"Filename": "Metal_CleanPaintedWithChips_2k_n.tga",
 								"Index": "0"
 							}
 						],
 						"Emissive": 
 						{
 						},
-						"Specular": 
-						[
-							{
-								"Filename": "Ground_SmoothRocks_RMHAO.tga",
-								"Index": "0"
-							}
-						],
-						"Gloss": 
-						[
-							{
-								"Filename": "Ground_SmoothRocks_2k_g.tga",
-								"Index": "0"
-							}
-						],
-						"Height": 
+						"RMHAO": 
 						[
 							{
-								"Filename": "Ground_SmoothRocks_2k_h.tga",
+								"Filename": "Metal_CleanPaintedWithChips_RMHAO3.tga",
 								"Index": "0"
 							}
 						]
@@ -82,15 +94,16 @@
 				},
 				{
 					"Type": "ModelObject",
-					"Name": "Terrain2",
-					"Position": "-100.0f, 1.0f, 0.0f",
+					"Name": "Plane 1",
+					"Position": "-30.0f, 1.0f, 0.0f",
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "100.0f, 100.0f, 100.0f",
-					"Lighting": "1",
+					"Scale": "2.0f, 2.0f, 2.0f",
 					"AlphaThreshold": "0.0f",
-					"TextureTilingFactor": "20.0f",
+					"HeightScale": "0.04f",
+					"Lighting": "1",
+					"TextureTilingFactor": "10.0f",
 					"Models": 
 					{
 						"Filename": "plane.obj"
@@ -100,38 +113,24 @@
 						"Diffuse": 
 						[
 							{
-								"Filename": "Metal_CleanPaintedWithChips_2k_alb.tga",
+								"Filename": "Ground_SmoothRocks_2k_alb.tga",
 								"Index": "0"
 							}
 						],
 						"Normal": 
 						[
 							{
-								"Filename": "Metal_CleanPaintedWithChips_2k_n.tga",
+								"Filename": "Ground_SmoothRocks_2k_n.tga",
 								"Index": "0"
 							}
 						],
 						"Emissive": 
 						{
 						},
-						"Specular": 
-						[
-							{
-								"Filename": "Metal_CleanPaintedWithChips_RMHAO3.tga",
-								"Index": "0"
-							}
-						],
-						"Gloss": 
-						[
-							{
-								"Filename": "Metal_CleanPaintedWithChips_2k_g.tga",
-								"Index": "0"
-							}
-						],
-						"Height": 
+						"RMHAO": 
 						[
 							{
-								"Filename": "Metal_CleanPaintedWithChips_2k_h.tga",
+								"Filename": "Ground_SmoothRocks_RMHAO.tga",
 								"Index": "0"
 							}
 						]
@@ -139,63 +138,63 @@
 				},
 				{
 					"Type": "ModelObject",
-					"Name": "Dumpster 1",
-					"Position": "15.0617f, 0.0f, -6.05827f",
-					"Rotation": "-90.0f, 0.0f, 90.0f",
+					"Name": "Cube 1",
+					"Position": "15.0f, 5.0f, 0.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "5.0f, 5.0f, 5.0f",
-					"Lighting": "1",
+					"Scale": "4.0f, 4.0f, 4.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "dumpster.3ds"
+						"Filename": "cube.obj"
 					},
 					"Materials": 
 					{
 						"Diffuse": 
 						[
 							{
-								"Filename": "Dumpster_DIFF_2048.tga",
-								"Index": "0"
+								"Filename": "Ground_SmoothRocks_2k_alb.tga",
+								"Index": "1"
 							}
 						],
 						"Normal": 
 						[
 							{
-								"Filename": "Dumpster_NRM_2048.tga",
-								"Index": "0"
+								"Filename": "Ground_SmoothRocks_2k_n.tga",
+								"Index": "1"
 							}
 						],
 						"Emissive": 
 						{
 						},
-						"Specular": 
-						{
-						},
-						"Gloss": 
-						{
-						},
-						"Height": 
-						{
-						}
+						"RMHAO": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_RMHAO.tga",
+								"Index": "1"
+							}
+						]
 					}
 				},
 				{
 					"Type": "ModelObject",
 					"Name": "sphere 1",
-					"Position": "0.0f, 2.0f, 10.0f",
+					"Position": "0.0f, 4.0f, 10.0f",
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.1f, 0.1f, 0.1f",
-					"Lighting": "1",
+					"Scale": "5.0f, 5.0f, 5.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "2_second_Ball.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -212,35 +211,30 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
+						"RMHAO": 
 						[
 							{
 								"Filename": "test1_RM.png",
 								"Index": "0"
 							}
-						],
-						"Gloss": 
-						{
-						},
-						"Height": 
-						{
-						}
+						]
 					}
 				},
 				{
 					"Type": "ModelObject",
 					"Name": "sphere 2",
-					"Position": "0.0f, 2.0f, 5.0f",
+					"Position": "0.0f, 4.0f, 5.0f",
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.1f, 0.1f, 0.1f",
-					"Lighting": "1",
+					"Scale": "5.0f, 5.0f, 5.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "2_second_Ball.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -257,35 +251,30 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
+						"RMHAO": 
 						[
 							{
 								"Filename": "test2_RM.png",
 								"Index": "0"
 							}
-						],
-						"Gloss": 
-						{
-						},
-						"Height": 
-						{
-						}
+						]
 					}
 				},
 				{
 					"Type": "ModelObject",
 					"Name": "sphere 3",
-					"Position": "0.0f, 2.0f, 0.0f",
+					"Position": "0.0f, 4.0f, 0.0f",
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.1f, 0.1f, 0.1f",
-					"Lighting": "1",
+					"Scale": "5.0f, 5.0f, 5.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "2_second_Ball.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -302,35 +291,30 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
+						"RMHAO": 
 						[
 							{
 								"Filename": "test3_RM.png",
 								"Index": "0"
 							}
-						],
-						"Gloss": 
-						{
-						},
-						"Height": 
-						{
-						}
+						]
 					}
 				},
 				{
 					"Type": "ModelObject",
 					"Name": "sphere 4",
-					"Position": "0.0f, 2.0f, -5.0f",
+					"Position": "0.0f, 4.0f, -5.0f",
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.1f, 0.1f, 0.1f",
-					"Lighting": "1",
+					"Scale": "5.0f, 5.0f, 5.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "2_second_Ball.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -347,35 +331,30 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
+						"RMHAO": 
 						[
 							{
 								"Filename": "test4_RM.png",
 								"Index": "0"
 							}
-						],
-						"Gloss": 
-						{
-						},
-						"Height": 
-						{
-						}
+						]
 					}
 				},
 				{
 					"Type": "ModelObject",
 					"Name": "sphere 5",
-					"Position": "0.0f, 2.0f, -10.0f",
+					"Position": "0.0f, 4.0f, -10.0f",
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.1f, 0.1f, 0.1f",
-					"Lighting": "1",
+					"Scale": "5.0f, 5.0f, 5.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "2_second_Ball.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -392,35 +371,30 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
+						"RMHAO": 
 						[
 							{
 								"Filename": "test5_RM.png",
 								"Index": "0"
 							}
-						],
-						"Gloss": 
-						{
-						},
-						"Height": 
-						{
-						}
+						]
 					}
 				},
 				{
 					"Type": "ModelObject",
 					"Name": "sphere 6",
-					"Position": "0.0f, 2.0f, -15.0f",
+					"Position": "0.0f, 4.0f, -15.0f",
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.1f, 0.1f, 0.1f",
-					"Lighting": "1",
+					"Scale": "5.0f, 5.0f, 5.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "2_second_Ball.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -437,35 +411,30 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
+						"RMHAO": 
 						[
 							{
 								"Filename": "test6_RM.png",
 								"Index": "0"
 							}
-						],
-						"Gloss": 
-						{
-						},
-						"Height": 
-						{
-						}
+						]
 					}
 				},
 				{
 					"Type": "ModelObject",
 					"Name": "light 1",
-					"Position": "-16.1514f, 10.0f, -11.7956f",
+					"Position": "-19.2421f, 10.0f, 5.45328f",
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.5f, 0.5f, 0.5f",
-					"Lighting": "1",
+					"Scale": "1.0f, 1.0f, 1.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "sphere.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -478,13 +447,7 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
-						{
-						},
-						"Gloss": 
-						{
-						},
-						"Height": 
+						"RMHAO": 
 						{
 						}
 					}
@@ -496,13 +459,14 @@
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.5f, 0.5f, 0.5f",
-					"Lighting": "1",
+					"Scale": "1.0f, 1.0f, 1.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "sphere.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -515,13 +479,7 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
-						{
-						},
-						"Gloss": 
-						{
-						},
-						"Height": 
+						"RMHAO": 
 						{
 						}
 					}
@@ -533,13 +491,14 @@
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.5f, 0.5f, 0.5f",
-					"Lighting": "1",
+					"Scale": "1.0f, 1.0f, 1.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "sphere.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -552,13 +511,7 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
-						{
-						},
-						"Gloss": 
-						{
-						},
-						"Height": 
+						"RMHAO": 
 						{
 						}
 					}
@@ -570,13 +523,14 @@
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.5f, 0.5f, 0.5f",
-					"Lighting": "1",
+					"Scale": "1.0f, 1.0f, 1.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "sphere.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -589,13 +543,7 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
-						{
-						},
-						"Gloss": 
-						{
-						},
-						"Height": 
+						"RMHAO": 
 						{
 						}
 					}
@@ -607,13 +555,14 @@
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.5f, 0.5f, 0.5f",
-					"Lighting": "1",
+					"Scale": "1.0f, 1.0f, 1.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "sphere.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -626,13 +575,7 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
-						{
-						},
-						"Gloss": 
-						{
-						},
-						"Height": 
+						"RMHAO": 
 						{
 						}
 					}
@@ -644,13 +587,14 @@
 					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "0.5f, 0.5f, 0.5f",
-					"Lighting": "1",
+					"Scale": "1.0f, 1.0f, 1.0f",
 					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
 					"TextureTilingFactor": "1.0f",
 					"Models": 
 					{
-						"Filename": "sphere.obj"
+						"Filename": "sphereNew4.3DS"
 					},
 					"Materials": 
 					{
@@ -663,54 +607,92 @@
 						"Emissive": 
 						{
 						},
-						"Specular": 
-						{
-						},
-						"Gloss": 
-						{
-						},
-						"Height": 
+						"RMHAO": 
 						{
 						}
 					}
 				},
 				{
 					"Type": "ModelObject",
-					"Name": "Skybox 1",
-					"Position": "2.32071f, 8.89734f, 7.00538f",
-					"Rotation": "0.0f, -0.95052f, 23.5525f",
+					"Name": "Terrain1",
+					"Position": "100.0f, -0.5f, 0.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
 					"OffsetRotation": "0.0f, 0.0f, 0.0f",
-					"Scale": "30000.0f, 30000.0f, 30000.0f",
-					"Lighting": "0",
+					"Scale": "25000.0f, 25000.0f, 25000.0f",
 					"AlphaThreshold": "0.0f",
-					"TextureTilingFactor": "1.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "1",
+					"TextureTilingFactor": "10.0f",
 					"Models": 
 					{
-						"Filename": "sphere_inverted.obj"
+						"Filename": "terrain_plane.obj"
 					},
 					"Materials": 
 					{
 						"Diffuse": 
 						[
 							{
-								"Filename": "gRbWE9O.jpg",
+								"Filename": "Ground_SmoothRocks_2k_alb.tga",
 								"Index": "1"
 							}
 						],
 						"Normal": 
-						{
-						},
+						[
+							{
+								"Filename": "Ground_SmoothRocks_2k_n.tga",
+								"Index": "1"
+							}
+						],
 						"Emissive": 
 						{
 						},
-						"Specular": 
+						"RMHAO": 
+						[
+							{
+								"Filename": "defaultRM.png",
+								"Index": "1"
+							}
+						]
+					},
+					"Shaders": 
+					{
+						"FragmentShader": "geometryPassInf.frag",
+						"VertexShader": "geometryPassInf.vert"
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "Skybox 1",
+					"Position": "-117.386f, 11.1996f, -70.2678f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "20000.0f, 20000.0f, 20000.0f",
+					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.0f",
+					"Lighting": "0",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "cube_inverted.obj"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "skydome6.png",
+								"Index": "0"
+							}
+						],
+						"Normal": 
 						{
 						},
-						"Gloss": 
+						"Emissive": 
 						{
 						},
-						"Height": 
+						"RMHAO": 
 						{
 						}
 					},
@@ -727,7 +709,7 @@
 					"Color": "1.0f, 1.0f, 1.0f",
 					"Intensity": "100.0f",
 					"OffsetPosition": "0.0f, 0.0f, 0.0f",
-					"Position": "-16.1514f, 10.0f, -11.7956f"
+					"Position": "-19.2421f, 10.0f, 5.45328f"
 				},
 				{
 					"Type": "PointLight",
@@ -795,10 +777,12 @@
 				{
 					"Type": "FreeCamera",
 					"Name": "Free Camera 1",
-					"Position": "2.32533f, 8.9038f, 7.00543f",
-					"Angle": "23.5525f, -0.95052f",
+					"Position": "-117.387f, 11.2024f, -70.272f",
+					"Angle": "25.5279f, -0.56376f",
 					"Speed": "1.0f",
 					"SprintSpeed": "50.0f",
+					"LowerLimit": "0.0f",
+					"UpperLimit": "500.0f",
 					"Keybindings": 
 					{
 						"ForwardKey": "26",

+ 925 - 0
Praxis3D/Data/Maps/default_lite2.pmap

@@ -0,0 +1,925 @@
+{
+	"LoadInBackground": "0",
+	"Systems": 
+	{
+		"Graphics": 
+		{
+			"Scene": 
+			{
+				"ModelPoolSize": "15",
+				"PointLightPoolSize": "10",
+				"SpotLightPoolSize": "10"
+			},
+			"Objects": 
+			[
+				{
+					"Type": "Camera",
+					"Name": "Camera 1"
+				},
+				{
+					"Type": "DirectionalLight",
+					"Name": "DirectionalLight 1",
+					"Color": "1.0f, 1.0f, 1.0f",
+					"Direction": "0.0134507f, -0.707043f, -0.707043f",
+					"Intensity": "0.1f"
+				},
+				{
+					"Type": "EnvironmentMapStatic",
+					"Position": "0.0f, 0.0f, 0.0f",
+					"Materials": 
+					[
+						{
+							"Filename": "posx.jpg"
+						},
+						{
+							"Filename": "negx.jpg"
+						},
+						{
+							"Filename": "posy.jpg"
+						},
+						{
+							"Filename": "negy.jpg"
+						},
+						{
+							"Filename": "posz.jpg"
+						},
+						{
+							"Filename": "negz.jpg"
+						}
+					]
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "Terrain2",
+					"Position": "-100.0f, -0.15f, 0.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "100.0f, 100.0f, 100.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "20.0f",
+					"Models": 
+					{
+						"Filename": "plane.obj"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "Metal_CleanPaintedWithChips_2k_alb.tga",
+								"Index": "0"
+							}
+						],
+						"Normal": 
+						[
+							{
+								"Filename": "Metal_CleanPaintedWithChips_2k_n.tga",
+								"Index": "0"
+							}
+						],
+						"Emissive": 
+						{
+						},
+						"RMHAO": 
+						[
+							{
+								"Filename": "Metal_CleanPaintedWithChips_RMHAO3.tga",
+								"Index": "0"
+							}
+						]
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "Plane 1",
+					"Position": "-30.0f, 5.0f, 0.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "20.0f, 20.0f, 20.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"HeightScale": "0.04f",
+					"TextureTilingFactor": "10.0f",
+					"Models": 
+					{
+						"Filename": "plane.obj"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_2k_alb.tga",
+								"Index": "0"
+							}
+						],
+						"Normal": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_2k_n.tga",
+								"Index": "0"
+							}
+						],
+						"Emissive": 
+						{
+						},
+						"RMHAO": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_RMHAO.tga",
+								"Index": "0"
+							}
+						]
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "Cube 1",
+					"Position": "15.0f, 5.0f, 0.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "4.0f, 4.0f, 4.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "cube.obj"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_2k_alb.tga",
+								"Index": "1"
+							}
+						],
+						"Normal": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_2k_n.tga",
+								"Index": "1"
+							}
+						],
+						"Emissive": 
+						{
+						},
+						"RMHAO": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_RMHAO.tga",
+								"Index": "1"
+							}
+						],
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "sphere 1",
+					"Position": "0.0f, 4.0f, 10.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "5.0f, 5.0f, 5.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "test_albedo.png",
+								"Index": "0"
+							}
+						],
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"RMHAO": 
+						[
+							{
+								"Filename": "test1_RM.png",
+								"Index": "0"
+							}
+						]
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "sphere 2",
+					"Position": "0.0f, 4.0f, 5.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "5.0f, 5.0f, 5.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "test_albedo.png",
+								"Index": "0"
+							}
+						],
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"RMHAO": 
+						[
+							{
+								"Filename": "test2_RM.png",
+								"Index": "0"
+							}
+						]
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "sphere 3",
+					"Position": "0.0f, 4.0f, 0.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "5.0f, 5.0f, 5.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "test_albedo.png",
+								"Index": "0"
+							}
+						],
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"RMHAO": 
+						[
+							{
+								"Filename": "test3_RM.png",
+								"Index": "0"
+							}
+						]
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "sphere 4",
+					"Position": "0.0f, 4.0f, -5.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "5.0f, 5.0f, 5.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "test_albedo.png",
+								"Index": "0"
+							}
+						],
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"RMHAO": 
+						[
+							{
+								"Filename": "test4_RM.png",
+								"Index": "0"
+							}
+						]
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "sphere 5",
+					"Position": "0.0f, 4.0f, -10.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "5.0f, 5.0f, 5.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "test_albedo.png",
+								"Index": "0"
+							}
+						],
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"RMHAO": 
+						[
+							{
+								"Filename": "test5_RM.png",
+								"Index": "0"
+							}
+						]
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "sphere 6",
+					"Position": "0.0f, 4.0f, -15.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "5.0f, 5.0f, 5.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "test_albedo.png",
+								"Index": "0"
+							}
+						],
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"RMHAO": 
+						[
+							{
+								"Filename": "test6_RM.png",
+								"Index": "0"
+							}
+						]
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "light 1",
+					"Position": "-2.20783f, 10.0f, -19.8776f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "1.0f, 1.0f, 1.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						{
+						},
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"Specular": 
+						{
+						},
+						"Gloss": 
+						{
+						},
+						"Height": 
+						{
+						}
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "light 2",
+					"Position": "9.12898f, 7.98369f, 9.59357f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "1.0f, 1.0f, 1.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						{
+						},
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"Specular": 
+						{
+						},
+						"Gloss": 
+						{
+						},
+						"Height": 
+						{
+						}
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "light 3",
+					"Position": "-6.94746f, 8.59811f, 7.54629f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "1.0f, 1.0f, 1.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						{
+						},
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"Specular": 
+						{
+						},
+						"Gloss": 
+						{
+						},
+						"Height": 
+						{
+						}
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "light 4",
+					"Position": "60.0f, 3.0f, 60.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "1.0f, 1.0f, 1.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						{
+						},
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"Specular": 
+						{
+						},
+						"Gloss": 
+						{
+						},
+						"Height": 
+						{
+						}
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "light 5",
+					"Position": "-40.0f, 3.0f, 1.96449f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "1.0f, 1.0f, 1.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						{
+						},
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"Specular": 
+						{
+						},
+						"Gloss": 
+						{
+						},
+						"Height": 
+						{
+						}
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "light 6",
+					"Position": "-20.0f, 3.0f, -20.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "1.0f, 1.0f, 1.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "sphereNew4.3DS"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						{
+						},
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"Specular": 
+						{
+						},
+						"Gloss": 
+						{
+						},
+						"Height": 
+						{
+						}
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "Terrain1",
+					"Position": "100.0f, -0.5f, 0.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Scale": "25000.0f, 25000.0f, 25000.0f",
+					"Lighting": "1",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "10.0f",
+					"Models": 
+					{
+						"Filename": "terrain_plane.obj"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_2k_alb.tga",
+								"Index": "0"
+							}
+						],
+						"Normal": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_2k_n.tga",
+								"Index": "0"
+							}
+						],
+						"Emissive": 
+						{
+						},
+						"Specular": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_RMHAO.tga",
+								"Index": "0"
+							}
+						],
+						"Gloss": 
+						{
+						},
+						"Height": 
+						[
+							{
+								"Filename": "Ground_SmoothRocks_2k_h.tga",
+								"Index": "0"
+							}
+						]
+					},
+					"Shaders": 
+					{
+						"FragmentShader": "geometryPassInf.frag",
+						"VertexShader": "geometryPassInf.vert"
+					}
+				},
+				{
+					"Type": "ModelObject",
+					"Name": "Skybox 1",
+					"Position": "0.0f, 0.0f, 0.0f",
+					"Rotation": "0.0f, 0.0f, 0.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.f, 0.0f",
+					"Scale": "20000.0f, 20000.0f, 20000.0f",
+					"Lighting": "0",
+					"AlphaThreshold": "0.0f",
+					"TextureTilingFactor": "1.0f",
+					"Models": 
+					{
+						"Filename": "cube.obj"
+					},
+					"Materials": 
+					{
+						"Diffuse": 
+						[
+							{
+								"Filename": "skydome6.png",
+								"Index": "0"
+							}
+						],
+						"Normal": 
+						{
+						},
+						"Emissive": 
+						{
+						},
+						"Specular": 
+						{
+						},
+						"Gloss": 
+						{
+						},
+						"Height": 
+						{
+						}
+					},
+					"Shaders": 
+					{
+						"FragmentShader": "skybox.frag",
+						"VertexShader": "skybox.vert"
+					}
+				},
+				{
+					"Type": "PointLight",
+					"Name": "PointLight 1",
+					"Attenuation": "0.0f, 0.0f, 1.0f",
+					"Color": "1.0f, 1.0f, 1.0f",
+					"Intensity": "100.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"Position": "-2.20783f, 10.0f, -19.8776f"
+				},
+				{
+					"Type": "PointLight",
+					"Name": "PointLight 2",
+					"Attenuation": "0.0f, 0.0f, 1.0f",
+					"Color": "1.0f, 1.0f, 1.0f",
+					"Intensity": "100.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"Position": "9.12898f, 7.98369f, 9.59357f"
+				},
+				{
+					"Type": "PointLight",
+					"Name": "PointLight 3",
+					"Attenuation": "0.0f, 0.0f, 1.0f",
+					"Color": "1.0f, 1.0f, 1.0f",
+					"Intensity": "100.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"Position": "-6.94746f, 8.59811f, 7.54629f"
+				},
+				{
+					"Type": "SpotLight",
+					"Name": "SpotLight 1",
+					"Attenuation": "0.0f, 0.0f, 1.0f",
+					"CutoffAngle": "60.0f",
+					"Color": "1.0f, 1.0f, 1.0f",
+					"Direction": "-1.0f, 0.0f, 0.0f",
+					"Intensity": "200.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Position": "60.0f, 3.0f, 60.0f"
+				},
+				{
+					"Type": "SpotLight",
+					"Name": "SpotLight 2",
+					"Attenuation": "0.0f, 0.0f, 1.0f",
+					"CutoffAngle": "60.0f",
+					"Color": "0.0f, 1.0f, 0.0f",
+					"Direction": "0.577353f, 0.577173f, 0.577525f",
+					"Intensity": "200.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Position": "-40.0f, 3.0f, 1.96449f"
+				},
+				{
+					"Type": "SpotLight",
+					"Name": "SpotLight 3",
+					"Attenuation": "0.0f, 0.0f, 1.0f",
+					"CutoffAngle": "60.0f",
+					"Color": "1.0f, 1.0f, 1.0f",
+					"Direction": "0.707107f, 0.0f, 0.707107f",
+					"Intensity": "200.0f",
+					"OffsetPosition": "0.0f, 0.0f, 0.0f",
+					"OffsetRotation": "0.0f, 0.0f, 0.0f",
+					"Position": "-20.0f, 3.0f, -20.0f"
+				}
+			]
+		},
+		"Scripting": 
+		{
+			"Scene": 
+			{
+			},
+			"Objects": 
+			[
+				{
+					"Type": "FreeCamera",
+					"Name": "Free Camera 1",
+					"Position": "7.96417f, 10.8363f, -6.76648f",
+					"Angle": "25.9187f, -0.4938f",
+					"Speed": "1.0f",
+					"SprintSpeed": "50.0f",
+					"LowerLimit": "0.0f",
+					"UpperLimit": "500.0f",
+					"Keybindings": 
+					{
+						"ForwardKey": "26",
+						"BackwardKey": "22",
+						"LeftStrafeKey": "4",
+						"RightStrafeKey": "7",
+						"SprintKey": "225"
+					}
+				},
+				{
+					"Type": "DebugUIScript",
+					"Name": "Debug UI Script 1",
+					"Keybindings": 
+					{
+						"DebugCaptureMouseKey": "67",
+						"DebugFullscreenKey": "66",
+						"DebugVertSyncKey": "68",
+						"CloseKey": "41"
+					}
+				},
+				{
+					"Type": "DebugMoveScript",
+					"Name": "Debug Move Script 1",
+					"Position": "0.0f, 10.0f, 0.0f",
+					"Radius": "20.0f",
+					"Rotation": "0.0f, 1.0f, 0.0f",
+					"Speed": "20.0f"
+				},
+				{
+					"Type": "WorldEditScript",
+					"Name": "World Edit Script 1",
+					"Speed": "2.5f",
+					"SprintSpeed": "25.0f",
+					"Keybindings": 
+					{
+						"ForwardKey": "96",
+						"BackwardKey": "90",
+						"UpKey": "95",
+						"DownKey": "89",
+						"LeftKey": "92",
+						"RightKey": "94",
+						"NextKey": "85",
+						"PreviousKey": "84",
+						"SprintKey": "225"
+					}
+				},
+				{
+					"Type": "SolarTimeScript",
+					"Name": "Solar Time Script 1",
+					"Hours": "12",
+					"Seconds": "0.0f",
+					"Latitude": "54.0f",
+					"Longitude": "54.0f",
+					"DayOfYear": "1",
+					"TimeMultiplier": "10.0f",
+					"OffsetPosition": "25.0f"
+				}
+			]
+		}
+	},
+	"ObjectLinks": 
+	[
+		{
+			"Subject": "Free Camera 1",
+			"Observer": "Camera 1"
+		},
+		{
+			"Subject": "Free Camera 1",
+			"Observer": "Skybox 1"
+		},
+		{
+			"Subject": "Solar Time Script 1",
+			"Observer": "DirectionalLight 1"
+		},
+		{
+			"Subject": "Debug Move Script 1",
+			"Observer": "PointLight 1"
+		},
+		{
+			"Subject": "Debug Move Script 1",
+			"Observer": "light 1"
+		},
+		{
+			"Subject": "PointLight 2",
+			"Observer": "light 2"
+		},
+		{
+			"Subject": "PointLight 3",
+			"Observer": "light 3"
+		},
+		{
+			"Subject": "SpotLight 1",
+			"Observer": "light 4"
+		},
+		{
+			"Subject": "SpotLight 2",
+			"Observer": "light 5"
+		},
+		{
+			"Subject": "SpotLight 3",
+			"Observer": "light 6"
+		}
+	]
+}

BIN
Praxis3D/Data/Materials/Bricks1_DISP.tif


BIN
Praxis3D/Data/Materials/Bricks1_NRM.tif


File diff suppressed because it is too large
+ 513 - 0
Praxis3D/Data/Models/Nanosuit.dae


+ 23 - 4
Praxis3D/Data/Shaders/finalPass.frag

@@ -1,9 +1,19 @@
-#version 450 core
+#version 430 core
+
+//#define ENABLE_TONE_MAPPING
 
 out vec4 outputColor;
 
 uniform sampler2D finalColorMap;
 uniform ivec2 screenSize;
+uniform float gamma;
+
+#ifdef ENABLE_TONE_MAPPING
+vec3 simpleToneMapping(vec3 p_color, float p_gamma)
+{
+    return pow(exp(-1.0 / (2.72 * p_color + 0.15)), vec3(1.0 / p_gamma));
+}
+#endif
 
 vec2 calcTexCoord(void)
 {
@@ -14,7 +24,16 @@ void main(void)
 {
 	// Calculate screen-space texture coordinates, for buffer access
 	vec2 texCoord = calcTexCoord();
-		
-	// Write the color from the final framebuffer to the default framebuffer
-	outputColor = vec4(texture(finalColorMap, texCoord).xyz, 1.0);
+	
+	// Perform gamma correction on the color from the final framebuffer
+	vec3 color = pow(texture(finalColorMap, texCoord).xyz, vec3(1.0 / gamma));
+	
+	#ifdef ENABLE_TONE_MAPPING
+	// Perform simple tonemapping on the final color
+	color = simpleToneMapping(color, gamma);
+	#endif
+	
+	// Write the color to the default framebuffer
+	//outputColor = vec4(1.0, 0.0, 0.0, 1.0);
+	outputColor = vec4(color, 1.0);
 }

+ 1 - 1
Praxis3D/Data/Shaders/finalPass.vert

@@ -1,4 +1,4 @@
-#version 450 core
+#version 430 core
 
 void main(void) 
 {

+ 217 - 656
Praxis3D/Data/Shaders/geometryPass.frag

@@ -1,177 +1,103 @@
-#version 330 core
+#version 430 core
+
+#define HEIGHT_SCALE_THRESHOLD 0.001
+#define ROUGHNESS_MIN 0.001
 
 // Some drivers require the following
 //precision highp float;
 
 // Geometry buffers
-layout(location = 0) out vec4 positionBuffer;
+layout(location = 0) out vec3 positionBuffer;
 layout(location = 1) out vec4 diffuseBuffer;
-layout(location = 2) out vec4 normalBuffer;
+layout(location = 2) out vec3 normalBuffer;
 layout(location = 3) out vec4 emissiveBuffer;
+layout(location = 4) out vec4 matPropertiesBuffer;
+
+
+uniform mat4 MVP;
+uniform mat4 modelMat;
+uniform mat4 viewMat;
+uniform mat4 modelViewMat;
+uniform mat4 projMat;
 
 // Variables from vertex shader
-in vec3 fragPos;
+in mat3 TBN;
 in vec2 texCoord;
+in vec3 fragPos;
 in vec3 normal;
-in mat3 TBN;
-
+in vec3 tangentFragPos;
+in vec3 tangentCameraPos;
+in float parallaxScale;
+
+/* Current combined texture channels:
+	Red: Roughness
+	Green: Metalness
+	Blue: Height
+	Alpha: Ambient Occlusion
+*/
+uniform sampler2D combinedTexture;
 uniform sampler2D diffuseTexture;
 uniform sampler2D normalTexture;
-uniform sampler2D specularTexture;
 uniform sampler2D emissiveTexture;
-uniform sampler2D glossTexture;
-uniform sampler2D heightTexture;
 
 uniform float alphaThreshold;
 uniform float emissiveThreshold;
-uniform float parallaxHeightScale;
-uniform vec3 cameraPosVec;
-
-vec2 simpleParallaxMapping(vec2 p_texCoords, vec3 p_viewDir, float p_height)
-{
-	vec2 parallax = p_viewDir.xy / p_viewDir.z * (p_height * 0.1f);
-    return p_texCoords + parallax; 
-}
 
-vec2 steepParallaxMapping(in vec2 T, in vec3 V)//, out float parallaxHeight)
-{
-   // determine number of layers from angle between V and N
-   const float minLayers = 5;
-   const float maxLayers = 15;
-   float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0, 0, 1), V)));
-
-   // height of each layer
-   float layerHeight = 1.0 / numLayers;
-   // depth of current layer
-   float currentLayerHeight = 0;
-   // shift of texture coordinates for each iteration
-   vec2 dtex = 0.1 * V.xy / V.z / numLayers;
-
-   // current texture coordinates
-   vec2 currentTextureCoords = T;
-
-   // get first depth from heightmap
-   float heightFromTexture = texture(heightTexture, currentTextureCoords).r;
-
-   // while point is above surface
-   while(heightFromTexture > currentLayerHeight)
-   {
-      // to the next layer
-      currentLayerHeight += layerHeight;
-      // shift texture coordinates along vector V
-      currentTextureCoords -= dtex;
-      // get new depth from heightmap
-      heightFromTexture = texture(heightTexture, currentTextureCoords).r;
-   }
-
-   // return results
-   //parallaxHeight = currentLayerHeight;
-   return currentTextureCoords;
-} 
-
-vec2 parallaxMapping(in vec2 T, in vec3 V)//, out float parallaxHeight)
-{
-   // determine optimal number of layers
-   const float minLayers = 15;
-   const float maxLayers = 25;
-   float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0, 0, 1), V)));
-
-   // height of each layer
-   float layerHeight = 1.0 / numLayers;
-   // current depth of the layer
-   float curLayerHeight = 0.1;
-   // shift of texture coordinates for each layer
-   vec2 dtex = 0.015 * V.xy / V.z / numLayers;
-
-   // current texture coordinates
-   vec2 currentTextureCoords = T;
-
-   // depth from heightmap
-   float heightFromTexture = texture(heightTexture, currentTextureCoords).r;
-
-   // while point is above the surface
-   while(heightFromTexture > curLayerHeight)
-   {
-      // to the next layer
-      curLayerHeight += layerHeight;
-      // shift of texture coordinates
-      currentTextureCoords -= dtex;
-      // new depth from heightmap
-      heightFromTexture = texture(heightTexture, currentTextureCoords).r;
-   }
-
-   ///////////////////////////////////////////////////////////
-
-   // previous texture coordinates
-   vec2 prevTCoords = currentTextureCoords + dtex;
-
-   // heights for linear interpolation
-   float nextH = heightFromTexture - curLayerHeight;
-   float prevH = texture(heightTexture, prevTCoords).r
-                           - curLayerHeight + layerHeight;
-						   
-   // proportions for linear interpolation
-   float weight = nextH / (nextH - prevH);
-
-   // interpolation of texture coordinates
-   vec2 finalTexCoords = prevTCoords * weight + currentTextureCoords * (1.0 - weight);
-
-   // interpolation of depth values
-   //parallaxHeight = curLayerHeight + prevH * weight + nextH * (1.0 - weight);
-
-   // return result
-   return finalTexCoords;
-}
-
-vec2 reliefParallaxMapping(vec2 p_texCoords, vec3 p_viewDir)
-{    
-	//float v = height * 0.04 - 0.02;
-	//vec2 newCoords = texCoord + (viewDir.xy * v);
-	
-	// number of depth layers
+/*
+vec2 steepParallaxMapping(vec2 texCoords, vec3 viewDir)
+{ 
+    // number of depth layers
     const float minLayers = 10;
     const float maxLayers = 20;
-    float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), p_viewDir)));  
+    float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));  
     // calculate the size of each layer
     float layerDepth = 1.0 / numLayers;
     // depth of current layer
     float currentLayerDepth = 0.0;
     // the amount to shift the texture coordinates per layer (from vector P)
-    vec2 P = p_viewDir.xy / p_viewDir.z * 0.01;
+    vec2 P = viewDir.xy / viewDir.z * height_scale; 
     vec2 deltaTexCoords = P / numLayers;
   
     // get initial values
-    vec2  currentTexCoords     = p_texCoords;
-    float currentDepthMapValue = texture(heightTexture, currentTexCoords).r;
-		  
+    vec2  currentTexCoords     = texCoords;
+    float currentDepthMapValue = texture(depthMap, currentTexCoords).r;
+      
     while(currentLayerDepth < currentDepthMapValue)
-    {		
+    {
         // shift texture coordinates along direction of P
         currentTexCoords -= deltaTexCoords;
         // get depthmap value at current texture coordinates
-        currentDepthMapValue = texture(heightTexture, currentTexCoords).r;  
+        currentDepthMapValue = texture(depthMap, currentTexCoords).r;  
         // get depth of next layer
         currentLayerDepth += layerDepth;  
     }
     
-	//return currentTexCoords;
-	
-    // -- parallax occlusion mapping interpolation from here on
-    // get texture coordinates before collision (reverse operations)
-    vec2 prevTexCoords = currentTexCoords + deltaTexCoords;
+    return currentTexCoords;
+}*/
 
-    // get depth after and before collision for linear interpolation
-    float afterDepth  = currentDepthMapValue - currentLayerDepth;
-    float beforeDepth = texture(heightTexture, prevTexCoords).r - currentLayerDepth + layerDepth;
- 
-    // interpolation of texture coordinates
-    float weight = afterDepth / (afterDepth - beforeDepth);
-    vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
+float getHeight(const vec2 p_texCoords)
+{
+	return 1.0 - texture(combinedTexture, p_texCoords).b;
+}
+float getHeight(const vec2 p_texCoords, const vec2 p_dPdx, const vec2 p_dPdy)
+{
+	return textureGrad(combinedTexture, p_texCoords, p_dPdx , p_dPdy).b;
+}
 
-	return finalTexCoords;
+float getRoughness(const vec2 p_texCoords)
+{
+	return max(texture(combinedTexture, p_texCoords).r, ROUGHNESS_MIN);
+}
+float getMetalness(const vec2 p_texCoords)
+{
+	return texture(combinedTexture, p_texCoords).g;
+}
+float getAmbientOcclusion(const vec2 p_texCoords)
+{
+	return texture(combinedTexture, p_texCoords).a;
 }
 
-vec2 reliefParallaxMapping2(vec2 p_texCoords, vec3 p_viewDir)
+vec2 reliefParallaxMapping(vec2 p_texCoords, vec3 p_viewDir)
 {   
 	// determine required number of layers
 	const float minLayers = 10;
@@ -189,7 +115,7 @@ vec2 reliefParallaxMapping2(vec2 p_texCoords, vec3 p_viewDir)
 	vec2 currentTextureCoords = p_texCoords;
 
 	// depth from heightmap
-	float heightFromTexture = texture(heightTexture, currentTextureCoords).r;
+	float heightFromTexture = getHeight(currentTextureCoords);
 
 	// while point is above surface
 	while(heightFromTexture > currentLayerHeight)
@@ -199,7 +125,7 @@ vec2 reliefParallaxMapping2(vec2 p_texCoords, vec3 p_viewDir)
 	  // shift texture coordinates along V
 	  currentTextureCoords -= dtex;
 	  // new depth from heightmap
-	  heightFromTexture = texture(heightTexture, currentTextureCoords).r;
+	  heightFromTexture = getHeight(currentTextureCoords);
 	}
 
 	///////////////////////////////////////////////////////////
@@ -222,7 +148,7 @@ vec2 reliefParallaxMapping2(vec2 p_texCoords, vec3 p_viewDir)
 	  deltaHeight /= 2;
 
 	  // new depth from heightmap
-	  heightFromTexture = texture(heightTexture, currentTextureCoords).r;
+	  heightFromTexture = getHeight(currentTextureCoords);
 
 	  // shift along or agains vector V
 	  if(heightFromTexture > currentLayerHeight) // below the surface
@@ -237,101 +163,146 @@ vec2 reliefParallaxMapping2(vec2 p_texCoords, vec3 p_viewDir)
 	  }
 	}
 
-	// return results
-	//parallaxHeight = currentLayerHeight;    
 	return currentTextureCoords;
 }
 
-vec2 parallaxOcclusionMapping(vec2 p_texCoords, vec3 p_viewDir)
+vec2 parallaxMappingNew(vec2 T, vec3 V)
 {
-	// determine optimal number of layers
-   const float minLayers = 10;
-   const float maxLayers = 15;
-   float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0, 0, 1), p_viewDir)));
-
-   // height of each layer
-   float layerHeight = 1.0 / numLayers;
-   // current depth of the layer
-   float curLayerHeight = 0.0;
-   // shift of texture coordinates for each layer
-   vec2 dtex = 0.012 * p_viewDir.xy / p_viewDir.z / numLayers;
-
-   // current texture coordinates
-   vec2 currentTextureCoords = p_texCoords;
-
-   // depth from heightmap
-   float heightFromTexture = texture(heightTexture, currentTextureCoords).r;
-
-   // while point is above the surface
-   while(heightFromTexture > curLayerHeight)
-   {
-      // to the next layer
-      curLayerHeight += layerHeight;
-      // shift of texture coordinates
-      currentTextureCoords -= dtex;
-      // new depth from heightmap
-      heightFromTexture = texture(heightTexture, currentTextureCoords).r;
-   }
-
-   ///////////////////////////////////////////////////////////
-
-   // previous texture coordinates
-   vec2 prevTCoords = currentTextureCoords + dtex;
-
-   // heights for linear interpolation
-   float nextH = heightFromTexture - curLayerHeight;
-   float prevH = texture(heightTexture, prevTCoords).r
-                           - curLayerHeight + layerHeight;
-
-   // proportions for linear interpolation
-   float weight = nextH / (nextH - prevH);
-
-   // interpolation of texture coordinates
-   vec2 finalTexCoords = prevTCoords * weight + currentTextureCoords * (1.0 - weight);
-
-   // interpolation of depth values
-   //parallaxHeight = curLayerHeight + prevH * weight + nextH * (1.0 - weight);
-
-   // return result
-   return finalTexCoords;
+	vec2 finalTexCoords = T;
+
+	// Calculate the parallax offset vector max length.
+	// This is equivalent to the tangent of the angle between the
+	// viewer position and the fragment location.
+	float fParallaxLimit = -length( V.xy ) / V.z;
+
+	// Scale the parallax limit according to heightmap scale.
+	fParallaxLimit *= 0.04f;						
+
+	// Calculate the parallax offset vector direction and maximum offset.
+	vec2 vOffsetDir = normalize( V.xy );
+	vec2 vMaxOffset = vOffsetDir * fParallaxLimit;
+
+	// Calculate the geometric surface normal vector, the vector from
+	// the viewer to the fragment, and the vector from the fragment
+	// to the light.
+	vec3 N = normalize( normal );
+	vec3 E = normalize( V );
+
+	// Calculate how many samples should be taken along the view ray
+	// to find the surface intersection.  This is based on the angle
+	// between the surface normal and the view vector.
+	float nNumSamples2 = mix( 20, 10, dot( E, N ) );
+	int nNumSamples = int(nNumSamples2);
+	
+	// Specify the view ray step size.  Each sample will shift the current
+	// view ray by this amount.
+	float fStepSize = 1.0 / nNumSamples;
+
+	// Calculate the texture coordinate partial derivatives in screen
+	// space for the tex2Dgrad texture sampling instruction.
+	vec2 dx = dFdx( T );
+	vec2 dy = dFdy( T );
+
+	// Initialize the starting view ray height and the texture offsets.
+	float fCurrRayHeight = 1.0;	
+	vec2 vCurrOffset = vec2( 0, 0 );
+	vec2 vLastOffset = vec2( 0, 0 );
+
+	float fLastSampledHeight = 1;
+	float fCurrSampledHeight = 1;
+
+	int nCurrSample = 0;
+
+	while ( nCurrSample < nNumSamples )
+	{
+		// Sample the heightmap at the current texcoord offset.  The heightmap 
+		// is stored in the alpha channel of the height/normal map.
+		//fCurrSampledHeight = tex2Dgrad( NH_Sampler, IN.texcoord + vCurrOffset, dx, dy ).a;
+		fCurrSampledHeight = getHeight(T + vCurrOffset, dx, dy); //NormalHeightMap.SampleGrad( LinearSampler, IN.texcoord + vCurrOffset, dx, dy ).a;
+
+		// Test if the view ray has intersected the surface.
+		if ( fCurrSampledHeight > fCurrRayHeight )
+		{
+			// Find the relative height delta before and after the intersection.
+			// This provides a measure of how close the intersection is to 
+			// the final sample location.
+			float delta1 = fCurrSampledHeight - fCurrRayHeight;
+			float delta2 = ( fCurrRayHeight + fStepSize ) - fLastSampledHeight;
+			float ratio = delta1/(delta1+delta2);
+
+			// Interpolate between the final two segments to 
+			// find the true intersection point offset.
+			vCurrOffset = (ratio) * vLastOffset + (1.0-ratio) * vCurrOffset;
+			
+			// Force the exit of the while loop
+			nCurrSample = nNumSamples + 1;	
+		}
+		else
+		{
+			// The intersection was not found.  Now set up the loop for the next
+			// iteration by incrementing the sample count,
+			nCurrSample++;
+
+			// take the next view ray height step,
+			fCurrRayHeight -= fStepSize;
+			
+			// save the current texture coordinate offset and increment
+			// to the next sample location, 
+			vLastOffset = vCurrOffset;
+			vCurrOffset += fStepSize * vMaxOffset;
+
+			// and finally save the current heightmap height.
+			fLastSampledHeight = fCurrSampledHeight;
+		}
+	}
+
+	// Calculate the final texture coordinate at the intersection point.
+	vec2 vFinalCoords = T + vCurrOffset;
+
+	// Use the final texture coordinates to get the normal vector, then 
+	// expand it from [0,1] to [-1,1] range.
+	//vec4 vFinalNormal = NormalHeightMap.Sample( LinearSampler, vFinalCoords ); //.a;
+		
+	// Sample the colormap at the final intersection point.
+	//vec4 vFinalColor = ColorMap.Sample( LinearSampler, vFinalCoords );
+
+	// Expand the final normal vector from [0,1] to [-1,1] range.
+	//vFinalNormal = vFinalNormal * 2.0f - 1.0f;
+
+	// Shade the fragment based on light direction and normal.
+	//vec3 vAmbient = vFinalColor.rgb * 0.1f;
+	//vec3 vDiffuse = vFinalColor.rgb * max( 0.0f, dot( L, vFinalNormal.xyz ) ) * 0.5f;
+	//vFinalColor.rgb = vAmbient + vDiffuse;
+
+	//OUT.color = vFinalColor;
+
+	return vFinalCoords;
 }
 
-vec2 parallaxOcclusionMapping2(vec2 p_texCoords, vec3 p_viewDir)
+vec2 parallaxOcclusionMapping(vec2 texCoords, vec3 viewDir, float p_LOD)
 {
-	float distanceToFrag = length(fragPos - cameraPosVec);
-	
-	if(distanceToFrag > 29.0)
-		return p_texCoords;
-	
-    // number of depth layers
-    const float minLayers = 10;
-    const float maxLayers = 15;
-    float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), p_viewDir)));
-	
-	if(distanceToFrag > 15.0)
-		numLayers = min(((30.0 - distanceToFrag) / 30.0), 1.0) * numLayers;
-		
+	// number of depth layers
+    const float minLayers = 15;
+    const float maxLayers = 20;
+    float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir))) * p_LOD;  
     // calculate the size of each layer
     float layerDepth = 1.0 / numLayers;
     // depth of current layer
     float currentLayerDepth = 0.0;
     // the amount to shift the texture coordinates per layer (from vector P)
-    vec2 P = p_viewDir.xy / p_viewDir.z * 0.02;
+    vec2 P = viewDir.xy / viewDir.z * parallaxScale; 
     vec2 deltaTexCoords = P / numLayers;
   
     // get initial values
-    vec2  currentTexCoords     = p_texCoords;
-    float currentDepthMapValue = texture(heightTexture, currentTexCoords).r;
-	float previousDepth = currentDepthMapValue;
+    vec2  currentTexCoords     = texCoords;
+    float currentDepthMapValue = getHeight(currentTexCoords);
       
     while(currentLayerDepth < currentDepthMapValue)
     {
         // shift texture coordinates along direction of P
         currentTexCoords -= deltaTexCoords;
         // get depthmap value at current texture coordinates
-        currentDepthMapValue = texture(heightTexture, currentTexCoords).r;  
-		
-		previousDepth = currentDepthMapValue;
+        currentDepthMapValue = getHeight(currentTexCoords);  
         // get depth of next layer
         currentLayerDepth += layerDepth;  
     }
@@ -342,8 +313,7 @@ vec2 parallaxOcclusionMapping2(vec2 p_texCoords, vec3 p_viewDir)
 
     // get depth after and before collision for linear interpolation
     float afterDepth  = currentDepthMapValue - currentLayerDepth;
-    float beforeDepth = texture(heightTexture, prevTexCoords).r - currentLayerDepth + layerDepth;
-    //float beforeDepth = previousDepth - currentLayerDepth + layerDepth;
+    float beforeDepth = getHeight(prevTexCoords) - currentLayerDepth + layerDepth;
  
     // interpolation of texture coordinates
     float weight = afterDepth / (afterDepth - beforeDepth);
@@ -352,458 +322,49 @@ vec2 parallaxOcclusionMapping2(vec2 p_texCoords, vec3 p_viewDir)
     return finalTexCoords;
 }
 
-/*vec2 distanceFragment(vec2 p_texCoords, vec3 p_viewDir)
-{
-//(v2fConnector v2f,
-
-  //uniform sampler2D colorTex,
-
-  //uniform sampler2D normalTex,
-
-  //uniform sampler3D distanceTex,
-
-  //uniform float3 normalizationFactor)
-
-//{
-  //f2fConnector f2f;
-
-  // Normalize the offset vector in texture space.
-  // The normalization factor ensures we are normalized with respect
-  // to a distance which is defined in terms of pixels.
-  float3 offset = normalize(p_viewDir);
-  //offset *= normalizationFactor;
-
-  float3 texCoord = p_texCoords;
-
-  // March a ray
-  for(int i = 0; i < 10; i++) 
-  {
-    float dist = texture(heightTexture, texCoord).r;
-    texCoord += dist * offset;
-  }
-
-  // Compute derivatives of unperturbed texcoords.
-  // This is because the offset texcoords will have discontinuities
-  // which lead to incorrect filtering.
-  vec2 dx = dFdx(p_texCoords);
-  vec2 dy = dFdy(p_texCoords);
-
-  // Do bump-mapped lighting in tangent space.
-  // 'normalTex' stores tangent-space normals remapped
-  // into the range [0, 1].
-  vec3 tanNormal = 2 * f3tex2D(normalTex, texCoord.xy, dx, dy) - 1;
-  vec3 tanLightVec = normalize(v2f.tanLightVec);
-  float diffuse = dot(tanNormal, tanLightVec);
-
-  // Multiply diffuse lighting by texture color
-  f2f.COL.rgb = diffuse * f3tex2D(colorTex, texCoord.xy, dx, dy);
-  f2f.COL.a = 1;
-
-  return f2f;
-}*/
-
-vec2 steepParallax(vec2 p_texCoords, vec3 p_viewDir)
-{
-	// We are at height bumpScale.  March forward until we hit a hair or the 
-    // base surface.  Instead of dropping down discrete y-voxels we should be
-    // marching in texels and dropping our y-value accordingly (TODO: fix)
-    float height = 1.0;
-
-    // Number of height divisions
-    float numSteps = 5;
-
-    /** Texture coordinate marched forward to intersection point */
-    vec2 offsetCoord = p_texCoords.xy;
-    vec4 NB = texture2D(heightTexture, offsetCoord);
-
-    vec3 tsE = normalize(p_viewDir);
-
-    // Increase steps at oblique angles
-    // Note: tsE.z = N dot V
-    numSteps = mix(numSteps*2, numSteps, p_viewDir.z);
-
-    // We have to negate tsE because we're walking away from the eye.
-    //vec2 delta = vec2(-_tsE.x, _tsE.y) * bumpScale / (_tsE.z * numSteps);
-    float step;
-    vec2 delta;
-
-
-    // Constant in z
-    step = 1.0 / numSteps;
-    delta = vec2(-p_viewDir.x, p_viewDir.y) * 1.0 / (p_viewDir.z * numSteps);
-
-        // Can also step along constant in xy; the results are essentially
-        // the same in each case.
-        // delta = 1.0 / (25.6 * numSteps) * vec2(-tsE.x, tsE.y);
-        // step = tsE.z * bumpScale * (25.6 * numSteps) / (length(tsE.xy) * 400);
-
-    while (NB.r < height) 
-	{
-        height -= step;
-        offsetCoord += delta;
-        NB = texture2D(heightTexture, offsetCoord);
-    }
-
-    height = NB.r;
-	
-	return offsetCoord;
-	
-    // Choose the color at the location we hit
-    //const vec3 color = texture2D(texture, offsetCoord).rgb;
-/*
-    tsL = normalize(tsL);
-
-    // Use the normals out of the bump map
-    vec3 tsN = NB.xyz * 2 - 1;
-
-    // Smooth normals locally along gradient to avoid making slices visible.
-    // The magnitude of the step should be a function of the resolution and
-    // of the bump scale and number of steps.
-//    tsN = normalize(texture2D(normalBumpMap, offsetCoord + vec2(tsN.x, -tsN.y) * mipScale).xyz * 2 - 1 + tsN);
-
-    const vec3 tsH = normalize(tsL + normalize(_tsE));
-
-    const float NdotL = max(0, dot(tsN, tsL));
-    const float NdotH = max(0, dot(tsN, tsH));
-    float spec = NdotH * NdotH;
-
-    vec3 lightColor = vec3(1.5, 1.5, 1) * 0.9;
-    vec3 ambient = vec3(0.4,0.4,0.6) * 1.4;
-
-    float selfShadow = 0;
-
-    // Don't bother checking for self-shadowing if we're on the
-    // back side of an object.
-    if (NdotL > 0) {
-
-        // Trace a shadow ray along the light vector.
-        const int numShadowSteps = mix(60,5,tsL.z);
-        step = 1.0 / numShadowSteps;
-        delta = vec2(tsL.x, -tsL.y) * bumpScale / (numShadowSteps * tsL.z);
-
-            // We start one iteration out to avoid shadow acne 
-            // (could start bumped a little without going
-            // a whole iteration).
-            height = NB.a + step * 0.1;
-
-            while ((NB.a < height) && (height < 1)) {
-                height += step;
-                offsetCoord += delta;
-                NB = texture2D(normalBumpMap, offsetCoord);
-            }
-
-            // We are in shadow if we left the loop because
-            // we hit a point
-            selfShadow = (NB.a < height);
-
-            // Shadows will make the whole scene darker, so up the light contribution
-            lightColor = lightColor * 1.2;
-        }
-        }
-
-        gl_FragColor.rgb = 
-            color * ambient + color * NdotL * selfShadow * lightColor;*/
-}
-
-vec2 steepParallax2(vec2 p_texCoords, vec3 p_viewDir)
-{
-	/*   // diffuse 
-    uniform sampler2D tex0;
-     //normal map and height map 
-    uniform sampler2D tex1;
-     
-    varying vec3 Normal;
-    varying vec3 Tangent;
-    varying vec3 Binormal;
-     
-    varying vec3 LightDirectionTS;
-    varying vec3 EyeDirectionTS;
-     
-    varying float Depth;
-     
-    vec3 GetNormal( vec2 coord )
-    {
-    vec3 ret = texture2D( tex1, coord ).xyz;
-    ret.xy = ret.xy * 2.0 - 1.0;
-     
-    ret.y *= -1.0;
-    return normalize( ret );
-    }
-     
-    float GetHeight( vec2 coord )
-    {
-    return texture2D( tex1, coord ).w;
-    }
-     
-    void main()
-    {*/
-	
-	float Depth = 1.0;
-	//vec3 LightDirection = normalize( LightDirectionTS );
-	vec3 EyeDirection = normalize( p_viewDir );
-	vec3 EyeRay = p_viewDir;
-	vec2 startCoord = p_texCoords;
-	vec2 newCoord = startCoord;
- 
-	// Common for Parallax
-	vec2 ParallaxXY = ( EyeRay ).xy/-EyeRay.z * Depth;
-	
-	// Steep Parallax
-	float Step = 0.01;
-	vec2 dt = ParallaxXY * Step;
-	float Height =0.5;
-	float oldHeight = 0.5;
-	vec2 Coord = startCoord;
-	vec2 oldCoord = Coord;
-	float HeightMap = texture2D(heightTexture, Coord).r;
-	float oldHeightMap = HeightMap;
- 
-	while( HeightMap < Height )
-	{
-		oldHeightMap = HeightMap;
-		oldHeight = Height;
-		oldCoord = Coord;
- 
-		Height -= Step;
-		Coord += dt;
-		HeightMap = texture2D(heightTexture, Coord).r;
-	}
-	//if( Coord.s <= 0.0 || Coord.t <= 0.0 || Coord.s >= 1.0 || Coord.t >= 1.0 )
-	// discard;
-	Coord = (Coord + oldCoord) * 0.5;
-	if( Height < 0.0 )
-	{
-		Coord = oldCoord;
-		Height = 0.0;
-	}
-	// else // interpolation
-	// {
-	// float ds = (GetHeight( oldCoord ) - oldHeight) * StepXYlength / ( -Step - oldHeightMap + HeightMap );
-	// Coord = oldCoord + dt * ds;
-	// Height = oldHeight + -Step/StepXYlength * ds;
-	// }
-	newCoord = Coord;
-	return Coord;
- 
-	/*vec4 colorMap = vec4( texture2D( tex0, newCoord ).xyz, 1.0 );
-	float heightMap = GetHeight( newCoord );
-	vec3 normalMap = GetNormal( newCoord );
- 
-	// Ambient
-	vec4 ambient_color = (gl_FrontLightModelProduct.sceneColor) +
-	(colorMap * gl_LightSource[0].ambient * gl_FrontMaterial.ambient);
- 
-	// Diffuse
-	float lambertTerm = max( dot( normalMap, LightDirection ), 0.0 );
-	vec4 diffuse_color = colorMap * gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * lambertTerm;
- 
-	// Specular
-	vec3 reflectDirection = 2.0 * dot( normalMap, LightDirection ) * normalMap - LightDirection; // in Tangen Space
- 
-	float specular = pow( max( dot(reflectDirection, EyeDirectionTS), 0.1 ), gl_FrontMaterial.shininess );
-	vec4 specular_color = gl_LightSource[0].specular * gl_FrontMaterial.specular * specular;
- 
-	// if( newCoord.s < 0.0 || newCoord.t < 0.0 || newCoord.s > 1.0 || newCoord.t > 1.0 )
-	// {
-	// discard;
-	// }
- 
-	gl_FragColor = vec4( ambient_color.xyz + diffuse_color.xyz + specular_color.xyz, 1.0 );*/
-}
-
 vec2 simpleParallaxMapping(vec2 p_texCoords, vec3 p_viewDir)
 { 
     //float height =  texture(heightTexture, p_texCoords).r;     
     //return p_texCoords - (p_viewDir.xy ) * (height * 0.01);
 	
-	float height =  texture(heightTexture, p_texCoords).r;    
+	float height =  getHeight(p_texCoords);    
     vec2 p = p_viewDir.xy  * (height * 0.02);
     return p_texCoords - p;
-	
 }
 
 void main(void)
-{	
-	// Simple parallax mapping (offset texture coordinates based on height)
-	//float height = texture(heightTexture, texCoord).r;
-	//float v = height * 0.04 - 0.02;
-	//vec2 newCoords = texCoord + (viewDir.xy * v);
-	
-    //vec3 viewDir = normalize(fs_in.TangentViewPos - fs_in.TangentFragPos);
-	
-    //vec3 viewDir2 = normalize((TBN * cameraPosVec) - (TBN * fragPos));
-   
-	//vec3 viewDir2 = normalize(TBN * (cameraPosVec - fragPos).xyz);
-	//viewDir2.x = -viewDir2.x;
-	//vec3 viewDir2 = normalize(cameraPosVec - fragPos);
-	//vec3 viewDir2 = normalize(TangentViewPos - TangentFragPos);
-	//vec3 viewDir2 = normalize(viewDir);
-	
-	//vec2 newCoords = parallaxMapping(viewDir, texCoord);
-	//vec2 newCoords = reliefParallaxMapping2(texCoord, viewDir);
-	//vec2 newCoords = texCoord;
-	
-	//vec2 newCoords = simpleParallaxMapping(texCoord, viewDir, texture(heightTexture, texCoord).r);
-	//vec3 et = viewDir;
+{ 	
+	vec3 viewDir = tangentCameraPos - tangentFragPos;
+	float distanceToFrag = length(viewDir);
+	viewDir = normalize(viewDir);
 	
-	//float h = 0.04 * (1.0 - texture(heightTexture, texCoord).r) + 0.02;
-
-                                                       // now offset texture coordinates
-                                                       // with height
-    //vec2 tex = texCoord - et.xy * h;// / et.z;
-	
-	//float height = texture(heightTexture, texCoord.st).r;
-	//float v = height * 0.04 - 0.02;
-	//tex = texCoord + (viewDir.xy * v);
+	vec2 newCoords = texCoord;
 	
-	/*const float numSteps  = 10.0;
-
-	//vec3 et = vec3 ( dot ( e, t ), dot ( e, b ), dot ( e, n ) );
-    float step   = 1.0 / numSteps;
-    vec2  dtex   = et.xy * 0.1 / ( numSteps * et.z );  // adjustment for one layer
-    float height = 1.0;                                  // height of the layer
-    vec2  tex    = texCoord.xy;                   // our initial guess
-    float h      = texture2D ( heightTexture, tex ).r;       // get height
-
-    if ( h < height )
-    {
-        height -= step;
-        tex    += dtex;
-        h       = texture2D ( heightTexture, tex ).r;
-
-        if ( h < height )
-        {
-            height -= step;
-            tex    += dtex;
-            h       = texture2D ( heightTexture, tex ).r;
-
-            if ( h < height )
-            {
-                height -= step;
-                tex    += dtex;
-                h       = texture2D ( heightTexture, tex ).r;
-
-                if ( h < height )
-                {
-                    height -= step;
-                    tex    += dtex;
-                    h       = texture2D ( heightTexture, tex ).r;
-
-                    if ( h < height )
-                    {
-                        height -= step;
-                        tex    += dtex;
-                        h       = texture2D ( heightTexture, tex ).r;
-                    }
-                }
-            }
-        }
-    }*/
+	//if(distanceToFrag > 29.0)
+	//	return p_texCoords;
 	
-	//vec2 newCoords = tex;
+    // number of depth layers
 	
-	/*float bumpScale = -10.0;
-     
-    // normalize the other tangent space vectors
-    vec3 viewVector = normalize(TangentViewPos - TangentFragPos);
-     
-    vec3 tsE = normalize(TangentViewPos);
- 
-    const float numSteps = 30.0; // How many steps the UV ray tracing should take
-    float height = 1.0;
-    float step = 1.0 / numSteps;
- 
-    vec2 offset = texCoord;
-    vec4 NB = texture2D(heightTexture, offset);
- 
-    vec2 delta = vec2(tsE.x, tsE.y) * bumpScale / (tsE.z * numSteps);
- 
-    // find UV offset
-    for (float i = 0.0; i < numSteps; i++) 
+	//if(distanceToFrag > 5.0)
+	//	numLayers = min(((20.0 - distanceToFrag) / 20.0), 1.0) * numLayers;
+	newCoords = parallaxOcclusionMapping(texCoord, viewDir, 1.0);
+	if(distanceToFrag < 9.90)
 	{
-        if (NB.a < height) 
-		{
-            height -= step;
-            offset += delta;
-            NB = texture2D(heightTexture, offset);
-        } 
-		else 
-		{
-            break;
-        }
-    }
-	
-	vec2 newCoords = offset;*/
-	
-    /*vec3 color = texture2D(base, offset).rgb;
-     
-     
-        vec3 normal = texture2D(map, offset).rgb * 2.0 - 1.0;
- 
-    // calculate this pixel's lighting
-        float nxDir = max(0.0, dot(normal, lightVector));
-        vec3 ambient = ambientColor * color;
- 
-        float specularPower = 0.0;
-        if(nxDir != 0.0)
-        {
-                vec3 halfVector = normalize(lightVector + viewVector);
-                float nxHalf = max(0.0, dot(normal, halfVector));
-                specularPower = pow(nxHalf, shininess);
-        }
-        vec3 specular = specularColor * specularPower;
-     
-     
-        vec3 pixel_color = ambient + (diffuseColor * nxDir * color) + specular;
-     
-    // find shadowing if enabled
-        if (shadow == 1.0) {
-            vec2 shadow_offset = offset;
-        vec3 tsH = normalize(lightVector + tsE);
-        float NdotL = max(0.0, dot(normal, lightVector));
-         
-        float selfShadow = 0.0;
-         
-        if (NdotL > 0.0) {
-             
-            const float numShadowSteps = 10.0;
-            step = 1.0 / numShadowSteps;
-            delta = vec2(lightVector.x, lightVector.y) * bumpScale / (numShadowSteps * lightVector.z);
-             
-            height = NB.a + step * .1;
-             
-            for (float i = 0.0; i < numShadowSteps; i++) {
-                if (NB.a < height && height < 1.0) {
-                    height += step;
-                    shadow_offset += delta;
-                    NB = texture2D(map, shadow_offset);
-                } else {
-                    break;
-                }
-            }
-             
-            selfShadow = float(NB.a < height);
-             
-        }
-         
-        if (selfShadow == 0.0) {
-        pixel_color *= .5;
-        }
-    }
-     
-    gl_FragColor = vec4(pixel_color, 1.0);
-     
-    if (offset.x < 0.0 || offset.x > 1.0 || offset.y < 0.0 || offset.y > 1.0) {
-        gl_FragColor.a = 0.0;
-    }*/
-	
-	vec3 viewDir = normalize(TBN * (cameraPosVec - fragPos).xyz * vec3(-1.0, 1.0, 1.0));
-	vec2 newCoords = texCoord;
+		float LOD = min(((10.0 - distanceToFrag) / 10.0), 1.0);
+		float LOD2 = clamp((distanceToFrag - 8.0) / 2.0, 0.0, 1.0);
 	
+		//if(parallaxScale > HEIGHT_SCALE_THRESHOLD)
+		//	newCoords = mix(parallaxOcclusionMapping(texCoord, viewDir, LOD), texCoord, 1.0 - LOD);
+	}
 	//if(distanceToFrag < 30.0)
-	newCoords = parallaxOcclusionMapping2(texCoord, viewDir);
+	//	newCoords = parallaxMappingNew2(texCoord, viewDir);
 	//vec2 newCoords = texCoord;
 	
+	// discards a fragment when sampling outside default texture region (fixes border artifacts)
+    //if(newCoords.x > 1.0 || newCoords.y > 1.0 || newCoords.x < 0.0 || newCoords.y < 0.0)
+    //    discard;
+	//vec2 testColor = parallaxMappingNew(texCoord, eye);
+	
 	// Get diffuse color
 	vec4 diffuse = texture(diffuseTexture, newCoords).rgba;
 	
@@ -811,10 +372,9 @@ void main(void)
 	if(diffuse.a < alphaThreshold)
 		discard;
 	
-	// Get gloss and specular values and emissive color
-	//float gloss = texture(glossTexture, newCoords).r;
-	float gloss = texture(specularTexture, newCoords).g;
-	float specular = texture(specularTexture, newCoords).r;
+	// Get roughness and metalness values, and emissive color
+	float roughness = getRoughness(newCoords);
+	float metalness = getMetalness(newCoords);
 	vec4 emissiveColor = texture(emissiveTexture, newCoords).rgba;
 	
 	// Apply emissive color only if it's above the threshold
@@ -830,11 +390,12 @@ void main(void)
 	
 	// Write diffuse color to the diffuse buffer
 	diffuseBuffer = diffuse;
+	// Write roughness, metalness to the material properties buffer
+	matPropertiesBuffer = vec4(roughness, metalness, 1.0, 1.0);
 	// Write emissive color into the emissive buffer
 	emissiveBuffer = emissiveColor;
-	// Write fragment's position in world space	to the position buffer, write gloss value in alpha channel
-	positionBuffer = vec4(fragPos, gloss);
-	// Perform normal mapping and write the new normal to the normal buffer, write specular value in alpha channel
-	normalBuffer = vec4(TBN * normalize(texture(normalTexture, newCoords).rgb * 2.0 - 1.0), specular);
-	//normalBuffer = vec4(normalize(normal), specular);
-}
+	// Write fragment's position in world space	to the position buffer
+	positionBuffer = fragPos;
+	// Perform normal mapping and write the new normal to the normal buffer
+	normalBuffer = TBN * normalize(texture(normalTexture, newCoords).rgb * 2.0 - 1.0);
+}

+ 22 - 7
Praxis3D/Data/Shaders/geometryPass.vert

@@ -1,4 +1,4 @@
-#version 330 core
+#version 430 core
 
 // Mesh buffers
 layout(location = 0) in vec3 vertexPosition;
@@ -8,29 +8,44 @@ layout(location = 3) in vec3 vertexTangent;
 layout(location = 4) in vec3 vertexBitangent;
 
 // Variables passed to fragment shader
-out vec3 fragPos;
+out mat3 TBN;
 out vec2 texCoord;
+out vec3 fragPos;
 out vec3 normal;
-out mat3 TBN;
+out vec3 tangentFragPos;
+out vec3 tangentCameraPos;
+out float parallaxScale;
 
 uniform mat4 MVP;
 uniform mat4 modelMat;
+uniform mat4 viewMat;
 uniform mat4 modelViewMat;
 uniform mat4 projMat;
+uniform vec3 cameraPosVec;
 uniform float textureTilingFactor;
+uniform float heightScale;
 
 void main(void)
 {		
 	// Multiply position and normal by model matrix (to convert them into world space)
     fragPos = vec3(modelMat * vec4(vertexPosition, 1.0));
-	normal = normalize(vec3(modelMat * vec4(vertexNormal, 0.0)));
+	normal = normalize(mat3(modelMat) * vertexNormal);
+	
+	// Copy the height scale value
+	parallaxScale = heightScale;
 	
 	// Multiply texture coordinates by the tiling factor. The higher the factor, the denser the tiling
 	texCoord = textureCoord * textureTilingFactor;
+		
+	// Compute TBN matrix
+    vec3 T = normalize(mat3(modelMat) * vertexTangent);
+    vec3 B = normalize(mat3(modelMat) * vertexBitangent);
 	
-	// Compute TBN matrix (method 1)
-	mat3 normalMatrix = transpose(inverse(mat3(modelMat)));
-	TBN = mat3(normalMatrix * vertexTangent, normalMatrix * vertexBitangent, normalMatrix * vertexNormal);
+	TBN = transpose(inverse(mat3(T, B, normal)));
+	mat3 TBN2 = transpose((mat3(T, B, normal)));
 	
+	tangentCameraPos = TBN2 * cameraPosVec;
+	tangentFragPos = TBN2 * fragPos;
+		
 	gl_Position = MVP * vec4(vertexPosition, 1.0);
 }

+ 11 - 8
Praxis3D/Data/Shaders/geometryPassInf.frag

@@ -1,4 +1,4 @@
-#version 450 core
+#version 430 core
 
 #define HEIGHT_SCALE_THRESHOLD 0.001
 
@@ -6,10 +6,11 @@
 //precision highp float;
 
 // Geometry buffers
-layout(location = 0) out vec4 positionBuffer;
+layout(location = 0) out vec3 positionBuffer;
 layout(location = 1) out vec4 diffuseBuffer;
-layout(location = 2) out vec4 normalBuffer;
+layout(location = 2) out vec3 normalBuffer;
 layout(location = 3) out vec4 emissiveBuffer;
+layout(location = 4) out vec4 matPropertiesBuffer;
 
 // Variables from vertex shader
 in mat3 TBN;
@@ -369,13 +370,15 @@ void main(void)
 	{
 		emissiveColor = vec4(0.0);
 	}
-		
+	
 	// Write diffuse color to the diffuse buffer
 	diffuseBuffer = diffuse;
+	// Write roughness, metalness to the material properties buffer
+	matPropertiesBuffer = vec4(roughness, metalness, 1.0, 1.0);
 	// Write emissive color into the emissive buffer
 	emissiveBuffer = emissiveColor;
-	// Write fragment's position in world space	to the position buffer, write roughness value in alpha channel
-	positionBuffer = vec4(fragPos, roughness);
-	// Perform normal mapping and write the new normal to the normal buffer, write metalness value in alpha channel
-	normalBuffer = vec4(TBN * normalize(texture(normalTexture, newCoords).rgb * 2.0 - 1.0), metalness);
+	// Write fragment's position in world space	to the position buffer
+	positionBuffer = fragPos;
+	// Perform normal mapping and write the new normal to the normal buffer
+	normalBuffer = TBN * normalize(texture(normalTexture, newCoords).rgb * 2.0 - 1.0);
 }

+ 1 - 1
Praxis3D/Data/Shaders/geometryPassInf.vert

@@ -1,4 +1,4 @@
-#version 450 core
+#version 430 core
 
 // Mesh buffers
 layout(location = 0) in vec3 vertexPosition;

+ 904 - 0
Praxis3D/Data/Shaders/lightPass 3.frag

@@ -0,0 +1,904 @@
+#version 430 core
+
+#define MAX_NUM_POINT_LIGHTS 20
+#define MAX_NUM_SPOT_LIGHTS 10
+
+layout(location = 0) out vec4 emissiveBuffer;
+layout(location = 1) out vec3 finalBuffer;
+
+//in vec2 texCoord;
+
+struct DirectionalLight
+{
+    vec3 m_color;
+    vec3 m_direction;
+    float m_intensity;
+};
+
+struct PointLight
+{
+    vec3 m_color;
+    vec3 m_position;
+	
+    float m_attenConstant;
+    float m_attenLinear;
+    float m_attenQuad;
+    float m_intensity;
+};
+struct SpotLight
+{
+    vec3 m_color;
+    vec3 m_position;
+    vec3 m_direction;
+	
+    float m_attenConstant;
+    float m_attenLinear;
+    float m_attenQuad;
+	
+    float m_intensity;
+    float m_cutoffAngle;
+};
+
+uniform sampler2D positionMap;
+uniform sampler2D diffuseMap;
+uniform sampler2D normalMap;
+uniform sampler2D matPropertiesMap;
+
+uniform samplerCube staticEnvMap;
+
+uniform mat4 modelViewMat;
+uniform mat4 viewMat;
+uniform vec3 cameraPosVec;
+uniform ivec2 screenSize;
+
+uniform int numPointLights;
+uniform int numSpotLights;
+
+uniform DirectionalLight directionalLight;
+
+// Using uniform buffer objects to pass light arrays and std140 layout for consistent variable spacing inside the buffer.
+// Array size is fixed, but is updated partially, with only the lights that are being used, passing number of lights as uniform.
+layout (std140) uniform PointLights
+{
+	PointLight pointLights[MAX_NUM_POINT_LIGHTS];
+};
+layout (std140) uniform SpotLights
+{
+	SpotLight spotLights[MAX_NUM_SPOT_LIGHTS];
+};
+
+vec3 worldPos;
+vec3 normal;
+vec3 fragmentToEye;
+float roughnessSqrt;
+
+// set important material values
+float roughnessVar = 0.1; // 0.1	// 0 : smooth, 1: rough
+//float roughnessVar = 0.8;
+float F0 = 0.02;//0.171968833;//1.0; 			// fresnel reflectance at normal incidence
+vec3 F0vec;
+//float k = 0.01; 				// fraction of diffuse reflection (specular reflection = 1 - k)
+float k = 0.8; //0.5
+float metallic;
+vec3 envColor;
+
+float ref_at_norm_incidence = F0;
+vec3 viewer;
+
+float saturate(float p_value)
+{
+	return clamp(p_value, 0.0f, 1.0f);
+}
+
+float G1V(float p_dotNV, float p_k)
+{
+    return 1.0f / (p_dotNV * (1.0f - p_k) + p_k);
+}
+
+float MicroFacetDistr_GGX(vec3 p_normal, vec3 p_halfVec, float p_roughnessSqrt)
+{
+	float NdotH = dot(p_normal, p_halfVec);
+	if(NdotH > 0.0)
+	{
+		float NdotHSqrt = NdotH * NdotH;
+		float microfacetDstrb = NdotHSqrt * p_roughnessSqrt + (1.0 - NdotHSqrt);
+		return (NdotH * p_roughnessSqrt) / (3.14 * microfacetDstrb * microfacetDstrb);
+	}
+	else
+		return 0.0;
+}
+
+float GeometryAtten_GGX(vec3 p_fragToEye, vec3 p_normal, vec3 p_halfVec, float p_roughnessSqrt)
+{
+    float VdotH = clamp(dot(p_fragToEye, p_halfVec), 0.0, 1.0);
+    float VdotN = clamp(dot(p_fragToEye, p_normal), 0.0, 1.0);
+	
+	float geoFactor = (VdotH / VdotN);
+	if(geoFactor > 0.0)
+	{
+		float VdotHSqrt = VdotH * VdotH;
+		float geoAtt = (1.0 - VdotHSqrt) / VdotHSqrt;
+		return 2.0 / (1.0 + sqrt(1.0 + p_roughnessSqrt * geoAtt));
+	}
+	else
+		return 0.0;
+}
+
+vec3 Fresnel_Schlick(float p_cosT, vec3 p_F0)
+{
+	return F0 + (vec3(1.0) - F0) * pow(1.0 - p_cosT, 5.0);
+}
+
+vec3 calcLightColor2(vec3 p_lightColor, vec3 p_lightDirection)
+{
+	//float NoV = saturate( dot(normal, V) );
+	float NoV = abs( dot(normal, fragmentToEye) ) + 0.00001;//1e-5;
+
+	// Diffuse_Lambert
+	//Shared.DiffuseMul = DiffuseColor * (1.0 / 3.14);
+
+	// D_GGX, Vis_SmithJointApprox
+	float m = roughnessVar * roughnessVar;
+	float m2 = m * m;
+	float SpecularMul = (0.5 / 3.14) * m2;
+	float VisMad = ( 2 * NoV * ( 1 - m ) + m, NoV * m );
+	
+	// F_Schlick
+	//SpecularMul *= saturate( 50.0 * k );
+	return vec3(1.0);
+}
+
+vec3 calcLightColor3(vec3 p_lightColor, vec3 p_lightDirection)
+{
+	// Compute any aliases and intermediary values
+    // -------------------------------------------
+	
+	vec3 half_vector = normalize(fragmentToEye - p_lightDirection );
+    float NdotL        = clamp( dot( normal, -p_lightDirection ), 0.0, 1.0 );
+    float NdotH        = clamp( dot( normal, half_vector ), 0.0, 1.0 );
+    float NdotV        = clamp( dot( normal, viewer ), 0.0, 1.0 );
+    float VdotH        = clamp( dot( viewer, half_vector ), 0.0, 1.0 );
+    float r_sq         = roughnessVar * roughnessVar;
+ 
+    // Evaluate the geometric term
+    // --------------------------------
+    float geo_numerator   = 2.0f * NdotH;
+    float geo_denominator = VdotH;
+ 
+    float geo_b = (geo_numerator * NdotV ) / geo_denominator;
+    float geo_c = (geo_numerator * NdotL ) / geo_denominator;
+    float geo   = min( 1.0f, min( geo_b, geo_c ) );
+ 
+    // Now evaluate the roughness term
+    // -------------------------------
+    float roughness;
+    
+	float roughness_a = 1.0f / ( 4.0f * r_sq * pow( NdotH, 4 ) );
+	float roughness_b = NdotH * NdotH - 1.0f;
+	float roughness_c = r_sq * NdotH * NdotH;
+	roughness = roughness_a * exp( roughness_b / roughness_c );
+ 
+    // Next evaluate the Fresnel value
+    // -------------------------------
+    float fresnel = pow( 1.0f - VdotH, 5.0f );
+    fresnel *= ( 1.0f - F0 );
+    fresnel += F0;
+ 
+    // Put all the terms together to compute
+    // the specular term in the equation
+    // -------------------------------------
+    float Rs_numerator   = ( fresnel * geo * roughness );
+    float Rs_denominator  = NdotV * NdotL;
+    float Rs             = Rs_numerator/ Rs_denominator;
+  
+    float specular = (fresnel * geo * roughness) / (NdotV * NdotL);
+    // Put all the parts together to generate
+    // the final colour
+    // --------------------------------------
+	
+	return p_lightColor * NdotL * specular;
+	
+    //float3 final = max(0.0f, NdotL) * (cSpecular * Rs + cDiffuse);
+ 
+    // Return the result
+    // -----------------
+    //return float4( final, 1.0f );
+}
+
+vec3 computePBRLighting(vec3 lightPos, vec3 lightColor, vec3 position, vec3 N, vec3 V, vec3 albedo, float roughness, vec3 F0) 
+{
+
+	float alpha = roughness*roughness;
+	vec3 L = normalize(lightPos - position);
+	vec3 H = normalize (V + L);
+
+	float dotNL = clamp (dot (N, L), 0.0, 1.0);
+	float dotNV = clamp (dot (N, V), 0.0, 1.0);
+	float dotNH = clamp (dot (N, H), 0.0, 1.0);
+	float dotLH = clamp (dot (L, H), 0.0, 1.0);
+
+	float D, vis;
+	vec3 F;
+
+	// NDF : GGX
+	float alphaSqr = alpha*alpha;
+	float pi = 3.1415926535;
+	float denom = dotNH * dotNH *(alphaSqr - 1.0) + 1.0;
+	D = alphaSqr / (pi * denom * denom);
+
+	// Fresnel (Schlick)
+	float dotLH5 = pow (1.0 - dotLH, 5.0);
+	F = F0 + (1.0 - F0)*(dotLH5);
+
+	// Visibility term (G) : Smith with Schlick's approximation
+	float k = alpha / 2.0;
+	vis = G1V (dotNL, k) * G1V (dotNV, k);
+
+	vec3 specular = /*dotNL **/ D * F * vis;
+
+	vec3 ambient = vec3(.01);
+
+	float invPi = 0.31830988618;
+	vec3 diffuse = (albedo * invPi);
+
+
+	return (diffuse + specular) * lightColor * dotNL ;
+}
+
+/*float SpecGGX(vec3 N, vec3 V, vec3 L, float roughness, float F0)
+{
+	float SqrRoughness = roughness*roughness;
+
+	vec3 H = normalize(V+L);
+
+	float NdotL = clamp(dot(N,L),0.0,1.0);
+	float NdotV = clamp(dot(N,V),0.0,1.0);
+	float NdotH = clamp(dot(N,H),0.0,1.0);
+	float LdotH = clamp(dot(L,H),0.0,1.0);
+
+	// Geom term
+	float RoughnessPow4 = SqrRoughness*SqrRoughness;
+	float pi = 3.14159;
+	float denom = NdotH * NdotH *(RoughnessPow4-1.0) + 1.0;
+	float D = RoughnessPow4/(pi * denom * denom);
+
+	// Fresnel term 
+	float LdotH5 = 1.0-LdotH;
+    LdotH5 = LdotH5*LdotH5*LdotH5*LdotH5*LdotH5;
+	float F = F0 + (1.0-F0)*(LdotH5);
+
+	// Vis term 
+	float k = SqrRoughness/2.0;
+	float Vis = G1V(NdotL,k)*G1V(NdotV,k);
+
+	float specular = NdotL * D * F * Vis;
+    
+	return specular;
+}*/
+
+vec3 LightingFuncGGX_REF(vec3 N, vec3 V, vec3 L, float roughness, vec3 F0)
+{
+    float alpha = roughness;//roughness*roughness;
+
+    vec3 H = normalize(V+L);
+
+    float dotNL = saturate(dot(N,L));
+    float dotNV = saturate(dot(N,V));
+    float dotNH = saturate(dot(N,H));
+    float dotLH = saturate(dot(L,H));
+
+    //float F, D, vis;
+	float D, vis;
+	vec3 F;
+
+    // D
+    float alphaSqr = alpha*alpha;
+    float pi = 3.14159f;
+    float denom = dotNH * dotNH *(alphaSqr-1.0) + 1.0f;
+    D = alphaSqr/(pi * denom * denom);
+
+    // F
+    float dotLH5 = pow(1.0f - dotLH, 5);
+	F = F0 + (vec3(1.0f) - F0) * (dotLH5);
+    //F = F0 + (1.0-F0)*(dotLH5);
+
+    // V
+    float k2 = alpha / 2.0f;
+    vis = G1V(dotNL, k2) * G1V(dotNV, k2);
+	
+	float metallic2 = (1.0f - metallic);// / 2.0f;
+	
+	vec3 specular;
+	
+	//if(metallic == 1.0f)
+	//{
+		specular = dotNL * D * F * vis;
+	//}
+	//else
+	//{
+		//specular = (dotNL) * (metallic2 + D * F * vis * (1.0 - metallic2));
+	//}
+	
+    //vec3 specular = (dotNL) * (metallic2 + D * F * vis * (1.0 - metallic2));
+	
+	//specular = ((1.0 - dotNL) * (1.0 - metallic2)) + D * F * vis;
+	//specular = ((1.0 - dotNL) * (1.0 - metallic2)) + (metallic2 + D * F * vis * (1.0 - metallic2));
+	
+    return specular;
+}
+
+float SpecGGX(vec3 N, vec3 V, vec3 L, float roughness, float F0 )
+{
+	float SqrRoughness = roughness*roughness;
+
+	vec3 H = normalize(V+L);
+
+	float NdotL = clamp(dot(N,L),0.0,1.0);
+	float NdotV = clamp(dot(N,V),0.0,1.0);
+	float NdotH = clamp(dot(N,H),0.0,1.0);
+	float LdotH = clamp(dot(L,H),0.0,1.0);
+
+	// Geom term
+	float RoughnessPow4 = SqrRoughness*SqrRoughness;
+	float pi = 3.14159;
+	float denom = NdotH * NdotH *(RoughnessPow4-1.0) + 1.0;
+	float D = RoughnessPow4/(pi * denom * denom);
+
+	// Fresnel term 
+	float LdotH5 = 1.0-LdotH;
+    LdotH5 = LdotH5*LdotH5*LdotH5*LdotH5*LdotH5;
+	float F = F0 + (1.0-F0)*(LdotH5);
+
+	// Vis term 
+	float k = SqrRoughness/2.0;
+	float Vis = G1V(NdotL,k)*G1V(NdotV,k);
+
+	float specular = NdotL * D * F * Vis;
+    
+	return specular;
+}
+
+vec3 calcLight(vec3 p_normal, vec3 p_fragToEye, vec3 p_lightColor, vec3 p_lightDirection, vec3 p_F0, float p_roughnessSqrt)
+{	
+	vec3 lightDir = -p_lightDirection;
+		
+	//float spec = SpecGGX(p_normal, p_fragToEye, lightDir, roughnessVar, F0);
+	vec3 spec = LightingFuncGGX_REF(p_normal, p_fragToEye, lightDir, roughnessSqrt, F0vec);
+	
+    float dif = dot(p_normal, lightDir);
+		
+	// Fresnel
+    float NdotV = clamp(dot(p_normal, p_fragToEye), 0.0, 1.0);
+	NdotV = pow(1.0 - NdotV, 5.0);
+	float Fresnel = metallic + (1.0 - metallic) * (NdotV);
+
+    // Tint lights
+    vec3 SpecColor = spec * p_lightColor;
+    vec3 DiffColor = dif * p_lightColor * (1.0 - Fresnel);
+	
+    vec3 lightSum = max(((DiffColor + SpecColor)), vec3(0.0, 0.0, 0.0));
+    
+	// Fresnel 2
+    /*vec3 H = normalize(fragmentToEye + lightDir);
+    float dotLH = saturate(dot(lightDir,H));
+    float dotLH5 = pow(1.0f - dotLH, 5);
+	float F = F0 + (1.0 - F0) * (dotLH5);
+	F = metallic + (1.0 - metallic) * F;*/
+	
+    // Add GI
+    //const float	cAmbientMin = 0.04;    
+    //float		ambient = cAmbientMin * (IsInSphere);    
+    //vec3		ColorAmbient = vec3(ambient,ambient,ambient);
+    //vec3		GIReflexion = GetGIReflexion ( normal, roughness );
+    
+    
+    //ColorAmbient = GIReflexion * cAmbientMin;
+        
+    //vec3 lightSum = max(((DiffColor + SpecColor) * (1.0 - cAmbientMin)), vec3(0.0, 0.0, 0.0));
+    //return ( lightSum + ColorAmbient + ( Fresnel * GIReflexion ) ) * IsInSphere;
+	
+    return lightSum;
+	
+	/*
+
+    float dotNL = saturate(dot(p_normal, -p_lightDirection));
+	
+	//spec = LightingFuncGGX_REF(p_normal, p_fragToEye, -p_lightDirection, p_roughnessSqrt, F0vec);
+	
+    vec3 H = normalize(p_fragToEye + (-p_lightDirection));
+    float dotLH = saturate(dot(-p_lightDirection,H));
+    float dotLH5 = pow(1.0f - dotLH, 5);
+    //F = F0 + (1.0-F0)*(dotLH5);
+	vec3 F = F0vec + (1.0f - F0vec) * (dotLH5);
+	
+	float metallic2 = 1.0 - metallic;
+	
+	float diffuse = (1.0 - dotNL) * (1.0 - metallic);
+		//return p_lightColor * NdotL * (k + specular * (1.0 - k));
+	
+	//return p_lightColor * spec;*/
+
+	/*/ Calculate the specular contribution
+    float3 ks = 0;
+    float3 specular = GGX_Specular(specularCubemap, normal, viewVector, roughness, F0, ks );
+    float3 kd = (1 - ks) * (1 - metallic);
+    // Calculate the diffuse contribution
+    float3 irradiance = texCUBE(diffuseCubemap_Sampler, normal ).rgb;
+    float3 diffuse = materialColour * irradiance;
+
+    return float4( kd * diffuse + /*ks* / specular, 1);  */   
+	
+	//vec3 reflectionVec = reflect(-p_fragToEye, p_normal);
+    /*vec3 radiance = vec3(0);
+	
+	//float NdotV = clamp(dot(p_normal, p_fragToEye), 0.0, 1.0);
+	float NdotL = clamp(dot(p_normal, -p_lightDirection), 0.0, 1.0);
+	
+	//if(NdotL > 0.0)
+	{
+       // vec3 halfVector = normalize(p_lightDirection - p_fragToEye);
+        vec3 halfVector = normalize(p_fragToEye + p_lightDirection);
+		float NdotH = clamp(dot(p_normal, halfVector), 0.0, 1.0);
+		float VdotH = clamp(dot(p_fragToEye, halfVector), 0.0, 1.0);
+		
+		float cosT = clamp(dot(p_lightDirection, p_normal), 0.0, 1.0); // NdotL
+		float sinT = sqrt(1.0 - (cosT * cosT));
+		
+		vec3 fresnel = Fresnel_Schlick(VdotH, p_F0);
+		float geometry = GeometryAtten_GGX(p_fragToEye, p_normal, halfVector, p_roughnessSqrt) * GeometryAtten_GGX(p_lightDirection, p_normal, halfVector, p_roughnessSqrt);
+		//float geometry = GeometryAtten_GGX(p_lightDirection, p_normal, halfVector, p_roughnessSqrt);
+		float denominator = clamp(4.0 * (NdotV * NdotH + 0.05), 0.0, 1.0);
+		
+		//kS += fresnel;
+		
+		radiance = p_lightColor * geometry * fresnel * sinT / denominator;
+	}
+	
+	return radiance;*/
+}
+
+vec3 calcLightColor(vec3 p_lightColor, vec3 p_lightDirection)
+{
+    // Get angle between normal and light direction
+    //float NdotL = max(dot(normal, -p_lightDirection), 0.0);
+	float NdotL = clamp( dot( normal, -p_lightDirection ), 0.0, 1.0 );
+    
+    float specular = 0.0;
+    if(NdotL > 0.0)
+    {
+        // Calculate neccessary values
+        vec3 halfVector = normalize(fragmentToEye - p_lightDirection );
+		
+		float NdotH = clamp( dot( normal, halfVector ), 0.0, 1.0 );
+		float NdotV = clamp( dot( normal, fragmentToEye ), 0.0, 1.0 );
+		float VdotH = clamp( dot( fragmentToEye, halfVector ), 0.0, 1.0 );
+		
+		/*float NdotL = max(dot(normal, -p_lightDirection), 0.0);
+        float NdotH = max(dot(normal, halfVector), 0.0); 
+        float NdotV = max(dot(normal, fragmentToEye), 0.0);
+		float VdotH = max(dot(fragmentToEye, halfVector), 0.0);*/
+        
+        // Calculate geometric attenuation (self shadowing of microfacets)
+        float NH2 = 2.0 * NdotH;
+        float g1 = (NH2 * NdotV) / VdotH;
+        float g2 = (NH2 * NdotL) / VdotH;
+        float geoAtt = min(1.0, min(g1, g2));
+     	
+		// Calculate microfacet distributions (roughness)
+		// Using Beckmann distribution function
+        float r1 = 1.0 / ( 4.0 * roughnessSqrt * pow(NdotH, 4.0));
+        float r2 = (NdotH * NdotH - 1.0) / (roughnessSqrt * NdotH * NdotH);
+        float microfacetDstrb = r1 * exp(r2);
+        
+		// Calculate fresnel effect (using Schlick's approximation)
+        float fresnel = pow(1.0 - VdotH, 5.0);
+        fresnel *= (1.0 - F0);
+        fresnel += F0;
+        
+		// Calculate specular component
+        specular = max((fresnel * geoAtt * microfacetDstrb) / (NdotV * NdotL * 3.14), 0.0);
+        //specular = (fresnel * geoAtt * microfacetDstrb) / (NdotV * NdotL * 3.14);
+		
+		//F0:"NdotL * (cSpecular * Rs + cDiffuse * (1-f0))"
+		
+		// Combine specular and diffuse components
+		return p_lightColor * NdotL * (k + specular * (1.0 - k));
+		//return p_lightColor * NdotL * specular;//(k + specular * (1.0 - k));
+    }
+	else
+	{
+		return vec3(0.0, 0.0, 0.0);
+	}
+}
+
+vec2 calcTexCoord(void)
+{
+    return gl_FragCoord.xy / screenSize;
+}
+
+vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
+{
+	return vec3(0.0);
+    /*float a = Roughness * Roughness;
+    float Phi = 2 * PI * Xi.x;
+    float CosTheta = sqrt((1 - Xi.y) / (1 + (a*a - 1) * Xi.y));
+    float SinTheta = sqrt(1 - CosTheta * CosTheta);
+    vec3 H;
+    H.x = SinTheta * cos(Phi);
+    H.y = SinTheta * sin(Phi);
+    H.z = CosTheta;
+    vec3 UpVector = abs(N.z) < 0.999 ? vec3(0, 0, 1) : vec3(1, 0, 0);
+    vec3 TangentX = normalize(cross(UpVector, N));
+    vec3 TangentY = cross(N, TangentX);
+
+    // Tangent to world space
+    return TangentX * H.x + TangentY * H.y + N * H.z;*/
+}
+
+vec3 PrefilterEnvMap( float Roughness , vec3 R )
+{
+	return vec3(0.0);
+    /*vec3 N = R;
+    vec3 V = R;
+    vec3 PrefilteredColor = vec3(0);
+    float TotalWeight = 0.0000001f;
+    const uint NumSamples = 1024;
+
+    for( uint i = 0; i < NumSamples; i++ )
+    {
+        vec2 Xi = vec2(RandomNumBuffer[i * 2 + 0], RandomNumBuffer[i * 2 + 1]);
+        vec3 H = ImportanceSampleGGX( Xi, Roughness , N );
+        vec3 L = 2 * dot( V, H ) * H - V;
+        float NoL = saturate( dot( N, L ) );
+
+        if( NoL > 0 )
+        {
+            PrefilteredColor += EnvMap.SampleLevel( linearSampler, L, 0 ).rgb * NoL;
+            TotalWeight += NoL;
+        }
+    }
+    return PrefilteredColor / TotalWeight;*/
+}
+
+vec3 S(vec2 p_vec)
+{
+	return vec3(1.0);
+}
+
+ float F(float VoH)
+ {
+	return 1.0f;
+ }
+ float G(float NoL, float NoV, float NoH, float VoH)
+ {
+	return 1.0f;
+ }
+	
+// Hammersley function (return random low-discrepency points)
+vec2 Hammersley(uint i, uint N)
+{
+  return vec2(
+    float(i) / float(N),
+    float(bitfieldReverse(i)) * 2.3283064365386963e-10
+  );
+}
+
+// Computes the exact mip-map to reference for the specular contribution.
+// Accessing the proper mip-map allows us to approximate the integral for this
+// angle of incidence on the current object.
+float compute_lod(uint NumSamples, float NoH)
+{
+	return 0.0;
+	//float dist = D(NoH); // Defined elsewhere as subroutine
+	//return 0.5 * (log2(float(Dimensions.x * Dimensions.y) / NumSamples) - log2(dist));
+}
+ 
+// Calculates the specular influence for a surface at the current fragment
+// location. This is an approximation of the lighting integral itself.
+vec3 radiance(vec3 N, vec3 V)
+{
+  // Precalculate rotation for +Z Hemisphere to microfacet normal.
+  //vec3 UpVector = abs(N.z) < 0.999 ? ZAxis : XAxis;
+  vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+  vec3 TangentX = normalize(cross( UpVector, N ));
+  vec3 TangentY = cross(N, TangentX);
+ 
+  // Note: I ended up using abs() for situations where the normal is
+  // facing a little away from the view to still accept the approximation.
+  // I believe this is due to a separate issue with normal storage, so
+  // you may only need to saturate() each dot value instead of abs().
+  float NoV = abs(dot(N, V));
+ 
+  // Approximate the integral for lighting contribution.
+  vec3 fColor = vec3(0.0);
+  const uint NumSamples = 20;
+  for (uint i = 0; i < NumSamples; ++i)
+  {
+    vec2 Xi = Hammersley(i, NumSamples);
+    vec3 Li = S(Xi); // Defined elsewhere as subroutine
+    vec3 H  = normalize(Li.x * TangentX + Li.y * TangentY + Li.z * N);
+    vec3 L  = normalize(-reflect(V, H));
+ 
+    // Calculate dot products for BRDF
+    float NoL = abs(dot(N, L));
+    float NoH = abs(dot(N, H));
+    float VoH = abs(dot(V, H));
+    float lod = compute_lod(NumSamples, NoH);
+ 
+    float F_ = F(VoH); // Defined elsewhere as subroutine
+    float G_ = G(NoL, NoV, NoH, VoH); // Defined elsewhere as subroutine
+    vec3 LColor = textureLod(staticEnvMap, L, lod).rgb;
+ 
+    // Since the sample is skewed towards the Distribution, we don't need
+    // to evaluate all of the factors for the lighting equation. Also note
+    // that this function is calculating the specular portion, so we absolutely
+    // do not add any more diffuse here.
+    fColor += F_ * G_ * LColor * VoH / (NoH * NoV);
+  }
+ 
+  // Average the results
+  return fColor / float(NumSamples);
+}
+ 
+vec3 main2()
+{
+  vec3 V = fragmentToEye;//normalize((-fragmentToEye * cameraPosVec).xyz);
+  vec3 color;
+ 
+  // No object, instead display the environment.
+  /*if (depth() == 1.0)
+  {
+    color = textureLod(staticEnvMap, -V, 0.0).rgb;
+  }*/
+ 
+  // Object, approximate the ambient light.
+  //else
+  //{
+    vec3 N = normalize((-fragmentToEye * normal).xyz);
+    vec3 L = normalize(-reflect(V, N));
+    float NoV = saturate(dot(N, V));
+    float NoL = saturate(dot(N, L));
+ 
+    // Calculate different portions of the color
+    vec3 irrMap = textureLod(staticEnvMap, N, 0.0).rgb;
+    vec3 Kdiff  = irrMap /** baseColor()*/ / 3.14159265358979323846;
+    vec3 Kspec  = radiance(N, V);
+ 
+    // Mix the materials
+    color = Kdiff;//BlendMaterial(Kdiff, Kspec);
+  //}
+	return color;
+  //fFragColor = vec4(color, 1.0);
+}
+
+void main(void) 
+{
+	// Calculate screen-space texture coordinates, for buffer access
+	vec2 texCoord = calcTexCoord();
+	
+	// Get diffuse color (full-bright) from diffuse buffer and gamma-correct it
+	vec3 diffuseColor = pow(texture(diffuseMap, texCoord).xyz, vec3(2.2));
+	// Get pixel's position in world space
+	vec3 worldPos = texture(positionMap, texCoord).xyz;
+	// Get normal (in world space) and normalize it to minimize floating point approximation errors
+	vec3 normal = normalize(texture(normalMap, texCoord).xyz);
+	// Get material properties
+	vec4 matProperties = texture(matPropertiesMap, texCoord).xyzw;
+	
+	// Extract roughness and metalness values
+	roughnessVar = matProperties.x;
+	metallic = matProperties.y;
+	
+	// Calculate view direction (fragment to eye vector)
+	fragmentToEye = normalize(cameraPosVec - worldPos);
+	
+	ref_at_norm_incidence = F0;
+	viewer = fragmentToEye;
+		
+	//fragmentToEye = normalize(worldPos - cameraPosVec);
+	//roughnessSqrt = roughnessVar;// * roughnessVar;
+
+	//k = 1.0 - positionAndGloss.w;
+	//roughnessVar = (normalAndSpecular.w + positionAndGloss.w) / 2.0;
+	roughnessSqrt = roughnessVar * roughnessVar;
+	
+	// ior = from 1.2 to 10.0
+	
+	//envColor = pow(textureLod(staticEnvMap, R, 0).xyz, vec3(2.2));
+	float ior = mix(1.5, 40.5, metallic);
+	ior = 4.5;
+	
+	F0 = abs((1.0 - ior) / (1.0 + ior));
+	F0 = F0 * F0;
+	F0vec = vec3(F0);
+	F0vec = mix(F0vec, diffuseColor, metallic);
+	
+	
+	//vec3 lightDir = -p_lightDirection;
+
+	//float spec = SpecGGX(p_normal, p_fragToEye, lightDir, roughnessVar, F0);
+	//vec3 lightDir = -normalize(directionalLight.m_direction);
+	//vec3 p_lightColor = vec3(1.0);
+	
+	//vec3 spec = SpecGGX(normal, fragmentToEye, R, roughnessVar, F0) * envColor;
+	
+    //float dif = dot(normal, lightDir);
+	//float dif = dot(p_normal, -p_lightDirection);
+	
+	// Fresnel
+    //float NdotV = clamp(dot(normal, fragmentToEye), 0.0, 1.0);
+	//NdotV = pow(1.0 - NdotV, 5.0);    
+	//float Fresnel = metallic + (1.0 - metallic) * (NdotV);
+
+    //vec3 H = normalize(fragmentToEye + R);
+    //float dotLH = saturate(dot(R,H));
+    //float dotLH5 = pow(1.0f - dotLH, 5);
+	//float F = F0 + (1.0 - F0) * (dotLH5);
+	//F = metallic + (1.0 - metallic) * F;
+	//vec3 F = F0vec + (vec3(1.0) - F0vec) * (dotLH5);
+	
+    // Tint lights
+    //vec3 SpecColor = spec * p_lightColor;
+    //vec3 DiffColor = dif * p_lightColor * (1.0 - Fresnel);
+	
+	
+    //float dif = dot(normal, R);
+    //vec3 DiffColor = dif * diffEnvColor * (1.0 - Fresnel);
+	
+	//envColor *= spec;
+	
+    // envColor = max(((/*diffuseColor*DiffColor +*/ envColor*spec)), vec3(0.0, 0.0, 0.0));
+		
+	// Fresnel
+    float NdotV = clamp(dot(normal, fragmentToEye), 0.0, 1.0);
+	NdotV = pow(1.0 - NdotV, 5.0);
+	float Fresnel = metallic + (1.0 - metallic) * (NdotV);
+	
+    //vec3 lightSum = max(((DiffColor + SpecColor)), vec3(0.0, 0.0, 0.0));
+	vec3 lightSum;
+	
+    vec3 I = normalize(worldPos - cameraPosVec);
+    vec3 R = normalize(reflect(I, normal));
+	
+	
+	vec3 diffEnvColor = (pow(textureLod(staticEnvMap, R, 9).xyz, vec3(2.2)) + 
+						pow(textureLod(staticEnvMap, R, 10).xyz, vec3(2.2)) +
+						pow(textureLod(staticEnvMap, R, 11).xyz, vec3(2.2))) / 3.0;
+						
+	int texLOD = 0;//int(10 * roughnessSqrt);
+	envColor = mix(pow(textureLod(staticEnvMap, R, 0).xyz, vec3(2.2)), pow(textureLod(staticEnvMap, R, 10).xyz, vec3(2.2)), 0.0);
+	
+	vec3 spec = min(LightingFuncGGX_REF(normal, fragmentToEye, R, roughnessSqrt, diffuseColor), 1.0);
+	
+    vec3 SpecColor = spec * envColor;
+    vec3 DiffColor = dot(normal, R) * diffEnvColor * (1.0 - Fresnel);
+		
+	vec3 Rnew = R;
+	
+	lightSum = main2();
+	
+	//Rnew = normalize(R + vec3(0.1, 0.0, 0.0));
+	//lightSum = calcLight(normal, fragmentToEye, pow(textureLod(staticEnvMap, Rnew, 0).xyz, vec3(2.2)), -R, vec3(F0), roughnessSqrt);
+	//lightSum = pow(textureLod(staticEnvMap, Rnew, 0).xyz, vec3(2.2)) * LightingFuncGGX_REF(normal, -I, Rnew, roughnessSqrt, F0vec);
+	//Rnew = normalize(R + vec3(0.08, 0.0, 0.0));
+	//lightSum += pow(textureLod(staticEnvMap, Rnew, 0).xyz, vec3(2.2)) * LightingFuncGGX_REF(normal, -I, Rnew, roughnessSqrt, F0vec);
+	//Rnew = normalize(R + vec3(-0.08, 0.0, 0.0));
+	//lightSum += pow(textureLod(staticEnvMap, Rnew, 0).xyz, vec3(2.2)) * LightingFuncGGX_REF(normal, -I, Rnew, roughnessSqrt, F0vec);
+	//Rnew = normalize(R + vec3(0.0, 0.08, 0.0));
+	//lightSum += pow(textureLod(staticEnvMap, Rnew, 0).xyz, vec3(2.2)) * LightingFuncGGX_REF(normal, -I, Rnew, roughnessSqrt, F0vec);
+	//Rnew = normalize(R + vec3(0.0, -0.08, 0.0));
+	//lightSum += pow(textureLod(staticEnvMap, Rnew, 0).xyz, vec3(2.2)) * LightingFuncGGX_REF(normal, -I, Rnew, roughnessSqrt, F0vec);
+	//Rnew = normalize(R + vec3(0.0, 0.0, 0.08));
+	//lightSum += pow(textureLod(staticEnvMap, Rnew, 0).xyz, vec3(2.2)) * LightingFuncGGX_REF(normal, -I, Rnew, roughnessSqrt, F0vec);
+	//Rnew = normalize(R + vec3(0.0, 0.0, -0.08));
+	//lightSum += pow(textureLod(staticEnvMap, Rnew, 0).xyz, vec3(2.2)) * LightingFuncGGX_REF(normal, -I, Rnew, roughnessSqrt, F0vec);
+	
+	//lightSum /= 6;
+	
+	//envColor += dif;
+	
+    //vec3 lightSum = max(((DiffColor + SpecColor)), vec3(0.0, 0.0, 0.0));
+    //float dotLH5 = pow(1.0f - dotLH, 5);
+    //F = F0 + (1.0-F0)*(dotLH5);
+	//F = F0 + (1.0f - F0) * (dotLH5);
+	
+    // Tint lights
+    //vec3 SpecColor = spec * p_lightColor;
+    //vec3 DiffColor = dif * p_lightColor * (1.0 - Fresnel);
+	//spec = max(((DiffColor + SpecColor)), vec3(0.0, 0.0, 0.0)) * directionalLight.m_intensity;
+	
+	//vec3 spec = LightingFuncGGX_REF(normal, fragmentToEye, -normalize(directionalLight.m_direction), roughnessSqrt, F0vec);
+	
+	//envColor = spec * pow(textureLod(staticEnvMap, R, 0).xyz, vec3(2.2));
+	//envColor = pow(textureLod(staticEnvMap, R, 5).xyz, vec3(2.2));
+	
+	//envColor = mix(pow(textureLod(staticEnvMap, R, 5).xyz, vec3(2.2)), pow(textureLod(staticEnvMap, R, 6).xyz, vec3(2.2)), 0.5);
+	
+	//float spec = SpecGGX(p_normal, p_fragToEye, R, roughnessVar, F0);
+	//envColor *= 
+	
+	//float reflectance = 0.5;
+	//F0vec = 0.16 * reflectance * reflectance * (1.0 - metallic) + diffuseColor * metallic;
+	
+	//float roughness = 1.0 - smoothness*smoothness;
+    //vec3 F0 = 0.16*reflectance*reflectance * (1.0-metalMask) + baseColor*metalMask;
+    //vec3 albedo = baseColor;
+	
+	//float3 F0 = abs ((1.0 - ior) / (1.0 + ior));
+	//F0 = F0 * F0;
+	//F0 = lerp(F0, materialColour.rgb, metallic);
+	
+	//k = 1.0 - normalAndSpecular.w;
+	//k = 0.2;
+	//roughnessVar = 0.1;// - ((positionAndGloss.w + normalAndSpecular.w) / 2.0);
+	
+	
+	// Declare final color of the fragment and add directional light to it
+	vec3 finalLightColor = calcLight(normal, fragmentToEye, directionalLight.m_color, normalize(directionalLight.m_direction), vec3(F0), roughnessSqrt) * directionalLight.m_intensity;// + directionalLight.m_color * 0.005;
+	//vec3 finalLightColor = vec3(0.0);
+	
+	for(int i = 0; i < numPointLights; i++)
+	{		
+		// Get light direction, extract length from it and normalize for usage as direction vector
+		vec3 lightDirection = worldPos - pointLights[i].m_position;
+		//vec3 lightDirection =  pointLights[i].m_position - worldPos;
+		float lightDistance = length(lightDirection);
+		lightDirection = normalize(lightDirection);
+		
+		// Add up constant, linear and quadratic attenuation
+		float attenuation = pointLights[i].m_attenConstant + 
+							pointLights[i].m_attenLinear * lightDistance + 
+							pointLights[i].m_attenQuad * lightDistance * lightDistance;
+						 
+		// Light color multiplied by intensity and divided by attenuation
+		
+		//finalLightColor += (calcLightColor(pointLights[i].m_color, lightDirection) * pointLights[i].m_intensity) / attenuation;
+		finalLightColor += (calcLight(normal, fragmentToEye, pointLights[i].m_color, lightDirection, vec3(F0), roughnessSqrt) * pointLights[i].m_intensity) / attenuation;
+		//finalLightColor += (computePBRLighting(pointLights[i].m_position, pointLights[i].m_color, worldPos, normal, fragmentToEye, diffuseColor, roughnessVar, F0vec) * pointLights[i].m_intensity) / attenuation;
+	}
+	
+	for(int i = 0; i < numSpotLights; i++)
+	{			
+		// Calculate direction from position of light to current pixel
+		vec3 lightToFragment = normalize(worldPos - spotLights[i].m_position);
+		
+		// Get dot product of light direction and direction of light to pixel, and use it as a factor for light strength
+		float spotLightFactor = dot(lightToFragment, spotLights[i].m_direction);
+		
+		// Early bail if pixel is outside of the cone of spot light
+		if(spotLightFactor > spotLights[i].m_cutoffAngle)
+		{
+			// Get light direction, extract length from it and normalize for usage as direction vector
+			vec3 lightDirection = worldPos - spotLights[i].m_position;
+			//vec3 lightDirection =  spotLights[i].m_position - worldPos;
+			float lightDistance = length(lightDirection);
+			lightDirection = normalize(lightDirection);
+			
+			// Add up constant, linear and quadratic attenuation
+			float attenuation = spotLights[i].m_attenConstant + 
+								spotLights[i].m_attenLinear * lightDistance + 
+								spotLights[i].m_attenQuad * lightDistance * lightDistance;
+			
+			// Light color multiplied by intensity
+			//finalLightColor += (calcLight(normal, fragmentToEye, pointLights[i].m_color, lightDirection, vec3(F0), roughnessSqrt) * pointLights[i].m_intensity) / attenuation;
+			vec3 lightColor = (calcLight(normal, fragmentToEye, spotLights[i].m_color, lightDirection, vec3(F0), roughnessSqrt) * spotLights[i].m_intensity);
+			//vec3 lightColor = (calcLightColor(spotLights[i].m_color, lightDirection) * spotLights[i].m_intensity);
+			
+			// Light restriction from cone
+			float coneAttenuation = (1.0 - (1.0 - spotLightFactor) * 1.0 / (1.0 - spotLights[i].m_cutoffAngle));
+			
+			finalLightColor += (lightColor / attenuation) * coneAttenuation;
+		}
+	}
+		
+	// Multiply the diffuse color by the amount of light the current pixel receives and gamma correct it
+	finalBuffer = pow(diffuseColor * finalLightColor, vec3(1.0 / 2.2));
+	//finalBuffer = vec3(roughnessVar, roughnessVar, roughnessVar);
+	//finalBuffer = vec4(texture(staticEnvMap, vec3(0.0, 0.0, 0.0)).xyz, 1.0);
+	//finalBuffer = vec4(metallic, metallic, metallic, 1.0);
+	//finalBuffer = vec4(pow(mix(diffuseColor, vec3(0.0, 0.0, 0.0), 1.0 - metallic) * finalLightColor, vec3(1.0 / 2.2)), 1.0);
+	//finalBuffer = vec4(pow(finalLightColor, vec3(1.0 / 2.2)), 1.0);
+	//finalBuffer = vec4(pow(diffuseColor, vec3(1.0 / 2.2)), 1.0);
+	//finalBuffer = vec4(texture(normalMap, texCoord).xyz, 1.0);
+	//finalBuffer = vec4(roughnessVar, roughnessVar, roughnessVar, 1.0);
+}

+ 99 - 311
Praxis3D/Data/Shaders/lightPass.frag

@@ -1,10 +1,11 @@
-#version 330
+#version 430 core
 
 #define MAX_NUM_POINT_LIGHTS 20
 #define MAX_NUM_SPOT_LIGHTS 10
+#define PI 3.1415926535
 
 layout(location = 0) out vec4 emissiveBuffer;
-layout(location = 1) out vec4 finalBuffer;
+layout(location = 1) out vec3 finalBuffer;
 
 //in vec2 texCoord;
 
@@ -42,12 +43,15 @@ struct SpotLight
 uniform sampler2D positionMap;
 uniform sampler2D diffuseMap;
 uniform sampler2D normalMap;
+uniform sampler2D matPropertiesMap;
 
-uniform ivec2 screenSize;
+uniform samplerCube staticEnvMap;
 
 uniform mat4 modelViewMat;
 uniform mat4 viewMat;
 uniform vec3 cameraPosVec;
+uniform ivec2 screenSize;
+uniform float gamma;
 
 uniform int numPointLights;
 uniform int numSpotLights;
@@ -68,19 +72,6 @@ layout (std140) uniform SpotLights
 vec3 worldPos;
 vec3 normal;
 vec3 fragmentToEye;
-float roughnessSqrt;
-
-// set important material values
-float roughnessVar = 0.1; // 0.1	// 0 : smooth, 1: rough
-//float roughnessVar = 0.8;
-float F0 = 0.02;//0.171968833;//1.0; 			// fresnel reflectance at normal incidence
-vec3 F0vec;
-//float k = 0.01; 				// fraction of diffuse reflection (specular reflection = 1 - k)
-float k = 0.8; //0.5
-float metallic;
-
-float ref_at_norm_incidence = F0;
-vec3 viewer;
 
 float saturate(float p_value)
 {
@@ -92,7 +83,7 @@ float G1V(float p_dotNV, float p_k)
     return 1.0f / (p_dotNV * (1.0f - p_k) + p_k);
 }
 
-float MicroFacetDistr_GGX(vec3 p_normal, vec3 p_halfVec, float p_roughnessSqrt)
+/*float MicroFacetDistr_GGX(vec3 p_normal, vec3 p_halfVec, float p_roughnessSqrt)
 {
 	float NdotH = dot(p_normal, p_halfVec);
 	if(NdotH > 0.0)
@@ -124,83 +115,7 @@ float GeometryAtten_GGX(vec3 p_fragToEye, vec3 p_normal, vec3 p_halfVec, float p
 vec3 Fresnel_Schlick(float p_cosT, vec3 p_F0)
 {
 	return F0 + (vec3(1.0) - F0) * pow(1.0 - p_cosT, 5.0);
-}
-
-vec3 calcLightColor2(vec3 p_lightColor, vec3 p_lightDirection)
-{
-	//float NoV = saturate( dot(normal, V) );
-	float NoV = abs( dot(normal, fragmentToEye) ) + 0.00001;//1e-5;
-
-	// Diffuse_Lambert
-	//Shared.DiffuseMul = DiffuseColor * (1.0 / 3.14);
-
-	// D_GGX, Vis_SmithJointApprox
-	float m = roughnessVar * roughnessVar;
-	float m2 = m * m;
-	float SpecularMul = (0.5 / 3.14) * m2;
-	float VisMad = ( 2 * NoV * ( 1 - m ) + m, NoV * m );
-	
-	// F_Schlick
-	//SpecularMul *= saturate( 50.0 * k );
-	return vec3(1.0);
-}
-
-vec3 calcLightColor3(vec3 p_lightColor, vec3 p_lightDirection)
-{
-	// Compute any aliases and intermediary values
-    // -------------------------------------------
-	
-	vec3 half_vector = normalize(fragmentToEye - p_lightDirection );
-    float NdotL        = clamp( dot( normal, -p_lightDirection ), 0.0, 1.0 );
-    float NdotH        = clamp( dot( normal, half_vector ), 0.0, 1.0 );
-    float NdotV        = clamp( dot( normal, viewer ), 0.0, 1.0 );
-    float VdotH        = clamp( dot( viewer, half_vector ), 0.0, 1.0 );
-    float r_sq         = roughnessVar * roughnessVar;
- 
-    // Evaluate the geometric term
-    // --------------------------------
-    float geo_numerator   = 2.0f * NdotH;
-    float geo_denominator = VdotH;
- 
-    float geo_b = (geo_numerator * NdotV ) / geo_denominator;
-    float geo_c = (geo_numerator * NdotL ) / geo_denominator;
-    float geo   = min( 1.0f, min( geo_b, geo_c ) );
- 
-    // Now evaluate the roughness term
-    // -------------------------------
-    float roughness;
-    
-	float roughness_a = 1.0f / ( 4.0f * r_sq * pow( NdotH, 4 ) );
-	float roughness_b = NdotH * NdotH - 1.0f;
-	float roughness_c = r_sq * NdotH * NdotH;
-	roughness = roughness_a * exp( roughness_b / roughness_c );
- 
-    // Next evaluate the Fresnel value
-    // -------------------------------
-    float fresnel = pow( 1.0f - VdotH, 5.0f );
-    fresnel *= ( 1.0f - F0 );
-    fresnel += F0;
- 
-    // Put all the terms together to compute
-    // the specular term in the equation
-    // -------------------------------------
-    float Rs_numerator   = ( fresnel * geo * roughness );
-    float Rs_denominator  = NdotV * NdotL;
-    float Rs             = Rs_numerator/ Rs_denominator;
-  
-    float specular = (fresnel * geo * roughness) / (NdotV * NdotL);
-    // Put all the parts together to generate
-    // the final colour
-    // --------------------------------------
-	
-	return p_lightColor * NdotL * specular;
-	
-    //float3 final = max(0.0f, NdotL) * (cSpecular * Rs + cDiffuse);
- 
-    // Return the result
-    // -----------------
-    //return float4( final, 1.0f );
-}
+}*/
 
 vec3 computePBRLighting(vec3 lightPos, vec3 lightColor, vec3 position, vec3 N, vec3 V, vec3 albedo, float roughness, vec3 F0) 
 {
@@ -242,179 +157,75 @@ vec3 computePBRLighting(vec3 lightPos, vec3 lightColor, vec3 position, vec3 N, v
 	return (diffuse + specular) * lightColor * dotNL ;
 }
 
-float SpecGGX(vec3 N, vec3 V, vec3 L, float roughness, float F0)
+vec3 LightingFuncGGX_REF(vec3 p_normal, vec3 p_viewDir, vec3 p_lightDir, float p_roughnessSqrt, vec3 p_F0)
+{
+	// Calculate half vector between view and light directions
+    vec3 halfVector = normalize(p_viewDir + p_lightDir);
+	
+	// Calculate required dot products
+    float dotNL = saturate(dot(p_normal, p_lightDir));
+    float dotNV = saturate(dot(p_normal, p_viewDir));
+    float dotNH = saturate(dot(p_normal, halfVector));
+    float dotLH = saturate(dot(p_lightDir, halfVector));
+
+	// Calculate microfacet distributions (based on roughness)
+	// Using GGX normal distribution function
+    float RoughnessPow4 = p_roughnessSqrt * p_roughnessSqrt;
+    float denom = dotNH * dotNH * (RoughnessPow4 - 1.0) + 1.0f;
+    float D = RoughnessPow4 / (PI * denom * denom);
+
+	// Calculate fresnel effect 
+	// Using Schlick's approximation
+    float dotLH5 = pow(1.0f - dotLH, 5);
+	vec3 F = p_F0 + (vec3(1.0f) - p_F0) * (dotLH5);
+
+	// Calculate geometric attenuation (or visibility term - self shadowing of microfacets)
+	// Using Smith with Schlick's approximation
+    float k2 = p_roughnessSqrt / 2.0f;
+    float G = G1V(dotNL, k2) * G1V(dotNV, k2);
+	
+	// Multiple all the terms together
+	return dotNL * D * F * G;
+}
+
+float SpecGGX(vec3 N, vec3 V, vec3 L, float roughness, float F0 )
 {
 	float SqrRoughness = roughness*roughness;
 
-	vec3 H = normalize(V+L);
+	vec3 H = normalize(V + L);
 
 	float NdotL = clamp(dot(N,L),0.0,1.0);
 	float NdotV = clamp(dot(N,V),0.0,1.0);
 	float NdotH = clamp(dot(N,H),0.0,1.0);
 	float LdotH = clamp(dot(L,H),0.0,1.0);
 
-	// Geom term
-	float RoughnessPow4 = SqrRoughness*SqrRoughness;
-	float pi = 3.14159;
-	float denom = NdotH * NdotH *(RoughnessPow4-1.0) + 1.0;
-	float D = RoughnessPow4/(pi * denom * denom);
+	float RoughnessPow4 = SqrRoughness * SqrRoughness;
+	float denom = NdotH * NdotH * (RoughnessPow4 - 1.0) + 1.0;
+	float D = RoughnessPow4 / (PI * denom * denom);
 
-	// Fresnel term 
-	float LdotH5 = 1.0-LdotH;
-    LdotH5 = LdotH5*LdotH5*LdotH5*LdotH5*LdotH5;
-	float F = F0 + (1.0-F0)*(LdotH5);
+	float LdotH5 = 1.0 - LdotH;
+    LdotH5 = LdotH5 * LdotH5 * LdotH5 * LdotH5 * LdotH5;
+	float F = F0 + (1.0 - F0) * (LdotH5);
 
-	// Vis term 
 	float k = SqrRoughness/2.0;
-	float Vis = G1V(NdotL,k)*G1V(NdotV,k);
+	float G = G1V(NdotL, k) * G1V(NdotV, k);
 
-	float specular = NdotL * D * F * Vis;
+	float specular = NdotL * D * F * G;
     
 	return specular;
 }
 
-vec3 LightingFuncGGX_REF(vec3 N, vec3 V, vec3 L, float roughness, vec3 F0)
-{
-    float alpha = roughness;//roughness*roughness;
-
-    vec3 H = normalize(V+L);
-
-    float dotNL = saturate(dot(N,L));
-    float dotNV = saturate(dot(N,V));
-    float dotNH = saturate(dot(N,H));
-    float dotLH = saturate(dot(L,H));
-
-    //float F, D, vis;
-	float D, vis;
-	vec3 F;
-
-    // D
-    float alphaSqr = alpha*alpha;
-    float pi = 3.14159f;
-    float denom = dotNH * dotNH *(alphaSqr-1.0) + 1.0f;
-    D = alphaSqr/(pi * denom * denom);
-
-    // F
-    float dotLH5 = pow(1.0f - dotLH, 5);
-    //F = F0 + (1.0-F0)*(dotLH5);
-	F = F0 + (1.0f - F0) * (dotLH5);
-
-    // V
-    float k2 = alpha / 2.0f;
-    vis = G1V(dotNL, k2) * G1V(dotNV, k2);
-	
-	float metallic2 = (1.0f - metallic);// / 2.0f;
-	
-	vec3 specular;
-	
-	//if(metallic == 1.0f)
-	//{
-		specular = dotNL * D * F * vis;
-	//}
-	//else
-	//{
-		//specular = (dotNL) * (metallic2 + D * F * vis * (1.0 - metallic2));
-	//}
-	
-    //vec3 specular = (dotNL) * (metallic2 + D * F * vis * (1.0 - metallic2));
-	
-	//specular = ((1.0 - dotNL) * (1.0 - metallic2)) + D * F * vis;
-	//specular = ((1.0 - dotNL) * (1.0 - metallic2)) + (metallic2 + D * F * vis * (1.0 - metallic2));
-	
-    return specular;
-}
-
-vec3 calcLight(vec3 p_normal, vec3 p_fragToEye, vec3 p_lightColor, vec3 p_lightDirection, vec3 p_F0, float p_roughnessSqrt)
+vec3 calcLightColor(vec3 p_normal, vec3 p_fragToEye, vec3 p_lightColor, vec3 p_lightDirection, vec3 p_F0, float p_diffuseAmount, float p_roughnessSqrt)
 {	
-	vec3 lightDir = -p_lightDirection;
-
-	float spec = SpecGGX(p_normal, p_fragToEye, lightDir, roughnessVar, F0);
-    float dif = dot(p_normal, lightDir);
-	//float dif = dot(p_normal, -p_lightDirection);
+	// Get specular and diffuse lighting
+	vec3 specularColor = LightingFuncGGX_REF(p_normal, p_fragToEye, p_lightDirection, p_roughnessSqrt, p_F0);
+    vec3 diffuseColor = vec3(clamp(dot(p_normal, p_lightDirection), 0.0, 1.0));
 	
-	// Fresnel
-    float NdotV = clamp(dot(p_normal, p_fragToEye), 0.0, 1.0);
-	NdotV = pow(1.0 - NdotV, 5.0);    
-	float Fresnel = metallic + (1.0 - metallic) * (NdotV);
-
-    // Tint lights
-    vec3 SpecColor = spec * p_lightColor;
-    vec3 DiffColor = dif * p_lightColor * (1.0 - Fresnel);
-    
-    // Add GI
-    //const float	cAmbientMin = 0.04;    
-    //float		ambient = cAmbientMin * (IsInSphere);    
-    //vec3		ColorAmbient = vec3(ambient,ambient,ambient);
-    //vec3		GIReflexion = GetGIReflexion ( normal, roughness );
-    
-    
-    //ColorAmbient = GIReflexion * cAmbientMin;
-        
-    //vec3 lightSum = max(((DiffColor + SpecColor) * (1.0 - cAmbientMin)), vec3(0.0, 0.0, 0.0));
-    //return ( lightSum + ColorAmbient + ( Fresnel * GIReflexion ) ) * IsInSphere;
-	
-    vec3 lightSum = max(((DiffColor + SpecColor)), vec3(0.0, 0.0, 0.0));
-    return lightSum;
-	
-	/*
-
-    float dotNL = saturate(dot(p_normal, -p_lightDirection));
-	
-	//spec = LightingFuncGGX_REF(p_normal, p_fragToEye, -p_lightDirection, p_roughnessSqrt, F0vec);
-	
-    vec3 H = normalize(p_fragToEye + (-p_lightDirection));
-    float dotLH = saturate(dot(-p_lightDirection,H));
-    float dotLH5 = pow(1.0f - dotLH, 5);
-    //F = F0 + (1.0-F0)*(dotLH5);
-	vec3 F = F0vec + (1.0f - F0vec) * (dotLH5);
-	
-	float metallic2 = 1.0 - metallic;
-	
-	float diffuse = (1.0 - dotNL) * (1.0 - metallic);
-		//return p_lightColor * NdotL * (k + specular * (1.0 - k));
-	
-	//return p_lightColor * spec;*/
-
-	/*/ Calculate the specular contribution
-    float3 ks = 0;
-    float3 specular = GGX_Specular(specularCubemap, normal, viewVector, roughness, F0, ks );
-    float3 kd = (1 - ks) * (1 - metallic);
-    // Calculate the diffuse contribution
-    float3 irradiance = texCUBE(diffuseCubemap_Sampler, normal ).rgb;
-    float3 diffuse = materialColour * irradiance;
-
-    return float4( kd * diffuse + /*ks* / specular, 1);  */   
-	
-	//vec3 reflectionVec = reflect(-p_fragToEye, p_normal);
-    /*vec3 radiance = vec3(0);
-	
-	//float NdotV = clamp(dot(p_normal, p_fragToEye), 0.0, 1.0);
-	float NdotL = clamp(dot(p_normal, -p_lightDirection), 0.0, 1.0);
-	
-	//if(NdotL > 0.0)
-	{
-       // vec3 halfVector = normalize(p_lightDirection - p_fragToEye);
-        vec3 halfVector = normalize(p_fragToEye + p_lightDirection);
-		float NdotH = clamp(dot(p_normal, halfVector), 0.0, 1.0);
-		float VdotH = clamp(dot(p_fragToEye, halfVector), 0.0, 1.0);
-		
-		float cosT = clamp(dot(p_lightDirection, p_normal), 0.0, 1.0); // NdotL
-		float sinT = sqrt(1.0 - (cosT * cosT));
-		
-		vec3 fresnel = Fresnel_Schlick(VdotH, p_F0);
-		float geometry = GeometryAtten_GGX(p_fragToEye, p_normal, halfVector, p_roughnessSqrt) * GeometryAtten_GGX(p_lightDirection, p_normal, halfVector, p_roughnessSqrt);
-		//float geometry = GeometryAtten_GGX(p_lightDirection, p_normal, halfVector, p_roughnessSqrt);
-		float denominator = clamp(4.0 * (NdotV * NdotH + 0.05), 0.0, 1.0);
-		
-		//kS += fresnel;
-		
-		radiance = p_lightColor * geometry * fresnel * sinT / denominator;
-	}
-	
-	return radiance;*/
+	// Add specular and diffuse together, and multiply it by the color of the light
+	return (specularColor + diffuseColor * p_diffuseAmount) * p_lightColor;
 }
 
-vec3 calcLightColor(vec3 p_lightColor, vec3 p_lightDirection)
+/*vec3 calcLightColorOld(vec3 p_lightColor, vec3 p_lightDirection)
 {
     // Get angle between normal and light direction
     //float NdotL = max(dot(normal, -p_lightDirection), 0.0);
@@ -429,12 +240,7 @@ vec3 calcLightColor(vec3 p_lightColor, vec3 p_lightDirection)
 		float NdotH = clamp( dot( normal, halfVector ), 0.0, 1.0 );
 		float NdotV = clamp( dot( normal, fragmentToEye ), 0.0, 1.0 );
 		float VdotH = clamp( dot( fragmentToEye, halfVector ), 0.0, 1.0 );
-		
-		/*float NdotL = max(dot(normal, -p_lightDirection), 0.0);
-        float NdotH = max(dot(normal, halfVector), 0.0); 
-        float NdotV = max(dot(normal, fragmentToEye), 0.0);
-		float VdotH = max(dot(fragmentToEye, halfVector), 0.0);*/
-        
+		        
         // Calculate geometric attenuation (self shadowing of microfacets)
         float NH2 = 2.0 * NdotH;
         float g1 = (NH2 * NdotV) / VdotH;
@@ -466,7 +272,7 @@ vec3 calcLightColor(vec3 p_lightColor, vec3 p_lightDirection)
 	{
 		return vec3(0.0, 0.0, 0.0);
 	}
-}
+}*/
 
 vec2 calcTexCoord(void)
 {
@@ -478,65 +284,47 @@ void main(void)
 	// Calculate screen-space texture coordinates, for buffer access
 	vec2 texCoord = calcTexCoord();
 	
-	// Get diffuse color (full-bright) from diffuse buffer and gamma-correct it
-	vec3 diffuseColor = pow(texture(diffuseMap, texCoord).xyz, vec3(2.2));
-	
-	// Get pixel's position in world space and gloss value from position buffer
-	vec4 positionAndGloss = texture(positionMap, texCoord);
-	// Get normal in world space and specular value from normal buffer 
-	vec4 normalAndSpecular = normalize(texture(normalMap, texCoord));
+	// Get diffuse color (full-bright) from diffuse buffer and convert it to linear space
+	vec3 diffuseColor = pow(texture(diffuseMap, texCoord).xyz, vec3(gamma));
+	// Get pixel's position in world space
+	vec3 worldPos = texture(positionMap, texCoord).xyz;
+	// Get normal (in world space) and normalize it to minimize floating point approximation errors
+	vec3 normal = normalize(texture(normalMap, texCoord).xyz);
+	// Get material properties
+	vec4 matProperties = texture(matPropertiesMap, texCoord).xyzw;
 	
-	// Extract world position
-	worldPos = positionAndGloss.xyz;
-	// Extract normal and normalize it to minimize floating point approximation errors
-	normal = normalize(normalAndSpecular.xyz);
+	// Extract roughness and metalness values
+	float roughnessVar = matProperties.x;
+	float metalness = matProperties.y;
 	
-	// ior = from 1.2 to 10.0
+	// Calculate view direction (fragment to eye vector)
+	fragmentToEye = normalize(cameraPosVec - worldPos);
 	
-	float ior = 40.5;
-	metallic = positionAndGloss.w;
+	float ior = mix(1.5, 40.5, metalness);
+	ior = 40.5;
 	
-	F0 = abs((1.0 - ior) / (1.0 + ior));
+	float F0 = abs((1.0 - ior) / (1.0 + ior));
 	F0 = F0 * F0;
-	F0vec = vec3(F0);
-	F0vec = mix(vec3(F0), diffuseColor, metallic);
-	
-	float reflectance = 0.5;
-	//F0vec = 0.16 * reflectance * reflectance * (1.0 - metallic) + diffuseColor * metallic;
-	
-	//float roughness = 1.0 - smoothness*smoothness;
-    //vec3 F0 = 0.16*reflectance*reflectance * (1.0-metalMask) + baseColor*metalMask;
-    //vec3 albedo = baseColor;
-	
-	//float3 F0 = abs ((1.0 - ior) / (1.0 + ior));
-	//F0 = F0 * F0;
-	//F0 = lerp(F0, materialColour.rgb, metallic);
-	
-	//k = 1.0 - normalAndSpecular.w;
-	//k = 0.2;
-	//roughnessVar = 0.1;// - ((positionAndGloss.w + normalAndSpecular.w) / 2.0);
+	vec3 F0vec = mix(vec3(F0), diffuseColor, metalness);
+		
+	// Fresnel for the diffuse color
+    float NdotV = clamp(dot(normal, fragmentToEye), 0.0, 1.0);
+	NdotV = pow(1.0 - NdotV, 5.0);
+	float diffuseAmount = 1.0 - (metalness + (1.0 - metalness) * (NdotV));
 	
-	ref_at_norm_incidence = F0;
-	viewer = fragmentToEye;
+	float roughnessSqrt = roughnessVar * roughnessVar;
 	
-	fragmentToEye = normalize(cameraPosVec - worldPos);
-	//fragmentToEye = normalize(worldPos - cameraPosVec);
-	roughnessVar = texture(normalMap, texCoord).w;
-	//roughnessSqrt = roughnessVar;// * roughnessVar;
-
-	//k = 1.0 - positionAndGloss.w;
-	//roughnessVar = (normalAndSpecular.w + positionAndGloss.w) / 2.0;
-	roughnessSqrt = roughnessVar * roughnessVar;
+	// ior = from 1.2 to 10.0
 	
 	// Declare final color of the fragment and add directional light to it
-	vec3 finalLightColor = calcLight(normal, fragmentToEye, directionalLight.m_color, normalize(directionalLight.m_direction), vec3(F0), roughnessSqrt) * directionalLight.m_intensity;// + directionalLight.m_color * 0.005;
-	//vec3 finalLightColor = vec3(0.0);
+	vec3 finalLightColor = calcLightColor(normal, fragmentToEye, directionalLight.m_color, normalize(-directionalLight.m_direction), F0vec, diffuseAmount, roughnessSqrt) * directionalLight.m_intensity;
+	
+	//vec3 finalLightColor = calcLightColor(normal, fragmentToEye, vec3(1.0, 1.0, 1.0), normalize(vec3(8.0, 10.0, 5.0)), F0vec, diffuseAmount, roughnessSqrt) * 1.0;
 	
 	for(int i = 0; i < numPointLights; i++)
 	{		
 		// Get light direction, extract length from it and normalize for usage as direction vector
-		vec3 lightDirection = worldPos - pointLights[i].m_position;
-		//vec3 lightDirection =  pointLights[i].m_position - worldPos;
+		vec3 lightDirection =  pointLights[i].m_position - worldPos;
 		float lightDistance = length(lightDirection);
 		lightDirection = normalize(lightDirection);
 		
@@ -544,12 +332,9 @@ void main(void)
 		float attenuation = pointLights[i].m_attenConstant + 
 							pointLights[i].m_attenLinear * lightDistance + 
 							pointLights[i].m_attenQuad * lightDistance * lightDistance;
-						 
+							
 		// Light color multiplied by intensity and divided by attenuation
-		
-		//finalLightColor += (calcLightColor(pointLights[i].m_color, lightDirection) * pointLights[i].m_intensity) / attenuation;
-		finalLightColor += (calcLight(normal, fragmentToEye, pointLights[i].m_color, lightDirection, vec3(F0), roughnessSqrt) * pointLights[i].m_intensity) / attenuation;
-		//finalLightColor += (computePBRLighting(pointLights[i].m_position, pointLights[i].m_color, worldPos, normal, fragmentToEye, diffuseColor, roughnessVar, F0vec) * pointLights[i].m_intensity) / attenuation;
+		finalLightColor += (calcLightColor(normal, fragmentToEye, pointLights[i].m_color, lightDirection, F0vec, diffuseAmount, roughnessSqrt) * pointLights[i].m_intensity) / attenuation;
 	}
 	
 	for(int i = 0; i < numSpotLights; i++)
@@ -564,8 +349,7 @@ void main(void)
 		if(spotLightFactor > spotLights[i].m_cutoffAngle)
 		{
 			// Get light direction, extract length from it and normalize for usage as direction vector
-			vec3 lightDirection = worldPos - spotLights[i].m_position;
-			//vec3 lightDirection =  spotLights[i].m_position - worldPos;
+			vec3 lightDirection =  spotLights[i].m_position - worldPos;
 			float lightDistance = length(lightDirection);
 			lightDirection = normalize(lightDirection);
 			
@@ -575,19 +359,23 @@ void main(void)
 								spotLights[i].m_attenQuad * lightDistance * lightDistance;
 			
 			// Light color multiplied by intensity
-			//finalLightColor += (calcLight(normal, fragmentToEye, pointLights[i].m_color, lightDirection, vec3(F0), roughnessSqrt) * pointLights[i].m_intensity) / attenuation;
-			vec3 lightColor = (calcLight(normal, fragmentToEye, spotLights[i].m_color, lightDirection, vec3(F0), roughnessSqrt) * spotLights[i].m_intensity);
-			//vec3 lightColor = (calcLightColor(spotLights[i].m_color, lightDirection) * spotLights[i].m_intensity);
+			vec3 lightColor = (calcLightColor(normal, fragmentToEye, spotLights[i].m_color, lightDirection, F0vec, diffuseAmount, roughnessSqrt) * spotLights[i].m_intensity);
 			
 			// Light restriction from cone
 			float coneAttenuation = (1.0 - (1.0 - spotLightFactor) * 1.0 / (1.0 - spotLights[i].m_cutoffAngle));
 			
-			finalLightColor += (lightColor / attenuation) * coneAttenuation; 
+			finalLightColor += (lightColor / attenuation) * coneAttenuation;
 		}
 	}
+	emissiveBuffer = vec4(1.0, 0.0, 0.0, 0.0);
 	
 	// Multiply the diffuse color by the amount of light the current pixel receives and gamma correct it
-	finalBuffer = vec4(pow(diffuseColor * finalLightColor, vec3(1.0 / 2.2)), 1.0);
+	
+	finalBuffer = diffuseColor * finalLightColor;//texture(diffuseMap, texCoord).xyz;
+	//finalBuffer = vec3(0.0, 1.0, 0.0);//diffuseColor * finalLightColor;
+	//finalBuffer = simpleToneMapping(diffuseColor * finalLightColor, 2.2);
+	//finalBuffer = vec3(roughnessVar, roughnessVar, roughnessVar);
+	//finalBuffer = vec4(texture(staticEnvMap, vec3(0.0, 0.0, 0.0)).xyz, 1.0);
 	//finalBuffer = vec4(metallic, metallic, metallic, 1.0);
 	//finalBuffer = vec4(pow(mix(diffuseColor, vec3(0.0, 0.0, 0.0), 1.0 - metallic) * finalLightColor, vec3(1.0 / 2.2)), 1.0);
 	//finalBuffer = vec4(pow(finalLightColor, vec3(1.0 / 2.2)), 1.0);

+ 5 - 5
Praxis3D/Data/Shaders/lightPass.vert

@@ -1,10 +1,10 @@
-#version 330
+#version 430 core
 
 void main(void) 
 {
+	// Determine texture coordinates
 	vec2 texCoord = vec2((gl_VertexID == 2) ?  2.0 :  0.0, (gl_VertexID == 1) ?  2.0 :  0.0);
-
-	gl_Position = vec4(texCoord * vec2(2.0, -2.0) + vec2(-1.0, 1.0), 1.0, 1.0);
-
-	//gl_Position = vec4(vertexPosition, 1.0);
+	
+	// Calculate the position, so that the triangle fills the whole screen
+	gl_Position = vec4(texCoord * vec2(2.0, -2.0) + vec2(-1.0, 1.0), 0.0, 1.0);
 }

+ 190 - 0
Praxis3D/Data/Shaders/reflectionPass.frag

@@ -0,0 +1,190 @@
+#version 430 core
+
+#define MAX_NUM_POINT_LIGHTS 20
+#define MAX_NUM_SPOT_LIGHTS 10
+#define PI 3.1415926535
+
+layout(location = 0) out vec4 emissiveBuffer;
+layout(location = 1) out vec3 finalBuffer;
+
+uniform sampler2D positionMap;
+uniform sampler2D diffuseMap;
+uniform sampler2D normalMap;
+uniform sampler2D matPropertiesMap;
+
+uniform samplerCube staticEnvMap;
+
+uniform mat4 modelViewMat;
+uniform mat4 viewMat;
+uniform vec3 cameraPosVec;
+uniform ivec2 screenSize;
+
+vec3 worldPos;
+vec3 normal;
+vec3 fragmentToEye;
+
+vec2 calcTexCoord(void)
+{
+    return gl_FragCoord.xy / screenSize;
+}
+
+float somestep(float t) 
+{
+    return pow(t,4.0);
+}
+
+vec3 textureAVG(samplerCube tex, vec3 tc) 
+{
+    const float diff0 = 0.35;
+    const float diff1 = 0.12;
+ 	vec3 s0 = texture(tex,tc).xyz;
+    vec3 s1 = texture(tex,tc+vec3(diff0)).xyz;
+    vec3 s2 = texture(tex,tc+vec3(-diff0)).xyz;
+    vec3 s3 = texture(tex,tc+vec3(-diff0,diff0,-diff0)).xyz;
+    vec3 s4 = texture(tex,tc+vec3(diff0,-diff0,diff0)).xyz;
+    
+    vec3 s5 = texture(tex,tc+vec3(diff1)).xyz;
+    vec3 s6 = texture(tex,tc+vec3(-diff1)).xyz;
+    vec3 s7 = texture(tex,tc+vec3(-diff1,diff1,-diff1)).xyz;
+    vec3 s8 = texture(tex,tc+vec3(diff1,-diff1,diff1)).xyz;
+    
+    return pow((s0 + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8) * 0.111111111, vec3(2.2));;
+}
+
+vec3 textureBlured(samplerCube tex, vec3 tc) 
+{
+   	vec3 r = textureAVG(staticEnvMap, vec3(1.0,0.0,0.0));
+    vec3 t = textureAVG(staticEnvMap, vec3(0.0,1.0,0.0));
+    vec3 f = textureAVG(staticEnvMap, vec3(0.0,0.0,1.0));
+    vec3 l = textureAVG(staticEnvMap, vec3(-1.0,0.0,0.0));
+    vec3 b = textureAVG(staticEnvMap, vec3(0.0,-1.0,0.0));
+    vec3 a = textureAVG(staticEnvMap, vec3(0.0,0.0,-1.0));
+        
+    float kr = dot(tc,vec3(1.0,0.0,0.0)) * 0.5 + 0.5; 
+    float kt = dot(tc,vec3(0.0,1.0,0.0)) * 0.5 + 0.5;
+    float kf = dot(tc,vec3(0.0,0.0,1.0)) * 0.5 + 0.5;
+    float kl = 1.0 - kr;
+    float kb = 1.0 - kt;
+    float ka = 1.0 - kf;
+    
+    kr = somestep(kr);
+    kt = somestep(kt);
+    kf = somestep(kf);
+    kl = somestep(kl);
+    kb = somestep(kb);
+    ka = somestep(ka);    
+    
+    float d;
+    vec3 ret;
+    ret  = f * kf; d  = kf;
+    ret += a * ka; d += ka;
+    ret += l * kl; d += kl;
+    ret += r * kr; d += kr;
+    ret += t * kt; d += kt;
+    ret += b * kb; d += kb;
+    
+    return ret / d;
+}
+
+vec3 getColor(vec3 p_normal, vec3 p_viewDirection, float p_metalness, float p_roughness, float p_Fresnel) 
+{
+	// material
+	float metallic = p_metalness;
+	float roughness = p_roughness;//sin(iGlobalTime*0.4) * 0.5 + 0.5;
+	float fresnel_pow = p_Fresnel;//0.5;// / (0.5 + roughness);
+	//const vec3 color_mod = vec3(1.000, 0.766, 0.336);
+	vec3 color_mod = vec3(1.0);
+	//vec3 light_color = texture(staticEnvMap,vec3(1.0,0.0,0.0)).xyz * 1.2;
+			
+	//vec3 point = ray * dist;
+	//vec3 normal = point - obj_pos;
+	//normal = normalize(normal);
+			
+	// IBL
+	vec3 ibl_diffuse = textureBlured(staticEnvMap, p_normal);
+	vec3 ibl_reflection = textureBlured(staticEnvMap, reflect(p_viewDirection,p_normal));
+	
+	// fresnel
+	float fresnel = max(1.0 - dot(p_normal,-p_viewDirection), 0.0);
+	fresnel = pow(fresnel,fresnel_pow);    
+	
+	// reflection        
+	vec3 refl = pow(texture(staticEnvMap,reflect(p_viewDirection,p_normal)).xyz, vec3(2.2));
+	refl = mix(refl, ibl_reflection, (1.0-fresnel) * roughness);
+	refl = mix(refl, ibl_reflection, roughness);
+	
+	// specular
+	//vec3 light = normalize(vec3(-0.5,1.0,0.0));
+	//float power = 1.0 / max(roughness * 0.4,0.01);
+	//vec3 spec = light_color * phong(light,ray,normal,power);
+	//refl -= spec;
+	
+	// diffuse
+	vec3 diff = ibl_diffuse;
+	diff = mix(diff, refl, fresnel);        
+
+	vec3 color = mix(diff, refl /* color_mod*/, metallic);// + spec;
+	return color;
+}
+
+void main(void) 
+{
+	// Calculate screen-space texture coordinates, for buffer access
+	vec2 texCoord = calcTexCoord();
+	
+	// Get diffuse color (full-bright) from diffuse buffer and gamma-correct it
+	vec3 diffuseColor = pow(texture(diffuseMap, texCoord).xyz, vec3(2.2));
+	// Get pixel's position in world space
+	vec3 worldPos = texture(positionMap, texCoord).xyz;
+	// Get normal (in world space) and normalize it to minimize floating point approximation errors
+	vec3 normal = normalize(texture(normalMap, texCoord).xyz);
+	// Get material properties
+	vec4 matProperties = texture(matPropertiesMap, texCoord).xyzw;
+	
+	// Extract roughness and metalness values
+	float roughnessVar = matProperties.x;
+	float metalness = matProperties.y;
+	
+	// Calculate the distance between camera and fragment
+	fragmentToEye = cameraPosVec - worldPos;
+	float distanceToFrag = length(fragmentToEye);
+	
+	// Calculate view direction (fragment to eye vector)
+	fragmentToEye = normalize(fragmentToEye);
+	
+    vec3 I = normalize(worldPos - cameraPosVec);
+    vec3 R = normalize(reflect(I, normal));
+	
+	float ior = mix(1.5, 40.5, metalness);
+	//ior = 0.05;
+	
+	float F0 = abs((1.0 - ior) / (1.0 + ior));
+	F0 = F0 * F0;
+	vec3 F0vec = mix(vec3(F0), diffuseColor, metalness);
+	
+    vec3 halfVector = normalize(I + R);
+    float dotLH = clamp(dot(R, halfVector), 0.0, 1.0);
+    float dotLH5 = pow(1.0f - dotLH, 5);
+	float F = F0 + (1.0f - F0) * (dotLH5);
+	
+	// Fresnel
+    float NdotV = clamp(dot(normal, fragmentToEye), 0.0, 1.0);
+	NdotV = pow(1.0 - NdotV, 5.0);
+	float Fresnel = metalness + (1.0 - metalness) * (NdotV);
+	
+	
+	float roughnessSqrt = roughnessVar * roughnessVar;
+	
+	
+	vec3 envColor;// = pow(textureLod(staticEnvMap, R, 0).xyz, vec3(2.2));
+	
+	
+	envColor = getColor(normal, I, metalness, roughnessVar, 3.0);
+	
+	//envColor = mix(pow(textureLod(staticEnvMap, R, 0).xyz, vec3(2.2)), pow(textureLod(staticEnvMap, R, 10).xyz, vec3(2.2)), 0.0);
+	
+	// Multiply the diffuse color by the amount of light the current pixel receives and gamma correct it
+	finalBuffer = envColor * diffuseColor;
+	//finalBuffer = vec3(0.0, 1.0, 0.0);
+	//finalBuffer = pow(diffuseColor, vec3(1.0 / 2.2));
+}

+ 10 - 0
Praxis3D/Data/Shaders/reflectionPass.vert

@@ -0,0 +1,10 @@
+#version 430 core
+
+void main(void) 
+{
+	// Determine texture coordinates
+	vec2 texCoord = vec2((gl_VertexID == 2) ?  2.0 :  0.0, (gl_VertexID == 1) ?  2.0 :  0.0);
+	
+	// Calculate the position, so that the triangle fills the whole screen
+	gl_Position = vec4(texCoord * vec2(2.0, -2.0) + vec2(-1.0, 1.0), 0.0, 1.0);
+}

+ 11 - 6
Praxis3D/Data/Shaders/skybox.frag

@@ -1,13 +1,18 @@
-#version 330
+#version 430 core
 
 layout(location = 1) out vec4 finalBuffer;
 
-in vec2 texCoord;
+in vec3 cubemapCoord;
 
-uniform sampler2D diffuseTexture;
+//uniform sampler2D diffuseTexture;
+uniform samplerCube staticEnvMap;
+uniform float gamma;
 
 void main(void) 
-{
-	// Write the color from model's texture
-	finalBuffer	= texture(diffuseTexture, texCoord).rgba;
+{	
+	// Convert the color from skybox texture to linear space (because it gets gamma-corrected at the final pass)
+	vec3 color = pow(texture(staticEnvMap, cubemapCoord).rgb, vec3(gamma));
+	
+	// Write the color from skybox texture to the final buffer
+	finalBuffer = vec4(0.0, 1.0, 0.0, 1.0);//vec4(color, 1.0);
 }

+ 5 - 5
Praxis3D/Data/Shaders/skybox.vert

@@ -1,15 +1,15 @@
-#version 330
+#version 430 core
 
 layout(location = 0) in vec3 vertexPosition;
-layout(location = 2) in vec2 textureCoord;
+//layout(location = 2) in vec2 textureCoord;
 
-out vec2 texCoord;
+out vec3 cubemapCoord;
 
 uniform mat4 MVP;
 
 void main(void) 
-{
-	texCoord = textureCoord;
+{	
+	cubemapCoord = vertexPosition;
 	
 	gl_Position = MVP * vec4(vertexPosition, 1.0);
 }

+ 11 - 10
Praxis3D/Data/config.ini

@@ -1,18 +1,19 @@
-window_position_x 290
-window_position_y 130
-window_size_windowed_x 1600
-window_size_windowed_y 900
-window_size_fullscreen_x 1920
-window_size_fullscreen_y 1080
-window_fullscreen 0
+window_position_x 250
+window_position_y 60
+window_size_windowed_x 1280
+window_size_windowed_y 768
+window_size_fullscreen_x 3325
+window_size_fullscreen_y 1871
+fullscreen 0
+fullscreen_borderless 1
 gl_context_major_version 4
-gl_context_minor_version 4
-vertical_sync 1
+gl_context_minor_version 3
+vertical_sync 0
 default_texture default.png
 generate_mipmaps 1
 gl_texture_anisotropy 16
 camera_freelook_speed 25
-face_culling 0
+face_culling 1
 fov 80
 z_near 0.1
 z_far 40000

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

@@ -39,8 +39,12 @@
 		"Source_ShaderLoader"	: "Shader Loader",
 		"Source_FileLoader"		: "File Loader",
 		"Source_SceneLoader"	: "Scene Loader",
+		"Source_LightingPass"	: "Lighting Rendering Pass",
 		"Source_GeometryBuffer"	: "Geometry Buffer",
+		"Source_GeometryPass"	: "Geometry Rendering Pass",
 		"Source_GraphicsObject"	: "Graphics Object",
+		"Source_FinalPass"		: "Final Rendering Pass",
+		"Source_ReflectionPass"	: "Reflection Rendering Pass",
 		"Source_ScriptObject"	: "Script Object",
 		"Source_PlayerObject"	: "Player Object",
 		"Source_GameObject"		: "Game Object",

+ 14 - 1
Praxis3D/Praxis3D.vcxproj

@@ -198,6 +198,7 @@
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -298,6 +299,9 @@
     <ClCompile Include="Source\PropertyLoader.cpp" />
     <ClCompile Include="Source\PropertySet.cpp" />
     <ClCompile Include="Source\Renderer.cpp" />
+    <ClCompile Include="Source\RendererBackend.cpp" />
+    <ClCompile Include="Source\RendererFrontend.cpp" />
+    <ClCompile Include="Source\RendererGL.cpp" />
     <ClCompile Include="Source\RendererScene.cpp" />
     <ClCompile Include="Source\RendererSystem.cpp" />
     <ClCompile Include="Source\RenderTask.cpp" />
@@ -306,7 +310,6 @@
     <ClCompile Include="Source\ScriptingScene.cpp" />
     <ClCompile Include="Source\ScriptingSystem.cpp" />
     <ClCompile Include="Source\ScriptingTask.cpp" />
-    <ClCompile Include="Source\ServiceBase.cpp" />
     <ClCompile Include="Source\ShaderLoader.cpp" />
     <ClCompile Include="Source\ShaderUniformUpdater.cpp" />
     <ClCompile Include="Source\SpinWait.cpp" />
@@ -328,6 +331,7 @@
     <ClInclude Include="Source\ChangeController.h" />
     <ClInclude Include="Source\Clock.h" />
     <ClInclude Include="Source\ClockLocator.h" />
+    <ClInclude Include="Source\CommonDefinitions.h" />
     <ClInclude Include="Source\Config.h" />
     <ClInclude Include="Source\ConfigLoader.h" />
     <ClInclude Include="Source\DebugMoveScript.h" />
@@ -337,15 +341,19 @@
     <ClInclude Include="Source\EngineDefinitions.h" />
     <ClInclude Include="Source\EngineState.h" />
     <ClInclude Include="Source\EnumFactory.h" />
+    <ClInclude Include="Source\EnvironmentMapObjects.h" />
     <ClInclude Include="Source\ErrorCodes.h" />
     <ClInclude Include="Source\ErrorHandler.h" />
     <ClInclude Include="Source\ErrorHandlerLocator.h" />
+    <ClInclude Include="Source\FinalPass.h" />
     <ClInclude Include="Source\Framebuffer.h" />
     <ClInclude Include="Source\GeometryBuffer.h" />
+    <ClInclude Include="Source\GeometryPass.h" />
     <ClInclude Include="Source\GraphicsDataSets.h" />
     <ClInclude Include="Source\Input.h" />
     <ClInclude Include="Source\KeyCommand.h" />
     <ClInclude Include="Source\LightingGraphicsObjects.h" />
+    <ClInclude Include="Source\LightingPass.h" />
     <ClInclude Include="Source\LoaderBase.h" />
     <ClInclude Include="Source\Loaders.h" />
     <ClInclude Include="Source\Math.h" />
@@ -357,9 +365,13 @@
     <ClInclude Include="Source\PlayState.h" />
     <ClInclude Include="Source\PropertyLoader.h" />
     <ClInclude Include="Source\PropertySet.h" />
+    <ClInclude Include="Source\ReflectionPass.h" />
     <ClInclude Include="Source\Renderer.h" />
+    <ClInclude Include="Source\RendererBackend.h" />
+    <ClInclude Include="Source\RendererFrontend.h" />
     <ClInclude Include="Source\RendererScene.h" />
     <ClInclude Include="Source\RendererSystem.h" />
+    <ClInclude Include="Source\RenderPassBase.h" />
     <ClInclude Include="Source\RenderTask.h" />
     <ClInclude Include="Source\RenderTaskBase.h" />
     <ClInclude Include="Source\Scancodes.h" />
@@ -379,6 +391,7 @@
     <ClInclude Include="Source\TaskManagerLocator.h" />
     <ClInclude Include="Source\TaskScheduler.h" />
     <ClInclude Include="Source\TextureLoader.h" />
+    <ClInclude Include="Source\UniformData.h" />
     <ClInclude Include="Source\Universal.h" />
     <ClInclude Include="Source\Utilities.h" />
     <ClInclude Include="Source\Window.h" />

+ 48 - 3
Praxis3D/Praxis3D.vcxproj.filters

@@ -106,6 +106,15 @@
     <Filter Include="Engine States\Source Files">
       <UniqueIdentifier>{819ed32a-501c-459f-a502-656acde391a4}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Renderer\Render Passes">
+      <UniqueIdentifier>{18ca1fc3-f7a9-4f5e-b088-22a01715d92f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Renderer\Render Passes\Header Files">
+      <UniqueIdentifier>{eda25418-0a69-4c4c-8b9a-7a4f8f6fc615}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Renderer\Render Passes\Source Files">
+      <UniqueIdentifier>{708c459e-c8f0-4a2c-b313-f0ab523d5163}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="main.cpp">
@@ -219,9 +228,6 @@
     <ClCompile Include="Source\Scancodes.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="Source\ServiceBase.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="Source\Universal.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
@@ -234,6 +240,15 @@
     <ClCompile Include="Source\WorldEditState.cpp">
       <Filter>Engine States\Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\RendererBackend.cpp">
+      <Filter>Renderer\Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\RendererGL.cpp">
+      <Filter>Renderer\Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\RendererFrontend.cpp">
+      <Filter>Renderer\Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Source\ErrorCodes.h">
@@ -431,6 +446,36 @@
     <ClInclude Include="resource.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Source\EnvironmentMapObjects.h">
+      <Filter>Renderer\Objects\Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\RendererBackend.h">
+      <Filter>Renderer\Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\RendererFrontend.h">
+      <Filter>Renderer\Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\CommonDefinitions.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\UniformData.h">
+      <Filter>Renderer\Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\RenderPassBase.h">
+      <Filter>Renderer\Render Passes\Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\GeometryPass.h">
+      <Filter>Renderer\Render Passes\Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\LightingPass.h">
+      <Filter>Renderer\Render Passes\Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\FinalPass.h">
+      <Filter>Renderer\Render Passes\Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\ReflectionPass.h">
+      <Filter>Renderer\Render Passes\Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="Data\Shaders\geomBillboard.pfrag">

+ 14 - 0
Praxis3D/Source/BaseGraphicsObjects.h

@@ -87,6 +87,20 @@ public:
 	
 	const inline GraphicsData &getBaseObjectData() const { return m_baseObjectData; }
 
+	// Setters for spacial data
+	inline void setScale(const Math::Vec3f &p_scale)				{ m_baseObjectData.m_scale = p_scale;				}
+	inline void setPosition(const Math::Vec3f &p_position)			{ m_baseObjectData.m_position = p_position;			}
+	inline void setRotation(const Math::Vec3f &p_rotation)			{ m_baseObjectData.m_rotation = p_rotation;			}
+	inline void setOffsetPosition(const Math::Vec3f &p_position)	{ m_baseObjectData.m_offsetPosition = p_position;	}
+	inline void setOffsetRotation(const Math::Vec3f &p_rotation)	{ m_baseObjectData.m_offsetRotation = p_rotation;	}
+
+	// Setters for misc data
+	inline void setAlphaThreshold(const float p_value)		{ m_baseObjectData.m_alphaThreshold = p_value;		}
+	inline void setEmissiveThreshold(const float p_value)	{ m_baseObjectData.m_emissiveThreshold = p_value;	}
+	inline void setHeightScale(const float p_value)			{ m_baseObjectData.m_heightScale = p_value;			}
+	inline void setTextureTilingFactor(const float p_value) { m_baseObjectData.m_textureTilingFactor = p_value; }
+	inline void setAffectedByLighting(const bool p_flag)	{ m_affectedByLighting = p_flag;					}
+
 protected:
 	// A flag telling if this object should be rendered during geometry pass or as a post-process (i.e. after lighting)
 	bool m_affectedByLighting;

+ 2 - 2
Praxis3D/Source/CameraGraphicsObject.h

@@ -9,7 +9,7 @@ class RendererScene;
 
 class CameraObject : public BaseGraphicsObject
 {
-	friend class RendererScene;
+	//friend class RendererScene;
 	friend class RendererState;
 	//friend class BaseGraphicsObject;
 public:
@@ -51,7 +51,7 @@ public:
 	{
 		// NOTE: rotation vector is used as a target vector; scale vector is used as up-vector (to save space)
 		//m_baseObjectData.m_modelMat.initCamera(m_baseObjectData.m_position, m_baseObjectData.m_rotation, m_baseObjectData.m_scale);
-		m_needsUpdate = false;
+		//m_needsUpdate = false;
 	}
 
 	// Interested in Model Matrix, that would act as view matrix (so camera could be attached to any object)

+ 34 - 1
Praxis3D/Source/CameraScript.h

@@ -72,7 +72,11 @@ class FreeCamera : public Camera
 public:
 	FreeCamera(SystemScene *p_systemScene, std::string p_name) : Camera(p_systemScene, p_name, Properties::FreeCamera)
 	{
+		m_enableLowerLimit = false;
+		m_enableUpperLimit = false;
 
+		m_lowerLimit = 0.0f;
+		m_upperLimit = 0.0f;
 	}
 
 	virtual ErrorCode init()
@@ -99,6 +103,12 @@ public:
 		propertySet.addProperty(Properties::Speed, m_speed);
 		propertySet.addProperty(Properties::SprintSpeed, m_fasterSpeed);
 
+		if(m_enableLowerLimit)
+			propertySet.addProperty(Properties::LowerLimit, m_lowerLimit);
+		if(m_enableUpperLimit)
+			propertySet.addProperty(Properties::UpperLimit, m_upperLimit);
+
+
 		// Add root key-binding property set
 		auto &keyBinds = propertySet.addPropertySet(Properties::Keybindings);
 
@@ -122,7 +132,7 @@ public:
 			m_horizontalAngle -= Config::inputVar().mouse_jaw * mouseInfo.m_movementX * (Config::inputVar().mouse_sensitivity * 0.01f);
 			m_verticalAngle -= Config::inputVar().mouse_pitch * mouseInfo.m_movementY * (Config::inputVar().mouse_sensitivity * 0.01f);
 
-			m_verticalAngle = Math::clip(m_verticalAngle, -Config::inputVar().mouse_pitch_clip, Config::inputVar().mouse_pitch_clip);
+			m_verticalAngle = Math::clamp(m_verticalAngle, -Config::inputVar().mouse_pitch_clip, Config::inputVar().mouse_pitch_clip);
 		}
 
 		// Calculate camera's rotation
@@ -146,6 +156,12 @@ public:
 		if(m_strafeRightKey.isActivated())
 			m_positionVec += m_horizontalVec * speed * p_deltaTime;
 
+		if(m_enableLowerLimit && m_positionVec.y < m_lowerLimit)
+			m_positionVec.y = m_lowerLimit;
+
+		if(m_enableUpperLimit && m_positionVec.y > m_upperLimit)
+			m_positionVec.y = m_upperLimit;
+
 		// Calculate camera's position based on the pressed movement keys
 		m_upVector = Math::cross(m_horizontalVec, m_targetVec);
 		m_modelMatrix.initCamera(m_positionVec, m_targetVec + m_positionVec, m_upVector);
@@ -217,10 +233,27 @@ public:
 		m_sprintKey.bind(p_string);
 	}
 
+	inline void setLowerLimit(const float p_limit)
+	{
+		m_enableLowerLimit = true;
+		m_lowerLimit = p_limit;
+	}
+	inline void setUpperLimit(const float p_limit)
+	{
+		m_enableUpperLimit = true;
+		m_upperLimit = p_limit;
+	}
+
 private:
 	KeyCommand	m_forwardKey,
 				m_backwardKey,
 				m_strafeLeftKey,
 				m_strafeRightKey,
 				m_sprintKey;
+	
+	float	m_lowerLimit,
+			m_upperLimit;
+
+	bool	m_enableLowerLimit,
+			m_enableUpperLimit;
 };

+ 55 - 20
Praxis3D/Source/ChangeController.cpp

@@ -23,11 +23,15 @@ ChangeController::ChangeController() : m_lastID(0), m_tlsNotifyList(TLS_OUT_OF_I
 	::TlsSetValue(m_tlsNotifyList, list);
 	m_notifyLists.push_back(list);
 
+	std::cout << "TlsSetValue: " << m_tlsNotifyList << ", " << list->size() << std::endl;
+
 	// Reserve space and prepare one-off notify lists for the main (this) thread
 	std::vector<OneTimeNotification> *oneOffList = new std::vector<OneTimeNotification>;
 	oneOffList->reserve((size_t)Config::engineVar().change_ctrl_oneoff_notify_list_reserv);
 	::TlsSetValue(m_tlsOneTimeNotifyList, oneOffList);
 	m_oneTimeNotifyLists.push_back(oneOffList);
+
+	std::cout << "TlsSetValue: " << m_tlsOneTimeNotifyList << ", " << oneOffList->size() << std::endl;
 }
 ChangeController::~ChangeController()
 {
@@ -39,17 +43,17 @@ ChangeController::~ChangeController()
 		if(m_subjectsList[subjectIndex].m_subject)
 		{
 			// Iterate over all subject's observers
-			for(decltype(m_subjectsList[subjectIndex].m_observersList.size()) observerIndex = 0; 
-			observerIndex < m_subjectsList[subjectIndex].m_observersList.size(); observerIndex++)
+			for(decltype(m_subjectsList[subjectIndex].m_observersList.size()) observerIndex = 0;
+				observerIndex < m_subjectsList[subjectIndex].m_observersList.size(); observerIndex++)
 			{
 				// Unregister the subject
 				unregisterSubject(m_subjectsList[subjectIndex].m_subject, m_subjectsList[subjectIndex].m_observersList[observerIndex].m_observer);
 			}
 		}
 	}
-	
+
 	// Free thread local storage
-	if (m_tlsNotifyList != TLS_OUT_OF_INDEXES)
+	if(m_tlsNotifyList != TLS_OUT_OF_INDEXES)
 		::TlsFree(m_tlsNotifyList);
 
 	if(m_tlsOneTimeNotifyList != TLS_OUT_OF_INDEXES)
@@ -230,6 +234,8 @@ ErrorCode ChangeController::distributeChanges(BitMask p_systemsToNotify, BitMask
 				}
 			}
 
+			//std::cout << currentList->size() << "; ";
+
 			// Clear out the list before moving to the next one
 			currentList->clear();
 		}
@@ -240,17 +246,17 @@ ErrorCode ChangeController::distributeChanges(BitMask p_systemsToNotify, BitMask
 		// If there are no messages to process, exit the loop
 		if(numberOfChanges == 0)
 			break;
-		
+
 		// If there are more changes to distribute than grain size, do it in parallel
-		if((unsigned int) (numberOfChanges > Config::engineVar().change_ctrl_grain_size && m_taskManager != nullptr))
+		if((unsigned int)(numberOfChanges > Config::engineVar().change_ctrl_grain_size && m_taskManager != nullptr))
 		{
 			// Process the notifications in a parallel loop
-			m_taskManager->parallelFor(nullptr, distributionCallback, this, 0, (unsigned int) numberOfChanges, Config::engineVar().change_ctrl_grain_size);
+			m_taskManager->parallelFor(nullptr, distributionCallback, this, 0, (unsigned int)numberOfChanges, Config::engineVar().change_ctrl_grain_size);
 		}
 		else
 		{
 			// Not enough notifications to distribute them in parallel, so process them in serial
-			distributeRange(0, (unsigned int) numberOfChanges);
+			distributeRange(0, (unsigned int)numberOfChanges);
 		}
 
 		if(m_changesToDistribute == Systems::Changes::All)
@@ -290,12 +296,28 @@ void ChangeController::changeOccurred(ObservedSubject *p_subject, BitMask p_chan
 		else
 		{
 			// Get thread local notification list
-			auto &notifyList = getNotifyList(m_tlsNotifyList);
+			auto *notifyList = getNotifyList(m_tlsNotifyList);
 
-			// Don't check for duplicates, for performance reasons
-			notifyList.push_back(Notification(p_subject, p_changedBits));
+			//std::cout << "test ( ";
+
+			//std::cout << m_tlsNotifyList << " ";
+
+			if(notifyList != nullptr)
+			{
+				// Don't check for duplicates, for performance reasons
+				notifyList->push_back(Notification(p_subject, p_changedBits));
+
+				//std::cout << "size: " << notifyList->size() << " ";
+			}
+			else
+			{
+				std::cout << std::endl << GetLastErrorAsString() << std::endl;
+				std::cout << "nullptr ";
+			}
 		}
 	}
+
+	//std::cout << ") test" << std::endl;
 }
 
 void ChangeController::oneTimeChange(ObservedSubject *p_subject, Observer *p_observer, BitMask p_changedBits)
@@ -372,6 +394,8 @@ void ChangeController::initThreadLocalData(void* p_controller)
 		notifyList->reserve((unsigned int)Config::engineVar().change_ctrl_notify_list_reserv);
 		::TlsSetValue(controller->m_tlsNotifyList, notifyList);
 
+		//std::cout << "TlsSetValue: " << controller->m_tlsNotifyList << ", " << notifyList->size() << std::endl;
+
 		// Lock muted while adding the new array to the list
 		SpinWait::Lock lock(controller->m_spinWaitUpdate);
 		controller->m_notifyLists.push_back(notifyList);
@@ -387,6 +411,8 @@ void ChangeController::initThreadLocalData(void* p_controller)
 		oneTimeNotifyList->reserve((unsigned int)Config::engineVar().change_ctrl_oneoff_notify_list_reserv);
 		::TlsSetValue(controller->m_tlsOneTimeNotifyList, oneTimeNotifyList);
 
+		//sstd::cout << "TlsSetValue: " << controller->m_tlsOneTimeNotifyList << ", " << oneTimeNotifyList->size() << std::endl;
+
 		// Lock muted while adding the new array to the list
 		SpinWait::Lock lock(controller->m_spinWaitUpdate);
 		controller->m_oneTimeNotifyLists.push_back(oneTimeNotifyList);
@@ -430,7 +456,7 @@ void ChangeController::distributionCallback(void *p_controller, unsigned int p_b
 void ChangeController::distributeRange(unsigned int p_begin, unsigned int p_end)
 {
 	// Loop through all the notification in the given range
-	for (size_t i = p_begin; i < p_end; i++)
+	for(size_t i = p_begin; i < p_end; i++)
 	{
 		// Get the notification and the subject
 		MappedNotification &notification = m_cumulativeNotifyList[i];
@@ -439,21 +465,21 @@ void ChangeController::distributeRange(unsigned int p_begin, unsigned int p_end)
 		// Distribute any desired changes
 		BitMask activeChanges = notification.m_changedBits & m_changesToDistribute;
 
-		if (activeChanges)
+		if(activeChanges)
 		{
 			// Clear the bit for the changes we are distributing
 			notification.m_changedBits &= ~activeChanges;
 
 			// Loop through all the observers and let them process the notification
 			std::vector<ObserverRequest> &observerList = subject.m_observersList;
-			for (size_t j = 0; j != observerList.size(); j++)
+			for(size_t j = 0; j != observerList.size(); j++)
 			{
 				// Determine if this observer is interested in this notification
 				BitMask changesToSend = observerList[j].m_interestBits & activeChanges;
-				if (changesToSend)
+				if(changesToSend)
 				{
 					// If this observer is part of the systems to be notified then we can pass it this notification
-					if (observerList[j].m_observerIdBits & m_systemsToNotify)
+					if(observerList[j].m_observerIdBits & m_systemsToNotify)
 					{
 						// Have the observer process this change (notification)
 						observerList[j].m_observer->changeOccurred(subject.m_subject, changesToSend);
@@ -477,7 +503,7 @@ ErrorCode ChangeController::removeSubject(ObservedSubject *p_subject)
 		_ASSERT(ID != unsigned int(-1));
 		_ASSERT(m_subjectsList[ID].m_subject == p_subject);
 
-		if (m_subjectsList.size() <= ID || m_subjectsList[ID].m_subject != p_subject)
+		if(m_subjectsList.size() <= ID || m_subjectsList[ID].m_subject != p_subject)
 		{
 			return ErrorCode::Failure;
 			// TODO ERROR FAILURE
@@ -490,7 +516,7 @@ ErrorCode ChangeController::removeSubject(ObservedSubject *p_subject)
 	}
 
 	std::vector<ObserverRequest>::iterator listIterator = observerList.begin();
-	for (; listIterator != observerList.end(); listIterator++)
+	for(; listIterator != observerList.end(); listIterator++)
 	{
 		p_subject->detach(listIterator->m_observer);
 	}
@@ -498,9 +524,18 @@ ErrorCode ChangeController::removeSubject(ObservedSubject *p_subject)
 	return returnError;
 }
 
-inline std::vector<ChangeController::Notification> &ChangeController::getNotifyList(unsigned int p_tlsIndex)
+inline std::vector<ChangeController::Notification> *ChangeController::getNotifyList(unsigned int p_tlsIndex)
 {
-	return *static_cast<std::vector<ChangeController::Notification>*>(::TlsGetValue(p_tlsIndex));
+	LPVOID test = ::TlsGetValue(p_tlsIndex);
+
+	unsigned int test2 = (unsigned int)test;
+
+	//std::cout << test2 << " ";
+
+	if(test2 > 0)
+		return static_cast<std::vector<ChangeController::Notification>*>(::TlsGetValue(p_tlsIndex));
+	else
+		return nullptr;
 }
 inline std::vector<ChangeController::OneTimeNotification> &ChangeController::getOneTimeNotifyList(unsigned int p_tlsIndex)
 {

+ 26 - 3
Praxis3D/Source/ChangeController.h

@@ -1,11 +1,14 @@
 
 #include <list>
-//#include <set>
 #include <vector>
 
 #include "ObserverBase.h"
 #include "SpinWait.h"
 
+#include <lmerr.h>
+#include <tchar.h>
+#include <windows.h>
+
 class TaskManager;
 
 class ChangeController : public Observer
@@ -55,7 +58,7 @@ private:
 	};
 	struct Notification
 	{
-		Notification(ObservedSubject *p_subject, BitMask p_changedBits) : 
+		Notification(ObservedSubject *p_subject, BitMask p_changedBits) :
 			m_subject(p_subject), m_changedBits(p_changedBits) { }
 
 		ObservedSubject *m_subject;
@@ -105,6 +108,26 @@ private:
 
 	ErrorCode removeSubject(ObservedSubject *p_subject);
 
-	std::vector<Notification> &getNotifyList(unsigned int p_tlsIndex);
+	std::vector<Notification> *getNotifyList(unsigned int p_tlsIndex);
 	std::vector<OneTimeNotification> &getOneTimeNotifyList(unsigned int p_tlsIndex);
+
+	//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
+	std::string GetLastErrorAsString()
+	{
+		//Get the error message, if any.
+		DWORD errorMessageID = ::GetLastError();
+		if(errorMessageID == 0)
+			return std::string(); //No error message has been recorded
+
+		LPSTR messageBuffer = nullptr;
+		size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+									 NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
+
+		std::string message(messageBuffer, size);
+
+		//Free the buffer.
+		LocalFree(messageBuffer);
+
+		return message;
+	}
 };

+ 177 - 0
Praxis3D/Source/CommandBuffer.h

@@ -0,0 +1,177 @@
+#pragma once
+
+#include "GraphicsDataSets.h"
+#include "RendererFrontend.h"
+
+class CommandBuffer
+{
+public:
+	struct Command
+	{
+		Command(RendererBackend::ScreenSpaceDrawCommand &p_screenSpaceCommand) : m_commandUnion(p_screenSpaceCommand), m_commandType(CommandType_ScreenSpaceDraw) { }
+		Command(RendererBackend::DrawCommand &p_drawCommand) : m_commandUnion(p_drawCommand), m_commandType(CommandType_Draw) { }
+		Command(RendererBackend::BindCommand &p_bindCommand) : m_commandUnion(p_bindCommand), m_commandType(CommandType_Bind) { }
+		Command(RendererBackend::LoadCommand &p_loadCommand) : m_commandUnion(p_loadCommand), m_commandType(CommandType_Load) { }
+
+		union CommandUnion
+		{
+			CommandUnion(RendererBackend::ScreenSpaceDrawCommand &p_screenSpaceCommand) : m_screenSpaceCommand(p_screenSpaceCommand) { }
+			CommandUnion(RendererBackend::DrawCommand &p_drawCommand) : m_drawCommand(p_drawCommand) { }
+			CommandUnion(RendererBackend::BindCommand &p_bindCommand) : m_bindCommand(p_bindCommand) { }
+			CommandUnion(RendererBackend::LoadCommand &p_loadCommand) : m_loadCommand(p_loadCommand) { }
+
+			RendererBackend::ScreenSpaceDrawCommand m_screenSpaceCommand;
+			RendererBackend::DrawCommand m_drawCommand;
+			RendererBackend::BindCommand m_bindCommand;
+			RendererBackend::LoadCommand m_loadCommand;
+		};
+
+		CommandUnion m_commandUnion;
+		const CommandType m_commandType;
+	};
+
+	typedef std::vector<std::pair<int64_t, Command>> Commands;
+
+	CommandBuffer() { }
+	~CommandBuffer() { }
+
+	inline void queueForDrawing(const RenderableObjectData &p_object, const unsigned int p_shaderHandle, const ShaderUniformUpdater &p_uniformUpdater, const Math::Mat4f &p_viewProjMatrix)
+	{
+		// Get the neccessary handles
+		const unsigned int modelHandle = p_object.m_model.getHandle();
+
+		// Calculare model-view-projection matrix
+		const Math::Mat4f modelViewProjMatrix = p_viewProjMatrix * p_object.m_baseObjectData.m_modelMat;
+
+		// Assign the object data that is later passed to the shaders
+		const UniformObjectData objectData(p_object.m_baseObjectData.m_modelMat,
+										   modelViewProjMatrix,
+										   p_object.m_baseObjectData.m_heightScale,
+										   p_object.m_baseObjectData.m_alphaThreshold,
+										   p_object.m_baseObjectData.m_emissiveThreshold,
+										   p_object.m_baseObjectData.m_textureTilingFactor);
+
+		// Calculate the sort key
+		RendererBackend::DrawCommands::value_type::first_type sortKey = 0;
+
+		// Add a draw command for each mesh, using the same object data
+		for(decltype(p_object.m_model.getNumMeshes()) meshIndex = 0, numMeshes = p_object.m_model.getNumMeshes(); meshIndex < numMeshes; meshIndex++)
+		{
+			m_commands.emplace_back(
+				sortKey,
+				RendererBackend::DrawCommand(
+					p_uniformUpdater,
+					objectData,
+					p_shaderHandle,
+					modelHandle,
+					p_object.m_model[meshIndex].m_numIndices,
+					p_object.m_model[meshIndex].m_baseVertex,
+					p_object.m_model[meshIndex].m_baseIndex,
+					p_object.m_materials[MaterialType_Diffuse][meshIndex].getHandle(),
+					p_object.m_materials[MaterialType_Normal][meshIndex].getHandle(),
+					p_object.m_materials[MaterialType_Emissive][meshIndex].getHandle(),
+					p_object.m_materials[MaterialType_Combined][meshIndex].getHandle())
+			);
+		}
+	}
+	inline void queueForDrawing(const unsigned int p_shaderHandle, const ShaderUniformUpdater &p_uniformUpdater, const Math::Mat4f &p_viewProjMatrix)
+	{
+		// Assign the object data that is later passed to the shaders
+		const UniformObjectData objectData(p_viewProjMatrix,
+										   p_viewProjMatrix,
+										   Config::graphicsVar().height_scale,
+										   Config::graphicsVar().alpha_threshold,
+										   Config::graphicsVar().emissive_threshold,
+										   Config::graphicsVar().texture_tiling_factor);
+
+		// Calculate the sort key
+		RendererBackend::DrawCommands::value_type::first_type sortKey = 0;
+
+		m_commands.emplace_back(
+			sortKey,
+			RendererBackend::ScreenSpaceDrawCommand(
+				p_uniformUpdater,
+				objectData,
+				p_shaderHandle)
+		);
+	}
+
+	inline void queueForLoading(ShaderLoader::ShaderProgram &p_shader)
+	{
+		// Calculate the sort key
+		RendererBackend::DrawCommands::value_type::first_type sortKey = 0;
+
+		m_commands.emplace_back(
+			sortKey,
+			RendererBackend::LoadCommand(p_shader.m_shaderFilename,
+										 p_shader.m_programHandle,
+										 p_shader.getUniformUpdater(),
+										 p_shader.m_shaderSource,
+										 p_shader.m_errorMessages));
+	}
+	inline void queueForLoading(ModelLoader::ModelHandle &p_model)
+	{
+		// Calculate the sort key
+		RendererBackend::DrawCommands::value_type::first_type sortKey = 0;
+
+		m_commands.emplace_back(
+			sortKey,
+			RendererBackend::LoadCommand(p_model.getFilename(),
+										 p_model.m_model->m_handle,
+										 p_model.m_model->m_buffers,
+										 p_model.m_model->m_numElements,
+										 p_model.m_model->m_bufferSize,
+										 p_model.m_model->getData()));
+	}
+	inline void queueForLoading(TextureLoader2D::Texture2DHandle &p_texture)
+	{
+		// Calculate the sort key
+		RendererBackend::DrawCommands::value_type::first_type sortKey = 0;
+
+		m_commands.emplace_back(
+			sortKey,
+			RendererBackend::LoadCommand(p_texture.getFilename(),
+										 p_texture.getHandleRef(),
+										 p_texture.getTextureFormat(),
+										 p_texture.getMipmapLevel(),
+										 p_texture.getTextureWidth(),
+										 p_texture.getTextureHeight(),
+										 p_texture.getData()));
+	}
+	inline void queueForLoading(RenderableObjectData &p_objectData)
+	{
+		// Load model
+		queueForLoading(p_objectData.m_model);
+
+		// Load shader only if it is custom
+		if(!p_objectData.m_shader->isDefaultProgram())
+			queueForLoading(*p_objectData.m_shader);
+
+		// Load all materials
+		for(decltype(p_objectData.m_numMaterials) i = 0; i < p_objectData.m_numMaterials; i++)
+			for(int matType = 0; matType < MaterialType_NumOfTypes; matType++)
+				queueForLoading(p_objectData.m_materials[matType][i]);
+	}
+
+	inline void queueForUpdate(RendererFrontend::LightUniformBuffer &p_lightBuffer)
+	{
+		// Calculate the sort key
+		RendererBackend::DrawCommands::value_type::first_type sortKey = 0;
+
+		m_commands.emplace_back(
+			sortKey,
+			RendererBackend::LoadCommand(p_lightBuffer.m_handle,
+										 p_lightBuffer.m_bufferType,
+										 p_lightBuffer.m_bufferUsage,
+										 p_lightBuffer.m_bindingIndex,
+										 p_lightBuffer.m_size,
+										 (void*)0));
+	}
+
+	Commands &getCommands()	{ return m_commands; }
+
+	void clearommands()	{ m_commands.clear(); }
+
+private:
+	Commands m_commands;
+};

+ 98 - 0
Praxis3D/Source/CommonDefinitions.h

@@ -0,0 +1,98 @@
+#pragma once
+
+#include <GL\glew.h>
+
+enum BindCommandType : unsigned int
+{
+	BindCommandType_Texture,
+	BindCommandType_Framebuffer
+};
+enum CommandType : unsigned int
+{
+	CommandType_Draw,
+	CommandType_ScreenSpaceDraw,
+	CommandType_Bind,
+	CommandType_Load
+};
+
+enum BufferType : unsigned int
+{
+	BufferType_Uniform		= GL_UNIFORM_BUFFER,
+	BufferType_Array		= GL_ARRAY_BUFFER,
+	BufferType_ElementArray = GL_ELEMENT_ARRAY_BUFFER
+};
+enum BufferUpdateType : unsigned int
+{
+	BufferUpdate_Data,		// updates the whole buffer at once
+	BufferUpdate_SubData	// updates part of the buffer (based on offset and size)
+};
+enum BufferUsageHint : unsigned int
+{
+	BufferUsageHint_Stream  = GL_STREAM_DRAW,
+	BufferUsageHint_Static  = GL_STATIC_DRAW,
+	BufferUsageHint_Dynamic = GL_DYNAMIC_DRAW
+};
+enum LightBufferBinding : unsigned int
+{
+	LightBufferBinding_PointLight = 0,
+	LightBufferBinding_SpotLight
+};
+enum LoadObjectType : unsigned int
+{
+	LoadObject_Buffer,
+	LoadObject_Shader,
+	LoadObject_Texture2D,
+	LoadObject_TextureCube,
+	LoadObject_Model
+};
+enum MiscLoadObjectType : unsigned int
+{
+	MiscLoadObj_StaticEnvMap
+};
+enum MaterialType : unsigned int
+{
+	MaterialType_Diffuse,
+	MaterialType_Normal,
+	MaterialType_Emissive,
+	MaterialType_Combined,
+	MaterialType_NumOfTypes,
+	MaterialType_Roughness = MaterialType_NumOfTypes,
+	MaterialType_Metalness,
+	MaterialType_Height,
+	MaterialType_AmbientOcclusion,
+	MaterialType_NumOfTypes_Extended
+};
+enum ModelBufferType : unsigned int
+{
+	// WARNING: do not modify, enum entries are order-sensitive
+	// (Model::m_numElements depends on this order)
+
+	ModelBuffer_Position = 0,
+	ModelBuffer_Normal,
+	ModelBuffer_TexCoord,
+	ModelBuffer_Tangents,
+	ModelBuffer_Bitangents,
+	ModelBuffer_NumTypesWithoutIndex,
+	ModelBuffer_Index = ModelBuffer_NumTypesWithoutIndex,
+	ModelBuffer_NumAllTypes
+};
+enum ShaderType : unsigned int
+{
+	// WARNING: do not change the order - enum entries are order-sensitive
+
+	ShaderType_Fragment,
+	ShaderType_Geometry,
+	ShaderType_Vertex,
+	ShaderType_TessControl,
+	ShaderType_TessEvaluation,
+	ShaderType_NumOfTypes
+};
+enum TextureFormat : int
+{
+	TextureFormat_Red	= GL_RED,
+	TextureFormat_Green = GL_GREEN,
+	TextureFormat_Blue	= GL_BLUE,
+	TextureFormat_Alpha = GL_ALPHA,
+	TextureFormat_RGB	= GL_RGB,
+	TextureFormat_RGBA	= GL_RGBA
+};

+ 23 - 5
Praxis3D/Source/Config.cpp

@@ -72,6 +72,9 @@ void Config::init()
 	AddVariablePredef(m_framebfrVar, gl_normal_buffer_internal_format);
 	AddVariablePredef(m_framebfrVar, gl_normal_buffer_texture_format);
 	AddVariablePredef(m_framebfrVar, gl_normal_buffer_texture_type);
+	AddVariablePredef(m_framebfrVar, gl_mat_properties_buffer_internal_format);
+	AddVariablePredef(m_framebfrVar, gl_mat_properties_buffer_texture_format);
+	AddVariablePredef(m_framebfrVar, gl_mat_properties_buffer_texture_type);
 	AddVariablePredef(m_framebfrVar, gl_blur_buffer_internal_format);
 	AddVariablePredef(m_framebfrVar, gl_blur_buffer_texture_type);
 	AddVariablePredef(m_framebfrVar, gl_blur_buffer_texture_format);
@@ -110,7 +113,6 @@ void Config::init()
 	AddVariablePredef(m_graphicsVar, multisample_samples);
 	AddVariablePredef(m_graphicsVar, alpha_threshold);
 	AddVariablePredef(m_graphicsVar, emissive_threshold);
-	AddVariablePredef(m_graphicsVar, parallax_height_scale);
 	AddVariablePredef(m_graphicsVar, fog_color_x);
 	AddVariablePredef(m_graphicsVar, fog_color_y);
 	AddVariablePredef(m_graphicsVar, fog_color_z);
@@ -123,6 +125,7 @@ void Config::init()
 	AddVariablePredef(m_graphicsVar, light_color_r);
 	AddVariablePredef(m_graphicsVar, light_color_g);
 	AddVariablePredef(m_graphicsVar, light_color_b);
+	AddVariablePredef(m_graphicsVar, height_scale);
 	AddVariablePredef(m_graphicsVar, texture_tiling_factor);
 	AddVariablePredef(m_graphicsVar, z_far);
 	AddVariablePredef(m_graphicsVar, z_near);
@@ -214,6 +217,10 @@ void Config::init()
 	AddVariablePredef(m_rendererVar, gaussian_blur_horizontal_vert_shader);
 	AddVariablePredef(m_rendererVar, light_pass_vert_shader);
 	AddVariablePredef(m_rendererVar, light_pass_frag_shader);
+	AddVariablePredef(m_rendererVar, final_pass_vert_shader);
+	AddVariablePredef(m_rendererVar, final_pass_frag_shader);
+	AddVariablePredef(m_rendererVar, reflection_pass_vert_shader);
+	AddVariablePredef(m_rendererVar, reflection_pass_frag_shader);
 	AddVariablePredef(m_rendererVar, dir_light_quad_offset_x);
 	AddVariablePredef(m_rendererVar, dir_light_quad_offset_y);
 	AddVariablePredef(m_rendererVar, dir_light_quad_offset_z);
@@ -244,7 +251,8 @@ void Config::init()
 	AddVariablePredef(m_shaderVar, alphaCullingUniform);
 	AddVariablePredef(m_shaderVar, alphaThresholdUniform);
 	AddVariablePredef(m_shaderVar, emissiveThresholdUniform);
-	AddVariablePredef(m_shaderVar, parallaxHeightScale);
+	AddVariablePredef(m_shaderVar, heightScaleUniform);
+	AddVariablePredef(m_shaderVar, combinedTextureUniform);
 	AddVariablePredef(m_shaderVar, textureTilingFactorUniform);
 	AddVariablePredef(m_shaderVar, dirLightColor);
 	AddVariablePredef(m_shaderVar, dirLightDirection);
@@ -265,7 +273,9 @@ void Config::init()
 	AddVariablePredef(m_shaderVar, diffuseMapUniform);
 	AddVariablePredef(m_shaderVar, normalMapUniform);
 	AddVariablePredef(m_shaderVar, emissiveMapUniform);
+	AddVariablePredef(m_shaderVar, matPropertiesMapUniform);
 	AddVariablePredef(m_shaderVar, blurMapUniform);
+	AddVariablePredef(m_shaderVar, finalMapUniform);
 	AddVariablePredef(m_shaderVar, sunGlowTextureUniform);
 	AddVariablePredef(m_shaderVar, skyMapTextureUniform);
 	AddVariablePredef(m_shaderVar, dirShadowMapTextureUniform);
@@ -290,6 +300,14 @@ void Config::init()
 	AddVariablePredef(m_textureVar, default_normal_texture);
 	AddVariablePredef(m_textureVar, default_specular_intensity);
 	AddVariablePredef(m_textureVar, default_specular_power);
+	AddVariablePredef(m_textureVar, diffuse_texture_format);
+	AddVariablePredef(m_textureVar, normal_texture_format);
+	AddVariablePredef(m_textureVar, emissive_texture_format);
+	AddVariablePredef(m_textureVar, roughness_texture_format);
+	AddVariablePredef(m_textureVar, metalness_texture_format);
+	AddVariablePredef(m_textureVar, height_texture_format);
+	AddVariablePredef(m_textureVar, ambientOcclusion_texture_format);
+	AddVariablePredef(m_textureVar, RMHAO_texture_format);
 	AddVariablePredef(m_textureVar, gl_texture_anisotropy);
 	AddVariablePredef(m_textureVar, gl_texture_magnification);
 	AddVariablePredef(m_textureVar, gl_texture_minification);
@@ -355,9 +373,9 @@ ErrorCode Config::loadFromFile(const std::string &p_filename)
 	   m_rendererVar.heightmap_combine_channel >= TextureColorChannelOffset::ColorOffset_NumChannels)
 		m_rendererVar.heightmap_combine_channel = TextureColorChannelOffset::ColorOffset_Alpha;
 
-	if(m_rendererVar.heightmap_combine_texture < Model::ModelMaterialType::ModelMat_diffuse ||
-	   m_rendererVar.heightmap_combine_texture >= Model::ModelMaterialType::NumOfModelMaterials)
-		m_rendererVar.heightmap_combine_texture = Model::ModelMaterialType::ModelMat_normal;
+	if(m_rendererVar.heightmap_combine_texture < MaterialType_Diffuse ||
+	   m_rendererVar.heightmap_combine_texture >= MaterialType_NumOfTypes)
+		m_rendererVar.heightmap_combine_texture = MaterialType_Normal;
 
 	return returnCode;
 }

+ 88 - 14
Praxis3D/Source/Config.h

@@ -109,34 +109,47 @@ namespace Properties
 	Code(Scale,) \
 	/* Graphics */ \
 	Code(AlphaThreshold, ) \
+	Code(AmbientOcclusion, ) \
 	Code(Attenuation,) \
 	Code(Camera,) \
 	Code(Color,) \
+	Code(CombinedTexture,) \
 	Code(CutoffAngle,) \
 	Code(Diffuse,) \
 	Code(Direction,) \
 	Code(DirectionalLight,) \
 	Code(Emissive,) \
+	Code(EnvironmentMapDynamic,) \
+	Code(EnvironmentMapStatic,) \
 	Code(FragmentShader,) \
 	Code(GeometryShader,) \
-	Code(Gloss,) \
 	Code(Graphics,) \
 	Code(Height,) \
+	Code(HeightScale,) \
 	Code(Intensity,) \
 	Code(Lighting,) \
 	Code(Materials,) \
+	Code(Metalness,) \
 	Code(Models,) \
 	Code(ModelObject,) \
 	Code(ModelPoolSize,) \
+	Code(NegativeX,) \
+	Code(NegativeY,) \
+	Code(NegativeZ,) \
 	Code(Normal,) \
+	Code(ParallaxHeightScale,) \
 	Code(PointLight,) \
 	Code(PointLightPoolSize,) \
+	Code(PositiveX,) \
+	Code(PositiveY,) \
+	Code(PositiveZ,) \
 	Code(PostProcess,) \
+	Code(RMHAO,) \
+	Code(Roughness,) \
 	Code(Shaders,) \
 	Code(ShaderPoolSize,) \
 	Code(ShaderGraphicsObject,) \
 	Code(ShaderModelObject,) \
-	Code(Specular,) \
 	Code(SpotLight,) \
 	Code(SpotLightPoolSize,) \
 	Code(TessControlShader,) \
@@ -175,6 +188,7 @@ namespace Properties
 	Code(FreeCamera,) \
 	Code(Latitude,) \
 	Code(Longitude,) \
+	Code(LowerLimit,) \
 	Code(InputScript,) \
 	Code(Hours,) \
 	Code(KeyCode,) \
@@ -187,6 +201,7 @@ namespace Properties
 	Code(Speed,) \
 	Code(SprintSpeed,) \
 	Code(TimeMultiplier,) \
+	Code(UpperLimit,) \
 	Code(WorldEditScript,) \
 	/* Window */ \
 	Code(Fullscreen,) \
@@ -217,34 +232,47 @@ namespace Properties
 		GetString(Rotation),
 		GetString(Scale),
 		GetString(AlphaThreshold),
+		GetString(AmbientOcclusion),
 		GetString(Attenuation),
 		GetString(Camera),
 		GetString(Color),
+		GetString(CombinedTexture),
 		GetString(CutoffAngle),
 		GetString(Diffuse),
 		GetString(Direction),
 		GetString(DirectionalLight),
 		GetString(Emissive),
+		GetString(EnvironmentMapDynamic),
+		GetString(EnvironmentMapStatic),
 		GetString(FragmentShader),
 		GetString(GeometryShader),
-		GetString(Gloss),
 		GetString(Graphics),
 		GetString(Height),
+		GetString(HeightScale),
 		GetString(Intensity),
 		GetString(Lighting),
 		GetString(Materials),
+		GetString(Metalness),
 		GetString(Models),
 		GetString(ModelObject),
 		GetString(ModelPoolSize),
+		GetString(NegativeX),
+		GetString(NegativeY),
+		GetString(NegativeZ),
 		GetString(Normal),
+		GetString(ParallaxHeightScale),
 		GetString(PointLight),
 		GetString(PointLightPoolSize),
+		GetString(PositiveX),
+		GetString(PositiveY),
+		GetString(PositiveZ),
 		GetString(PostProcess),
+		GetString(RMHAO),
+		GetString(Roughness),
 		GetString(Shaders),
 		GetString(ShaderPoolSize),
 		GetString(ShaderGraphicsObject),
 		GetString(ShaderModelObject),
-		GetString(Specular),
 		GetString(SpotLight),
 		GetString(SpotLightPoolSize),
 		GetString(TessControlShader),
@@ -280,6 +308,7 @@ namespace Properties
 		GetString(FreeCamera),
 		GetString(Latitude),
 		GetString(Longitude),
+		GetString(LowerLimit),
 		GetString(InputScript),
 		GetString(Hours),
 		GetString(KeyCode),
@@ -292,6 +321,7 @@ namespace Properties
 		GetString(Speed),
 		GetString(SprintSpeed),
 		GetString(TimeMultiplier),
+		GetString(UpperLimit),
 		GetString(WorldEditScript),
 		GetString(Fullscreen),
 		GetString(MouseCapture),
@@ -393,8 +423,8 @@ public:
 	{
 		FramebfrVariables()
 		{
-			gl_position_buffer_internal_format = GL_RGBA32F;
-			gl_position_buffer_texture_format = GL_RGBA;
+			gl_position_buffer_internal_format = GL_RGB32F;
+			gl_position_buffer_texture_format = GL_RGB;
 			gl_position_buffer_texture_type = GL_FLOAT;
 
 			gl_diffuse_buffer_internal_format = GL_RGBA16F;
@@ -405,16 +435,20 @@ public:
 			gl_emissive_buffer_texture_format = GL_RGBA;
 			gl_emissive_buffer_texture_type = GL_FLOAT;
 
-			gl_normal_buffer_internal_format = GL_RGBA16F;
-			gl_normal_buffer_texture_format = GL_RGBA;
+			gl_normal_buffer_internal_format = GL_RGB16F;
+			gl_normal_buffer_texture_format = GL_RGB;
 			gl_normal_buffer_texture_type = GL_FLOAT;
 
+			gl_mat_properties_buffer_internal_format = GL_RGBA16F;
+			gl_mat_properties_buffer_texture_format = GL_RGBA;
+			gl_mat_properties_buffer_texture_type = GL_FLOAT;
+
 			gl_blur_buffer_internal_format = GL_RGBA16F;
 			gl_blur_buffer_texture_format = GL_RGBA;
 			gl_blur_buffer_texture_type = GL_FLOAT;
 
-			gl_final_buffer_internal_format = GL_RGBA16F;
-			gl_final_buffer_texture_format = GL_RGBA;
+			gl_final_buffer_internal_format = GL_RGB16F;
+			gl_final_buffer_texture_format = GL_RGB;
 			gl_final_buffer_texture_type = GL_FLOAT;
 
 			gl_depth_buffer_internal_format = GL_DEPTH_COMPONENT32F;
@@ -453,6 +487,10 @@ public:
 		int gl_normal_buffer_texture_format;
 		int gl_normal_buffer_texture_type;
 
+		int gl_mat_properties_buffer_internal_format;
+		int gl_mat_properties_buffer_texture_format;
+		int gl_mat_properties_buffer_texture_type;
+
 		int gl_blur_buffer_internal_format;
 		int gl_blur_buffer_texture_type;
 		int gl_blur_buffer_texture_format;
@@ -510,7 +548,6 @@ public:
 			rendering_res_y = 900;
 			alpha_threshold = 0.0f;
 			emissive_threshold = 0.3f;
-			parallax_height_scale = 0.1f;
 			fog_color_x = 0.55f;
 			fog_color_y = 0.55f;
 			fog_color_z = 0.55f;
@@ -523,6 +560,7 @@ public:
 			light_color_r = 1.0f;
 			light_color_g = 1.0f;
 			light_color_b = 1.0f;
+			height_scale = 0.0f;
 			texture_tiling_factor = 1.0f;
 			z_far = 8000.0f;
 			z_near = 0.1f;
@@ -543,7 +581,6 @@ public:
 		int rendering_res_y;
 		float alpha_threshold;
 		float emissive_threshold;
-		float parallax_height_scale;
 		float fog_color_x;
 		float fog_color_y;
 		float fog_color_z;
@@ -556,6 +593,7 @@ public:
 		float light_color_r;
 		float light_color_g;
 		float light_color_b;
+		float height_scale;
 		float texture_tiling_factor;
 		float z_far;
 		float z_near;
@@ -724,6 +762,10 @@ public:
 			gaussian_blur_horizontal_vert_shader = "gaussianBlurHorizontal.vert";
 			light_pass_vert_shader = "lightPass.vert";
 			light_pass_frag_shader = "lightPass.frag";
+			final_pass_vert_shader = "finalPass.vert";
+			final_pass_frag_shader = "finalPass.frag";
+			reflection_pass_vert_shader = "reflectionPass.vert";
+			reflection_pass_frag_shader = "reflectionPass.frag";
 			dir_light_quad_offset_x = 0.0f;
 			dir_light_quad_offset_y = 0.0f;
 			dir_light_quad_offset_z = 0.0f;
@@ -764,6 +806,10 @@ public:
 		std::string gaussian_blur_horizontal_vert_shader;
 		std::string light_pass_vert_shader;
 		std::string light_pass_frag_shader;
+		std::string final_pass_vert_shader;
+		std::string final_pass_frag_shader;
+		std::string reflection_pass_vert_shader;
+		std::string reflection_pass_frag_shader;
 		float dir_light_quad_offset_x;
 		float dir_light_quad_offset_y;
 		float dir_light_quad_offset_z;
@@ -797,7 +843,7 @@ public:
 			alphaCullingUniform = "alphaCulling";
 			alphaThresholdUniform = "alphaThreshold";
 			emissiveThresholdUniform = "emissiveThreshold";
-			parallaxHeightScale = "parallaxHeightScale";
+			heightScaleUniform = "heightScale";
 			textureTilingFactorUniform = "textureTilingFactor";
 
 			dirLightColor = "directionalLight.m_color";
@@ -823,7 +869,9 @@ public:
 			diffuseMapUniform = "diffuseMap";
 			normalMapUniform = "normalMap";
 			emissiveMapUniform = "emissiveMap";
+			matPropertiesMapUniform = "matPropertiesMap";
 			blurMapUniform = "blurMap";
+			finalMapUniform = "finalColorMap";
 
 			sunGlowTextureUniform = "sunGlowMap";
 			skyMapTextureUniform = "skyMap";
@@ -834,6 +882,10 @@ public:
 			emissiveTextureUniform = "emissiveTexture";
 			glossTextureUniform = "glossTexture";
 			heightTextureUniform = "heightTexture";
+			combinedTextureUniform = "combinedTexture";
+
+			dynamicEnvMapUniform = "dynamicEnvMap";
+			staticEnvMapUniform = "staticEnvMap";
 
 			fogDensityUniform = "fogDensity";
 			fogColorUniform = "fogColor";
@@ -857,7 +909,7 @@ public:
 		std::string alphaCullingUniform;
 		std::string alphaThresholdUniform;
 		std::string emissiveThresholdUniform;
-		std::string parallaxHeightScale;
+		std::string heightScaleUniform;
 		std::string textureTilingFactorUniform;
 
 		std::string dirLightColor;
@@ -883,7 +935,9 @@ public:
 		std::string diffuseMapUniform;
 		std::string normalMapUniform;
 		std::string emissiveMapUniform;
+		std::string matPropertiesMapUniform;
 		std::string blurMapUniform;
+		std::string finalMapUniform;
 
 		std::string sunGlowTextureUniform;
 		std::string skyMapTextureUniform;
@@ -894,6 +948,10 @@ public:
 		std::string emissiveTextureUniform;
 		std::string glossTextureUniform;
 		std::string heightTextureUniform;
+		std::string combinedTextureUniform;
+
+		std::string dynamicEnvMapUniform;
+		std::string staticEnvMapUniform;
 
 		std::string fogDensityUniform;
 		std::string fogColorUniform;
@@ -914,6 +972,14 @@ public:
 			default_normal_texture = "default_normal.png";
 			default_specular_intensity = 1.0f;
 			default_specular_power = 32.0f;
+			diffuse_texture_format = GL_RGBA;
+			normal_texture_format = GL_RGB;
+			emissive_texture_format = GL_RGBA;
+			roughness_texture_format = GL_R;
+			metalness_texture_format = GL_R;
+			height_texture_format = GL_R;
+			ambientOcclusion_texture_format = GL_R;
+			RMHAO_texture_format = GL_RGBA;
 			gl_texture_anisotropy = 16;
 			gl_texture_magnification = GL_LINEAR;
 			gl_texture_minification = GL_LINEAR_MIPMAP_LINEAR;
@@ -927,6 +993,14 @@ public:
 		std::string default_normal_texture;
 		float default_specular_intensity;
 		float default_specular_power;
+		int diffuse_texture_format;
+		int normal_texture_format;
+		int emissive_texture_format;
+		int roughness_texture_format;
+		int metalness_texture_format;
+		int height_texture_format;
+		int ambientOcclusion_texture_format;
+		int RMHAO_texture_format;
 		int gl_texture_anisotropy;
 		int gl_texture_magnification;
 		int gl_texture_minification;

+ 33 - 3
Praxis3D/Source/DebugUIScript.h

@@ -11,9 +11,12 @@ public:
 	DebugUIScript(SystemScene *p_systemScene, std::string p_name)
 		: BaseScriptObject(p_systemScene, p_name, Properties::DebugUIScript)
 	{
-
 		m_elapsedTime = 0.0f;
 		m_showFPSInterval = 1.0f;
+
+		m_benchmarkElapsed = 0.0f;
+		m_numFramesElapsed = 0;
+		m_benchmarkOn = false;
 	}
 	~DebugUIScript() { }
 
@@ -52,6 +55,29 @@ public:
 
 	virtual void update(const float p_deltaTime)
 	{
+		/*if(m_benchmarkOn)
+		{
+			m_benchmarkElapsed += p_deltaTime;
+			m_numFramesElapsed++;
+			if(m_numFramesElapsed == 10000)
+			{
+				printf("Benchmark Sample Frames: %i\n", m_numFramesElapsed);
+				printf("Benchmark MS: %f\n", m_benchmarkElapsed / m_numFramesElapsed);
+				printf("Benchmark FPS: %f\n", 1.0f / (m_benchmarkElapsed / m_numFramesElapsed));
+
+				//m_benchmarkOn = false;
+				m_numFramesElapsed = 0;
+				m_benchmarkElapsed = 0.0f;
+
+				if(Config::windowVar().fullscreen)
+				{
+					m_benchmarkOn = false;
+				}
+
+				WindowLocator::get().setFullscreen(!Config::windowVar().fullscreen);
+			}
+		}*/
+
 		if(m_closeWindowCommand.isActivated())
 		{
 			// Mark the state of the engine as not running anymore, and it will be shut down after the current frame
@@ -92,8 +118,8 @@ public:
 
 			std::string vsyncString = Config::windowVar().vertical_sync ? "VSYNC: ON" : "VSYNC: OFF";
 
-			WindowLocator::get().setWindowTitle(Config::windowVar().name + " | " + vsyncString + " | FPS: " +
-												Utilities::toString(roundf(ClockLocator::get().getFPS())));
+			//WindowLocator::get().setWindowTitle(Config::windowVar().name + " | " + vsyncString + " | FPS: " +
+			//									Utilities::toString(roundf(ClockLocator::get().getFPS())));
 		}
 	}
 
@@ -149,4 +175,8 @@ protected:
 
 	float	m_elapsedTime,
 			m_showFPSInterval;
+
+	float	m_benchmarkElapsed;
+	int		m_numFramesElapsed;
+	bool	m_benchmarkOn;
 };

+ 385 - 198
Praxis3D/Source/DeferredRenderer.cpp

@@ -15,7 +15,11 @@ DeferredRenderer::DeferredRenderer()
 	m_spotLightBufferHandle = 0;
 	m_pointLightBufferHandle = 0;
 
-	for(int i = 0; i < Model::NumOfModelMaterials; i++)
+	m_shaderGeometry = 0;
+	m_shaderLightPass = 0;
+	m_shaderFinalPass = 0;
+
+	for(int i = 0; i < MaterialType_NumOfTypes; i++)
 		m_boundTextureHandles[i] = 0;
 }
 DeferredRenderer::~DeferredRenderer()
@@ -30,11 +34,11 @@ ErrorCode DeferredRenderer::init()
 	// Get the current screen size
 	m_screenSize.x = Config::graphicsVar().current_resolution_x;
 	m_screenSize.y = Config::graphicsVar().current_resolution_y;
-
+	
 	// Initialize gbuffer (and also pass the screen size to be used as the buffer size)
 	m_gbuffer = new GeometryBuffer((unsigned int) m_screenSize.x, (unsigned int) m_screenSize.y);
 
-	// Check if the gbuffer initialization was successful
+	// Initialize gbuffer and check if it was successful
 	if(ErrHandlerLoc::get().ifSuccessful(m_gbuffer->init(), returnCode))
 	{
 		// Create a property-set used to load geometry shader
@@ -47,17 +51,44 @@ ErrorCode DeferredRenderer::init()
 		lightShaderProperties.addProperty(Properties::VertexShader, Config::rendererVar().light_pass_vert_shader);
 		lightShaderProperties.addProperty(Properties::FragmentShader, Config::rendererVar().light_pass_frag_shader);
 
+		// Create a property-set used to load reflection shader
+		PropertySet reflectionShaderProperties(Properties::Shaders);
+		reflectionShaderProperties.addProperty(Properties::VertexShader, Config::rendererVar().reflection_pass_vert_shader);
+		reflectionShaderProperties.addProperty(Properties::FragmentShader, Config::rendererVar().reflection_pass_frag_shader);
+
 		// Create shaders
 		m_shaderGeometry = Loaders::shader().load(geomShaderProperties);
 		m_shaderLightPass = Loaders::shader().load(lightShaderProperties);
+		m_shaderReflectionPass = Loaders::shader().load(reflectionShaderProperties);
 
-		// Load geometry shaders
+		// Load geometry shader
 		m_shaderGeometry->loadToMemory();
-		m_shaderGeometry->loadToVideoMemory();
+		
+		//m_shaderGeometry->loadToVideoMemory();
 
-		// Load lighting shaders
+		// Load lighting shader
 		m_shaderLightPass->loadToMemory();
-		m_shaderLightPass->loadToVideoMemory();
+		//m_shaderLightPass->loadToVideoMemory();
+
+		// Load reflection shader
+		m_shaderReflectionPass->loadToMemory();
+		//m_shaderReflectionPass->loadToVideoMemory();
+
+#ifndef SETTING_USE_BLIT_FRAMEBUFFER
+
+		// Create a property-set used to load final shader
+		PropertySet finalShaderProperties(Properties::Shaders);
+		finalShaderProperties.addProperty(Properties::VertexShader, Config::rendererVar().final_pass_vert_shader);
+		finalShaderProperties.addProperty(Properties::FragmentShader, Config::rendererVar().final_pass_frag_shader);
+
+		// Create shader
+		m_shaderFinalPass = Loaders::shader().load(finalShaderProperties);
+
+		// Load final shader
+		m_shaderFinalPass->loadToMemory();
+		//m_shaderFinalPass->loadToVideoMemory();
+
+#endif // SETTING_USE_BLIT_FRAMEBUFFER
 
 		// Load fullscreen triangle (used to render post-processing effects)
 		m_fullscreenTriangle.load();
@@ -86,10 +117,10 @@ ErrorCode DeferredRenderer::init()
 		GLint pointLightBlockSize = 0;
 		GLint spotLightBlockSize = 0;
 
-		m_shaderLightPass->bind();
+		//m_shaderLightPass->bind();
 
 		// Get point light buffer's uniform block index
-		auto pointLightBlockIndex = glGetUniformBlockIndex(m_shaderLightPass->getShaderHandle(), "PointLights");
+		auto pointLightBlockIndex = glGetUniformBlockIndex(m_shaderLightPass->getShaderHandle(), Config::shaderVar().pointLightBuffer.c_str());
 		// Get point light buffer's uniform block size
 		glGetActiveUniformBlockiv(m_shaderLightPass->getShaderHandle(), pointLightBlockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &pointLightBlockSize);
 		// Bind the uniform buffer at point light binding point
@@ -142,86 +173,89 @@ void DeferredRenderer::endRenderCycle(float p_deltaTime)
 
 void DeferredRenderer::renderFrame(const SceneObjects &p_sceneObjects, const float p_deltaTime)
 {
-	// Load all the objects in the load-to-gpu queue. This needs to be done before any rendering, as objects in this
-	// array might have been also added to objects-to-render arrays, so they need to be loaded first
-	for(decltype(p_sceneObjects.m_objectsToLoad.size()) i = 0, size = p_sceneObjects.m_objectsToLoad.size(); i < size; i++)
-	{
-		p_sceneObjects.m_objectsToLoad[i]->loadToVideoMemory();
+	//// Load all the objects in the load-to-gpu queue. This needs to be done before any rendering, as objects in this
+	//// array might have been also added to objects-to-render arrays, so they need to be loaded first
+	//for(decltype(p_sceneObjects.m_objectsToLoad.size()) i = 0, size = p_sceneObjects.m_objectsToLoad.size(); i < size; i++)
+	//{
+	//	p_sceneObjects.m_objectsToLoad[i]->loadToVideoMemory();
 
-		// In case shader failed to load or was not specified, assign a geometry shader
-		if(p_sceneObjects.m_objectsToLoad[i]->m_shader->isDefaultProgram())
-			p_sceneObjects.m_objectsToLoad[i]->m_shader = m_shaderGeometry;
-		else
-		{
-			p_sceneObjects.m_objectsToLoad[i]->m_shader->bind();
-			p_sceneObjects.m_objectsToLoad[i]->m_shader->getUniformUpdater().updateTextureUniforms(*m_rendererState);
-		}
-
-	}
-
-	m_gbuffer->initFrame();
+	//	// In case shader failed to load or was not specified, assign a geometry shader
+	//	if(p_sceneObjects.m_objectsToLoad[i]->m_shader->isDefaultProgram())
+	//		p_sceneObjects.m_objectsToLoad[i]->m_shader = m_shaderGeometry;
+	//	else
+	//	{
+	//		p_sceneObjects.m_objectsToLoad[i]->m_shader->bind();
+	//		p_sceneObjects.m_objectsToLoad[i]->m_shader->getUniformUpdater().updateTextureUniforms(*m_rendererState);
+	//	}
 
-	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-	
-	//m_testVec = Math::Vec4f(1.0, 0.0, 0.0, 0.0);
+	//}
+	//	
+	//m_cubemap = p_sceneObjects.m_staticSkybox;
 
-	m_currentCamera = p_sceneObjects.m_camera;
+	//m_gbuffer->initFrame();
+	//
+	//m_currentCamera = p_sceneObjects.m_camera;
 
-	update();
+	//update();
 
-	geometryPass(p_sceneObjects, p_deltaTime);
+	//geometryPass(p_sceneObjects, p_deltaTime);
 
-	lightingPass(p_sceneObjects, p_deltaTime);
+	//lightingPass(p_sceneObjects, p_deltaTime);
 
-	postLightingPass(p_sceneObjects, p_deltaTime);
+	//reflectionPass(p_sceneObjects, p_deltaTime);
 
-	finalPass();
+	//postLightingPass(p_sceneObjects, p_deltaTime);
+	//
+	//finalPass();
 }
 
 void DeferredRenderer::geometryPass(const SceneObjects &p_sceneObjects, const float p_deltaTime)
 {
-	// Bind buffers
-	m_gbuffer->initGeometryPass();
-
-	// Enable face culling 
-	//if(Config::rendererVar().face_culling)
-	//	glEnable(GL_CULL_FACE);
-
-	//glDepthMask(GL_TRUE);			// Make sure to turn on depth testing
-	//glEnable(GL_DEPTH_TEST);		// as this is much like a regular forward render pass
-	//glDisable(GL_BLEND);
-
-	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-	glClear(GL_DEPTH_BUFFER_BIT);
-
-	m_shaderGeometry->bind();
-	m_shaderGeometry->getUniformUpdater().updateFrame(*m_rendererState);
-	m_shaderGeometry->getUniformUpdater().updateTextureUniforms(*m_rendererState);
-	m_boundShaderHandle = m_shaderGeometry->getShaderHandle();
-
-	// Iterate over all objects to be rendered with geometry shader
-	for(decltype(p_sceneObjects.m_modelObjects.size()) objIndex = 0, numObjects = p_sceneObjects.m_modelObjects.size(); objIndex < numObjects; objIndex++)
-	{
-		drawModelObject(p_sceneObjects.m_modelObjects[objIndex], m_shaderGeometry);
-	}
-
-	// Iterate over all objects to be rendered with a custom shader
-	for(decltype(p_sceneObjects.m_customShaderObjects.size()) objIndex = 0, numObjects = p_sceneObjects.m_customShaderObjects.size(); objIndex < numObjects; objIndex++)
-	{
-		// If shader handle is not already bound, bind it
-		//if(p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->getShaderHandle() != m_boundShaderHandle)
-		{
-			p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->bind();
-			p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->getUniformUpdater().updateFrame(*m_rendererState);
-
-			m_boundShaderHandle = p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->getShaderHandle();
-		}
-
-		if(p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->isTessellated())
-			drawTessellatedObject(p_sceneObjects.m_customShaderObjects[objIndex], p_sceneObjects.m_customShaderObjects[objIndex]->m_shader);
-		else
-			drawModelObject(p_sceneObjects.m_customShaderObjects[objIndex], p_sceneObjects.m_customShaderObjects[objIndex]->m_shader);
-	}
+	//m_objects.clear();
+
+	//// Bind buffers
+	//m_gbuffer->initGeometryPass();
+	//
+	//glEnable(GL_DEPTH_TEST);		// Enable depth testing, as this is much like a regular forward render pass
+	//glClear(GL_DEPTH_BUFFER_BIT);	// Make sure to clear the depth buffer for the new frame
+	//
+	//m_objects.clear();
+
+	//for(decltype(p_sceneObjects.m_modelObjects.size()) objIndex = 0, numObjects = p_sceneObjects.m_modelObjects.size(); objIndex < numObjects; objIndex++)
+	//	drawModelObjectTest(*p_sceneObjects.m_modelObjects[objIndex], m_shaderGeometry);
+
+	//drawObjectsTest(m_objects);
+
+	//return;
+
+	//m_shaderGeometry->bind();
+	//m_shaderGeometry->getUniformUpdater().updateFrame(*m_rendererState);
+	//m_shaderGeometry->getUniformUpdater().updateTextureUniforms(*m_rendererState);
+	//m_boundShaderHandle = m_shaderGeometry->getShaderHandle();
+
+	//// Iterate over all objects to be rendered with geometry shader
+	//for(decltype(p_sceneObjects.m_modelObjects.size()) objIndex = 0, numObjects = p_sceneObjects.m_modelObjects.size(); objIndex < numObjects; objIndex++)
+	//{
+	//	drawModelObject(p_sceneObjects.m_modelObjects[objIndex], m_shaderGeometry);
+	//}
+
+	//// Iterate over all objects to be rendered with a custom shader
+	//for(decltype(p_sceneObjects.m_customShaderObjects.size()) objIndex = 0, numObjects = p_sceneObjects.m_customShaderObjects.size(); objIndex < numObjects; objIndex++)
+	//{
+	//	// If shader handle is not already bound, bind it
+	//	//if(p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->getShaderHandle() != m_boundShaderHandle)
+	//	{
+	//		p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->bind();
+	//		p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->getUniformUpdater().updateFrame(*m_rendererState);
+
+	//		m_boundShaderHandle = p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->getShaderHandle();
+	//	}
+
+	//	if(p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->isTessellated())
+	//		drawTessellatedObject(p_sceneObjects.m_customShaderObjects[objIndex], p_sceneObjects.m_customShaderObjects[objIndex]->m_shader);
+	//	else
+	//		drawModelObject(p_sceneObjects.m_customShaderObjects[objIndex], p_sceneObjects.m_customShaderObjects[objIndex]->m_shader);
+	//}
 
 	// Unbind VBO so it is not changed from outside
 	//glBindVertexArray(0);
@@ -229,81 +263,99 @@ void DeferredRenderer::geometryPass(const SceneObjects &p_sceneObjects, const fl
 
 void DeferredRenderer::lightingPass(const SceneObjects &p_sceneObjects, const float p_deltaTime)
 {
-	m_gbuffer->initLightPass();
+	//m_gbuffer->initLightPass();
 
-	//glEnable(GL_BLEND);
-	//glBlendFunc(GL_ONE, GL_ONE);
-	glDisable(GL_DEPTH_TEST);
-	//glDisable(GL_CULL_FACE);
+	//glDisable(GL_DEPTH_TEST);
 
-	// Bind and update the point light buffer
-	glBindBuffer(GL_UNIFORM_BUFFER, m_pointLightBufferHandle);
-	glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(PointLightDataSet) * p_sceneObjects.m_pointLights.size(), 
-					p_sceneObjects.m_pointLights.data());
+	//// Bind and update the point light buffer
+	//glBindBuffer(GL_UNIFORM_BUFFER, m_pointLightBufferHandle);
+	//glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(PointLightDataSet) * p_sceneObjects.m_pointLights.size(), 
+	//				p_sceneObjects.m_pointLights.data());
 
-	// Bind and update the spot light buffer
-	glBindBuffer(GL_UNIFORM_BUFFER, m_spotLightBufferHandle);
-	glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(SpotLightDataSet) * p_sceneObjects.m_spotLights.size(),
-					p_sceneObjects.m_spotLights.data());
+	//// Bind and update the spot light buffer
+	//glBindBuffer(GL_UNIFORM_BUFFER, m_spotLightBufferHandle);
+	//glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(SpotLightDataSet) * p_sceneObjects.m_spotLights.size(),
+	//				p_sceneObjects.m_spotLights.data());
 
-	// Update the directional light data set (or clear it if there is no directional light in the scene)
-	if(p_sceneObjects.m_directionalLight != nullptr)
-		m_directionalLight = *p_sceneObjects.m_directionalLight;
-	else
-		m_directionalLight.clear();
+	//// Update the directional light data set (or clear it if there is no directional light in the scene)
+	//if(p_sceneObjects.m_directionalLight != nullptr)
+	//	m_directionalLight = *p_sceneObjects.m_directionalLight;
+	//else
+	//	m_directionalLight.clear();
 
-	// Update the current number of lights in the light buffers
-	m_numPointLights = p_sceneObjects.m_pointLights.size();
-	m_numSpotLights = p_sceneObjects.m_spotLights.size();
+	//// Update the current number of lights in the light buffers
+	//m_numPointLights = p_sceneObjects.m_pointLights.size();
+	//m_numSpotLights = p_sceneObjects.m_spotLights.size();
 
-	m_shaderLightPass->bind();
-	m_shaderLightPass->getUniformUpdater().updateTextureUniforms(*m_rendererState);
-	m_shaderLightPass->getUniformUpdater().updateFrame(*m_rendererState);
+	//m_shaderLightPass->bind();
+	//m_shaderLightPass->getUniformUpdater().updateTextureUniforms(*m_rendererState);
+	//m_shaderLightPass->getUniformUpdater().updateFrame(*m_rendererState);
 
-	m_fullscreenTriangle.bind();
-	m_fullscreenTriangle.render();
-	//glBindVertexArray(0);
+	//m_fullscreenTriangle.bind();
+	//m_fullscreenTriangle.render();
 }
 
 void DeferredRenderer::postLightingPass(const SceneObjects & p_sceneObjects, const float p_deltaTime)
 {
-	//glDepthMask(GL_FALSE);
-	//glEnable(GL_DEPTH_TEST);
-	//glDepthFunc(GL_LEQUAL);
+	//glEnable(GL_DEPTH_TEST);	// Enable depth testing, as this is much like a regular forward render pass
+
+	//// Iterate over all objects to be rendered with a custom shader
+	//for(decltype(p_sceneObjects.m_postLightingObjects.size()) objIndex = 0, numObjects = p_sceneObjects.m_postLightingObjects.size(); objIndex < numObjects; objIndex++)
+	//{
+	//	// If shader handle is not already bound, bind it
+	//	//if(p_sceneObjects.m_postLightingObjects[objIndex]->m_shader->getShaderHandle() != m_boundShaderHandle)
+	//	{
+	//		p_sceneObjects.m_postLightingObjects[objIndex]->m_shader->bind();
+	//		p_sceneObjects.m_postLightingObjects[objIndex]->m_shader->getUniformUpdater().updateFrame(*m_rendererState);
+	//		p_sceneObjects.m_postLightingObjects[objIndex]->m_shader->getUniformUpdater().updateTextureUniforms(*m_rendererState);
+
+	//		m_boundShaderHandle = p_sceneObjects.m_postLightingObjects[objIndex]->m_shader->getShaderHandle();
+	//	}
+
+	//	drawModelObject(p_sceneObjects.m_postLightingObjects[objIndex], p_sceneObjects.m_postLightingObjects[objIndex]->m_shader);
+	//}
+}
 
-	//glDisable(GL_BLEND);
-	//glEnable(GL_BLEND);
-	//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+void DeferredRenderer::reflectionPass(const SceneObjects & p_sceneObjects, const float p_deltaTime)
+{
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_ONE, GL_ONE);
 
-	//glDisable(GL_CULL_FACE);
+	glActiveTexture(GL_TEXTURE0 + StaticEnvMap);
+	glBindTexture(GL_TEXTURE_CUBE_MAP, m_cubemap->getCubemapHandle());
 
-	//glDepthMask(GL_TRUE);			// Make sure to turn on depth testing
-	glEnable(GL_DEPTH_TEST);		// as this is much like a regular forward render pass
-	//glDepthFunc(GL_LESS);
-	//glDisable(GL_BLEND);
+	//m_shaderReflectionPass->bind();
+	//m_shaderReflectionPass->getUniformUpdater().updateTextureUniforms(*m_rendererState);
+	//m_shaderReflectionPass->getUniformUpdater().updateFrame(*m_rendererState);
 
-	// Iterate over all objects to be rendered with a custom shader
-	for(decltype(p_sceneObjects.m_postLightingObjects.size()) objIndex = 0, numObjects = p_sceneObjects.m_postLightingObjects.size(); objIndex < numObjects; objIndex++)
-	{
-		// If shader handle is not already bound, bind it
-		//if(p_sceneObjects.m_postLightingObjects[objIndex]->m_shader->getShaderHandle() != m_boundShaderHandle)
-		{
-			p_sceneObjects.m_postLightingObjects[objIndex]->m_shader->bind();
-			p_sceneObjects.m_postLightingObjects[objIndex]->m_shader->getUniformUpdater().updateFrame(*m_rendererState);
-			p_sceneObjects.m_postLightingObjects[objIndex]->m_shader->getUniformUpdater().updateTextureUniforms(*m_rendererState);
-
-			m_boundShaderHandle = p_sceneObjects.m_postLightingObjects[objIndex]->m_shader->getShaderHandle();
-		}
+	m_fullscreenTriangle.bind();
+	m_fullscreenTriangle.render();
 
-		drawModelObject(p_sceneObjects.m_postLightingObjects[objIndex], p_sceneObjects.m_postLightingObjects[objIndex]->m_shader);
-	}
+	glDisable(GL_BLEND);
 }
 
 void DeferredRenderer::finalPass()
 {
 	m_gbuffer->initFinalPass();
+
+#ifdef SETTING_USE_BLIT_FRAMEBUFFER
+
 	glBlitFramebuffer(0, 0, m_screenSize.x, m_screenSize.y,
 					  0, 0, m_screenSize.x, m_screenSize.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+#else
+
+	glDisable(GL_DEPTH_TEST);
+	
+	//m_shaderFinalPass->bind();
+	//m_shaderFinalPass->getUniformUpdater().updateTextureUniforms(*m_rendererState);
+	//m_shaderFinalPass->getUniformUpdater().updateFrame(*m_rendererState);
+
+	m_fullscreenTriangle.bind();
+	m_fullscreenTriangle.render();
+
+#endif // SETTING_USE_BLIT_FRAMEBUFFER
+
+
 }
 
 void DeferredRenderer::update()
@@ -330,93 +382,228 @@ void DeferredRenderer::update()
 
 void DeferredRenderer::drawModelObject(const RenderableObjectData *p_renderableObject, const ShaderLoader::ShaderProgram *p_shader)
 {
-	// Assign a current base object data
-	m_currentObjectData = &(p_renderableObject->m_baseObjectData);
-	
-	// Calculate matrices
-	m_modelViewMatrix = m_currentCamera->getBaseObjectData().m_modelMat * m_currentObjectData->m_modelMat;
-	m_modelViewProjMatrix = m_projMatrix * m_modelViewMatrix;
+	//// Assign a current base object data
+	//m_currentObjectData = &(p_renderableObject->m_baseObjectData);
+	//
+	//// Calculate matrices
+	//m_modelViewMatrix = m_currentCamera->getBaseObjectData().m_modelMat * m_currentObjectData->m_modelMat;
+	//m_modelViewProjMatrix = m_projMatrix * m_modelViewMatrix;
+
+	//// Update per-model uniforms
+	//p_shader->getUniformUpdater().updateModel(*m_rendererState);
+	//	
+	//// Bind model's VAO
+	//glBindVertexArray(p_renderableObject->m_model.getHandle());
+
+	//// Iterate over all the meshes in the model
+	//for(decltype(p_renderableObject->m_model.getNumMeshes()) meshIndex = 0, numMeshes = p_renderableObject->m_model.getNumMeshes(); meshIndex < numMeshes; meshIndex++)
+	//{
+	//	// Update per-mesh uniforms
+	//	p_shader->getUniformUpdater().updateMesh(*m_rendererState);
+
+	//	// Iterate over all materials and bind them
+	//	for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+	//	{
+	//		// Get texture handle
+	//		unsigned int textureHandle = p_renderableObject->m_materials[matType][p_renderableObject->m_model[meshIndex].m_materialIndex].getHandle();
+
+	//		// If texture handle is not already bound, bind it
+	//		//if(textureHandle != m_boundTextureHandles[matType])
+	//		//{
+	//			glActiveTexture(GL_TEXTURE0 + matType);
+	//			glBindTexture(GL_TEXTURE_2D, textureHandle);
+	//		//	m_boundTextureHandles[matType] = textureHandle;
+	//		//}
+	//	}
+	//	
+	//	// Draw the actual geometry
+	//	glDrawElementsBaseVertex(GL_TRIANGLES, 
+	//							 p_renderableObject->m_model[meshIndex].m_numIndices, 
+	//							 GL_UNSIGNED_INT,
+	//							 (void*)(sizeof(unsigned int) * p_renderableObject->m_model[meshIndex].m_baseIndex), 
+	//							 p_renderableObject->m_model[meshIndex].m_baseVertex);
+	//}
+}
 
-	// Update per-model uniforms
-	p_shader->getUniformUpdater().updateModel(*m_rendererState);
-		
-	// Bind model's VAO
-	glBindVertexArray(p_renderableObject->m_model.getHandle());
+void DeferredRenderer::drawTessellatedObject(const RenderableObjectData *p_renderableObject, const ShaderLoader::ShaderProgram *p_shader)
+{
+	//glPatchParameteri(GL_PATCH_VERTICES, 3);
+
+	//// Assign a current base object data
+	//m_currentObjectData = &(p_renderableObject->m_baseObjectData);
+
+	//// Calculate matrices
+	//m_modelViewMatrix = m_currentCamera->getBaseObjectData().m_modelMat * m_currentObjectData->m_modelMat;
+	//m_modelViewProjMatrix = m_projMatrix * m_modelViewMatrix;
+
+	//// Update per-model uniforms
+	//p_shader->getUniformUpdater().updateModel(*m_rendererState);
+	////p_shader->getUniformUpdater().updateTextureUniforms(*m_rendererState);
+
+	//// Bind model's VAO
+	//glBindVertexArray(p_renderableObject->m_model.getHandle());
+
+	//// Iterate over all the meshes in the model
+	//for(decltype(p_renderableObject->m_model.getNumMeshes()) meshIndex = 0, numMeshes = p_renderableObject->m_model.getNumMeshes(); meshIndex < numMeshes; meshIndex++)
+	//{
+	//	// Update per-mesh uniforms
+	//	p_shader->getUniformUpdater().updateMesh(*m_rendererState);
+
+	//	// Iterate over all materials and bind them
+	//	for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+	//	{
+	//		// Get texture handle
+	//		unsigned int textureHandle = p_renderableObject->m_materials[matType][p_renderableObject->m_model[meshIndex].m_materialIndex].getHandle();
+
+	//		// If texture handle is not already bound, bind it
+	//		//if(textureHandle != m_boundTextureHandles[matType])
+	//		{
+	//			glActiveTexture(GL_TEXTURE0 + matType);
+	//			glBindTexture(GL_TEXTURE_2D, textureHandle);
+	//			m_boundTextureHandles[matType] = textureHandle;
+	//		}
+	//	}
+
+	//	// Draw the actual geometry
+	//	glDrawElementsBaseVertex(GL_PATCHES,
+	//							 p_renderableObject->m_model[meshIndex].m_numIndices,
+	//							 GL_UNSIGNED_INT,
+	//							 (void*)(sizeof(unsigned int) * p_renderableObject->m_model[meshIndex].m_baseIndex),
+	//							 p_renderableObject->m_model[meshIndex].m_baseVertex);
+	//}
+}
 
-	// Iterate over all the meshes in the model
-	for(decltype(p_renderableObject->m_model.getNumMeshes()) meshIndex = 0, numMeshes = p_renderableObject->m_model.getNumMeshes(); meshIndex < numMeshes; meshIndex++)
+void DeferredRenderer::drawModelObjectTest(const RenderableObjectData &p_object, const ShaderLoader::ShaderProgram *p_shader)
+{
+
+	////m_objects.emplace_back(0, RendererBackend::RenderDataset());
+
+	//const unsigned int shaderHandle = p_shader->getShaderHandle();
+	//const unsigned int modelHandle = p_object.m_model.getHandle();
+	//const ShaderUniformUpdater &uniformUpdater = p_shader->getUniformUpdater();
+
+	//for(decltype(p_object.m_model.getNumMeshes()) meshIndex = 0, numMeshes = p_object.m_model.getNumMeshes(); meshIndex < numMeshes; meshIndex++)
+	//{
+	//	m_objects.emplace_back(0, RendererBackend::DrawCommand(
+	//		uniformUpdater,
+	//		
+	//		shaderHandle, 
+	//		modelHandle,
+	//		p_object.m_model[meshIndex].m_numIndices,
+	//		p_object.m_model[meshIndex].m_baseVertex,
+	//		p_object.m_model[meshIndex].m_baseIndex
+	//		));
+	//}
+
+	/*
+	// Declare temp values used for indexing
+	size_t shaderIndex = 0;
+	size_t modelIndex = 0;
+
+	// Get different object handles
+	//auto shaderHandle = p_object.m_shader->getShaderHandle();
+	auto shaderHandle = p_shader->getShaderHandle();
+	auto modelVAOHandle = p_object.m_model.getHandle();
+
+	// Loop through the shader array, to check if the current shader has already been added
+	for(shaderIndex = 0; shaderIndex < m_objects.m_numShaders; shaderIndex++)
+		if(m_objects.m_shaders[shaderIndex].m_shaderHandle == shaderHandle)
+			break;
+
+	// If the shader has not been added already, add it
+	if(m_objects.m_shaders.empty() || m_objects.m_shaders[shaderIndex].m_shaderHandle != shaderHandle)
 	{
-		// Update per-mesh uniforms
-		p_shader->getUniformUpdater().updateMesh(*m_rendererState);
+		// Assign correct shader index
+		shaderIndex = m_objects.m_shaders.size();
 
-		// Iterate over all materials and bind them
-		for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
-		{
-			// Get texture handle
-			unsigned int textureHandle = p_renderableObject->m_materials[matType][p_renderableObject->m_model[meshIndex].m_materialIndex].getHandle();
-
-			// If texture handle is not already bound, bind it
-			//if(textureHandle != m_boundTextureHandles[matType])
-			//{
-				glActiveTexture(GL_TEXTURE0 + matType);
-				glBindTexture(GL_TEXTURE_2D, textureHandle);
-			//	m_boundTextureHandles[matType] = textureHandle;
-			//}
-		}
-		
-		// Draw the actual geometry
-		glDrawElementsBaseVertex(GL_TRIANGLES, 
-								 p_renderableObject->m_model[meshIndex].m_numIndices, 
-								 GL_UNSIGNED_INT,
-								 (void*)(sizeof(unsigned int) * p_renderableObject->m_model[meshIndex].m_baseIndex), 
-								 p_renderableObject->m_model[meshIndex].m_baseVertex);
+		// Add the current shader to the array
+		//m_objects.m_shaders.push_back(RendererBackend::RendererShader(p_object.m_shader->getUniformUpdater(), shaderHandle));
+		m_objects.m_shaders.push_back(RendererBackend::RendererShader(p_shader->getUniformUpdater(), shaderHandle));
+
+		// Increment shader count
+		m_objects.m_numShaders++;
+	}
+
+	// If the shader is not the first one in the shader array,
+	// assign model index depending on the number of models from previous shader
+	modelIndex = shaderIndex > 0 ? m_objects.m_shaders[shaderIndex - 1].m_numModels - 1 : 0;
+
+	// Loop through the model array, to check if the current model has already been added
+	for(; modelIndex < m_objects.m_shaders[shaderIndex].m_numModels; modelIndex++)
+		if(m_objects.m_models[modelIndex].m_VAO == modelVAOHandle)
+			break;
+
+	// If the model has not been added already, add it
+	if(m_objects.m_models.empty() || m_objects.m_models[modelIndex].m_VAO != modelVAOHandle)
+	{
+		// Assign correct model index
+		modelIndex = m_objects.m_models.size();
+
+		// Add the current model to the array
+		m_objects.m_models.push_back(RendererBackend::RendererModel());
+
+		// Increment model count
+		m_objects.m_shaders[shaderIndex].m_numModels++;
+	}
+
+	for(decltype(p_object.m_model.getNumMeshes()) meshIndex = 0, numMeshes = p_object.m_model.getNumMeshes(); meshIndex < numMeshes; meshIndex++)
+	{
+		m_objects.m_meshes.push_back(RendererBackend::RendererMesh(p_object.m_model[meshIndex]));
 	}
+
+	m_objects.m_models[modelIndex].m_numMeshes += p_object.m_model.getNumMeshes() - 1;*/
 }
 
-void DeferredRenderer::drawTessellatedObject(const RenderableObjectData *p_renderableObject, const ShaderLoader::ShaderProgram *p_shader)
+void DeferredRenderer::drawObjectsTest(const RendererBackend::DrawCommands &p_objects)
 {
-	glPatchParameteri(GL_PATCH_VERTICES, 3);
+	for(decltype(p_objects.size()) i = 0, size = p_objects.size(); i < size; i++)
+	{
+		// Bind shader
+		glUseProgram(p_objects[i].second.m_shaderHandle);
 
-	// Assign a current base object data
-	m_currentObjectData = &(p_renderableObject->m_baseObjectData);
+		//m_currentObjectData = &(p_objects[i].first);
 
-	// Calculate matrices
-	m_modelViewMatrix = m_currentCamera->getBaseObjectData().m_modelMat * m_currentObjectData->m_modelMat;
-	m_modelViewProjMatrix = m_projMatrix * m_modelViewMatrix;
+		// Calculate matrices
+		//m_modelViewMatrix = m_currentCamera->getBaseObjectData().m_modelMat * m_currentObjectData->m_modelMat;
+		//m_modelViewProjMatrix = m_projMatrix * m_modelViewMatrix;
 
-	// Update per-model uniforms
-	p_shader->getUniformUpdater().updateModel(*m_rendererState);
-	//p_shader->getUniformUpdater().updateTextureUniforms(*m_rendererState);
+		//p_objects[i].second.m_uniformUpdater.updateTextureUniforms(*m_rendererState);
+		//p_objects[i].second.m_uniformUpdater.updateFrame(*m_rendererState);
+		//p_objects[i].second.m_uniformUpdater.updateModel(*m_rendererState);
 
-	// Bind model's VAO
-	glBindVertexArray(p_renderableObject->m_model.getHandle());
+		// Bind model's VAO
+		glBindVertexArray(p_objects[i].second.m_modelHandle);
 
-	// Iterate over all the meshes in the model
-	for(decltype(p_renderableObject->m_model.getNumMeshes()) meshIndex = 0, numMeshes = p_renderableObject->m_model.getNumMeshes(); meshIndex < numMeshes; meshIndex++)
+		// Draw the actual geometry
+		glDrawElementsBaseVertex(GL_TRIANGLES,
+								 p_objects[i].second.m_numIndices,
+								 GL_UNSIGNED_INT,
+								 (void*)(sizeof(unsigned int) * p_objects[i].second.m_baseIndex),
+								 p_objects[i].second.m_baseVertex);
+	}
+
+	/*for(decltype(p_objects.m_numShaders) shaderIndex = 0; shaderIndex < p_objects.m_numShaders; shaderIndex++)
 	{
-		// Update per-mesh uniforms
-		p_shader->getUniformUpdater().updateMesh(*m_rendererState);
+		// Bind shader
+		glUseProgram(p_objects.m_shaders[shaderIndex].m_shaderHandle);
+		p_objects.m_shaders[shaderIndex].m_uniformUpdater.updateTextureUniforms(*m_rendererState);
+		p_objects.m_shaders[shaderIndex].m_uniformUpdater.updateFrame(*m_rendererState);
+		p_objects.m_shaders[shaderIndex].m_uniformUpdater.updateModel(*m_rendererState);
 
-		// Iterate over all materials and bind them
-		for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+		for(decltype(p_objects.m_shaders[shaderIndex].m_numModels) modelIndex = 0; modelIndex < p_objects.m_shaders[shaderIndex].m_numModels; modelIndex++)
 		{
-			// Get texture handle
-			unsigned int textureHandle = p_renderableObject->m_materials[matType][p_renderableObject->m_model[meshIndex].m_materialIndex].getHandle();
+			// Bind model's VAO
+			glBindVertexArray(p_objects.m_models[modelIndex].m_VAO);
 
-			// If texture handle is not already bound, bind it
-			//if(textureHandle != m_boundTextureHandles[matType])
+			for(decltype(p_objects.m_models[modelIndex].m_numMeshes) meshIndex = 0; meshIndex < p_objects.m_models[modelIndex].m_numMeshes; meshIndex++)
 			{
-				glActiveTexture(GL_TEXTURE0 + matType);
-				glBindTexture(GL_TEXTURE_2D, textureHandle);
-				m_boundTextureHandles[matType] = textureHandle;
+				// Draw the actual geometry
+				glDrawElementsBaseVertex(GL_TRIANGLES,
+										 p_objects.m_meshes[meshIndex].m_mesh.m_numIndices,
+										 GL_UNSIGNED_INT,
+										 (void*)(sizeof(unsigned int) * p_objects.m_meshes[meshIndex].m_mesh.m_baseIndex),
+										 p_objects.m_meshes[meshIndex].m_mesh.m_baseVertex);
 			}
 		}
-
-		// Draw the actual geometry
-		glDrawElementsBaseVertex(GL_PATCHES,
-								 p_renderableObject->m_model[meshIndex].m_numIndices,
-								 GL_UNSIGNED_INT,
-								 (void*)(sizeof(unsigned int) * p_renderableObject->m_model[meshIndex].m_baseIndex),
-								 p_renderableObject->m_model[meshIndex].m_baseVertex);
-	}
+	}*/
 }

+ 29 - 16
Praxis3D/Source/DeferredRenderer.h

@@ -6,6 +6,9 @@
 #include "ModelGraphicsObjects.h"
 #include "Renderer.h"
 
+#include "RendererBackend.h"
+#include "EnvironmentMapObjects.h"
+
 class DeferredRenderer : public Renderer
 {
 	friend class DeferredRendererState;
@@ -63,31 +66,43 @@ protected:
 		GLuint	m_vao,
 				m_vbo;
 	};
-
+	
 	// Renders meshes and populates the geometry buffers
-	virtual void geometryPass(const SceneObjects &p_sceneObjects, const float p_deltaTime);
+	void geometryPass(const SceneObjects &p_sceneObjects, const float p_deltaTime);
 
 	// Calculates lighting in a screen-space pass
-	virtual void lightingPass(const SceneObjects &p_sceneObjects, const float p_deltaTime);
+	void lightingPass(const SceneObjects &p_sceneObjects, const float p_deltaTime);
 
 	// Renders the objects that are unaffected by lighting
-	virtual void postLightingPass(const SceneObjects &p_sceneObjects, const float p_deltaTime);
+	void postLightingPass(const SceneObjects &p_sceneObjects, const float p_deltaTime);
+
+	//
+	void reflectionPass(const SceneObjects &p_sceneObjects, const float p_deltaTime);
 
 	// Copies the final buffer to the screen by blitting it
-	virtual void finalPass();
+	void finalPass();
 
 	// Updates frame-dependent variables (like view, projection matrices)
-	virtual void update();
+	void update();
 
 	void drawModelObject(const RenderableObjectData *p_renderableObject, const ShaderLoader::ShaderProgram *p_shader);
 	void drawTessellatedObject(const RenderableObjectData *p_renderableObject, const ShaderLoader::ShaderProgram *p_shader);
 
+
+	void drawModelObjectTest(const RenderableObjectData &p_object, const ShaderLoader::ShaderProgram *p_shader);
+	void drawObjectsTest(const RendererBackend::DrawCommands &p_objects);
+
 	// Shaders
 	ShaderLoader::ShaderProgram	*m_shaderGeometry,
-								*m_shaderLightPass;
+								*m_shaderLightPass,
+								*m_shaderReflectionPass,
+								*m_shaderFinalPass;
 
 	// Framebuffers
 	GeometryBuffer *m_gbuffer;
+
+	// Renderer front end, used as an interface to talk to graphics API
+	//RendererFrontend m_frontEnd;
 	
 	// Light buffer handles (on VRAM)
 	unsigned int m_pointLightBufferHandle,
@@ -96,14 +111,18 @@ protected:
 	// Current number of lights in the light buffers
 	size_t	m_numPointLights,
 			m_numSpotLights;
-
+	
 	// Currently bound object handles
-	unsigned int m_boundTextureHandles[Model::NumOfModelMaterials],
+	unsigned int m_boundTextureHandles[MaterialType_NumOfTypes],
 				 m_boundShaderHandle;
 	
 	DirectionalLightDataSet m_directionalLight;
 	DeferredRendererState *m_rendererState;
 	static SingleTriangle m_fullscreenTriangle;
+
+	EnvironmentMapStatic *m_cubemap;
+
+	RendererBackend::DrawCommands m_objects;
 };
 
 class DeferredRendererState : public RendererState
@@ -120,13 +139,7 @@ public:
 	const virtual float getDirLightintensity()			const { return m_deferredRenderer->m_directionalLight.m_intensity;	}
 	const virtual unsigned int getNumPointLights()		const { return (unsigned int)m_deferredRenderer->m_numPointLights;	}
 	const virtual unsigned int getNumSpotLights()		const { return (unsigned int)m_deferredRenderer->m_numSpotLights;	}
-	
-	const virtual unsigned int getBlurBufferPos()		const { return GeometryBuffer::GBufferTextureType::GBufferBlur;		}
-	const virtual unsigned int getDiffuseBufferPos()	const { return GeometryBuffer::GBufferTextureType::GBufferDiffuse;	}
-	const virtual unsigned int getEmissiveBufferPos()	const { return GeometryBuffer::GBufferTextureType::GBufferEmissive; }
-	const virtual unsigned int getNormalBufferPos()		const { return GeometryBuffer::GBufferTextureType::GBufferNormal;	}
-	const virtual unsigned int getPositionBufferPos()	const { return GeometryBuffer::GBufferTextureType::GBufferPosition; }
-	
+		
 protected:
 	DeferredRendererState(DeferredRenderer *p_renderer) : RendererState(p_renderer), m_deferredRenderer(p_renderer) { }
 

+ 7 - 2
Praxis3D/Source/Engine.cpp

@@ -163,8 +163,13 @@ ErrorCode Engine::init()
 	if(loaderError != ErrorCode::Success)
 		ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
 
-	// Initialize texture loader
-	loaderError = Loaders::texture().init();
+	// Initialize texture2D loader
+	loaderError = Loaders::texture2D().init();
+	if(loaderError != ErrorCode::Success)
+		ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
+
+	// Initialize textureCubemap loader
+	loaderError = Loaders::textureCubemap().init();
 	if(loaderError != ErrorCode::Success)
 		ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
 	

+ 4 - 1
Praxis3D/Source/EngineDefinitions.h

@@ -4,4 +4,7 @@
 
 // Enable multithreading
 #define SETTING_MULTITHREADING_ENABLED
-#define SETTING_ATOMIC_VARIABLES_ENABLED
+#define SETTING_ATOMIC_VARIABLES_ENABLED
+
+// Use glBlitFramebuffer to copy the final buffer to the default back-buffer, instead of rendering a full-screen triangle
+//#define SETTING_USE_BLIT_FRAMEBUFFER

+ 2 - 2
Praxis3D/Source/EnvironmentMapObjects.h

@@ -28,9 +28,9 @@ public:
 	// Loads cubemap to video memory; should only be called by renderer thread
 	ErrorCode loadToVideoMemory()
 	{
-		ErrorCode returnError;
+		ErrorCode returnError = ErrorCode::Success;
 
-		returnError = m_cubemap.loadToVideoMemory();
+		//returnError = m_cubemap.loadToVideoMemory();
 
 		//if(returnError == ErrorCode::Success)
 		//	m_cubemapHandle = m_cubemap.getHandle();

+ 24 - 1
Praxis3D/Source/ErrorCodes.h

@@ -1,5 +1,7 @@
 #pragma once
 
+#include <string>
+
 #include "EnumFactory.h"
 
 /*   ___________________________________________________________________________________________________
@@ -81,8 +83,12 @@ DECLARE_ENUM(ErrorCode, ERROR_CODES)
     Code(Source_ShaderLoader,) \
     Code(Source_FileLoader,) \
     Code(Source_SceneLoader,) \
+    Code(Source_LightingPass,) \
     Code(Source_GeometryBuffer,) \
+    Code(Source_GeometryPass,) \
     Code(Source_GraphicsObject,) \
+    Code(Source_FinalPass,) \
+    Code(Source_ReflectionPass,) \
     Code(Source_ScriptObject,) \
     Code(Source_PlayerObject,) \
     Code(Source_GameObject,) \
@@ -91,4 +97,21 @@ DECLARE_ENUM(ErrorCode, ERROR_CODES)
     Code(Source_PropertyLoader,) \
     Code(Source_Window,) \
     Code(Source_NumberOfErrorSources,) 
-DECLARE_ENUM(ErrorSource, ERROR_SOURCE)
+DECLARE_ENUM(ErrorSource, ERROR_SOURCE)
+
+// Holds an error code and an error message
+struct ErrorMessage
+{
+	ErrorMessage() : m_errorCode(Success), m_errorSource(Source_Unknown) { }
+	ErrorMessage(const ErrorCode p_errorCode) : m_errorCode(p_errorCode) { }
+	ErrorMessage(const ErrorCode p_errorCode, const ErrorSource p_errorsource)
+		: m_errorCode(p_errorCode), m_errorSource(p_errorsource) { }
+	ErrorMessage(const ErrorCode p_errorCode, const ErrorSource p_errorsource, const std::string &p_errorMessage)
+		: m_errorCode(p_errorCode), m_errorSource(p_errorsource), m_errorMessage(p_errorMessage) { }
+
+	const inline bool containsError() const { return m_errorCode != Success; }
+
+	ErrorCode m_errorCode;
+	ErrorSource m_errorSource;
+	std::string m_errorMessage;
+};

+ 6 - 2
Praxis3D/Source/ErrorHandler.cpp

@@ -59,8 +59,12 @@ ErrorHandler::ErrorHandler()
 	m_errHashmap[GetString(Source_ShaderLoader)]	= NumberOfErrorCodes + Source_ShaderLoader;
 	m_errHashmap[GetString(Source_FileLoader)]		= NumberOfErrorCodes + Source_FileLoader;
 	m_errHashmap[GetString(Source_SceneLoader)]		= NumberOfErrorCodes + Source_SceneLoader;
+	m_errHashmap[GetString(Source_LightingPass)]	= NumberOfErrorCodes + Source_LightingPass;
 	m_errHashmap[GetString(Source_GeometryBuffer)]	= NumberOfErrorCodes + Source_GeometryBuffer;
+	m_errHashmap[GetString(Source_GeometryPass)]	= NumberOfErrorCodes + Source_GeometryPass;
 	m_errHashmap[GetString(Source_GraphicsObject)]	= NumberOfErrorCodes + Source_GraphicsObject;
+	m_errHashmap[GetString(Source_FinalPass)]		= NumberOfErrorCodes + Source_FinalPass;
+	m_errHashmap[GetString(Source_ReflectionPass)]	= NumberOfErrorCodes + Source_ReflectionPass;
 	m_errHashmap[GetString(Source_ScriptObject)]	= NumberOfErrorCodes + Source_ScriptObject;
 	m_errHashmap[GetString(Source_PlayerObject)]	= NumberOfErrorCodes + Source_PlayerObject;
 	m_errHashmap[GetString(Source_GameObject)]		= NumberOfErrorCodes + Source_GameObject;
@@ -157,7 +161,7 @@ void ErrorHandler::log(ErrorType p_errorType, ErrorSource p_errorSource, std::st
 				p_error.pop_back();
 
 			// TODO make the error question data driven
-			if(!WindowLocator().get().spawnYesNoErrorBox(m_errorTypeStrings[p_errorType], m_errorSources[p_errorSource] + ": " + p_error + ".\n\nWould you like to continue?"))
+			if(!WindowLocator().get().spawnYesNoErrorBox(m_errorTypeStrings[p_errorType] + ": " + m_errorSources[p_errorSource], m_errorSources[p_errorSource] + ": " + p_error + ".\n\nWould you like to continue?"))
 				Config::m_engineVar.running = false;
 
 			break;
@@ -165,7 +169,7 @@ void ErrorHandler::log(ErrorType p_errorType, ErrorSource p_errorSource, std::st
 
 		case ErrorType::FatalError:
 		{
-			WindowLocator().get().spawnErrorBox(m_errorTypeStrings[p_errorType], m_errorSources[p_errorSource] + ": " + p_error + ".");
+			WindowLocator().get().spawnErrorBox(m_errorTypeStrings[p_errorType] + ": " + m_errorSources[p_errorSource], m_errorSources[p_errorSource] + ": " + p_error + ".");
 			Config::m_engineVar.running = false;
 
 			break;

+ 1 - 1
Praxis3D/Source/ErrorHandler.h

@@ -106,7 +106,7 @@ private:
 		CoutConsole() { }
 		~CoutConsole() { }
 
-		void displayMessage(std::string p_message) { printf("%s\n", p_message.c_str()); } //std::cout << p_message << std::endl;
+		void displayMessage(std::string p_message) { printf("%s\n", p_message.c_str()); }
 	};
 	
 	ErrorData m_errorData[ErrorCode::NumberOfErrorCodes];

+ 74 - 0
Praxis3D/Source/FinalPass.h

@@ -0,0 +1,74 @@
+#pragma once
+
+#include "RenderPassBase.h"
+
+class FinalPass : public RenderPass
+{
+public:
+	FinalPass(RendererFrontend &p_renderer) : RenderPass(p_renderer) { }
+
+	ErrorCode init()
+	{
+		ErrorCode returnError;
+
+		m_name = "Final Rendering Pass";
+		
+		// Create a property-set used to load geometry shader
+		PropertySet finalShaderProperties(Properties::Shaders);
+		finalShaderProperties.addProperty(Properties::VertexShader, Config::rendererVar().final_pass_vert_shader);
+		finalShaderProperties.addProperty(Properties::FragmentShader, Config::rendererVar().final_pass_frag_shader);
+
+		// Create shaders
+		m_shaderFinalPass = Loaders::shader().load(finalShaderProperties);
+
+		// Load shaders to memory
+		returnError = m_shaderFinalPass->loadToMemory();
+
+		if(returnError == ErrorCode::Success)
+		{
+			// Queue the shaders to be loaded to GPU
+			m_renderer.queueForLoading(*m_shaderFinalPass);
+		}
+
+		return returnError;
+	}
+
+	void update(const SceneObjects &p_sceneObjects, const float p_deltaTime)
+	{
+#ifdef SETTING_USE_BLIT_FRAMEBUFFER
+
+		// Set the default framebuffer to blit pixels to
+		m_renderer.m_backend.getGeometryBuffer()->bindFramebufferForWriting(GeometryBuffer::FramebufferDefault);
+
+		// Set final framebuffer to blit pixels from
+		m_renderer.m_backend.getGeometryBuffer()->bindFramebufferForReading(GeometryBuffer::FramebufferGeometry);
+
+		// Bind final framebuffer
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferFinal, GeometryBuffer::GBufferFinal);
+
+#else
+
+		// Bind final framebuffer
+		//m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferFinal, GeometryBuffer::GBufferFinal);
+
+		glDisable(GL_DEPTH_TEST);
+
+		// Bind final framebuffer
+		//glActiveTexture(GL_TEXTURE0 + GeometryBuffer::GBufferFinal);
+		//glBindTexture(GL_TEXTURE_2D, GeometryBuffer::GBufferFinal);
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferFinal);
+
+		// Set the default framebuffer to be drawn to
+		m_renderer.m_backend.getGeometryBuffer()->bindFramebufferForWriting(GeometryBuffer::FramebufferDefault);
+
+
+#endif // SETTING_USE_BLIT_FRAMEBUFFER
+
+		m_renderer.queueForDrawing(m_shaderFinalPass->getShaderHandle(), m_shaderFinalPass->getUniformUpdater(), p_sceneObjects.m_camera->getBaseObjectData().m_modelMat);
+
+		m_renderer.passScreenSpaceDrawCommandsToBackend();
+	}
+
+private:
+	ShaderLoader::ShaderProgram	*m_shaderFinalPass;
+};

+ 25 - 5
Praxis3D/Source/GeometryBuffer.cpp

@@ -8,7 +8,6 @@ GeometryBuffer::GeometryBuffer(unsigned int p_bufferWidth, unsigned int p_buffer
 	m_depthBuffer = 0;
 	m_finalBuffer = 0;
 	m_finalPassBuffer = GBufferFinal;
-	//m_finalPassBuffer = GBufferDiffuse;
 
 	m_emissiveAndFinalBuffers[0] = GL_COLOR_ATTACHMENT0 + GBufferEmissive;
 	m_emissiveAndFinalBuffers[1] = GL_COLOR_ATTACHMENT0 + GBufferFinal;
@@ -67,6 +66,10 @@ ErrorCode GeometryBuffer::init()
 		m_textureFormats[GBufferNormal] = Config::FramebfrVariables().gl_normal_buffer_texture_format;
 		m_textureTypes[GBufferNormal] = Config::FramebfrVariables().gl_normal_buffer_texture_type;
 
+		m_internalFormats[GBufferMatProperties] = Config::FramebfrVariables().gl_mat_properties_buffer_internal_format;
+		m_textureFormats[GBufferMatProperties] = Config::FramebfrVariables().gl_mat_properties_buffer_texture_format;
+		m_textureTypes[GBufferMatProperties] = Config::FramebfrVariables().gl_mat_properties_buffer_texture_type;
+
 		m_internalFormats[GBufferEmissive] = Config::FramebfrVariables().gl_emissive_buffer_internal_format;
 		m_textureFormats[GBufferEmissive] = Config::FramebfrVariables().gl_emissive_buffer_texture_format;
 		m_textureTypes[GBufferEmissive] = Config::FramebfrVariables().gl_emissive_buffer_texture_type;
@@ -209,6 +212,7 @@ void GeometryBuffer::initGeometryPass()
 {
 	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO);
 	glDrawBuffers(GBufferNumTextures, m_texBuffers);		// Bind geometry pass buffers to write to
+	glClear(GL_COLOR_BUFFER_BIT);
 }
 void GeometryBuffer::initLightPass()
 {
@@ -221,15 +225,31 @@ void GeometryBuffer::initLightPass()
 	glActiveTexture(GL_TEXTURE0 + GBufferNormal);
 	glBindTexture(GL_TEXTURE_2D, m_GBTextures[GBufferNormal]);
 
+	glActiveTexture(GL_TEXTURE0 + GBufferMatProperties);
+	glBindTexture(GL_TEXTURE_2D, m_GBTextures[GBufferMatProperties]);
+
 	glDrawBuffers(2, m_emissiveAndFinalBuffers);
 }
 void GeometryBuffer::initFinalPass()
 {
-	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);				// Set default framebuffer to paste to
-	glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBO);			// Set GBuffer's framebuffer to copy from
+#ifdef SETTING_USE_BLIT_FRAMEBUFFER
+
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);			// Set default framebuffer to paste to
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBO);		// Set GBuffer's framebuffer to copy from
 	glReadBuffer(GL_COLOR_ATTACHMENT0 + GBufferFinal);	// Bind final buffer, to copy from
-}
 
+#else
+
+	// Bind final framebuffer
+	glActiveTexture(GL_TEXTURE0 + GBufferFinal);
+	glBindTexture(GL_TEXTURE_2D, m_finalBuffer);
+
+	// Set the default framebuffer to be drawn to
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+
+#endif // SETTING_USE_BLIT_FRAMEBUFFER
+}
+/*
 void GeometryBuffer::bindForReading(GBufferTextureType p_buffer, int p_activeTexture)
 {
 	glActiveTexture(GL_TEXTURE0 + p_activeTexture);
@@ -271,4 +291,4 @@ void GeometryBuffer::bindForReading(GBufferTextureType p_buffer)
 void GeometryBuffer::bindForWriting(GBufferTextureType p_buffer)
 {
 	glDrawBuffer(GL_COLOR_ATTACHMENT0 + p_buffer);
-}
+}*/

+ 92 - 4
Praxis3D/Source/GeometryBuffer.h

@@ -6,18 +6,27 @@
 class GeometryBuffer : public Framebuffer
 {
 public:
+	enum GBufferFramebufferType : unsigned int
+	{
+		FramebufferDefault,
+		FramebufferGeometry
+	};
+
 	enum GBufferTextureType : unsigned int
 	{
 		GBufferPosition,
 		GBufferDiffuse,
 		GBufferNormal,
 		GBufferEmissive,
+		GBufferMatProperties,
 		GBufferNumTextures,
 		GBufferFinal = GBufferNumTextures,
 		GBufferBlur,
 		GBufferTotalNumTextures
 	};
 
+	typedef unsigned int GBufferTexture;
+
 	GeometryBuffer(unsigned int p_bufferWidth, unsigned int p_bufferHeight);
 	~GeometryBuffer();
 	
@@ -32,11 +41,90 @@ public:
 	virtual void initGeometryPass();	// Bind geometry buffers for drawing
 	virtual void initLightPass();		// Bind buffers from geometry pass so they can be accessed when rendering lights
 	virtual void initFinalPass();		// Bind the final buffer to 'read from' and the default screen buffer to 'write to'
-
-	void bindForReading(GBufferTextureType p_buffer, int p_activeTexture);
-	void bindForReading(GBufferTextureType p_buffer);
-	void bindForWriting(GBufferTextureType p_buffer);
 	
+	inline void bindBufferForReading(GBufferTextureType p_buffer, int p_activeTexture)
+	{
+		glActiveTexture(GL_TEXTURE0 + p_activeTexture);
+		switch(p_buffer)
+		{
+		case GeometryBuffer::GBufferPosition:
+		case GeometryBuffer::GBufferDiffuse:
+		case GeometryBuffer::GBufferNormal:
+		case GeometryBuffer::GBufferEmissive:
+			glBindTexture(GL_TEXTURE_2D, m_GBTextures[p_buffer]);
+			break;
+		case GeometryBuffer::GBufferMatProperties:
+			glBindTexture(GL_TEXTURE_2D, m_GBTextures[p_buffer]);
+			break;
+		case GeometryBuffer::GBufferFinal:
+			glBindTexture(GL_TEXTURE_2D, m_finalBuffer);
+			break;
+		case GeometryBuffer::GBufferBlur:
+			glBindTexture(GL_TEXTURE_2D, m_blurBuffer);
+			break;
+		}
+	}
+	inline void bindBufferForReading(GBufferTextureType p_buffer)
+	{
+		glActiveTexture(GL_TEXTURE0);
+		switch(p_buffer)
+		{
+		case GeometryBuffer::GBufferPosition:
+		case GeometryBuffer::GBufferDiffuse:
+		case GeometryBuffer::GBufferNormal:
+		case GeometryBuffer::GBufferEmissive:
+			glBindTexture(GL_TEXTURE_2D, m_GBTextures[p_buffer]);
+			break;
+		case GeometryBuffer::GBufferMatProperties:
+			glBindTexture(GL_TEXTURE_2D, m_GBTextures[p_buffer]);
+			break;
+		case GeometryBuffer::GBufferFinal:
+			glBindTexture(GL_TEXTURE_2D, m_finalBuffer);
+			break;
+		case GeometryBuffer::GBufferBlur:
+			glBindTexture(GL_TEXTURE_2D, m_blurBuffer);
+			break;
+		}
+	}
+	inline void bindBufferForWriting(GBufferTextureType p_buffer)
+	{
+		glDrawBuffer(GL_COLOR_ATTACHMENT0 + p_buffer);
+	}
+	inline void bindBuffersForWriting(const std::vector<GLenum> &p_buffers)
+	{
+		glDrawBuffers(p_buffers.size(), p_buffers.data() );
+	}
+	
+	inline void bindFramebufferForReading(GBufferFramebufferType p_framebufferType)
+	{
+		switch(p_framebufferType)
+		{
+		case GeometryBuffer::FramebufferDefault:
+			glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+			break;
+		case GeometryBuffer::FramebufferGeometry:
+			glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBO);
+			break;
+		}
+	}
+	inline void bindFramebufferForWriting(GBufferFramebufferType p_framebufferType)
+	{
+		switch(p_framebufferType)
+		{
+		case GeometryBuffer::FramebufferDefault:
+			glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+			break;
+		case GeometryBuffer::FramebufferGeometry:
+			glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO);
+			break;
+		}
+	}
+
+	inline GLenum getBufferLocation(GBufferTextureType p_buffer)
+	{
+		return GL_COLOR_ATTACHMENT0 + p_buffer;
+	}
+
 protected:
 
 	GLuint  m_GBTextures[GBufferNumTextures],	// Geometry pass textures

+ 84 - 0
Praxis3D/Source/GeometryPass.h

@@ -0,0 +1,84 @@
+#pragma once
+
+#include "RenderPassBase.h"
+
+class GeometryPass : public RenderPass
+{
+public:
+	GeometryPass(RendererFrontend &p_renderer) : RenderPass(p_renderer) { }
+
+	ErrorCode init()
+	{
+		ErrorCode returnError;
+
+		m_name = "Geometry Rendering Pass";
+
+		// Create a property-set used to load geometry shader
+		PropertySet geomShaderProperties(Properties::Shaders);
+		geomShaderProperties.addProperty(Properties::VertexShader, Config::rendererVar().geometry_pass_vert_shader);
+		geomShaderProperties.addProperty(Properties::FragmentShader, Config::rendererVar().geometry_pass_frag_shader);
+
+		// Create shaders
+		m_shaderGeometry = Loaders::shader().load(geomShaderProperties);
+
+		// Load shaders to memory
+		returnError = m_shaderGeometry->loadToMemory();
+
+		if(returnError == ErrorCode::Success)
+		{
+			// Queue the shaders to be loaded to GPU
+			m_renderer.queueForLoading(*m_shaderGeometry);
+		}
+
+		return returnError;
+	}
+
+	void update(const SceneObjects &p_sceneObjects, const float p_deltaTime)
+	{
+		// Bind the geometry framebuffer to be used
+		m_renderer.m_backend.getGeometryBuffer()->bindFramebufferForWriting(GeometryBuffer::FramebufferGeometry);
+
+		// Bind all the geometry buffer textures to be drawned to
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GeometryBuffer::GBufferPosition);
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GeometryBuffer::GBufferDiffuse);
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GeometryBuffer::GBufferNormal);
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GeometryBuffer::GBufferEmissive);
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForWriting(GeometryBuffer::GBufferMatProperties);
+
+		// Initialize the geometry framebuffer for the geometry pass
+		m_renderer.m_backend.getGeometryBuffer()->initGeometryPass();
+
+		// Get known shader details
+		auto geomShaderHandle = m_shaderGeometry->getShaderHandle();
+		auto &geomUniformUpdater = m_shaderGeometry->getUniformUpdater();
+
+		// Iterate over all objects to be rendered with geometry shader
+		for(decltype(p_sceneObjects.m_modelObjects.size()) objIndex = 0, numObjects = p_sceneObjects.m_modelObjects.size(); objIndex < numObjects; objIndex++)
+		{
+			m_renderer.queueForDrawing(*p_sceneObjects.m_modelObjects[objIndex],
+								geomShaderHandle, 
+								geomUniformUpdater, 
+								m_renderer.m_viewProjMatrix);
+		}
+
+		// Iterate over all objects to be rendered with a custom shader
+		for(decltype(p_sceneObjects.m_customShaderObjects.size()) objIndex = 0, numObjects = p_sceneObjects.m_customShaderObjects.size(); objIndex < numObjects; objIndex++)
+		{
+			m_renderer.queueForDrawing(*p_sceneObjects.m_customShaderObjects[objIndex],
+				p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->getShaderHandle(),
+				p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->getUniformUpdater(),
+				m_renderer.m_viewProjMatrix);
+
+				//queueForDrawing(*p_sceneObjects.m_customShaderObjects[objIndex], 
+				//				p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->getShaderHandle(),
+				//				p_sceneObjects.m_customShaderObjects[objIndex]->m_shader->getUniformUpdater(),
+				//				viewProjMatrix);
+		}
+
+		// Pass all the draw commands to be executed
+		m_renderer.passDrawCommandsToBackend();
+	}
+	
+private:
+	ShaderLoader::ShaderProgram	*m_shaderGeometry;
+};

+ 7 - 6
Praxis3D/Source/GraphicsDataSets.h

@@ -6,7 +6,7 @@
 // All graphics objects contain an instance of this struct, which holds the necessary spacial and other data
 struct GraphicsData
 {
-	GraphicsData() : m_scale(1.0f, 1.0f, 1.0f), m_alphaThreshold(0.0f), m_emissiveThreshold(0.0f), m_textureTilingFactor(1.0f) { }
+	GraphicsData() : m_scale(1.0f, 1.0f, 1.0f), m_alphaThreshold(0.0f), m_emissiveThreshold(0.0f), m_heightScale(0.0f), m_textureTilingFactor(1.0f) { }
 
 	Math::Vec3f m_position,
 				m_rotation,
@@ -18,6 +18,7 @@ struct GraphicsData
 
 	float	m_alphaThreshold,
 			m_emissiveThreshold,
+			m_heightScale,
 			m_textureTilingFactor;
 };
 
@@ -28,7 +29,7 @@ struct RenderableObjectData
 		m_shader(p_shader),
 		m_baseObjectData(p_baseObjectData) { }
 
-	void loadToVideoMemory()
+	/*void loadToVideoMemory()
 	{
 		ErrorCode error;
 
@@ -45,15 +46,15 @@ struct RenderableObjectData
 			for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
 				if(!ErrHandlerLoc::get().ifSuccessful(m_materials[matType][i].loadToVideoMemory(), error))
 					ErrHandlerLoc::get().log(error);
-	}
+	}*/
 
 	GraphicsData &m_baseObjectData;
 
 	ModelLoader::ModelHandle m_model;
 	ShaderLoader::ShaderProgram *m_shader;
-	std::vector<bool> m_defaultMaterial[Model::NumOfModelMaterials];
-	std::vector<TextureLoader::Texture2DHandle> m_materials[Model::NumOfModelMaterials];
-	std::vector<TextureLoader::Texture2DHandle>::size_type m_numMaterials;
+	std::vector<bool> m_defaultMaterial[MaterialType_NumOfTypes];
+	std::vector<TextureLoader2D::Texture2DHandle> m_materials[MaterialType_NumOfTypes];
+	std::vector<TextureLoader2D::Texture2DHandle>::size_type m_numMaterials;
 
 	// Unused, as renderer checks texture handle not being 0 instead
 	//std::bitset<Model::NumOfModelMaterials> m_materialPresent;

+ 26 - 7
Praxis3D/Source/LightingGraphicsObjects.h

@@ -5,7 +5,7 @@
 
 class DirectionalLightObject : public SystemObject
 {
-	friend class RendererScene;
+	//friend class RendererScene;
 public:
 	DirectionalLightObject(SystemScene *p_systemScene, const std::string &p_name, DirectionalLightDataSet p_lightDataSet)
 		: SystemObject(p_systemScene, p_name, Properties::DirectionalLight), m_lightDataSet(p_lightDataSet), m_active(true) { }
@@ -74,7 +74,10 @@ public:
 	const inline DirectionalLightDataSet &getLightDataSet() const { return m_lightDataSet; }
 
 	// Setters
-	inline void setActive(bool p_flag) { m_active = p_flag; }
+	inline void setActive(bool p_flag)							{ m_active = p_flag;						}
+	inline void setColor(const Math::Vec3f &p_color)			{ m_lightDataSet.m_color = p_color;			}
+	inline void setDirection(const Math::Vec3f &p_direction)	{ m_lightDataSet.m_direction = p_direction; }
+	inline void setIntensity(const float p_intensity)			{ m_lightDataSet.m_intensity = p_intensity; }
 
 private:
 	DirectionalLightDataSet m_lightDataSet;
@@ -84,7 +87,7 @@ private:
 
 class PointLightObject : public SystemObject
 {
-	friend class RendererScene;
+	//friend class RendererScene;
 public:
 	PointLightObject(SystemScene *p_systemScene, const std::string &p_name, PointLightDataSet p_lightDataSet)
 		: SystemObject(p_systemScene, p_name, Properties::PointLight), m_lightDataSet(p_lightDataSet), m_active(true) { }
@@ -153,10 +156,16 @@ public:
 	// Getters
 	const inline bool active() const { return m_active; }
 	const inline PointLightDataSet &getLightDataSet() const { return m_lightDataSet; }
+	const inline Math::Vec3f &getOffsetPosition() const { return m_offsetPosition; }
 
 	// Setters
-	inline void setActive(bool p_flag) { m_active = p_flag; }
-
+	inline void setActive(bool p_flag)								{ m_active = p_flag;							}
+	inline void setColor(const Math::Vec3f &p_color)				{ m_lightDataSet.m_color = p_color;				}
+	inline void setPosition(const Math::Vec3f &p_position)			{ m_lightDataSet.m_position = p_position;		}
+	inline void setAttenuation(const Math::Vec3f &p_attenuation)	{ m_lightDataSet.m_attenuation = p_attenuation;	}
+	inline void setOffsetPosition(const Math::Vec3f &p_position)	{ m_offsetPosition = p_position;				}
+	inline void setIntensity(const float p_intensity)				{ m_lightDataSet.m_intensity = p_intensity;		}
+	
 private:
 	PointLightDataSet m_lightDataSet;
 
@@ -167,7 +176,7 @@ private:
 
 class SpotLightObject : public SystemObject
 {
-	friend class RendererScene;
+	//friend class RendererScene;
 public:
 	SpotLightObject(SystemScene *p_systemScene, const std::string &p_name, SpotLightDataSet p_lightDataSet)
 		: SystemObject(p_systemScene, p_name, Properties::SpotLight), m_lightDataSet(p_lightDataSet), m_active(true) { }
@@ -255,9 +264,19 @@ public:
 	// Getters
 	const inline bool active() const { return m_active; }
 	const inline SpotLightDataSet &getLightDataSet() const { return m_lightDataSet; }
+	const inline Math::Vec3f &getOffsetPosition() const { return m_offsetPosition; }
+	const inline Math::Vec3f &getOffsetRotation() const { return m_offsetRotation; }
 
 	// Setters
-	inline void setActive(bool p_flag) { m_active = p_flag; }
+	inline void setActive(bool p_flag)								{ m_active = p_flag;							}
+	inline void setColor(const Math::Vec3f &p_color)				{ m_lightDataSet.m_color = p_color;				}
+	inline void setPosition(const Math::Vec3f &p_position)			{ m_lightDataSet.m_position = p_position;		}
+	inline void setDirection(const Math::Vec3f &p_direction)		{ m_lightDataSet.m_direction = p_direction;		}
+	inline void setAttenuation(const Math::Vec3f &p_attenuation)	{ m_lightDataSet.m_attenuation = p_attenuation; }
+	inline void setOffsetPosition(const Math::Vec3f &p_position)	{ m_offsetPosition = p_position;				}
+	inline void setOffsetRotation(const Math::Vec3f &p_rotation)	{ m_offsetRotation = p_rotation;				}
+	inline void setCutoffAngle(const float p_cutoffAngle)			{ m_lightDataSet.m_cutoffAngle = p_cutoffAngle; }
+	inline void setIntensity(const float p_intensity)				{ m_lightDataSet.m_intensity = p_intensity;		}
 
 private:
 	SpotLightDataSet m_lightDataSet;

+ 95 - 0
Praxis3D/Source/LightingPass.h

@@ -0,0 +1,95 @@
+#pragma once
+
+#include "RenderPassBase.h"
+
+class LightingPass : public RenderPass
+{
+public:
+	LightingPass(RendererFrontend &p_renderer) : RenderPass(p_renderer) { }
+
+	ErrorCode init()
+	{
+		ErrorCode returnError;
+
+		m_name = "Lighting Rendering Pass";
+
+		// Set lightbuffer values
+		m_pointLightBuffer.m_bindingIndex = LightBufferBinding_PointLight;
+		m_spotLightBuffer.m_bindingIndex = LightBufferBinding_SpotLight;
+
+		// Set the light buffer sizes
+		m_pointLightBuffer.m_size = sizeof(PointLightDataSet) * Config::graphicsVar().max_num_point_lights;
+		m_spotLightBuffer.m_size = sizeof(SpotLightDataSet) * Config::graphicsVar().max_num_spot_lights;
+		
+		// Set buffer values
+		m_emissiveAndFinalBuffers.resize(2);
+		m_emissiveAndFinalBuffers[0] = m_renderer.m_backend.getGeometryBuffer()->getBufferLocation(GeometryBuffer::GBufferEmissive);
+		m_emissiveAndFinalBuffers[1] = m_renderer.m_backend.getGeometryBuffer()->getBufferLocation(GeometryBuffer::GBufferFinal);
+
+		// Create a property-set used to load lighting shader
+		PropertySet lightShaderProperties(Properties::Shaders);
+		lightShaderProperties.addProperty(Properties::VertexShader, Config::rendererVar().light_pass_vert_shader);
+		lightShaderProperties.addProperty(Properties::FragmentShader, Config::rendererVar().light_pass_frag_shader);
+
+		// Create shaders
+		m_shaderLightPass = Loaders::shader().load(lightShaderProperties);
+
+		// Load shaders to memory
+		returnError = m_shaderLightPass->loadToMemory();
+
+		if(returnError == ErrorCode::Success)
+		{
+			// Queue the shaders to be loaded to GPU
+			m_renderer.queueForLoading(*m_shaderLightPass);
+		}
+
+		// Queue light buffers to be created
+		m_renderer.queueForLoading(m_pointLightBuffer);
+		m_renderer.queueForLoading(m_spotLightBuffer);
+
+		return returnError;
+	}
+
+	void update(const SceneObjects &p_sceneObjects, const float p_deltaTime)
+	{
+		// Setup point light buffer values
+		m_pointLightBuffer.m_size = sizeof(PointLightDataSet) * p_sceneObjects.m_pointLights.size();
+		m_pointLightBuffer.m_data = (void*)p_sceneObjects.m_pointLights.data();
+
+		// Setup spot light buffer values
+		m_spotLightBuffer.m_size = sizeof(SpotLightDataSet) * p_sceneObjects.m_spotLights.size();
+		m_spotLightBuffer.m_data = (void*)p_sceneObjects.m_spotLights.data();
+
+		// Bind textures for reading
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferPosition, GeometryBuffer::GBufferPosition);
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferDiffuse, GeometryBuffer::GBufferDiffuse);
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferNormal, GeometryBuffer::GBufferNormal);
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferMatProperties, GeometryBuffer::GBufferMatProperties);
+
+		// Bind textures for writing
+		m_renderer.m_backend.getGeometryBuffer()->bindBuffersForWriting(m_emissiveAndFinalBuffers);
+
+		// Queue light buffer updates (so that new values that were just setup are sent to the GPU)
+		m_renderer.queueForUpdate(m_pointLightBuffer);
+		m_renderer.queueForUpdate(m_spotLightBuffer);
+
+		// Pass update commands so they are executed 
+		m_renderer.passUpdateCommandsToBackend();
+
+		// Queue the screen space triangle, using lighting shader, to be drawned
+		m_renderer.queueForDrawing(m_shaderLightPass->getShaderHandle(), m_shaderLightPass->getUniformUpdater(), p_sceneObjects.m_camera->getBaseObjectData().m_modelMat);
+
+		// Pass the draw command so it is executed
+		m_renderer.passScreenSpaceDrawCommandsToBackend();
+	}
+
+private:
+	ShaderLoader::ShaderProgram	*m_shaderLightPass;
+
+	// Buffer handles used for binding
+	std::vector<GeometryBuffer::GBufferTexture> m_emissiveAndFinalBuffers;
+
+	// Light buffers
+	RendererFrontend::LightUniformBuffer m_pointLightBuffer, 
+										 m_spotLightBuffer;
+};

+ 1 - 3
Praxis3D/Source/LoaderBase.h

@@ -60,7 +60,7 @@ public:
 		inline bool operator==(std::string p_string) { return m_filename == p_string; }
 
 		inline ErrorCode unloadMemory()		 { return static_cast<TObject*>(this)->unloadMemory();		}
-		inline ErrorCode unloadVideoMemory() { return static_cast<TObject*>(this)->unloadVideoMemory(); }
+		inline ErrorCode unloadVideoMemory() { return ErrorCode::Success; /*return static_cast<TObject*>(this)->unloadVideoMemory();*/ }
 
 	protected:
 		bool m_loadedToMemory;
@@ -143,8 +143,6 @@ protected:
 	// Swap the object with the last element of vector and pop_back
 	inline void removeObject(UniqueObject &p_object)
 	{
-		//static_cast<TDerived*>(this)->removeObject(p_object);
-
 		auto uniqueID = p_object.getUniqueID();
 		if(!(uniqueID < 0) && uniqueID < m_objectPool.size())
 		{

+ 2 - 1
Praxis3D/Source/Loaders.cpp

@@ -2,4 +2,5 @@
 
 ModelLoader Loaders::m_modelLoader;
 ShaderLoader Loaders::m_shaderLoader;
-TextureLoader Loaders::m_textureLoader;
+TextureLoader2D Loaders::m_texture2DLoader;
+TextureLoaderCubemap Loaders::m_textureCubemapLoader;

+ 5 - 2
Praxis3D/Source/Loaders.h

@@ -11,9 +11,12 @@ class Loaders
 public:
 	inline static ModelLoader &model() { return m_modelLoader; }
 	inline static ShaderLoader &shader() { return m_shaderLoader; }
-	inline static TextureLoader &texture() { return m_textureLoader; }
+	inline static TextureLoader2D &texture2D() { return m_texture2DLoader; }
+	inline static TextureLoaderCubemap &textureCubemap() { return m_textureCubemapLoader; }
+	
 private:
 	static ModelLoader m_modelLoader;
 	static ShaderLoader m_shaderLoader;
-	static TextureLoader m_textureLoader;
+	static TextureLoader2D m_texture2DLoader;
+	static TextureLoaderCubemap m_textureCubemapLoader;
 };

+ 9 - 9
Praxis3D/Source/Math.cpp

@@ -66,10 +66,10 @@ namespace Math
 	void Mat4f::perspective(const float p_FOV, const int p_screenWidth, const int p_screenHeight, const float p_zNear, const float p_zFar)
 	{
 		float	radFOV = toRadian(p_FOV),
-			height = cosf(0.5f * radFOV) / sinf(0.5f * radFOV),
-			width = height * p_screenHeight / p_screenWidth,
-			zRange = p_zFar - p_zNear;
-
+				height = cosf(0.5f * radFOV) / sinf(0.5f * radFOV),
+				width = height * p_screenHeight / p_screenWidth,
+				zRange = p_zFar - p_zNear;
+				
 		m[0] = width;					 m[4] = 0.0f;			m[8] = 0.0f;								m[12] = 0.0f;
 		m[1] = 0.0f;					 m[5] = height;			m[9] = 0.0f;								m[13] = 0.0f;
 		m[2] = 0.0f;					 m[6] = 0.0f;			m[10] = -(p_zNear + p_zFar) / zRange;		m[14] = -(2.0f * p_zFar * p_zNear) / zRange;
@@ -78,11 +78,11 @@ namespace Math
 	void Mat4f::perspective(const float p_FOV, const float p_aspectRatio, const float p_zNear, const float p_zFar)
 	{
 		float	range = tanf(toRadian(p_FOV / 2.0f)) * p_zNear,
-			left = -range * p_aspectRatio,
-			right = range * p_aspectRatio,
-			bottom = -range,
-			top = range,
-			zRange = p_zFar - p_zNear;
+				left = -range * p_aspectRatio,
+				right = range * p_aspectRatio,
+				bottom = -range,
+				top = range,
+				zRange = p_zFar - p_zNear;
 
 		m[0] = (2.0f * p_zNear) / (right - left);	 m[4] = 0.0f;									m[8] = 0.0f;								m[12] = 0.0f;
 		m[1] = 0.0f;								 m[5] = (2.0f * p_zNear) / (top - bottom);		m[9] = 0.0f;								m[13] = 0.0f;

+ 127 - 15
Praxis3D/Source/Math.h

@@ -3,7 +3,6 @@
 //#define _USE_MATH_DEFINES
 
 #include <cmath>
-//#include <iostream>
 
 #define E			2.71828182845904523536
 #define LOG2E		1.44269504088896340736
@@ -38,6 +37,58 @@ namespace Math
 		{
 			x = p_valueX;	y = p_valueY;
 		}
+
+		const inline Vec2i &operator=(const Vec2i& p_vec)
+		{
+			x = p_vec.x;
+			y = p_vec.y;
+
+			return *this;
+		}
+		const inline Vec2i &operator+=(const Vec2i& p_vec)
+		{
+			x += p_vec.x;
+			y += p_vec.y;
+
+			return *this;
+		}
+		const inline Vec2i &operator-=(const Vec2i& p_vec)
+		{
+			x -= p_vec.x;
+			y -= p_vec.y;
+
+			return *this;
+		}
+		const inline Vec2i &operator*=(const Vec2i& p_vec)
+		{
+			x *= p_vec.x;
+			y *= p_vec.y;
+
+			return *this;
+		}
+		const inline Vec2i &operator*=(const int p_multiplier)
+		{
+			x *= p_multiplier;
+			y *= p_multiplier;
+
+			return *this;
+		}
+		const inline Vec2i &operator/=(const Vec2i& p_vec)
+		{
+			x /= p_vec.x;
+			y /= p_vec.y;
+
+			return *this;
+		}
+		const inline Vec2i &operator/=(const int p_divider)
+		{
+			x /= p_divider;
+			y /= p_divider;
+
+			return *this;
+		}
+		const inline bool operator==(Vec2i& p_vec) const { return (x == p_vec.x && y == p_vec.y); }
+		const inline bool operator!=(Vec2i& p_vec) const { return (x != p_vec.x || y != p_vec.y); }
 	};
 	struct Vec2f
 	{
@@ -57,6 +108,58 @@ namespace Math
 		}
 		Vec2f(const Vec3f p_vec);
 		Vec2f(const Vec4f p_vec);
+
+		const inline Vec2f &operator=(const Vec2f& p_vec)
+		{
+			x = p_vec.x;
+			y = p_vec.y;
+
+			return *this;
+		}
+		const inline Vec2f &operator+=(const Vec2f& p_vec)
+		{
+			x += p_vec.x;
+			y += p_vec.y;
+
+			return *this;
+		}
+		const inline Vec2f &operator-=(const Vec2f& p_vec)
+		{
+			x -= p_vec.x;
+			y -= p_vec.y;
+
+			return *this;
+		}
+		const inline Vec2f &operator*=(const Vec2f& p_vec)
+		{
+			x *= p_vec.x;
+			y *= p_vec.y;
+
+			return *this;
+		}
+		const inline Vec2f &operator*=(const float p_float)
+		{
+			x *= p_float;
+			y *= p_float;
+
+			return *this;
+		}
+		const inline Vec2f &operator/=(const Vec2f& p_vec)
+		{
+			x /= p_vec.x;
+			y /= p_vec.y;
+
+			return *this;
+		}
+		const inline Vec2f &operator/=(const float p_float)
+		{
+			x /= p_float;
+			y /= p_float;
+
+			return *this;
+		}
+		const inline bool operator==(Vec2f& p_vec) const { return (x == p_vec.x && y == p_vec.y); }
+		const inline bool operator!=(Vec2f& p_vec) const { return (x != p_vec.x || y != p_vec.y); }
 	};
 	struct Vec3f
 	{
@@ -136,8 +239,8 @@ namespace Math
 
 			return *this;
 		}
-		inline bool operator==(Vec3f& p_vec) { return (x == p_vec.x && y == p_vec.y && z == p_vec.z); }
-		inline bool operator!=(Vec3f& p_vec) { return (x != p_vec.x || y != p_vec.y || z != p_vec.z); }
+		const inline bool operator==(Vec3f& p_vec) const { return (x == p_vec.x && y == p_vec.y && z == p_vec.z); }
+		const inline bool operator!=(Vec3f& p_vec) const { return (x != p_vec.x || y != p_vec.y || z != p_vec.z); }
 
 		const inline float getMax() const { return (x > y) ? (x > z) ? x : z : (y > z) ? y : z; }
 		const inline float squareLength() const { return (x * x + y * y + z * z); }
@@ -197,16 +300,26 @@ namespace Math
 		}
 	};
 
-	const inline Vec3f operator+(const Vec3f& p_left, const Vec3f& p_right) { return Vec3f(p_left.x + p_right.x, p_left.y + p_right.y, p_left.z + p_right.z); }
-	const inline Vec3f operator-(const Vec3f& p_left, const Vec3f& p_right) { return Vec3f(p_left.x - p_right.x, p_left.y - p_right.y, p_left.z - p_right.z); }
-	const inline Vec3f operator*(const float p_float, const Vec3f& p_vec) { return Vec3f(p_vec.x * p_float, p_vec.y * p_float, p_vec.z * p_float); }
-	const inline Vec3f operator*(const Vec3f& p_vec, const float p_float) { return Vec3f(p_vec.x * p_float, p_vec.y * p_float, p_vec.z * p_float); }
-	const inline float operator*(const Vec3f& p_left, const Vec3f& p_right) { return (p_left.x * p_right.x, p_left.y * p_right.y, p_left.z * p_right.z); }
-	const inline Vec3f operator/(const float p_float, const Vec3f& p_vec) { return (p_vec * (1 / p_float)); }
-	const inline Vec3f operator/(const Vec3f& p_vec, const float p_float) { return p_vec * (1 / p_float); }
-	const inline Vec3f operator/(const Vec3f& p_left, const Vec3f& p_right) { return Vec3f(p_left.x / p_right.x, p_left.y / p_right.y, p_left.z / p_right.z); }
-	const inline Vec3f operator-(const Vec3f& p_vec) { return Vec3f(-p_vec.x, -p_vec.y, -p_vec.z); }
-	const inline float dot(const Vec3f& p_left, const Vec3f& p_right) { return (p_left.x * p_right.x + p_left.y * p_right.y + p_left.z * p_right.z); }
+	const inline Vec2f operator+(const Vec2f& p_left, const Vec2f& p_right)	{ return Vec2f(p_left.x + p_right.x, p_left.y + p_right.y); }
+	const inline Vec2f operator-(const Vec2f& p_left, const Vec2f& p_right)	{ return Vec2f(p_left.x - p_right.x, p_left.y - p_right.y); }
+	const inline Vec2f operator*(const float p_float, const Vec2f& p_vec)	{ return Vec2f(p_vec.x * p_float, p_vec.y * p_float); }
+	const inline Vec2f operator*(const Vec2f& p_vec, const float p_float)	{ return Vec2f(p_vec.x * p_float, p_vec.y * p_float); }
+	const inline float operator*(const Vec2f& p_left, const Vec2f& p_right) { return (p_left.x * p_right.x, p_left.y * p_right.y); }
+	const inline Vec2f operator/(const float p_float, const Vec2f& p_vec)	{ return (p_vec * (1 / p_float)); }
+	const inline Vec2f operator/(const Vec2f& p_vec, const float p_float)	{ return p_vec * (1 / p_float); }
+	const inline Vec2f operator/(const Vec2f& p_left, const Vec2f& p_right) { return Vec2f(p_left.x / p_right.x, p_left.y / p_right.y); }
+	const inline Vec2f operator-(const Vec2f& p_vec)						{ return Vec2f(-p_vec.x, -p_vec.y); }
+
+	const inline Vec3f operator+(const Vec3f& p_left, const Vec3f& p_right)	{ return Vec3f(p_left.x + p_right.x, p_left.y + p_right.y, p_left.z + p_right.z); }
+	const inline Vec3f operator-(const Vec3f& p_left, const Vec3f& p_right)	{ return Vec3f(p_left.x - p_right.x, p_left.y - p_right.y, p_left.z - p_right.z); }
+	const inline Vec3f operator*(const float p_float, const Vec3f& p_vec)	{ return Vec3f(p_vec.x * p_float, p_vec.y * p_float, p_vec.z * p_float); }
+	const inline Vec3f operator*(const Vec3f& p_vec, const float p_float)	{ return Vec3f(p_vec.x * p_float, p_vec.y * p_float, p_vec.z * p_float); }
+	const inline float operator*(const Vec3f& p_left, const Vec3f& p_right)	{ return (p_left.x * p_right.x, p_left.y * p_right.y, p_left.z * p_right.z); }
+	const inline Vec3f operator/(const float p_float, const Vec3f& p_vec)	{ return (p_vec * (1 / p_float)); }
+	const inline Vec3f operator/(const Vec3f& p_vec, const float p_float)	{ return p_vec * (1 / p_float); }
+	const inline Vec3f operator/(const Vec3f& p_left, const Vec3f& p_right)	{ return Vec3f(p_left.x / p_right.x, p_left.y / p_right.y, p_left.z / p_right.z); }
+	const inline Vec3f operator-(const Vec3f& p_vec)						{ return Vec3f(-p_vec.x, -p_vec.y, -p_vec.z); }
+	const inline float dot(const Vec3f& p_left, const Vec3f& p_right)		{ return (p_left.x * p_right.x + p_left.y * p_right.y + p_left.z * p_right.z); }
 	const inline Vec3f operator^(const Vec3f& p_left, const Vec3f& p_right)
 	{
 		return Vec3f(p_left.y * p_right.z - p_left.z * p_right.y,
@@ -458,8 +571,7 @@ namespace Math
 	inline float toRadian(const float p_float) { return (p_float * (float) PI / 180.0f); }
 	inline float toDegree(const float p_float) { return (p_float * 180.0f / (float) PI); }
 	inline float getMax(const float p_left, const float p_right) { return p_left > p_right ? p_left : p_right; }
-	//inline void clampMinMax(float &p_value, float p_clampMin, float p_clampMax) { if(p_value > p_clampMax) p_value = p_clampMax; else if(p_value < p_clampMin) p_value = p_clampMin; }
 
 	template <typename T>
-	inline T clip(T p_in, T p_low, T p_high) { return std::min(std::max(p_in, p_low), p_high); }
+	inline T clamp(T p_in, T p_low, T p_high) { return std::min(std::max(p_in, p_low), p_high); }
 }

+ 37 - 29
Praxis3D/Source/ModelGraphicsObjects.h

@@ -10,12 +10,13 @@ class RendererScene;
 
 class ModelObject : public LoadableGraphicsObject
 {
-	friend class RendererScene;
+	//friend class RendererScene;
 public:
 	ModelObject(SystemScene *p_systemScene, const std::string &p_name, ModelLoader::ModelHandle &p_model, Properties::PropertyID p_objectType = Properties::ModelObject)
 		: LoadableGraphicsObject(p_systemScene, p_name, p_objectType, p_model, Loaders::shader().load())
 	{
 		m_customShader = false;
+		m_baseObjectData.m_heightScale = Config::graphicsVar().height_scale;
 		m_baseObjectData.m_alphaThreshold = Config::graphicsVar().alpha_threshold;
 		m_baseObjectData.m_emissiveThreshold = Config::graphicsVar().emissive_threshold;
 	}
@@ -24,6 +25,7 @@ public:
 		: LoadableGraphicsObject(p_systemScene, p_name, p_objectType, p_model, p_shader)
 	{
 		m_customShader = true;
+		m_baseObjectData.m_heightScale = Config::graphicsVar().height_scale;
 		m_baseObjectData.m_alphaThreshold = Config::graphicsVar().alpha_threshold;
 		m_baseObjectData.m_emissiveThreshold = Config::graphicsVar().emissive_threshold;
 	}
@@ -61,7 +63,7 @@ public:
 		decltype(m_rendererData.m_model.getMaterialArrays()) materials = m_rendererData.m_model.getMaterialArrays();
 		
 		// Reserve space in the material arrays before populating them
-		for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+		for(int matType = 0; matType < MaterialType_NumOfTypes; matType++)
 		{
 			m_rendererData.m_materials[matType].reserve(materials.m_numMaterials);
 			m_rendererData.m_defaultMaterial[matType].reserve(materials.m_numMaterials);
@@ -78,7 +80,7 @@ public:
 		// Override from model only if the existing entry is empty. If neither texture's
 		// filenames are present, use a default texture filename instead (as a fall-back mechanism)
 		for(decltype(materials.m_numMaterials) i = 0, size = materials.m_numMaterials; i < size; i++)
-			for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+			for(int matType = 0; matType < MaterialType_NumOfTypes; matType++)
 				if(m_materialNames.m_materials[matType][i].isEmpty())
 					if(!materials.m_materials[matType][i].isEmpty())
 					{
@@ -94,9 +96,9 @@ public:
 		// Iterate over each material, and try to load it (from filename). If the filename is empty,
 		// texture loader is simply going to give out a default texture.
 		for(decltype(m_materialNames.m_numMaterials) i = 0; i < m_materialNames.m_numMaterials; i++)
-			for(unsigned int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+			for(unsigned int matType = 0; matType < MaterialType_NumOfTypes; matType++)
 			{
-				m_rendererData.m_materials[matType].push_back(Loaders::texture().load2D(m_materialNames.m_materials[matType][i].m_filename, static_cast<Model::ModelMaterialType>(matType), false));
+				m_rendererData.m_materials[matType].push_back(Loaders::texture2D().load(m_materialNames.m_materials[matType][i].m_filename, static_cast<MaterialType>(matType), false));
 				m_rendererData.m_defaultMaterial[matType].push_back(m_materialNames.m_materials[matType][i].m_defaultMaterial);
 			}
 		
@@ -105,7 +107,7 @@ public:
 		// Load each texture to memory (if it has been loaded before, it will simple continue without loading)
 		for(decltype(m_materialNames.m_numMaterials) i = 0; i < m_materialNames.m_numMaterials; i++)
 			// Load each material type to memory. If it returns an error, log it
-			for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+			for(int matType = 0; matType < MaterialType_NumOfTypes; matType++)
 				if(!ErrHandlerLoc::get().ifSuccessful(m_rendererData.m_materials[matType][i].loadToMemory(), error))
 					ErrHandlerLoc::get().log(error, ErrorSource::Source_GraphicsObject);
 		
@@ -124,18 +126,18 @@ public:
 	}
 
 	// Loads model and materials from memory to video memory; should only be called by renderer thread
-	virtual ErrorCode loadToVideoMemory()
+	ErrorCode loadToVideoMemory()
 	{
 		// Error code used for checking the success of loading; it is not returned
 		ErrorCode error = ErrorCode::Success;
 
 		// Load the model to video memory; log an error if it occurs
-		if(!ErrHandlerLoc::get().ifSuccessful(m_rendererData.m_model.loadToVideoMemory(), error))
-			ErrHandlerLoc::get().log(error);
+		//if(!ErrHandlerLoc::get().ifSuccessful(m_rendererData.m_model.loadToVideoMemory(), error))
+		//	ErrHandlerLoc::get().log(error);
 
 		// Iterate over all materials and load them to video memory; log an error if loading failed
 		for(decltype(m_rendererData.m_numMaterials) i = 0; i < m_rendererData.m_numMaterials; i++)
-			for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+			for(int matType = 0; matType < MaterialType_NumOfTypes; matType++)
 				if(!ErrHandlerLoc::get().ifSuccessful(m_rendererData.m_materials[matType][i].loadToVideoMemory(), error))
 					ErrHandlerLoc::get().log(error);
 
@@ -143,7 +145,7 @@ public:
 	}
 
 	// Exports all the data of the object as a PropertySet
-	virtual PropertySet exportObject()
+	PropertySet exportObject()
 	{
 		// Create the root property set
 		PropertySet propertySet(Properties::ArrayEntry);
@@ -156,8 +158,9 @@ public:
 		propertySet.addProperty(Properties::OffsetPosition, m_baseObjectData.m_offsetPosition);
 		propertySet.addProperty(Properties::OffsetRotation, m_baseObjectData.m_offsetRotation);
 		propertySet.addProperty(Properties::Scale, m_baseObjectData.m_scale);
-		propertySet.addProperty(Properties::Lighting, m_affectedByLighting);
 		propertySet.addProperty(Properties::AlphaThreshold, m_baseObjectData.m_alphaThreshold);
+		propertySet.addProperty(Properties::HeightScale, m_baseObjectData.m_heightScale);
+		propertySet.addProperty(Properties::Lighting, m_affectedByLighting);
 		propertySet.addProperty(Properties::TextureTilingFactor, m_baseObjectData.m_textureTilingFactor);
 
 		// Add model
@@ -166,19 +169,17 @@ public:
 
 		// Add material root property set
 		auto &materials = propertySet.addPropertySet(Properties::Materials);
-		PropertySet *materialTypes[Model::NumOfModelMaterials];
+		PropertySet *materialTypes[MaterialType_NumOfTypes];
 		
 		// Declare individual material property sets
-		materialTypes[Model::ModelMat_diffuse] = new PropertySet(Properties::Diffuse);
-		materialTypes[Model::ModelMat_normal] = new PropertySet(Properties::Normal);
-		materialTypes[Model::ModelMat_emissive] = new PropertySet(Properties::Emissive);
-		materialTypes[Model::ModelMat_specular] = new PropertySet(Properties::Specular);
-		materialTypes[Model::ModelMat_gloss] = new PropertySet(Properties::Gloss);
-		materialTypes[Model::ModelMat_height] = new PropertySet(Properties::Height);
+		materialTypes[MaterialType_Diffuse] = new PropertySet(Properties::Diffuse);
+		materialTypes[MaterialType_Normal] = new PropertySet(Properties::Normal);
+		materialTypes[MaterialType_Emissive] = new PropertySet(Properties::Emissive);
+		materialTypes[MaterialType_Combined] = new PropertySet(Properties::RMHAO);
 
 		// Iterate over each material and add it only if it's not using the default texture
 		for(decltype(m_rendererData.m_numMaterials) i = 0; i < m_rendererData.m_numMaterials; i++)
-			for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+			for(int matType = 0; matType < MaterialType_NumOfTypes; matType++)
 				if(!m_rendererData.m_defaultMaterial[matType][i])
 				{
 					auto &materialEntry = materialTypes[matType]->addPropertySet(Properties::ArrayEntry);
@@ -187,7 +188,7 @@ public:
 				}
 
 		// Add individual material property sets and delete temporary values
-		for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+		for(int matType = 0; matType < MaterialType_NumOfTypes; matType++)
 		{
 			materials.addPropertySet(*materialTypes[matType]);
 			delete materialTypes[matType];
@@ -200,24 +201,24 @@ public:
 			auto &shaders = propertySet.addPropertySet(Properties::Shaders);
 
 			// Iterate over all shader types and add the ones that are present as properties
-			for(unsigned int i = 0; i < ShaderLoader::ShaderType::ShaderNumOfTypes; i++)
+			for(unsigned int i = 0; i < ShaderType_NumOfTypes; i++)
 				if(m_rendererData.m_shader->shaderPresent(i))
 				{
 					switch(i)
 					{
-					case ShaderLoader::ShaderArrayTypes::ArrayFragment:
+					case ShaderType_Fragment:
 						shaders.addProperty(Properties::FragmentShader, m_rendererData.m_shader->getShaderFilename(i));
 						break;
-					case ShaderLoader::ShaderArrayTypes::ArrayGeometry:
+					case ShaderType_Geometry:
 						shaders.addProperty(Properties::GeometryShader, m_rendererData.m_shader->getShaderFilename(i));
 						break;
-					case ShaderLoader::ShaderArrayTypes::ArrayVertex:
+					case ShaderType_Vertex:
 						shaders.addProperty(Properties::VertexShader, m_rendererData.m_shader->getShaderFilename(i));
 						break;
-					case ShaderLoader::ShaderArrayTypes::ArrayTessControl:
+					case ShaderType_TessControl:
 						shaders.addProperty(Properties::TessControlShader, m_rendererData.m_shader->getShaderFilename(i));
 						break;
-					case ShaderLoader::ShaderArrayTypes::ArrayTessEvaluation:
+					case ShaderType_TessEvaluation:
 						shaders.addProperty(Properties::TessEvaluationShader, m_rendererData.m_shader->getShaderFilename(i));
 						break;
 					}
@@ -228,7 +229,7 @@ public:
 	}
 
 	// Adds a material filename to a specific material type and index
-	inline void addMaterial(Model::ModelMaterialType p_matType, const std::string &p_fileName, const unsigned int p_materialIndex)
+	inline void addMaterial(MaterialType p_matType, const std::string &p_fileName, const unsigned int p_materialIndex)
 	{
 		if(!p_fileName.empty())
 		{
@@ -248,7 +249,14 @@ public:
 	inline void setLighting(const bool p_flag)					{ m_affectedByLighting = p_flag;						}
 	inline void setAlphaThreshold(const float p_threshold)		{ m_baseObjectData.m_alphaThreshold = p_threshold;		}
 	inline void setEmissiveThreshold(const float p_threshold)	{ m_baseObjectData.m_emissiveThreshold = p_threshold;	}
+	inline void setHeightScale(const float p_scale)				{ m_baseObjectData.m_heightScale = p_scale;				}
 	inline void setTextureTilingFactor(const float p_factor)	{ m_baseObjectData.m_textureTilingFactor = p_factor;	}
+	inline void setDefaultMaterial(const unsigned int p_materialType, const std::string &p_filename)
+	{
+		// Check if material type index is within bounds
+		if(p_materialType < MaterialType_NumOfTypes)
+			m_defaultMaterials[p_materialType] = p_filename;
+	}
 
 protected:
 	// Clears data that's not useful after loading (like material names, etc)
@@ -259,7 +267,7 @@ protected:
 
 	Model::MaterialArrays m_materialNames;
 
-	std::string m_defaultMaterials[Model::Model::NumOfModelMaterials];
+	std::string m_defaultMaterials[MaterialType_NumOfTypes];
 	
 	// If the object hasn't got a custom shader, the regular geometry shader in the renderer is used
 	bool m_customShader;

+ 83 - 81
Praxis3D/Source/ModelLoader.cpp

@@ -11,6 +11,9 @@
 
 #include "Loaders.h"
 
+// This initialization depends on the order of BufferType enum entries
+const int Model::m_numElements[ModelBuffer_NumAllTypes] = { 3, 3, 2, 3, 3, 0 };
+
 ErrorCode Model::loadToMemory()
 {
 	// If the model is not currently already being loaded in another thread
@@ -27,8 +30,7 @@ ErrorCode Model::loadToMemory()
 
 		// Assign flags for assimp loader
 		unsigned int assimpFlags = 0;
-		if(Config::modelVar().calcTangentSpace)
-			assimpFlags |= aiProcess_CalcTangentSpace;
+
 		if(Config::modelVar().joinIdenticalVertices)
 			assimpFlags |= aiProcess_JoinIdenticalVertices;
 		if(Config::modelVar().makeLeftHanded)
@@ -81,58 +83,6 @@ ErrorCode Model::loadToMemory()
 
 	return m_loadingToMemoryError;
 }
-ErrorCode Model::loadToVideoMemory()
-{
-	ErrorCode returnError = ErrorCode::Success;
-	
-	// Create and bind the Vertex Array Object
-	glGenVertexArrays(1, &m_handle);
-	glBindVertexArray(m_handle);
-
-	// Create the m_buffers
-	glGenBuffers(sizeof(m_buffers) / sizeof(m_buffers[0]), m_buffers);
-
-	// Upload indices
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[IndexBuffer]);
-	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_indices[0]) * m_numVertices, &m_indices[0], GL_STATIC_DRAW);
-
-	// Upload positions
-	glBindBuffer(GL_ARRAY_BUFFER, m_buffers[PositionBuffer]);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(m_positions[0]) * m_numVertices, &m_positions[0], GL_STATIC_DRAW);
-	glEnableVertexAttribArray(PositionBuffer);
-	glVertexAttribPointer(PositionBuffer, 3, GL_FLOAT, GL_FALSE, 0, 0);
-
-	// Upload normals
-	glBindBuffer(GL_ARRAY_BUFFER, m_buffers[NormalBuffer]);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(m_normals[0]) * m_numVertices, &m_normals[0], GL_STATIC_DRAW);
-	glEnableVertexAttribArray(NormalBuffer);
-	glVertexAttribPointer(NormalBuffer, 3, GL_FLOAT, GL_FALSE, 0, 0);
-
-	// Upload texture coordinates
-	glBindBuffer(GL_ARRAY_BUFFER, m_buffers[TexCoordBuffer]);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(m_texCoords[0]) * m_numVertices, &m_texCoords[0], GL_STATIC_DRAW);
-	glEnableVertexAttribArray(TexCoordBuffer);
-	glVertexAttribPointer(TexCoordBuffer, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
-	// Upload tangents
-	glBindBuffer(GL_ARRAY_BUFFER, m_buffers[TangentsBuffer]);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(m_tangents[0]) * m_numVertices, &m_tangents[0], GL_STATIC_DRAW);
-	glEnableVertexAttribArray(TangentsBuffer);
-	glVertexAttribPointer(TangentsBuffer, 3, GL_FLOAT, GL_FALSE, 0, 0);
-
-	// Upload bitangents
-	glBindBuffer(GL_ARRAY_BUFFER, m_buffers[BitangentsBuffer]);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(m_bitangents[0]) * m_numVertices, &m_bitangents[0], GL_STATIC_DRAW);
-	glEnableVertexAttribArray(BitangentsBuffer);
-	glVertexAttribPointer(BitangentsBuffer, 3, GL_FLOAT, GL_FALSE, 0, 0);
-
-	// Make sure the VAO is not changed from the outside
-	glBindVertexArray(0);
-
-	setLoadedToVideoMemory(true);
-
-	return returnError;
-}
 ErrorCode Model::unloadMemory()
 {
 	ErrorCode returnError = ErrorCode::Success;
@@ -145,19 +95,19 @@ ErrorCode Model::unloadMemory()
 	m_bitangents.clear();
 	m_meshPool.clear();
 
-	for(int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+	for(int matType = 0; matType < MaterialType_NumOfTypes; matType++)
 		m_materials.m_materials[matType].clear();
 
 	return returnError;
 }
-ErrorCode Model::unloadVideoMemory()
+/*ErrorCode Model::unloadVideoMemory()
 {
 	ErrorCode returnError = ErrorCode::Success;
 
 	glDeleteBuffers(NumBufferTypes, m_buffers);
 
 	return returnError;
-}
+}*/
 
 void Model::loadFromFile()
 {
@@ -201,62 +151,111 @@ ErrorCode Model::loadFromScene(const aiScene &p_assimpScene)
 	m_bitangents.resize(m_numVertices);
 	m_indices.resize(numIndicesTotal);
 
+	// Set buffer sizes
+	m_bufferSize[ModelBuffer_Position]		= sizeof(m_positions[0])	* m_numVertices;
+	m_bufferSize[ModelBuffer_Normal]		= sizeof(m_normals[0])		* m_numVertices;
+	m_bufferSize[ModelBuffer_TexCoord]		= sizeof(m_texCoords[0])	* m_numVertices;
+	m_bufferSize[ModelBuffer_Tangents]		= sizeof(m_tangents[0])		* m_numVertices;
+	m_bufferSize[ModelBuffer_Bitangents]	= sizeof(m_bitangents[0])	* m_numVertices;
+	m_bufferSize[ModelBuffer_Index]			= sizeof(m_indices[0])		* m_numVertices;
+
 	// Deal with each mesh
 	returnError = loadMeshes(p_assimpScene.mMeshes, p_assimpScene.mNumMeshes);
 	
 	// Load material file names
 	if(returnError == ErrorCode::Success)
 		returnError = loadMaterials(p_assimpScene.mMaterials, p_assimpScene.mNumMaterials);
-	
+
 	return returnError;
 }
 ErrorCode Model::loadMeshes(aiMesh **p_assimpMeshes, size_t p_numMeshes)
 {
 	ErrorCode returnError = ErrorCode::Success;
 
-	for(unsigned int meshIndex = 0, verticeIndex = 0, indicesIndex = 0; meshIndex < p_numMeshes; meshIndex++)
+	for(size_t meshIndex = 0, verticeIndex = 0, indicesIndex = 0; meshIndex < p_numMeshes; meshIndex++)
 	{
 		// Make sure that the texture coordinates array exist (by checking if the first member of the array does)
 		bool textureCoordsExist = p_assimpMeshes[meshIndex]->mTextureCoords[0] ? true : false;
 
 		// Check if arrays exist (to not cause an error if they are absent)
-		bool normalsExist = p_assimpMeshes[meshIndex]->mNormals != nullptr;
-		bool tangentsExist = p_assimpMeshes[meshIndex]->mTangents != nullptr;
-		bool bitangentsExist = p_assimpMeshes[meshIndex]->mBitangents != nullptr;
+		//bool normalsExist = p_assimpMeshes[meshIndex]->mNormals != nullptr;
+		const bool tangentsExist = p_assimpMeshes[meshIndex]->mTangents != nullptr;
+		const bool bitangentsExist = p_assimpMeshes[meshIndex]->mBitangents != nullptr;
+		for(decltype(m_positions.size()) i = 0, size = m_positions.size(); i < size; i++)
+		{
 
+		}
 		// Put the mesh data from assimp to memory
-		for(unsigned int i = 0; i < p_assimpMeshes[meshIndex]->mNumVertices; i++, verticeIndex++)
+		for(decltype(p_assimpMeshes[meshIndex]->mNumVertices) i = 0, tangentIndex = 2, size = p_assimpMeshes[meshIndex]->mNumVertices; i < size; i++, verticeIndex++)
 		{
 			m_positions[verticeIndex].x = p_assimpMeshes[meshIndex]->mVertices[i].x;
 			m_positions[verticeIndex].y = p_assimpMeshes[meshIndex]->mVertices[i].y;
 			m_positions[verticeIndex].z = p_assimpMeshes[meshIndex]->mVertices[i].z;
 
-			if(normalsExist)
+			m_normals[verticeIndex].x = p_assimpMeshes[meshIndex]->mNormals[i].x;
+			m_normals[verticeIndex].y = p_assimpMeshes[meshIndex]->mNormals[i].y;
+			m_normals[verticeIndex].z = p_assimpMeshes[meshIndex]->mNormals[i].z;
+
+			if(textureCoordsExist)
 			{
-				m_normals[verticeIndex].x = p_assimpMeshes[meshIndex]->mNormals[i].x;
-				m_normals[verticeIndex].y = p_assimpMeshes[meshIndex]->mNormals[i].y;
-				m_normals[verticeIndex].z = p_assimpMeshes[meshIndex]->mNormals[i].z;
+				m_texCoords[verticeIndex].x = p_assimpMeshes[meshIndex]->mTextureCoords[0][i].x;
+				m_texCoords[verticeIndex].y = p_assimpMeshes[meshIndex]->mTextureCoords[0][i].y;
 			}
-
-			if(tangentsExist)
+			
+			if(!tangentsExist || !bitangentsExist)
+			{
+				if(verticeIndex == tangentIndex)
+				{
+					// Get vertex positions of the polygon
+					const Math::Vec3f &v0 = m_positions[verticeIndex - 2];
+					const Math::Vec3f &v1 = m_positions[verticeIndex - 1];
+					const Math::Vec3f &v2 = m_positions[verticeIndex - 0];
+
+					// Get texture coordinates of the polygon
+					const Math::Vec2f &uv0 = m_texCoords[verticeIndex - 2];
+					const Math::Vec2f &uv1 = m_texCoords[verticeIndex - 1];
+					const Math::Vec2f &uv2 = m_texCoords[verticeIndex - 0];
+
+					// Get normals of the polygon
+					const Math::Vec3f &n0 = m_normals[verticeIndex - 2];
+					const Math::Vec3f &n1 = m_normals[verticeIndex - 1];
+					const Math::Vec3f &n2 = m_normals[verticeIndex - 0];
+
+					// Calculate position difference
+					Math::Vec3f deltaPos1 = v1 - v0;
+					Math::Vec3f deltaPos2 = v2 - v0;
+
+					// Calculate texture coordinate difference
+					Math::Vec2f deltaUV1 = uv1 - uv0;
+					Math::Vec2f deltaUV2 = uv2 - uv0;
+
+					// Calculate tangent and bitangent
+					float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
+					Math::Vec3f tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
+					Math::Vec3f bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r;
+
+					// Orthogonalize using Gram–Schmidt process, to make tangents and bitangents smooth based on normal
+					m_tangents[verticeIndex - 2] = Math::normalize(tangent - n0 * Math::dot(n0, tangent));
+					m_tangents[verticeIndex - 1] = Math::normalize(tangent - n1 * Math::dot(n1, tangent));
+					m_tangents[verticeIndex - 0] = Math::normalize(tangent - n2 * Math::dot(n2, tangent));
+
+					m_bitangents[verticeIndex - 2] = Math::normalize(bitangent - n0 * Math::dot(n0, bitangent));
+					m_bitangents[verticeIndex - 1] = Math::normalize(bitangent - n1 * Math::dot(n1, bitangent));
+					m_bitangents[verticeIndex - 0] = Math::normalize(bitangent - n2 * Math::dot(n2, bitangent));
+
+					tangentIndex += 3;
+				}
+			}
+			else
 			{
 				m_tangents[verticeIndex].x = p_assimpMeshes[meshIndex]->mTangents[i].x;
 				m_tangents[verticeIndex].y = p_assimpMeshes[meshIndex]->mTangents[i].y;
 				m_tangents[verticeIndex].z = p_assimpMeshes[meshIndex]->mTangents[i].z;
-			}
 
-			if(bitangentsExist)
-			{
 				m_bitangents[verticeIndex].x = p_assimpMeshes[meshIndex]->mBitangents[i].x;
 				m_bitangents[verticeIndex].y = p_assimpMeshes[meshIndex]->mBitangents[i].y;
 				m_bitangents[verticeIndex].z = p_assimpMeshes[meshIndex]->mBitangents[i].z;
 			}
-
-			if(textureCoordsExist)
-			{
-				m_texCoords[verticeIndex].x = p_assimpMeshes[meshIndex]->mTextureCoords[0][i].x;
-				m_texCoords[verticeIndex].y = p_assimpMeshes[meshIndex]->mTextureCoords[0][i].y;
-			}
 		}
 
 		// Put the m_indices data from assimp to memory
@@ -287,14 +286,16 @@ ErrorCode Model::loadMaterials(aiMaterial **p_assimpMaterials, size_t p_numMater
 	for(unsigned int index = 0, i = 0; i < m_materials.m_numMaterials; i++)
 	{
 		if(p_assimpMaterials[i]->GetTexture(aiTextureType_DIFFUSE, index, &materialPath) == aiReturn_SUCCESS)
-			m_materials.m_materials[ModelMat_diffuse][i].m_filename = materialPath.data;
+			m_materials.m_materials[MaterialType_Diffuse][i].m_filename = materialPath.data;
 
 		if(p_assimpMaterials[i]->GetTexture(aiTextureType_NORMALS, index, &materialPath) == aiReturn_SUCCESS)
-			m_materials.m_materials[ModelMat_normal][i].m_filename = materialPath.data;
+			m_materials.m_materials[MaterialType_Normal][i].m_filename = materialPath.data;
 
 		if(p_assimpMaterials[i]->GetTexture(aiTextureType_EMISSIVE, index, &materialPath) == aiReturn_SUCCESS)
-			m_materials.m_materials[ModelMat_emissive][i].m_filename = materialPath.data;
+			m_materials.m_materials[MaterialType_Emissive][i].m_filename = materialPath.data;
 
+		// Unused with the new shading model (PBS). Might be used in the future to combine textures into one (RMHAO)
+		/*
 		if(p_assimpMaterials[i]->GetTexture(aiTextureType_SPECULAR, index, &materialPath) == aiReturn_SUCCESS)
 			m_materials.m_materials[ModelMat_specular][i].m_filename = materialPath.data;
 
@@ -304,6 +305,7 @@ ErrorCode Model::loadMaterials(aiMaterial **p_assimpMaterials, size_t p_numMater
 		if((p_assimpMaterials[i]->GetTexture(aiTextureType_HEIGHT, index, &materialPath) == aiReturn_SUCCESS) ||
 		   (p_assimpMaterials[i]->GetTexture(aiTextureType_DISPLACEMENT, index, &materialPath) == aiReturn_SUCCESS))
 			m_materials.m_materials[ModelMat_height][i].m_filename = materialPath.data;
+			*/
 	}
 
 	return returnError;

+ 44 - 142
Praxis3D/Source/ModelLoader.h

@@ -4,6 +4,7 @@
 #include <bitset>
 #include <GL\glew.h>
 
+#include "CommonDefinitions.h"
 #include "ErrorHandlerLocator.h"
 #include "LoaderBase.h"
 #include "Math.h"
@@ -21,26 +22,6 @@ class Model : public LoaderBase<ModelLoader, Model>::UniqueObject
 public:
 	// Note: caution with modifying. Correlates with enum in Renderer class, for convenience
 	// Note: the order is sensitive
-	enum ModelMaterialType : unsigned int
-	{
-		ModelMat_diffuse = 0,
-		ModelMat_normal,
-		ModelMat_emissive,
-		ModelMat_specular,
-		ModelMat_gloss,
-		ModelMat_height,
-		NumOfModelMaterials
-	};
-	enum BufferType : unsigned int
-	{
-		PositionBuffer = 0,
-		NormalBuffer,
-		TexCoordBuffer,
-		TangentsBuffer,
-		BitangentsBuffer,
-		IndexBuffer,
-		NumBufferTypes
-	};
 
 	struct Mesh
 	{
@@ -84,7 +65,7 @@ public:
 		// Resizes all the vectors and assigns a new number of materials
 		void resize(std::vector<Material>::size_type p_size)
 		{
-			for(unsigned int i = 0; i < NumOfModelMaterials; i++)
+			for(unsigned int i = 0; i < MaterialType_NumOfTypes; i++)
 				m_materials[i].resize(p_size);
 			m_numMaterials = p_size;
 		}
@@ -92,38 +73,32 @@ public:
 		// Frees memory of the vectors by swapping them with empty ones
 		void clear()
 		{
-			for(unsigned int i = 0; i < NumOfModelMaterials; i++)
+			for(unsigned int i = 0; i < MaterialType_NumOfTypes; i++)
 				std::vector<Material>().swap(m_materials[i]);
 			m_numMaterials = 0;
 		}
 
-		std::vector<Material> m_materials[NumOfModelMaterials];
+		std::vector<Material> m_materials[MaterialType_NumOfTypes];
 		std::vector<Material>::size_type m_numMaterials;
 	};
 
-
 	Model(LoaderBase<ModelLoader, Model> *p_loaderBase, std::string p_filename, size_t p_uniqueID, unsigned int p_handle) : UniqueObject(p_loaderBase, p_uniqueID, p_filename), m_handle(p_handle)
 	{
 		m_isBeingLoaded = false;
 
+		m_currentNumMeshes = 0;
 		m_numVertices = 0;
 		m_numMeshes = 0;
-		//m_numMaterials = 0;
 		m_handle = 0;
-		m_currentNumMeshes = 0;
-		
-		for(int i = 0; i < NumBufferTypes; i++)
+
+		for(int i = 0; i < ModelBuffer_NumAllTypes; i++)
 			m_buffers[i] = 0;
 	}
 
 	// Loads data from HDD to RAM and restructures it to be used to fill buffers later
 	ErrorCode loadToMemory();
-	// Loads data from RAM to buffer and uploads them to VRAM
-	ErrorCode loadToVideoMemory();
 	// Deletes data stored in RAM. Does not delete buffers that are loaded on GPU VRAM.
 	ErrorCode unloadMemory();
-	// Deletes buffers from GPU VRAM.
-	ErrorCode unloadVideoMemory();
 
 	// Loads the model data from file (using internal filename)
 	void loadFromFile();
@@ -137,10 +112,39 @@ public:
 	ErrorCode loadTextures(aiTexture **p_assimpTextures, size_t p_numTextures);
 
 	inline MaterialArrays &getMaterialArrays() { return m_materials; }
+	// Returns an array of pointers to buffer data
+	/*const inline void **getData()
+	{
+		void **data = nullptr;
+		//const void *data[ModelBuffer_Index + 1];
+
+		data[ModelBuffer_Position]		= &m_positions[0];
+		data[ModelBuffer_Normal]		= &m_normals[0];
+		data[ModelBuffer_TexCoord]		= &m_texCoords[0];
+		data[ModelBuffer_Tangents]		= &m_tangents[0];
+		data[ModelBuffer_Bitangents]	= &m_bitangents[0];
+		data[ModelBuffer_Index]			= &m_indices[0];
+
+		return (const void**)data;
+	}*/
+	const inline void **getData()
+	{
+		const void **data = new const void*[ModelBuffer_Index + 1];
+
+		data[ModelBuffer_Position]		= &m_positions[0];
+		data[ModelBuffer_Normal]		= &m_normals[0];
+		data[ModelBuffer_TexCoord]		= &m_texCoords[0];
+		data[ModelBuffer_Tangents]		= &m_tangents[0];
+		data[ModelBuffer_Bitangents]	= &m_bitangents[0];
+		data[ModelBuffer_Index]			= &m_indices[0];
+
+		return data;
+	}
 
 	// m_handle is a VAO handle
 	unsigned int m_handle;
-	unsigned int m_buffers[NumBufferTypes];
+	unsigned int m_buffers[ModelBuffer_NumAllTypes];
+	int64_t m_bufferSize[ModelBuffer_NumAllTypes];
 
 	std::vector<Mesh> m_meshPool;
 	
@@ -150,7 +154,7 @@ public:
 	std::vector<Math::Vec2f> m_texCoords;
 	std::vector<Math::Vec3f> m_tangents;
 	std::vector<Math::Vec3f> m_bitangents;
-
+	
 	MaterialArrays m_materials;
 
 	size_t	m_numVertices,
@@ -160,6 +164,8 @@ public:
 	size_t	m_currentNumMeshes;
 
 	tbb::atomic<bool> m_isBeingLoaded;
+
+	const static int m_numElements[ModelBuffer_NumAllTypes];
 };
 
 // Model Loader, CRTP inheritance from Loader Base. Designed to be used for loading models,
@@ -220,102 +226,12 @@ public:
 	// and hiding internal data from outside classes. Private constructor.
 	class ModelHandle
 	{
+		friend class CommandBuffer;
 		friend class ModelLoader;
+		friend class RendererFrontend;
 	public:
 		~ModelHandle() { m_model->decRefCounter(); }
-
-		// Bind VAO for rendering if it is loaded
-		// Load the model buffers to GPU memory instead if it's not loaded
-		void bind()
-		{
-			// Declare the handle to bind at the start here, and bind it at the end of the function,
-			// so there is only one path to bind function and the branch can be predicted easier on CPU
-			decltype(m_model->m_handle) handle = m_model->m_handle;
-			
-			// If the model buffers are loaded, just bind the VAO (by leaving the handle as it is).
-			// Otherwise load buffers to GPU. This way, the model loading is hidden away,
-			// so graphics system doesn't have to deal with it. The thread that calls bind
-			// on a model is guaranteed to be rendering thread, so it is safe to load it.
-			if(!m_model->loadedToVideoMemory())
-			{
-				if(m_model->loadedToMemory())
-				{
-					ErrorCode error = m_model->loadToVideoMemory();
-
-					// If loading to video memory was successful, set mesh number, so that object could get rendered.
-					// Otherwise log an error
-					if(error == ErrorCode::Success)
-					{
-						// Reassign the handle, since it must have changed when loading to video memory
-						handle = m_model->m_handle;
-						m_model->m_currentNumMeshes = m_model->m_numMeshes;
-					}
-					else
-						ErrHandlerLoc::get().log(error, ErrorSource::Source_ModelLoader, m_model->getFilename());
-
-					// Set loaded to video memory flag to true even if loading failed.
-					// This way, the failed loading attempt is not repeated every frame.
-					// (And since loaded to memory flag is already true, it is not the cause,
-					// and it will not "fix" itself)
-					// EDIT: it is now set inside loadToVideoMemory() function
-					//m_model->setLoadedToVideoMemory(true);
-					m_model->m_currentNumMeshes = m_model->m_numMeshes;
-				}
-				else
-				{
-					// Make VAO into zero in case it's not ready to be rendered yet
-					handle = 0;
-				}
-
-			}
-
-			// Bind VAO
-			glBindVertexArray(handle);
-		}
-
-		// Perform a complete load, if not loaded already (from HDD to memory to video memory)
-		// WARNING: should probably only be called from rendering thread, since this code deals with graphics API
-		ErrorCode preload()
-		{
-			ErrorCode returnError = ErrorCode::Success;
-
-			// If it's not loaded to video memory already
-			if(!m_model->loadedToVideoMemory())
-			{
-				// If it's loaded to memory
-				if(m_model->loadedToMemory())
-				{
-					// Load to video memory
-					returnError = m_model->loadToVideoMemory();
-					m_model->setLoadedToVideoMemory(true);
-
-					// If loading to video memory was successful, set mesh number, so that object could get rendered
-					if(returnError == ErrorCode::Success)
-						m_model->m_currentNumMeshes = m_model->m_numMeshes;
-				}
-				// If it's not loaded to memory
-				else
-				{
-					// Load to memory
-					returnError = m_model->loadToMemory();
-
-					// If loading to memory was successful
-					if(returnError == ErrorCode::Success)
-					{
-						m_model->setLoadedToMemory(true);
-						returnError = m_model->loadToVideoMemory();
-						m_model->setLoadedToVideoMemory(true);
-
-						// If loading to video memory was successful, set mesh number, so that object could get rendered
-						if(returnError == ErrorCode::Success)
-							m_model->m_currentNumMeshes = m_model->m_numMeshes;
-					}
-				}
-			}
-
-			return returnError;
-		}
-
+		
 		// Loads data from HDD to RAM and restructures it to be used to fill buffers later
 		ErrorCode loadToMemory(bool p_setLoadedToMemoryFlag = true)
 		{
@@ -334,21 +250,7 @@ public:
 
 			return returnError;
 		}
-
-		// Loads data from RAM to buffer and uploads them to VRAM
-		// WARNING: should probably only be called from rendering thread, since this code deals with graphics API
-		ErrorCode loadToVideoMemory()
-		{
-			ErrorCode returnError = ErrorCode::Success;
-
-			// If it's not loaded to video memory already, and has been loaded to memory, call load
-			if(!m_model->loadedToVideoMemory())
-				if(m_model->loadedToMemory())
-					returnError = m_model->loadToVideoMemory();
-
-			return returnError;
-		}
-
+		
 		// Assignment operator
 		ModelHandle &operator=(const ModelHandle &p_modelHandle)
 		{

+ 1 - 1
Praxis3D/Source/ObjectPool.h

@@ -152,7 +152,7 @@ public:
 	}
 
 	// Takes only the constructor arguments and initializes the template object by calling the constructor
-	// internally. This way, it eliminates the need for temporary variables; returns an ErrorCode of pool is full
+	// internally. This way, it eliminates the need for temporary variables; returns an ErrorCode if pool is full
 	template<class... T_Args>
 	inline ErrorCode add(T_Args&&... p_args)
 	{

+ 43 - 0
Praxis3D/Source/ReflectionPass.h

@@ -0,0 +1,43 @@
+#pragma once
+
+#include "RenderPassBase.h"
+
+class ReflectionPass : public RenderPass
+{
+public:
+	ReflectionPass(RendererFrontend &p_renderer) : RenderPass(p_renderer) { }
+
+	ErrorCode init()
+	{
+		ErrorCode returnError;
+
+		m_name = "Reflection Rendering Pass";
+
+		// Create a property-set used to load reflection shader
+		PropertySet reflectionShaderProperties(Properties::Shaders);
+		reflectionShaderProperties.addProperty(Properties::VertexShader, Config::rendererVar().reflection_pass_vert_shader);
+		reflectionShaderProperties.addProperty(Properties::FragmentShader, Config::rendererVar().reflection_pass_frag_shader);
+
+		// Create shaders
+		m_shaderReflectionPass = Loaders::shader().load(reflectionShaderProperties);
+
+		// Load shaders to memory
+		m_shaderReflectionPass->loadToMemory();
+
+		if(returnError == ErrorCode::Success)
+		{
+			// Queue the shaders to be loaded to GPU
+			m_renderer.queueForLoading(*m_shaderReflectionPass);
+		}
+
+		return returnError;
+	}
+
+	void update(const SceneObjects &p_sceneObjects, const float p_deltaTime)
+	{
+
+	}
+
+private:
+	ShaderLoader::ShaderProgram	*m_shaderReflectionPass;
+};

+ 29 - 0
Praxis3D/Source/RenderPassBase.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include "CommandBuffer.h"
+#include "Config.h"
+#include "RendererFrontend.h"
+
+class RenderPass
+{
+public:
+	RenderPass(RendererFrontend &p_renderer) : m_renderer(p_renderer) { }
+
+	virtual ErrorCode init() = 0;
+
+	virtual void update(const SceneObjects &p_sceneObjects, const float p_deltaTime) = 0;
+
+	inline CommandBuffer::Commands &getCommands() { return m_commandBuffer.getCommands(); }
+
+	inline void setID(unsigned int p_ID) { m_ID = p_ID; }
+
+	inline const std::string &getName() const { return m_name; }
+	inline unsigned int getID() const { return m_ID; }
+
+protected:
+	unsigned int m_ID;
+	std::string m_name;
+
+	RendererFrontend &m_renderer;
+	CommandBuffer m_commandBuffer;
+};

+ 4 - 4
Praxis3D/Source/RenderTask.cpp

@@ -1,10 +1,11 @@
 
 #include <iostream>
 
-#include "RenderTask.h"
+#include "RendererFrontend.h"
 #include "RendererScene.h"
+#include "RenderTask.h"
 
-RenderTask::RenderTask(RendererScene *p_rendererScene, Renderer *p_renderer)
+RenderTask::RenderTask(RendererScene *p_rendererScene, RendererFrontend &p_renderer)
 	: SystemTask(p_rendererScene), m_rendererScene(p_rendererScene), m_renderer(p_renderer)
 {
 
@@ -18,6 +19,5 @@ RenderTask::~RenderTask()
 void RenderTask::update(const float p_deltaTime)
 {
 	m_rendererScene->update(p_deltaTime);
-
-	m_renderer->renderFrame(m_rendererScene->getSceneObjects(), p_deltaTime);
+	m_renderer.renderFrame(m_rendererScene->getSceneObjects(), p_deltaTime);
 }

+ 4 - 3
Praxis3D/Source/RenderTask.h

@@ -1,15 +1,16 @@
 #pragma once
 
-#include "Renderer.h"
+//#include "RendererFrontend.h"
 #include "System.h"
 
 class RendererScene;
+class RendererFrontend;
 
 class RenderTask : public SystemTask
 {
 	friend class RendererScene;
 public:
-	RenderTask(RendererScene *p_rendererScenem, Renderer *p_renderer);
+	RenderTask(RendererScene *p_rendererScenem, RendererFrontend &p_renderer);
 	~RenderTask();
 
 	Systems::TypeID getSystemType() { return Systems::Graphics; }
@@ -19,7 +20,7 @@ public:
 	bool isPrimaryThreadOnly() { return true; }
 
 protected:
-	Renderer *m_renderer;
+	RendererFrontend &m_renderer;
 	RendererScene *m_rendererScene;
 };
 

+ 23 - 14
Praxis3D/Source/Renderer.h

@@ -5,6 +5,7 @@
 #include "CameraGraphicsObject.h"
 #include "ClockLocator.h"
 #include "ErrorCodes.h"
+#include "GeometryBuffer.h"
 #include "GraphicsDataSets.h"
 #include "Math.h"
 #include "ModelLoader.h"
@@ -30,15 +31,19 @@ protected:
 	// Note: caution with modifying. Correlates with enum in Model class, for convenience
 	enum TextureTypes : unsigned int
 	{
-		DiffuseTexture = Model::ModelMat_diffuse,
-		NormalTexture = Model::ModelMat_normal,
-		EmissiveTexture = Model::ModelMat_emissive,
-		SpecularTexture = Model::ModelMat_specular,
-		GlossMapTexture = Model::ModelMat_gloss,
-		HeightMapTexture,
+		DiffuseTexture	= MaterialType_Diffuse,
+		NormalTexture	= MaterialType_Normal,
+		EmissiveTexture = MaterialType_Emissive,
+		CombinedTexture = MaterialType_Combined,
 		NumTextureTypes,
 	};
 
+	enum CubemapTypes : unsigned int
+	{
+		StaticEnvMap = GeometryBuffer::GBufferTextureType::GBufferNumTextures,
+		DynamicEnvMap
+	};
+
 	// Recalculates the projection matrix
 	void updateProjectionMatrix()
 	{
@@ -72,6 +77,7 @@ public:
 	const inline float getElapsedTime()					const { return ClockLocator::get().getElapsedSecondsF();				}
 	const inline float getAlphaThreshold()				const { return m_renderer->m_currentObjectData->m_alphaThreshold;		}
 	const inline float getEmissiveThreshold()			const { return m_renderer->m_currentObjectData->m_emissiveThreshold;	}
+	const inline float getHeightScale()					const { return m_renderer->m_currentObjectData->m_heightScale;			}
 	const inline float getTextureTilingFactor()			const { return m_renderer->m_currentObjectData->m_textureTilingFactor;	}
 
 	const virtual Math::Vec3f &getDirLightColor()		const { return m_emptyVec; }
@@ -89,18 +95,21 @@ public:
 	const virtual Math::Vec3f getFogColor()				const { return m_emptyVec; }
 	const virtual float getFogDensity()					const { return 0.0f; }
 
-	const virtual unsigned int getBlurBufferPos()		const { return 0; }
-	const virtual unsigned int getDiffuseBufferPos()	const { return 0; }
-	const virtual unsigned int getEmissiveBufferPos()	const { return 0; }
-	const virtual unsigned int getNormalBufferPos()		const { return 0; }
-	const virtual unsigned int getPositionBufferPos()	const { return 0; }
+	const unsigned int getBlurMapPosition()				const { return GeometryBuffer::GBufferTextureType::GBufferBlur;			 }
+	const unsigned int getDiffuseMapPosition()			const { return GeometryBuffer::GBufferTextureType::GBufferDiffuse;		 }
+	const unsigned int getEmissiveMapPosition()			const { return GeometryBuffer::GBufferTextureType::GBufferEmissive;		 }
+	const unsigned int getMatPropertiesMapPosition()	const { return GeometryBuffer::GBufferTextureType::GBufferMatProperties; }
+	const unsigned int getNormalMapPosition()			const { return GeometryBuffer::GBufferTextureType::GBufferNormal;		 }
+	const unsigned int getPositionMapPosition()			const { return GeometryBuffer::GBufferTextureType::GBufferPosition;		 }
+	const unsigned int getFinalMapPosition()			const { return GeometryBuffer::GBufferTextureType::GBufferFinal;		 }
 
 	const inline unsigned int getDiffuseTexturePos()	const { return Renderer::TextureTypes::DiffuseTexture;		}
 	const inline unsigned int getEmissiveTexturePos()	const { return Renderer::TextureTypes::EmissiveTexture;		}
-	const inline unsigned int getHeightTexturePos()		const { return Renderer::TextureTypes::HeightMapTexture;	}
 	const inline unsigned int getNormalTexturePos()		const { return Renderer::TextureTypes::NormalTexture;		}
-	const inline unsigned int getSpecularTexturePos()	const { return Renderer::TextureTypes::SpecularTexture;		}
-	const inline unsigned int getGlossTexturePos()		const { return Renderer::TextureTypes::GlossMapTexture;		}
+	const inline unsigned int getCombinedTexturePos()	const { return Renderer::TextureTypes::CombinedTexture;		}
+
+	const inline unsigned int getDynamicEnvMapPos()	const { return Renderer::CubemapTypes::DynamicEnvMap;	}
+	const inline unsigned int getStaticEnvMapPos()	const { return Renderer::CubemapTypes::StaticEnvMap;	}
 
 	const virtual Math::Mat4f getTestMat()	const { return m_emptyMatrix;	}
 	const virtual Math::Vec4f getTestVec()	const { return Math::Vec4f();	}

+ 135 - 2
Praxis3D/Source/RendererBackend.cpp

@@ -1,6 +1,139 @@
 #include "RendererBackend.h"
 
-ErrorCode RendererBackend::init()
+RendererBackend::SingleTriangle RendererBackend::m_fullscreenTriangle;
+
+RendererBackend::RendererBackend()
+{
+	m_gbuffer = nullptr;
+}
+
+RendererBackend::~RendererBackend()
 {
-	return ErrorCode::Success;
 }
+
+ErrorCode RendererBackend::init(const UniformFrameData &p_frameData)
+{
+	ErrorCode returnCode = ErrorCode::Success;
+
+	// Initialize gbuffer (and also pass the screen size to be used as the buffer size)
+	m_gbuffer = new GeometryBuffer((unsigned int)p_frameData.m_screenSize.x, (unsigned int)p_frameData.m_screenSize.y);
+
+	// Check if the gbuffer initialization was successful
+	if(ErrHandlerLoc::get().ifSuccessful(m_gbuffer->init(), returnCode))
+	{
+		// Load fullscreen triangle (used to render post-processing effects)
+		m_fullscreenTriangle.load();
+
+		// Enable / disable face culling
+		if(Config::rendererVar().face_culling)
+			glEnable(GL_CULL_FACE);
+		else
+			glDisable(GL_CULL_FACE);
+
+		// Enable / disable depth test
+		if(Config::rendererVar().depth_test)
+			glEnable(GL_DEPTH_TEST);
+		else
+			glDisable(GL_DEPTH_TEST);
+
+		glDepthFunc(GL_LESS);
+
+		// Set face culling mode
+		glCullFace(Config::rendererVar().face_culling_mode);
+
+		// Set depth test function
+		glDepthFunc(Config::rendererVar().depth_test_func);
+	}
+	return returnCode;
+}
+
+void RendererBackend::processUpdate(const BufferUpdateCommands &p_updateCommands, const UniformFrameData &p_frameData)
+{
+	for(decltype(p_updateCommands.size()) i = 0, size = p_updateCommands.size(); i < size; i++)
+	{
+		processCommand(p_updateCommands[i], p_frameData);
+	}
+}
+
+void RendererBackend::processLoading(LoadCommands &p_loadCommands, const UniformFrameData &p_frameData)
+{
+	for(decltype(p_loadCommands.size()) i = 0, size = p_loadCommands.size(); i < size; i++)
+	{
+		processCommand(p_loadCommands[i], p_frameData);
+	}
+}
+
+void RendererBackend::processDrawing(const DrawCommands &p_drawCommands, const UniformFrameData &p_frameData)
+{
+	for(decltype(p_drawCommands.size()) i = 0, size = p_drawCommands.size(); i < size; i++)
+	{
+		// Get uniform data
+		const UniformObjectData &uniformObjectData = p_drawCommands[i].second.m_uniformObjectData;
+		//UniformData uniformData(p_drawCommands[i].second.m_uniformObjectData, p_frameData);
+
+		// Get various handles
+		const auto shaderHandle = p_drawCommands[i].second.m_shaderHandle;
+		const auto &uniformUpdater = p_drawCommands[i].second.m_uniformUpdater;
+
+		// Bind the shader
+		bindShader(shaderHandle);
+
+		// Update shader uniforms
+		textureUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+		frameUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+		modelUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+		meshUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+
+		// Bind VAO
+		bindVAO(p_drawCommands[i].second.m_modelHandle);
+
+		// Bind textures
+		glActiveTexture(GL_TEXTURE0 + MaterialType_Diffuse);
+		glBindTexture(GL_TEXTURE_2D, p_drawCommands[i].second.m_matDiffuse);
+
+		glActiveTexture(GL_TEXTURE0 + MaterialType_Normal);
+		glBindTexture(GL_TEXTURE_2D, p_drawCommands[i].second.m_matNormal);
+
+		glActiveTexture(GL_TEXTURE0 + MaterialType_Combined);
+		glBindTexture(GL_TEXTURE_2D, p_drawCommands[i].second.m_matCombined);
+
+		glActiveTexture(GL_TEXTURE0 + MaterialType_Emissive);
+		glBindTexture(GL_TEXTURE_2D, p_drawCommands[i].second.m_matEmissive);
+
+		// Draw the geometry
+		glDrawElementsBaseVertex(GL_TRIANGLES,
+								 p_drawCommands[i].second.m_numIndices,
+								 GL_UNSIGNED_INT,
+								 (void*)(sizeof(unsigned int) * p_drawCommands[i].second.m_baseIndex),
+								 p_drawCommands[i].second.m_baseVertex);
+	}
+}
+
+void RendererBackend::processDrawing(const ScreenSpaceDrawCommands &p_screenSpaceDrawCommands, const UniformFrameData & p_frameData)
+{
+	for(decltype(p_screenSpaceDrawCommands.size()) i = 0, size = p_screenSpaceDrawCommands.size(); i < size; i++)
+	{
+		// Get uniform data
+		const UniformObjectData &uniformObjectData = p_screenSpaceDrawCommands[i].second.m_uniformObjectData;
+
+		// Get various handles
+		const auto shaderHandle = p_screenSpaceDrawCommands[i].second.m_shaderHandle;
+		const auto &uniformUpdater = p_screenSpaceDrawCommands[i].second.m_uniformUpdater;
+
+		// Bind the shader
+		bindShader(shaderHandle);
+
+		// Update shader uniforms
+		textureUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+		frameUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+		modelUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+		meshUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+
+		// Bind VAO
+		m_fullscreenTriangle.bind();
+
+		// Draw the full-screen triangle
+		m_fullscreenTriangle.render();
+	}
+}
+

+ 839 - 144
Praxis3D/Source/RendererBackend.h

@@ -1,206 +1,901 @@
 #pragma once
+#pragma warning (disable : 4996)
 
 #include <stdint.h>
 
 #include "Config.h"
+#include "GeometryBuffer.h"
 #include "Loaders.h"
+#include "ShaderUniformUpdater.h"
+#include "UniformData.h"
 
-struct UniformRendererData
+class RendererBackend
 {
-	Math::Vec2i m_screenSize;
+public:
+	// An empty buffer used to render a single triangle that covers the whole screen
+	// (the vertices are calculated inside the shader, hence an empty buffer)
+	class SingleTriangle
+	{
+	public:
+		SingleTriangle() : m_vao(0), m_vbo(0) { }
+		~SingleTriangle()
+		{
+			glDeleteBuffers(1, &m_vbo);
+			glDeleteBuffers(1, &m_vao);
+		}
+
+		// Creates an empty buffer, assigns a VAO
+		inline void load()
+		{
+			glGenBuffers(1, &m_vbo);
+			glGenVertexArrays(1, &m_vao);
+			glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
+			glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_STATIC_DRAW);
+			glBindBuffer(GL_ARRAY_BUFFER, 0);
+		}
+		// Binds VAO and VBO
+		inline void bind() const
+		{
+			glBindVertexArray(m_vao);
+			glBindVertexBuffer(0, m_vbo, 0, 0);
+		}
+		// Issues a draw call
+		inline void render() const { glDrawArrays(GL_TRIANGLES, 0, 3); }
 
-	Math::Mat4f m_projMatrix,
-				m_viewProjMatrix;
-};
+	private:
+		GLuint	m_vao,
+				m_vbo;
+	};
 
-struct UniformObjectData
-{
-	UniformObjectData()
+	// Draw command holds all the neccessary data to draw a piece of geometry (a mesh)
+	struct DrawCommand
 	{
-		m_heightScale = 0.0f;
-		m_alphaThreshold = 0.0f;
-		m_emissiveThreshold = 0.0f;
-		m_textureTilingFactor = 1.0f;
-	}
+		DrawCommand(const ShaderUniformUpdater &p_uniformUpdater, 
+					const UniformObjectData &p_uniformObjectData, 
+					const unsigned int p_shaderHandle,
+					const unsigned int p_modelHandle,
+					const unsigned int p_numIndices,
+					const unsigned int p_baseVertex,
+					const unsigned int p_baseIndex,
+					const unsigned int p_matDiffuse,
+					const unsigned int p_matNormal,
+					const unsigned int p_matEmissive,
+					const unsigned int p_matCombined) :
+
+			m_uniformUpdater(p_uniformUpdater), 
+			m_uniformObjectData(p_uniformObjectData),
+			m_shaderHandle(p_shaderHandle),
+			m_modelHandle(p_modelHandle),
+			m_numIndices(p_numIndices),
+			m_baseVertex(p_baseVertex),
+			m_baseIndex(p_baseIndex),
+			m_matDiffuse(p_matDiffuse),
+			m_matNormal(p_matNormal),
+			m_matEmissive(p_matEmissive),
+			m_matCombined(p_matCombined) { }
 
-	Math::Mat4f m_modelMat,
-				m_modelViewProjMatrix;
+		const ShaderUniformUpdater &m_uniformUpdater;
+		const UniformObjectData m_uniformObjectData;
 
-	float	m_heightScale, 
-			m_alphaThreshold,
-			m_emissiveThreshold,
-			m_textureTilingFactor;
-};
+		const unsigned int m_shaderHandle;
+		const unsigned int m_modelHandle;
 
-struct UniformData
-{
-	UniformData(const UniformObjectData &p_objectData, const UniformRendererData &p_rendererData)
-		: m_objectData(p_objectData), m_rendererData(p_rendererData) { }
+		const unsigned int m_numIndices;
+		const unsigned int m_baseVertex;
+		const unsigned int m_baseIndex;
 
-	const UniformObjectData &m_objectData;
-	const UniformRendererData &m_rendererData;
-};
+		const unsigned int m_matDiffuse;
+		const unsigned int m_matNormal;
+		const unsigned int m_matEmissive;
+		const unsigned int m_matCombined;
+	};
 
-class RendererBackend
-{
-public:	
-	enum MaterialTypes : unsigned int
-	{
-		DiffuseMaterial,
-		NormalMaterial,
-		EmissiveMaterial,
-		CombinedMaterial,
-		NumMaterialTypes
+	// Screen-space draw command is used to render a full-screen triangle, intended for
+	// post-processing effects and off-screen rendering
+	struct ScreenSpaceDrawCommand
+	{
+		ScreenSpaceDrawCommand(const ShaderUniformUpdater &p_uniformUpdater,
+							   const UniformObjectData &p_uniformObjectData,
+							   const unsigned int p_shaderHandle) :
+			m_uniformUpdater(p_uniformUpdater),
+			m_uniformObjectData(p_uniformObjectData),
+			m_shaderHandle(p_shaderHandle) { }
+
+		const ShaderUniformUpdater &m_uniformUpdater;
+		const UniformObjectData m_uniformObjectData;
+
+		const unsigned int m_shaderHandle;
 	};
 
-	/*struct RendererMesh
+	// Used for binding textures and framebuffers for reading and writing
+	struct BindCommand
 	{
-		RendererMesh(const Model::Mesh &p_mesh) : m_mesh(p_mesh) { }
+		BindCommand(BindCommandType p_type,
+					const unsigned int p_bufferHandle,
+					const unsigned int p_bindPosition,
+					const bool p_bindForReading) :
+			m_type(p_type),
+			m_bufferHandle(p_bufferHandle),
+			m_bindPosition(p_bindPosition),
+			m_bindForReading(p_bindForReading) { }
+
+		const unsigned int m_bufferHandle;
+		const unsigned int m_bindPosition;	// used as glActiveTexture parameter
+		const bool m_bindForReading;		// true = bind for reading; false = bind for writing
+
+		const BindCommandType m_type;
+	};
 
-		const Model::Mesh &m_mesh;
+	// Used to upload data to a buffer that's on GPU, in a specified manner
+	struct BufferUpdateCommand
+	{
+		BufferUpdateCommand(const unsigned int p_bufferHandle,
+					  const int64_t p_offset,
+					  const int64_t p_size,
+					  const void *p_data = NULL,
+					  const BufferUpdateType p_updateType = BufferUpdate_Data,
+					  const BufferType p_bufferType = BufferType_Uniform) :
+			m_bufferHandle(p_bufferHandle),
+			m_offset(p_offset),
+			m_size(p_size),
+			m_data(p_data),
+			m_updateType(p_updateType),
+			m_bufferType(p_bufferType) { }
+
+		const BufferUpdateType m_updateType;
+		const BufferType m_bufferType;
+
+		const unsigned int m_bufferHandle;
+		const void *m_data;
+		const int64_t	m_offset,
+						m_size;
 	};
-	struct RendererModel
+
+	// Used for loading various objects (i.e. textures, models, shader, etc) to GPU
+	struct LoadCommand
 	{
-		RendererModel()
+		LoadCommand(unsigned int &p_handle,
+					const BufferType p_bufferType,
+					const BufferUsageHint p_bufferUsage,
+					const unsigned int p_bindingIndex,
+					const int64_t p_size,
+					const void *p_data) :
+			m_handle(p_handle),
+			m_objectType(LoadObject_Buffer),
+			m_objectData(p_bufferType, p_bufferUsage, p_bindingIndex, p_size, p_data) { }
+
+		LoadCommand(const std::string &p_name, 
+					unsigned int &p_handle,
+					unsigned int (&p_buffers)[ModelBuffer_NumAllTypes],
+					const int (&p_numElements)[ModelBuffer_NumAllTypes],
+					const int64_t(&p_size)[ModelBuffer_NumAllTypes],
+					const void **m_data) :
+			m_handle(p_handle),
+			m_objectType(LoadObject_Model),
+			m_objectData(p_name, p_buffers, p_numElements, p_size, m_data) { }
+
+		LoadCommand(const std::string(&p_names)[ShaderType_NumOfTypes],
+					unsigned int &p_handle,
+					ShaderUniformUpdater &p_uniformUpdater,
+					std::string(&p_source)[ShaderType_NumOfTypes],
+					ErrorMessage(&p_errorMessages)[ShaderType_NumOfTypes]) :
+			m_handle(p_handle),
+			m_objectType(LoadObject_Shader),
+			m_objectData(p_names, p_uniformUpdater, p_source, p_errorMessages) { }
+
+		LoadCommand(const std::string &p_name, 
+					unsigned int &p_handle,
+					const TextureFormat p_texFormat,
+					const int p_mipmapLevel,
+					const unsigned int p_textureWidth,
+					const unsigned int p_textureHeight,
+					const void *p_data) :
+			m_handle(p_handle),
+			m_objectType(LoadObject_Texture2D),
+			m_objectData(p_name, p_texFormat, p_mipmapLevel, p_textureWidth, p_textureHeight, p_data) { }
+
+		LoadCommand(unsigned int &p_handle,
+					const TextureFormat p_texFormat,
+					const int p_mipmapLevel,
+					const unsigned int p_textureWidth,
+					const unsigned int p_textureHeight,
+					const void **p_data) :
+			m_handle(p_handle),
+			m_objectType(LoadObject_TextureCube),
+			m_objectData(p_texFormat, p_mipmapLevel, p_textureWidth, p_textureHeight, p_data) { }
+
+
+		struct BufferLoadData
 		{
-			m_numMeshes = 0;
+			BufferLoadData(const BufferType p_bufferType,
+						   const BufferUsageHint p_bufferUsage,
+						   const unsigned int p_bindingIndex,
+						   const int64_t p_size,
+						   const void *p_data) :
+				m_bufferType(p_bufferType),
+				m_bufferUsage(p_bufferUsage),
+				m_bindingIndex(p_bindingIndex),
+				m_size(p_size),
+				m_data(p_data) { }
+
+			const BufferType m_bufferType;
+			const BufferUsageHint m_bufferUsage;
+			const unsigned int m_bindingIndex;
+			const int64_t m_size;
+			const void *m_data;
+		};
+		struct ModelLoadData
+		{
+			ModelLoadData(const std::string &p_name,
+						  unsigned int(&p_buffers)[ModelBuffer_NumAllTypes],
+						  const int(&p_numElements)[ModelBuffer_NumAllTypes],
+						  const int64_t(&p_size)[ModelBuffer_NumAllTypes],
+						  const void **m_data) :
+				m_name(p_name),
+				m_data(m_data),
+				m_buffers(p_buffers)
+			{
+				std::copy(std::begin(p_numElements), std::end(p_numElements), std::begin(m_numElements));
+				std::copy(std::begin(p_size), std::end(p_size), std::begin(m_size));
+			}
+
+			const std::string &m_name;
+			unsigned int (&m_buffers)[ModelBuffer_NumAllTypes];
+			int m_numElements[ModelBuffer_NumAllTypes];
+			int64_t m_size[ModelBuffer_NumAllTypes];
+			const void **m_data;
+		};
+		struct ShaderLoadData
+		{
+			ShaderLoadData(const std::string(&p_names)[ShaderType_NumOfTypes],
+						   ShaderUniformUpdater &p_uniformUpdater,
+						   std::string(&p_source)[ShaderType_NumOfTypes],
+						   ErrorMessage(&p_errorMessages)[ShaderType_NumOfTypes]):
+				m_names(p_names),
+				m_uniformUpdater(p_uniformUpdater),
+				m_errorMessages(p_errorMessages),
+				m_source(p_source) { }
+
+			ShaderUniformUpdater &m_uniformUpdater;
+			std::string(&m_source)[ShaderType_NumOfTypes];
+			ErrorMessage (&m_errorMessages)[ShaderType_NumOfTypes];
+			const std::string (&m_names)[ShaderType_NumOfTypes];
+		};
+		struct Texture2DLoadData
+		{
+			Texture2DLoadData(const std::string &p_name,
+							  const TextureFormat p_texFormat,
+							  const int p_mipmapLevel,
+							  const unsigned int p_textureWidth,
+							  const unsigned int p_textureHeight,
+							  const void *p_data) :
+				m_name(p_name),
+				m_texFormat(p_texFormat),
+				m_mipmapLevel(p_mipmapLevel),
+				m_textureWidth(p_textureWidth),
+				m_textureHeight(p_textureHeight),
+				m_data(p_data) { }
+
+			const std::string &m_name;
+			const TextureFormat m_texFormat;
+			const unsigned int m_textureWidth;
+			const unsigned int m_textureHeight;
+			const int m_mipmapLevel;
+			const void *m_data;
+		};
+		struct CubemapLoadData
+		{
+			CubemapLoadData(const TextureFormat p_texFormat,
+							const int p_mipmapLevel,
+							const unsigned int p_textureWidth,
+							const unsigned int p_textureHeight,
+							const void **p_data) :
+				m_texFormat(p_texFormat),
+				m_mipmapLevel(p_mipmapLevel),
+				m_textureWidth(p_textureWidth),
+				m_textureHeight(p_textureHeight),
+				m_data(p_data) { }
+
+			const TextureFormat m_texFormat;
+			const unsigned int m_textureWidth;
+			const unsigned int m_textureHeight;
+			const int m_mipmapLevel;
+			const void **m_data;
+		};
+
+		union ObjectData
+		{
+			ObjectData(const BufferType p_bufferType,
+					   const BufferUsageHint p_bufferUsage,
+					   const unsigned int p_bindingIndex,
+					   const int64_t p_size,
+					   const void *p_data) :
+				m_bufferData(p_bufferType, p_bufferUsage, p_bindingIndex, p_size, p_data) { }
+
+			ObjectData(const std::string &p_name, 
+					   unsigned int(&p_buffers)[ModelBuffer_NumAllTypes],
+					   const int(&p_numElements)[ModelBuffer_NumAllTypes],
+					   const int64_t(&p_size)[ModelBuffer_NumAllTypes],
+					   const void **m_data) :
+				m_modelData(p_name, p_buffers, p_numElements, p_size, m_data) { }
+
+			ObjectData(const std::string(&p_names)[ShaderType_NumOfTypes],
+					   ShaderUniformUpdater &p_uniformUpdater,
+					   std::string(&p_source)[ShaderType_NumOfTypes],
+					   ErrorMessage(&p_errorMessages)[ShaderType_NumOfTypes]) :
+				m_shaderData(p_names, p_uniformUpdater, p_source, p_errorMessages) { }
+
+			ObjectData(const std::string &p_name, 
+					   const TextureFormat p_texFormat,
+					   const int p_mipmapLevel,
+					   const unsigned int p_textureWidth,
+					   const unsigned int p_textureHeight,
+					   const void *p_data) :
+				m_tex2DData(p_name, p_texFormat, p_mipmapLevel, p_textureWidth, p_textureHeight, p_data) { }
+
+			ObjectData(const TextureFormat p_texFormat,
+					   const int p_mipmapLevel,
+					   const unsigned int p_textureWidth,
+					   const unsigned int p_textureHeight,
+					   const void **p_data) :
+				m_cubeMapData(p_texFormat, p_mipmapLevel, p_textureWidth, p_textureHeight, p_data) { }
+
+
+			BufferLoadData m_bufferData;
+			ModelLoadData m_modelData;
+			ShaderLoadData m_shaderData;
+			Texture2DLoadData m_tex2DData;
+			CubemapLoadData m_cubeMapData;
+		};
+
+		const LoadObjectType m_objectType;
+		ObjectData m_objectData;
+		unsigned int &m_handle;
+	};
+
+	// First element is a sort key, second element is an object to draw
+	typedef std::vector<std::pair<int64_t, DrawCommand>> DrawCommands;
+	typedef std::vector<std::pair<int64_t, ScreenSpaceDrawCommand>> ScreenSpaceDrawCommands;
+
+	typedef std::vector<LoadCommand> LoadCommands;
+	typedef std::vector<BufferUpdateCommand> BufferUpdateCommands;
+
+	RendererBackend();
+	~RendererBackend();
+
+	ErrorCode init(const UniformFrameData &p_frameData);
+	
+	void processUpdate(const BufferUpdateCommands &p_updateCommands, const UniformFrameData &p_frameData);
+	void processLoading(LoadCommands &p_loadCommands, const UniformFrameData &p_frameData);
+	void processDrawing(const DrawCommands &p_drawCommands, const UniformFrameData &p_frameData);
+	void processDrawing(const ScreenSpaceDrawCommands &p_screenSpaceDrawCommands, const UniformFrameData &p_frameData);
+
+	inline GeometryBuffer *getGeometryBuffer() { return m_gbuffer; }
+
+protected:
+	// Currently bound and last updated objects
+	struct CurrentState
+	{
+		CurrentState()
+		{
+			reset();
 		}
-		RendererModel(const GLuint p_VAO) : m_VAO(p_VAO)
+
+		inline void reset()
 		{
-			m_numMeshes = 0;
+			m_boundUniformBuffer = 0;
+			m_boundShader = 0;
+			m_boundVAO = 0;
+
+			m_lastTexUpdate = 0;
+			m_lastFrameUpdate = 0;
+			m_lastModelUpdate = 0;
+			m_lastMeshUpdate = 0;
 		}
 
-		GLuint m_VAO;
-		size_t m_numMeshes;
+		unsigned int m_boundUniformBuffer;
+		unsigned int m_boundShader;
+		unsigned int m_boundVAO;
+
+		unsigned int m_lastTexUpdate;
+		unsigned int m_lastFrameUpdate;
+		unsigned int m_lastModelUpdate;
+		unsigned int m_lastMeshUpdate;
 	};
-	struct RendererShader
+	
+	// Handle binding functions
+	inline void bindShader(const unsigned int p_shaderHandle)
 	{
-		RendererShader(const ShaderUniformUpdater &p_shaderUniform, const GLuint p_shaderHandle) : m_uniformUpdater(p_shaderUniform), m_shaderHandle(p_shaderHandle)
+		// Check if the shader is not already bound
+		if(p_shaderHandle != m_rendererState.m_boundShader)
 		{
-			m_numModels = 0;
+			// Bind the shader
+			glUseProgram(p_shaderHandle);
+			m_rendererState.m_boundShader = p_shaderHandle;
 		}
-
-		const GLuint m_shaderHandle;
-		const ShaderUniformUpdater &m_uniformUpdater;
-		size_t m_numModels;
-	};
-	struct RendererMaterial
+	}
+	inline void bindVAO(const unsigned int p_VAO)
 	{
-		RendererMaterial()
+		// Check if the VAO is not already bound
+		if(p_VAO != m_rendererState.m_boundVAO)
 		{
-			m_numMeshes = 0;
+			// Bind the VAO
+			glBindVertexArray(p_VAO);
+			m_rendererState.m_boundVAO = p_VAO;
 		}
+	}
+	inline void bindUniformBuffer(const unsigned int p_bufferHandle)
+	{
+		// Check if the uniform buffer is not already bound
+		if(p_bufferHandle != m_rendererState.m_boundUniformBuffer)
+		{
+			// Bind the uniform buffer
+			glBindBuffer(GL_UNIFORM_BUFFER, p_bufferHandle);
+			m_rendererState.m_boundUniformBuffer = p_bufferHandle;
+		}
+	}
 
-		GLuint m_materials[NumMaterialTypes];
-		size_t m_numMeshes;
-	};
-
-	struct Dataset_Mesh
+	// Uniform update functions
+	inline void textureUniformUpdate(const unsigned int p_shaderHandle, const ShaderUniformUpdater &p_uniformUpdater, const UniformObjectData &p_objectData, const UniformFrameData &p_frameData)
 	{
-		Dataset_Mesh() : m_mesh(nullptr) { }
+		// Check if the texture uniforms haven't been updated already
+		if(m_rendererState.m_lastTexUpdate != p_shaderHandle)
+		{
+			// Declare uniform data
+			UniformData uniformData(p_objectData, p_frameData);
 
-		const Model::Mesh *m_mesh;
-	};
-	struct Dataset_Model
+			// Update texture uniforms
+			p_uniformUpdater.updateTextureUniforms(uniformData);
+			m_rendererState.m_lastTexUpdate = p_shaderHandle;
+		}
+	}
+	inline void frameUniformUpdate(const unsigned int p_shaderHandle, const ShaderUniformUpdater &p_uniformUpdater,const UniformObjectData &p_objectData, const UniformFrameData &p_frameData)
 	{
-		Dataset_Model() : m_VAO(0) { }
-		Dataset_Model(unsigned int p_VAO) : m_VAO(p_VAO) { }
+		// Check if the frame uniforms haven't been updated already
+		//if(m_rendererState.m_lastFrameUpdate != p_shaderHandle)
+		{
+			bindShader(p_shaderHandle);
 
-		unsigned int m_VAO;
+			// Declare uniform data
+			UniformData uniformData(p_objectData, p_frameData);
 
-		std::vector<Dataset_Mesh> m_meshes;
-	};
-	struct Dataset_Shader
+			// Update frame uniforms
+			p_uniformUpdater.updateFrame(uniformData);
+			m_rendererState.m_lastFrameUpdate = p_shaderHandle;
+		}
+	}
+	inline void modelUniformUpdate(const unsigned int p_shaderHandle, const ShaderUniformUpdater &p_uniformUpdater, const UniformObjectData &p_objectData, const UniformFrameData &p_frameData)
 	{
-		Dataset_Shader() : m_shaderHandle(0), m_numModels(0), m_modelVectorSize(0), m_uniformUpdater(nullptr) { }
-		Dataset_Shader(unsigned int p_shaderHandle, const ShaderUniformUpdater *p_uniformUpdater)
-			: m_shaderHandle(p_shaderHandle), m_numModels(0), m_modelVectorSize(0), m_uniformUpdater(p_uniformUpdater) { }
-
-		void clear()
+		// Check if the model uniforms haven't been updated already
+		//if(m_rendererState.m_lastModelUpdate != p_shaderHandle)
 		{
-			for(std::vector<Dataset_Model>::size_type i = 0; i < m_modelVectorSize; i++)
-				m_models[i].m_meshes.clear();
-
-			m_numModels = 0;
+			// Declare uniform data
+			UniformData uniformData(p_objectData, p_frameData);
+			
+			// Update model uniforms
+			p_uniformUpdater.updateModel(uniformData);
+			m_rendererState.m_lastModelUpdate = p_shaderHandle;
 		}
-
-		unsigned int m_shaderHandle;
-		const ShaderUniformUpdater *m_uniformUpdater;
-
-		std::vector<Dataset_Model> m_models;
-		std::vector<Dataset_Model>::size_type m_numModels;
-		std::vector<Dataset_Shader>::size_type m_modelVectorSize;
-	};
-
-	struct Datasets
+	}
+	inline void meshUniformUpdate(const unsigned int p_shaderHandle, const ShaderUniformUpdater &p_uniformUpdater,const UniformObjectData &p_objectData, const UniformFrameData &p_frameData)
 	{
-		Datasets() : m_numShaders(0), m_shaderVectorSize(0) { }
+		// Check if the mesh uniforms haven't been updated already
+		if(m_rendererState.m_lastMeshUpdate != p_shaderHandle)
+		{
+			// Declare uniform data
+			UniformData uniformData(p_objectData, p_frameData);
 
-		std::vector<Dataset_Shader> m_shaders;
-		std::vector<Dataset_Shader>::size_type m_numShaders;
-		std::vector<Dataset_Shader>::size_type m_shaderVectorSize;
-	};
+			// Update mesh uniforms
+			p_uniformUpdater.updateMesh(uniformData);
+			m_rendererState.m_lastMeshUpdate = p_shaderHandle;
+		}
+	}
 	
-	struct RenderableObjects
+	inline void processCommand(const DrawCommand &p_command, const UniformFrameData &p_frameData)
+	{
+		// Get uniform data
+		UniformData uniformData(p_command.m_uniformObjectData, p_frameData);
+		
+		// Bind the shader
+		bindShader(p_command.m_shaderHandle);
+
+		// Update shader uniforms
+		frameUniformUpdate(	 p_command.m_shaderHandle, p_command.m_uniformUpdater, p_command.m_uniformObjectData, p_frameData);
+		modelUniformUpdate(	 p_command.m_shaderHandle, p_command.m_uniformUpdater, p_command.m_uniformObjectData, p_frameData);
+		meshUniformUpdate(	 p_command.m_shaderHandle, p_command.m_uniformUpdater, p_command.m_uniformObjectData, p_frameData);
+
+		//p_command.m_uniformUpdater.updateBlockBindingPoints();
+
+		// Bind VAO
+		bindVAO(p_command.m_modelHandle);
+
+		// Draw the geometry
+		glDrawElementsBaseVertex(GL_TRIANGLES,
+								 p_command.m_numIndices,
+								 GL_UNSIGNED_INT,
+								 (void*)(sizeof(unsigned int) * p_command.m_baseIndex),
+								 p_command.m_baseVertex);
+	}
+	inline void processCommand(const ScreenSpaceDrawCommand &p_command, const UniformFrameData &p_frameData)
 	{
-		RenderableObjects()
+		// Get uniform data
+		UniformData uniformData(p_command.m_uniformObjectData, p_frameData);
+		
+		// Bind the shader
+		bindShader(p_command.m_shaderHandle);
+
+		// Update shader uniforms
+		frameUniformUpdate(p_command.m_shaderHandle, p_command.m_uniformUpdater, p_command.m_uniformObjectData, p_frameData);
+		textureUniformUpdate(p_command.m_shaderHandle, p_command.m_uniformUpdater, p_command.m_uniformObjectData, p_frameData);
+		//modelUniformUpdate(p_command.m_shaderHandle, p_command.m_uniformUpdater, p_command.m_uniformObjectData, p_frameData);
+		//meshUniformUpdate(p_command.m_shaderHandle, p_command.m_uniformUpdater, p_command.m_uniformObjectData, p_frameData);
+
+		m_fullscreenTriangle.bind();
+		m_fullscreenTriangle.render();
+	}
+	inline void processCommand(const BufferUpdateCommand &p_command, const UniformFrameData &p_frameData)
+	{
+		// Bind the buffer
+		bindUniformBuffer(p_command.m_bufferHandle);
+		
+		// Update the buffer based on the specified way
+		switch(p_command.m_updateType)
 		{
-			m_numShaders = 0;
+		case BufferUpdate_Data:
+			glBufferData(p_command.m_bufferType,
+						 p_command.m_size,
+						 p_command.m_data,
+						 GL_DYNAMIC_DRAW);
+			break;
+
+		case BufferUpdate_SubData:
+			glBufferSubData(p_command.m_bufferType,
+							p_command.m_offset,
+							p_command.m_size,
+							p_command.m_data);
+
+			break;
 		}
-		void clear()
+	}
+	inline void processCommand(LoadCommand &p_command, const UniformFrameData &p_frameData)
+	{
+		switch(p_command.m_objectType)
 		{
-			m_shaders.clear();
-			m_models.clear();
-			m_materials.clear();
-			m_meshes.clear();
-			m_numShaders = 0;
+		case LoadObject_Buffer:
+		{
+			// Create the buffer
+			glGenBuffers(1, &p_command.m_handle);
+
+			// Bind the buffer
+			glBindBuffer(p_command.m_objectData.m_bufferData.m_bufferType, p_command.m_handle);
+
+			// Fill the buffer
+			glBufferData(p_command.m_objectData.m_bufferData.m_bufferType, 
+						 p_command.m_objectData.m_bufferData.m_size, 
+						 p_command.m_objectData.m_bufferData.m_data,
+						 p_command.m_objectData.m_bufferData.m_bufferUsage);
+
+			// Bind the buffer to the binding index so it can be accessed in a shader
+			glBindBufferBase(p_command.m_objectData.m_bufferData.m_bufferType, 
+							 p_command.m_objectData.m_bufferData.m_bindingIndex,
+							 p_command.m_handle);
 		}
+		break;
 
-		std::vector<RendererShader>		m_shaders;
-		std::vector<RendererModel>		m_models;
-		std::vector<RendererMaterial>	m_materials;
-		std::vector<RendererMesh>		m_meshes;
-
-		size_t m_numShaders;
-	};*/
-
-	struct DrawCommand
-	{
-		DrawCommand(const ShaderUniformUpdater &p_uniformUpdater, unsigned int p_shaderHandle, unsigned int p_modelHandle,
-					  unsigned int p_numIndices, unsigned int p_baseVertex, unsigned int p_baseIndex) : m_uniformUpdater(p_uniformUpdater)
+		case LoadObject_Shader:
 		{
-			m_shaderHandle = p_shaderHandle;
-			m_modelHandle = p_modelHandle;
-			m_numIndices = p_numIndices;
-			m_baseVertex = p_baseVertex;
-			m_baseIndex = p_baseIndex;
+			unsigned int shaderHandles[ShaderType_NumOfTypes] = {};
+			unsigned int shaderTypes[ShaderType_NumOfTypes] = {
+				GL_FRAGMENT_SHADER,
+				GL_GEOMETRY_SHADER,
+				GL_VERTEX_SHADER,
+				GL_TESS_CONTROL_SHADER,
+				GL_TESS_EVALUATION_SHADER };
+
+			// Clear error queue (TODO: remove in the future)
+			glGetError();
+
+			// Create shader program handle
+			p_command.m_handle = glCreateProgram();
+
+			// Check for errors
+			GLenum glError = glGetError();
+			if(glError != GL_NO_ERROR)
+			{
+				// Log an error with every shader info log
+				for(unsigned int i = 0; i < ShaderType_NumOfTypes; i++)
+				{
+					p_command.m_objectData.m_shaderData.m_errorMessages[i].m_errorCode = ErrorCode::Shader_creation_failed;
+					p_command.m_objectData.m_shaderData.m_errorMessages[i].m_errorSource = ErrorSource::Source_ShaderLoader;
+				}
+
+				std::string combinedNames;
+
+				// For every shader filename, if it's not empty, add it to the combined filename
+				for(unsigned int i = 0; i < ShaderType_NumOfTypes; i++)
+					if(!p_command.m_objectData.m_shaderData.m_names[i].empty())
+						combinedNames += p_command.m_objectData.m_shaderData.m_names[i] + ", ";
+				
+				// Remove the last 2 characters from the filename (comma and space)
+				if(!combinedNames.empty())
+				{
+					combinedNames.pop_back();
+					combinedNames.pop_back();
+				}
+
+				// Log an error with the error handler
+				ErrHandlerLoc::get().log(ErrorCode::Shader_creation_failed,
+										 ErrorSource::Source_ShaderLoader,
+										 "\"" + combinedNames + "\":\n" + Utilities::toString(glError));
+			}
+			else
+			{
+				// Create individual shaders
+				for(unsigned int i = 0; i < ShaderType_NumOfTypes; i++)
+				{
+					if(!p_command.m_objectData.m_shaderData.m_source[i].empty())
+					{
+						// Create a shader handle
+						shaderHandles[i] = glCreateShader(shaderTypes[i]);
+
+						// Check for errors
+						GLenum glError = glGetError();
+						if(glError != GL_NO_ERROR)
+						{
+							// Log an error with a shader info log
+							p_command.m_objectData.m_shaderData.m_errorMessages[i].m_errorCode = ErrorCode::Shader_creation_failed;
+							p_command.m_objectData.m_shaderData.m_errorMessages[i].m_errorSource = ErrorSource::Source_ShaderLoader;
+
+							// Log an error with the error handler
+							ErrHandlerLoc::get().log(ErrorCode::Shader_creation_failed,
+													 ErrorSource::Source_ShaderLoader,
+													 "\"" + p_command.m_objectData.m_shaderData.m_names[i] + "\":\n" + Utilities::toString(glError));
+						}
+						else
+						{
+							// Pass shader source code and compile it
+							const char *shaderSource = p_command.m_objectData.m_shaderData.m_source[i].c_str();
+							glShaderSource(shaderHandles[i], 1, &shaderSource, NULL);
+							glCompileShader(shaderHandles[i]);
+
+							// Check for shader compilation errors
+							GLint shaderCompileResult = 0;
+							glGetShaderiv(shaderHandles[i], GL_COMPILE_STATUS, &shaderCompileResult);
+
+							// Check for errors
+							GLenum glError = glGetError();
+							// If compilation failed
+							if(shaderCompileResult == 0)
+							{
+								// Assign an error
+								int shaderCompileLogLength = 0;
+								glGetShaderiv(shaderHandles[i], GL_INFO_LOG_LENGTH, &shaderCompileLogLength);
+
+								// Get the actual error message
+								std::vector<char> shaderCompileErrorMessage(shaderCompileLogLength);
+								glGetShaderInfoLog(shaderHandles[i], shaderCompileLogLength, NULL, &shaderCompileErrorMessage[0]);
+
+								// Convert vector of chars to a string
+								std::string errorMessageTemp;
+								for(int i = 0; shaderCompileErrorMessage[i]; i++)
+									errorMessageTemp += shaderCompileErrorMessage[i];
+
+								// Log an error with a shader info log
+								p_command.m_objectData.m_shaderData.m_errorMessages[i].m_errorCode = ErrorCode::Shader_compile_failed;
+								p_command.m_objectData.m_shaderData.m_errorMessages[i].m_errorSource = ErrorSource::Source_ShaderLoader;
+								p_command.m_objectData.m_shaderData.m_errorMessages[i].m_errorMessage = errorMessageTemp;
+
+								// Log an error with the error handler
+								ErrHandlerLoc::get().log(ErrorCode::Shader_compile_failed,
+														 ErrorSource::Source_ShaderLoader,
+														 "\"" + p_command.m_objectData.m_shaderData.m_names[i] + "\":\n" + errorMessageTemp);
+
+								// Reset the shader handle
+								shaderHandles[i] = 0;
+							}
+							else
+							{
+								// Attach shader to the program handle
+								glAttachShader(p_command.m_handle, shaderHandles[i]);
+
+								// Check for errors
+								GLenum glError = glGetError();
+								if(glError != GL_NO_ERROR)
+								{
+									// Reset the shader handle
+									shaderHandles[i] = 0;
+
+									// Log an error with a shader info log
+									p_command.m_objectData.m_shaderData.m_errorMessages[i].m_errorCode = ErrorCode::Shader_attach_failed;
+									p_command.m_objectData.m_shaderData.m_errorMessages[i].m_errorSource = ErrorSource::Source_ShaderLoader;
+									p_command.m_objectData.m_shaderData.m_errorMessages[i].m_errorMessage = Utilities::toString(glError);
+
+									// Log an error with the error handler
+									ErrHandlerLoc::get().log(ErrorCode::Shader_compile_failed,
+															 ErrorSource::Source_ShaderLoader,
+															 "\"" + p_command.m_objectData.m_shaderData.m_names[i] + "\":\n" + Utilities::toString(glError));
+								}
+							}
+						}
+					}
+				}
+
+				GLint shaderLinkingResult;
+				glLinkProgram(p_command.m_handle);
+
+				// Check for linking errors. If an error has occurred, get the error message and throw an exception
+				glGetProgramiv(p_command.m_handle, GL_LINK_STATUS, &shaderLinkingResult);
+
+				// If shader loading was successfull
+				if(shaderLinkingResult)
+				{
+
+					glUseProgram(p_command.m_handle);
+
+					// Generate uniform update list, after the shader has been compiled
+					p_command.m_objectData.m_shaderData.m_uniformUpdater.generateUpdateList();
+
+					// Update some of the uniforms (that do not change frame to frame)
+					//p_command.m_objectData.m_shaderData.m_uniformUpdater.generateUpdateList();
+					p_command.m_objectData.m_shaderData.m_uniformUpdater.updateTextureUniforms();
+					p_command.m_objectData.m_shaderData.m_uniformUpdater.updateBlockBindingPoints();
+				}
+				// If shader loading failed
+				else
+				{
+					// Reset shader handle
+					p_command.m_handle = 0;
+
+					GLsizei shaderLinkLogLength = 0;
+					std::string errorMessageTemp;
+					glGetShaderiv(p_command.m_handle, GL_INFO_LOG_LENGTH, &shaderLinkLogLength);
+
+					// Sometimes OpenGL cannot retrieve the error string, so check that just in case
+					if(shaderLinkLogLength > 0)
+					{
+						// Get the actual error message
+						std::vector<char> shaderLinkErrorMessage(shaderLinkLogLength);
+						glGetShaderInfoLog(p_command.m_handle, shaderLinkLogLength, NULL, &shaderLinkErrorMessage[0]);
+
+						// Convert vector of chars to a string
+						for(int i = 0; shaderLinkErrorMessage[i]; i++)
+							errorMessageTemp += shaderLinkErrorMessage[i];
+					}
+					else
+						errorMessageTemp = "Couldn't retrieve the error";
+
+					// Log an error with a shader info log
+					p_command.m_objectData.m_shaderData.m_errorMessages[0].m_errorCode = ErrorCode::Shader_link_failed;
+					p_command.m_objectData.m_shaderData.m_errorMessages[0].m_errorSource = ErrorSource::Source_ShaderLoader;
+					p_command.m_objectData.m_shaderData.m_errorMessages[0].m_errorMessage = errorMessageTemp;
+
+					// Log an error with the error handler
+					ErrHandlerLoc::get().log(ErrorCode::Shader_link_failed, ErrorSource::Source_ShaderLoader, errorMessageTemp);
+				}
+
+				// Iterate over all shaders and detach them
+				for(unsigned int i = 0; i < ShaderType_NumOfTypes; i++)
+				{
+					// If shader is valid
+					if(shaderHandles[i] != 0)
+					{
+						glDetachShader(p_command.m_handle, shaderHandles[i]);
+					}
+				}
+			}
 		}
+			break;
 
-		const ShaderUniformUpdater &m_uniformUpdater;
-		const UniformObjectData m_uniformObjectData;
-
-		unsigned int m_shaderHandle;
-		unsigned int m_modelHandle;
-
-		unsigned int m_numIndices;
-		unsigned int m_baseVertex;
-		unsigned int m_baseIndex;
-	};
+		case LoadObject_Texture2D:
+		{
+			// Generate, bind and upload the texture
+			glGenTextures(1, &p_command.m_handle);
+			glBindTexture(GL_TEXTURE_2D, p_command.m_handle);
+			glTexImage2D(GL_TEXTURE_2D,
+						 p_command.m_objectData.m_tex2DData.m_mipmapLevel,
+						 p_command.m_objectData.m_tex2DData.m_texFormat,
+						 p_command.m_objectData.m_tex2DData.m_textureWidth, 
+						 p_command.m_objectData.m_tex2DData.m_textureHeight,
+						 0, 
+						 p_command.m_objectData.m_tex2DData.m_texFormat,
+						 GL_UNSIGNED_BYTE, 
+						 p_command.m_objectData.m_tex2DData.m_data);
+
+			// Generate  mipmaps if they are enabled
+			if(Config::textureVar().generate_mipmaps)
+				glGenerateMipmap(GL_TEXTURE_2D);
+
+			// Texture filtering mode, when image is minimized
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Config::textureVar().gl_texture_minification);
+			// Texture filtering mode, when image is magnified
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Config::textureVar().gl_texture_magnification);
+			// Texture anisotropic filtering
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, Config::textureVar().gl_texture_anisotropy);
+		}
+			break;
 
-	// First element is a sort key, second element is an object to draw
-	typedef std::vector<std::pair<int64_t, DrawCommand>> DrawCommands;
+		case LoadObject_TextureCube:
+		{
+			// Generate, bind and upload the texture
+			glGenTextures(1, &p_command.m_handle);
+			glBindTexture(GL_TEXTURE_CUBE_MAP, p_command.m_handle);
+
+			for (unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+			{
+				glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
+					p_command.m_objectData.m_cubeMapData.m_mipmapLevel,
+					p_command.m_objectData.m_cubeMapData.m_texFormat,
+					p_command.m_objectData.m_cubeMapData.m_textureWidth,
+					p_command.m_objectData.m_cubeMapData.m_textureHeight,
+					0,
+					p_command.m_objectData.m_cubeMapData.m_texFormat,
+					GL_UNSIGNED_BYTE,
+					p_command.m_objectData.m_cubeMapData.m_data[face]);
+
+				// Release memory
+				//FreeImage_Unload(m_bitmap[face]);
+				//m_pixelData[face] = nullptr;
+				//m_bitmap[face] = nullptr;
+
+			}
+			
+			glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+
+			// Generate  mipmaps if they are enabled
+			if (Config::textureVar().generate_mipmaps)
+				glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+
+			// Texture filtering mode, when image is minimized
+			glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, Config::textureVar().gl_texture_minification);
+			// Texture filtering mode, when image is magnified
+			glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, Config::textureVar().gl_texture_magnification);
+			// Texture anisotropic filtering
+			glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, Config::textureVar().gl_texture_anisotropy);
+		}
+			break;
 
-	RendererBackend() { }
-	~RendererBackend() { }
+		case LoadObject_Model:
+		{
+			// Create and bind the Vertex Array Object
+			glGenVertexArrays(1, &p_command.m_handle);
+			glBindVertexArray(p_command.m_handle);
+
+			// Create the m_buffers
+			glGenBuffers(sizeof(p_command.m_objectData.m_modelData.m_buffers) / sizeof(p_command.m_objectData.m_modelData.m_buffers[0]), p_command.m_objectData.m_modelData.m_buffers);
+
+			// Upload indices
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_command.m_objectData.m_modelData.m_buffers[ModelBuffer_Index]);
+			glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
+						 p_command.m_objectData.m_modelData.m_size[ModelBuffer_Index], 
+						 p_command.m_objectData.m_modelData.m_data[ModelBuffer_Index], 
+						 GL_STATIC_DRAW);
+
+			// Loop over all the buffer types except index buffer 
+			// (since index buffer does not share the same properties as other buffer types)
+			for(unsigned int i = 0; i < ModelBuffer_NumTypesWithoutIndex; i++)
+			{
+				// Bind a buffer and upload data to it
+				glBindBuffer(GL_ARRAY_BUFFER, p_command.m_objectData.m_modelData.m_buffers[i]);
+				glBufferData(GL_ARRAY_BUFFER,
+							 p_command.m_objectData.m_modelData.m_size[i],
+							 p_command.m_objectData.m_modelData.m_data[i],
+							 GL_STATIC_DRAW);
+
+				// Enable and bind the buffer to a vertex attribute array (so it can be accessed in the shader)
+				glEnableVertexAttribArray(i);
+				glVertexAttribPointer(i, p_command.m_objectData.m_modelData.m_numElements[i], GL_FLOAT, GL_FALSE, 0, 0);
+			}
+		}
+			break;
 
-	ErrorCode init();
+		default:
+			break;
+		}
+	}
 
-	//void renderObjects(DrawCommands &p_objects);
-	
-protected:
+	CurrentState m_rendererState;
 
-	//const CameraObject *m_currentCamera;
-	//const GraphicsData *m_currentObjectData;
+	static SingleTriangle m_fullscreenTriangle;
 
-	UniformRendererData m_uniformRendererData;
+	GeometryBuffer *m_gbuffer;
 };

+ 68 - 72
Praxis3D/Source/RendererFrontend.cpp

@@ -1,93 +1,89 @@
 
+#include "GeometryPass.h"
+#include "LightingPass.h"
+#include "FinalPass.h"
+#include "ReflectionPass.h"
 #include "RendererFrontend.h"
 
 ErrorCode RendererFrontend::init()
 {
-	return ErrorCode::Success;
-}
-
-void RendererFrontend::renderFrame(const SceneObjects &p_sceneObjects, const float p_deltaTime)
-{
-	// Load all the objects in the load-to-gpu queue. This needs to be done before any rendering, as objects in this
-	// array might have been also added to objects-to-render arrays, so they need to be loaded first
-	for(decltype(p_sceneObjects.m_objectsToLoad.size()) i = 0, size = p_sceneObjects.m_objectsToLoad.size(); i < size; i++)
-	{
-		p_sceneObjects.m_objectsToLoad[i]->loadToVideoMemory();
+	ErrorCode returnCode = ErrorCode::Success;
 
-		// In case shader failed to load or was not specified, assign a geometry shader
-		//if(p_sceneObjects.m_objectsToLoad[i]->m_shader->isDefaultProgram())
-			//p_sceneObjects.m_objectsToLoad[i]->m_shader = m_shaderGeometry;
-		//else
-		//{
-			//p_sceneObjects.m_objectsToLoad[i]->m_shader->bind();
-			//p_sceneObjects.m_objectsToLoad[i]->m_shader->getUniformUpdater().updateTextureUniforms(*m_rendererState);
-		//}
-
-	}
-
-	// Iterate over all objects to be rendered with geometry shader
-	for(decltype(p_sceneObjects.m_modelObjects.size()) objIndex = 0, numObjects = p_sceneObjects.m_modelObjects.size(); objIndex < numObjects; objIndex++)
-	{
-		
-
-		//drawModelObject(p_sceneObjects.m_modelObjects[objIndex], m_shaderGeometry);
-	}
-}
+	// Get the current screen size
+	m_frameData.m_screenSize.x = Config::graphicsVar().current_resolution_x;
+	m_frameData.m_screenSize.y = Config::graphicsVar().current_resolution_y;
 
-void RendererFrontend::queueForDrawing(const RenderableObjectData &p_object)
-{
-	/*/ Declare temp values used for indexing
-	size_t shaderIndex = 0;
-	size_t modelIndex = 0;
+	// Initialize renderer backend and check if it was successful
+	if (!ErrHandlerLoc::get().ifSuccessful(m_backend.init(m_frameData), returnCode))
+		return returnCode;
 
-	// Get different object handles
-	auto shaderHandle = p_object.m_shader->getShaderHandle();
-	auto modelVAOHandle = p_object.m_model.getHandle();
+	// Add geometry rendering pass, if it was initialized successfuly
+	GeometryPass *geometryPass = new GeometryPass(*this);
+	if (geometryPass->init() == ErrorCode::Success)
+		m_renderingPasses.push_back(geometryPass);
 
-	// Loop through the shader array, to check if the current shader has already been added
-	for(shaderIndex = 0; shaderIndex < m_objects.m_numShaders; shaderIndex++)
-		if(m_objects.m_shaders[shaderIndex].m_shaderHandle == shaderHandle)
-			break;
+	// Add lighting rendering pass, if it was initialized successfuly
+	LightingPass *lightingPass = new LightingPass(*this);
+	if (lightingPass->init() == ErrorCode::Success)
+		m_renderingPasses.push_back(lightingPass);
 
-	// If the shader has not been added already, add it
-	if(m_objects.m_shaders[shaderIndex].m_shaderHandle != shaderHandle)
-	{
-		// Assign correct shader index
-		shaderIndex = m_objects.m_shaders.size();
+	// Add final rendering pass, if it was initialized successfuly
+	FinalPass *finalPass = new FinalPass(*this);
+	if (finalPass->init() == ErrorCode::Success)
+		m_renderingPasses.push_back(finalPass);
 
-		// Add the current shader to the array
-		m_objects.m_shaders.push_back(RendererBackend::RendererShader(p_object.m_shader->getUniformUpdater(), shaderHandle));
+	updateProjectionMatrix();
 
-		// Increment shader count
-		m_objects.m_numShaders++;
-	}
+	passLoadCommandsToBackend();
 
-	// If the shader is not the first one in the shader array,
-	// assign model index depending on the number of models from previous shader
-	modelIndex = shaderIndex > 0 ? m_objects.m_shaders[shaderIndex - 1].m_numModels - 1 : 0;
+	return returnCode;
+}
 
-	// Loop through the model array, to check if the current model has already been added
-	for(; modelIndex < m_objects.m_shaders[shaderIndex].m_numModels; modelIndex++)
-		if(m_objects.m_models[modelIndex].m_VAO == modelVAOHandle)
-			break;
+void RendererFrontend::renderFrame(const SceneObjects &p_sceneObjects, const float p_deltaTime)
+{
+	// Clear draw commands at the beggining of each frame
+	m_drawCommands.clear();
 
-	// If the model has not been added already, add it
-	if(m_objects.m_models[modelIndex].m_VAO != modelVAOHandle)
+	// Load all the objects in the load-to-gpu queue. This needs to be done before any rendering, as objects in this
+	// array might have been also added to objects-to-render arrays, so they need to be loaded first
+	for (decltype(p_sceneObjects.m_objectsToLoad.size()) i = 0, size = p_sceneObjects.m_objectsToLoad.size(); i < size; i++)
 	{
-		// Assign correct model index
-		modelIndex = m_objects.m_models.size();
-
-		// Add the current model to the array
-		m_objects.m_models.push_back(RendererBackend::RendererModel());
-
-		// Increment model count
-		m_objects.m_shaders[shaderIndex].m_numModels++;
+		queueForLoading(*p_sceneObjects.m_objectsToLoad[i]);
 	}
 
-	for(decltype(p_object.m_model.getNumMeshes()) meshIndex = 0, numMeshes = p_object.m_model.getNumMeshes(); meshIndex < numMeshes; meshIndex++)
+	// Handle loading before any rendering takes place
+	passLoadCommandsToBackend();
+
+	// Calculate view and view-projection matrix here, so it is only done once, since it only changes between frames
+	m_frameData.m_viewMatrix = p_sceneObjects.m_camera->getBaseObjectData().m_modelMat;
+	m_frameData.m_viewProjMatrix = m_frameData.m_projMatrix * p_sceneObjects.m_camera->getBaseObjectData().m_modelMat;
+	
+	// Set the camera position
+	m_frameData.m_cameraPosition = p_sceneObjects.m_camera->getVec3(nullptr, Systems::Changes::Spacial::Position);
+	
+	// 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;
+	m_frameData.m_dirLightIntensity = p_sceneObjects.m_directionalLight->m_intensity;
+	m_frameData.m_dirLightDirection = p_sceneObjects.m_directionalLight->m_direction;
+	m_frameData.m_dirLightDirection.normalize();
+
+	// Set number of lights so they can be send to the shader
+	m_frameData.m_numPointLights = p_sceneObjects.m_pointLights.size();
+	m_frameData.m_numSpotLights = p_sceneObjects.m_spotLights.size();
+	
+	// Prepare the geometry buffer for a new frame and a geometry pass
+	m_backend.getGeometryBuffer()->initFrame();
+	m_backend.getGeometryBuffer()->initGeometryPass();
+
+	glEnable(GL_DEPTH_TEST);		// Enable depth testing, as this is much like a regular forward render pass
+	glClear(GL_DEPTH_BUFFER_BIT);	// Make sure to clear the depth buffer for the new frame
+	glDisable(GL_CULL_FACE);
+
+	//m_renderingPasses[0]->update(p_sceneObjects, p_deltaTime);
+
+	for(decltype(m_renderingPasses.size()) i = 0, size = m_renderingPasses.size(); i < size; i++)
 	{
-		m_objects.m_meshes.push_back(RendererBackend::RendererMesh(p_object.m_model[meshIndex]));
+		m_renderingPasses[i]->update(p_sceneObjects, p_deltaTime);
 	}
-
-	m_objects.m_models[modelIndex].m_numMeshes += p_object.m_model.getNumMeshes() - 1;*/
 }
+

+ 228 - 3
Praxis3D/Source/RendererFrontend.h

@@ -4,18 +4,243 @@
 #include "RendererBackend.h"
 #include "RendererScene.h"
 
+class RenderPass;
+
 class RendererFrontend
 {
+	friend class GeometryPass;
+	friend class LightingPass;
+	friend class FinalPass;
+	friend class ReflectionPass;
 public:
+	// A handle for buffer that holds data of lights
+	struct LightUniformBuffer
+	{
+		LightUniformBuffer() : m_bufferType(BufferType_Uniform), m_bufferUsage(BufferUsageHint_Dynamic)
+		{
+			m_data = 0;
+			m_size = 0;
+			m_offset = 0;
+			m_handle = 0;
+			m_bindingIndex = 0;
+		}
+
+		int64_t m_size;
+		unsigned int m_offset;
+		unsigned int m_handle;
+		unsigned int m_bindingIndex;
+		void *m_data;
+
+		const BufferType m_bufferType;
+		const BufferUsageHint m_bufferUsage;
+	};
+
 	RendererFrontend() { }
 	~RendererFrontend() { }
 
 	ErrorCode init();
 
+	// Renders a complete frame
 	void renderFrame(const SceneObjects &p_sceneObjects, const float p_deltaTime);
 
-	void queueForDrawing(const RenderableObjectData &p_object);
-
 protected:
-	//RendererBackend::RenderableObjects m_objects;
+	inline void queueForDrawing(const RenderableObjectData &p_object, const unsigned int p_shaderHandle, const ShaderUniformUpdater &p_uniformUpdater, const Math::Mat4f &p_viewProjMatrix)
+	{
+		// Get the neccessary handles
+		const unsigned int modelHandle = p_object.m_model.getHandle();
+
+		// Calculare model-view-projection matrix
+		const Math::Mat4f modelViewProjMatrix = p_viewProjMatrix * p_object.m_baseObjectData.m_modelMat;
+
+		unsigned int materials[MaterialType_NumOfTypes];
+
+		for(decltype(p_object.m_materials[0].size()) i = 0; i < MaterialType_NumOfTypes; i++)
+		{
+			//materials[i] = p_object.m_materials[i]
+		}
+
+		// Assign the object data that is later passed to the shaders
+		const UniformObjectData objectData(p_object.m_baseObjectData.m_modelMat,
+										   modelViewProjMatrix,
+										   p_object.m_baseObjectData.m_heightScale,
+										   p_object.m_baseObjectData.m_alphaThreshold,
+										   p_object.m_baseObjectData.m_emissiveThreshold,
+										   p_object.m_baseObjectData.m_textureTilingFactor);
+
+		// Calculate the sort key
+		RendererBackend::DrawCommands::value_type::first_type sortKey = 0;
+		
+		// Add a draw command for each mesh, using the same object data
+		for(decltype(p_object.m_model.getNumMeshes()) meshIndex = 0, numMeshes = p_object.m_model.getNumMeshes(); meshIndex < numMeshes; meshIndex++)
+		{
+			m_drawCommands.emplace_back(
+				sortKey,
+				RendererBackend::DrawCommand(
+					p_uniformUpdater,
+					objectData,
+					p_shaderHandle,
+					modelHandle,
+					p_object.m_model[meshIndex].m_numIndices,
+					p_object.m_model[meshIndex].m_baseVertex,
+					p_object.m_model[meshIndex].m_baseIndex,
+					p_object.m_materials[MaterialType_Diffuse][meshIndex].getHandle(),
+					p_object.m_materials[MaterialType_Normal][meshIndex].getHandle(),
+					p_object.m_materials[MaterialType_Emissive][meshIndex].getHandle(),
+					p_object.m_materials[MaterialType_Combined][meshIndex].getHandle())
+				);
+		}
+	}
+	inline void queueForDrawing(const unsigned int p_shaderHandle, const ShaderUniformUpdater &p_uniformUpdater, const Math::Mat4f &p_viewProjMatrix)
+	{
+		// Assign the object data that is later passed to the shaders
+		const UniformObjectData objectData(p_viewProjMatrix,
+										   p_viewProjMatrix,
+										   Config::graphicsVar().height_scale,
+										   Config::graphicsVar().alpha_threshold,
+										   Config::graphicsVar().emissive_threshold,
+										   Config::graphicsVar().texture_tiling_factor);
+
+		// Calculate the sort key
+		RendererBackend::DrawCommands::value_type::first_type sortKey = 0;
+
+		m_screenSpaceDrawCommands.emplace_back(
+			sortKey,
+			RendererBackend::ScreenSpaceDrawCommand(
+				p_uniformUpdater,
+				objectData,
+				p_shaderHandle)
+			);
+	}
+
+	inline void queueForLoading(ShaderLoader::ShaderProgram &p_shader)
+	{
+		m_loadCommands.emplace_back(p_shader.m_shaderFilename,
+									p_shader.m_programHandle,
+									p_shader.getUniformUpdater(),
+									p_shader.m_shaderSource, 
+									p_shader.m_errorMessages);
+	}
+	inline void queueForLoading(ModelLoader::ModelHandle &p_model)
+	{
+		m_loadCommands.emplace_back(p_model.getFilename(),
+									p_model.m_model->m_handle,
+									p_model.m_model->m_buffers,
+									p_model.m_model->m_numElements,
+									p_model.m_model->m_bufferSize,
+									p_model.m_model->getData());
+	}
+	inline void queueForLoading(TextureLoader2D::Texture2DHandle &p_texture)
+	{
+		m_loadCommands.emplace_back(p_texture.getFilename(),
+									p_texture.getHandleRef(),
+									p_texture.getTextureFormat(),
+									p_texture.getMipmapLevel(),
+									p_texture.getTextureWidth(),
+									p_texture.getTextureHeight(),
+									p_texture.getData());
+	}
+	inline void queueForLoading(TextureLoaderCubemap::TextureCubemapHandle p_texture)
+	{
+		m_loadCommands.emplace_back(
+			p_texture.getHandleRef(),
+			p_texture.getTextureFormat(),
+			p_texture.getMipmapLevel(),
+			p_texture.getTextureWidth(),
+			p_texture.getTextureHeight(),
+			p_texture.getData());
+	}
+	inline void queueForLoading(RenderableObjectData &p_objectData)
+	{
+		// Load model
+		queueForLoading(p_objectData.m_model);
+
+		// Load shader only if it is custom
+		if(!p_objectData.m_shader->isDefaultProgram())
+			queueForLoading(*p_objectData.m_shader);
+
+		// Load all materials
+		for(decltype(p_objectData.m_numMaterials) i = 0; i < p_objectData.m_numMaterials; i++)
+			for(int matType = 0; matType < MaterialType_NumOfTypes; matType++)
+				queueForLoading(p_objectData.m_materials[matType][i]);
+	}
+	inline void queueForLoading(LightUniformBuffer &p_lightBuffer)
+	{
+		m_loadCommands.emplace_back(p_lightBuffer.m_handle,
+			p_lightBuffer.m_bufferType,
+			p_lightBuffer.m_bufferUsage,
+			p_lightBuffer.m_bindingIndex,
+			p_lightBuffer.m_size,
+			p_lightBuffer.m_data);
+	}
+
+	inline void queueForUpdate(LightUniformBuffer &p_lightBuffer)
+	{
+		m_bufferUpdateCommands.emplace_back(p_lightBuffer.m_handle,
+			p_lightBuffer.m_offset,
+			p_lightBuffer.m_size,
+			p_lightBuffer.m_data,
+			BufferUpdateType::BufferUpdate_SubData,
+			BufferType::BufferType_Uniform);
+	}
+
+	inline void passLoadCommandsToBackend()
+	{
+		// Pass the queued load commands to the backend to be loaded to GPU
+		m_backend.processLoading(m_loadCommands, m_frameData);
+
+		// Clear load commands, since they have already been passed to backend
+		m_loadCommands.clear();
+	}
+	inline void passDrawCommandsToBackend()
+	{
+		// Pass the queued draw commands to the backend to be sent to GPU
+		m_backend.processDrawing(m_drawCommands, m_frameData);
+
+		// Clear draw commands
+		m_drawCommands.clear();
+	}
+	inline void passScreenSpaceDrawCommandsToBackend()
+	{
+		// Pass the queued screen-space draw commands to the backend to be sent to GPU
+		m_backend.processDrawing(m_screenSpaceDrawCommands, m_frameData);
+
+		// Clear draw commands
+		m_screenSpaceDrawCommands.clear();
+	}
+	inline void passUpdateCommandsToBackend()
+	{
+		// Pass the buffer update commands to the backend, so the buffers are updated on the GPU
+		m_backend.processUpdate(m_bufferUpdateCommands, m_frameData);
+
+		// Clear update commands, since they have already been passed to backend
+		m_bufferUpdateCommands.clear();
+	}
+	//inline void pass
+
+	//inline void 
+
+	// Recalculates the projection matrix
+	inline void updateProjectionMatrix()
+	{
+		m_frameData.m_projMatrix.perspective(Config::graphicsVar().fov, 
+											 m_frameData.m_screenSize.x, 
+											 m_frameData.m_screenSize.y, 
+											 Config::graphicsVar().z_near, 
+											 Config::graphicsVar().z_far);
+	}
+
+	// Renderer backend, serves as an interface layer to GPU
+	RendererBackend m_backend;
+	
+	UniformFrameData m_frameData;
+	
+	// Renderer commands
+	RendererBackend::DrawCommands m_drawCommands;
+	RendererBackend::LoadCommands m_loadCommands;
+	RendererBackend::BufferUpdateCommands m_bufferUpdateCommands;
+	RendererBackend::ScreenSpaceDrawCommands m_screenSpaceDrawCommands;
+
+	std::vector<RenderPass*> m_renderingPasses;
+
+	Math::Mat4f m_viewProjMatrix;
 };

+ 132 - 138
Praxis3D/Source/RendererScene.cpp

@@ -6,6 +6,7 @@ RendererScene::RendererScene(RendererSystem *p_system, SceneLoader *p_sceneLoade
 {
 	m_renderTask = new RenderTask(this, p_system->getRenderer());
 	m_camera = nullptr;
+	m_skybox = nullptr;
 }
 
 RendererScene::~RendererScene()
@@ -73,7 +74,7 @@ ErrorCode RendererScene::preload()
 		if(m_modelObjPool[i].allocated() && !(m_modelObjPool[i].getObject()->loadedToMemory()))
 		{
 			// Add the object to be loaded later
-			m_objectsBeingLoaded.push_back(LoadableObjectAndIndex(m_modelObjPool[i].getObject(), m_modelObjPool[i].getIndex()));
+			m_objectsBeingLoaded.push_back(LoadableGraphicsObjectAndIndex(m_modelObjPool[i].getObject(), m_modelObjPool[i].getIndex()));
 
 			// Increment the number of allocated objects (early bail mechanism)
 			numAllocObjecs++;
@@ -88,7 +89,7 @@ ErrorCode RendererScene::preload()
 		if(m_shaderObjPool[i].allocated() && !(m_shaderObjPool[i].getObject()->loadedToMemory()))
 		{
 			// Add the object to be loaded later
-			m_objectsBeingLoaded.push_back(LoadableObjectAndIndex(m_shaderObjPool[i].getObject(), m_shaderObjPool[i].getIndex()));
+			m_objectsBeingLoaded.push_back(LoadableGraphicsObjectAndIndex(m_shaderObjPool[i].getObject(), m_shaderObjPool[i].getIndex()));
 
 			// Increment the number of allocated objects (early bail mechanism)
 			numAllocObjecs++;
@@ -118,7 +119,7 @@ void RendererScene::loadInBackground()
 		if(m_modelObjPool[i].allocated() && !(m_modelObjPool[i].getObject()->loadedToMemory()))
 		{
 			// Add object to 'being loaded' list and start loading it in a background thread
-			m_objectsBeingLoaded.push_back(LoadableObjectAndIndex(m_modelObjPool[i].getObject(), m_modelObjPool[i].getIndex()));
+			m_objectsBeingLoaded.push_back(LoadableGraphicsObjectAndIndex(m_modelObjPool[i].getObject(), m_modelObjPool[i].getIndex()));
 			TaskManagerLocator::get().startBackgroundThread(std::bind(&ModelObject::loadToMemory, m_modelObjPool[i].getObject()));
 
 			// Increment the number of allocated objects (early bail mechanism)
@@ -134,7 +135,7 @@ void RendererScene::loadInBackground()
 		if(m_shaderObjPool[i].allocated() && !(m_shaderObjPool[i].getObject()->loadedToMemory()))
 		{
 			// Add object to 'being loaded' list and start loading it in a background thread
-			m_objectsBeingLoaded.push_back(LoadableObjectAndIndex(m_shaderObjPool[i].getObject(), m_shaderObjPool[i].getIndex()));
+			m_objectsBeingLoaded.push_back(LoadableGraphicsObjectAndIndex(m_shaderObjPool[i].getObject(), m_shaderObjPool[i].getIndex()));
 			TaskManagerLocator::get().startBackgroundThread(std::bind(&ModelObject::loadToMemory, m_shaderObjPool[i].getObject()));
 
 			// Increment the number of allocated objects (early bail mechanism)
@@ -253,6 +254,45 @@ void RendererScene::update(const float p_deltaTime)
 			i++;
 	}
 
+	//	 _______________________________
+	//	|								|
+	//	|		Misc Loaded Objects		|
+	//	|_______________________________|
+	//
+	// Iterate over currently loading objects
+	/*for (decltype(m_miscObjectsBeingLoaded.size()) i = 0, size = m_miscObjectsBeingLoaded.size(),
+		maxObjects = Config::rendererVar().objects_loaded_per_frame; i < size;)
+	{
+		// If the object has loaded to memory already, add to load queue
+		if (m_miscObjectsBeingLoaded[i].m_loadableObject->loadedToMemory())
+		{
+			// If object should be activated after loading (for example wasn't set to be deleted while loading)
+			if (m_miscObjectsBeingLoaded[i].m_activateAfterLoading)
+			{
+				// Make object active, so it is passed to the renderer for drawing
+				//m_miscObjectsBeingLoaded[i].m_loadableObject->setActive(true);
+
+				// Add the object to objects-to-load list, that will be sent to the renderer to process
+				m_sceneObjects.m_objectsToLoad.push_back(&m_miscObjectsBeingLoaded[i].m_loadableObject->getRenderableObjectData());
+			}
+			else
+			{
+				// Remove the object from pool
+				removeObjectFromPool(&m_miscObjectsBeingLoaded[i]);
+			}
+
+			// Remove the object from the current list
+			m_miscObjectsBeingLoaded.erase(m_miscObjectsBeingLoaded.begin() + i);
+
+			// If the max number of object to be processed per frame has been reached, break from the loop
+			if (--maxObjects == 0)
+				break;
+		}
+		// If current object is still loading, advance the index
+		else
+			i++;
+	}*/
+
 	//	 ___________________________
 	//	|							|
 	//	|		Model Objects		|
@@ -365,6 +405,8 @@ void RendererScene::update(const float p_deltaTime)
 	// Update camera and put it in scene object list
 	m_camera->update(p_deltaTime);
 	m_sceneObjects.m_camera = m_camera;
+
+	m_sceneObjects.m_staticSkybox = m_skybox;
 	m_sceneObjects.m_directionalLight = &m_directionalLight->getLightDataSet();
 }
 
@@ -387,6 +429,9 @@ SystemObject *RendererScene::createObject(const PropertySet &p_properties)
 	case Properties::DirectionalLight:
 		newObject = loadDirectionalLight(p_properties);
 		break;
+	case Properties::EnvironmentMapStatic:
+		newObject = loadEnvMapStatic(p_properties);
+		break;
 	case Properties::PointLight:
 		newObject = loadPointLight(p_properties);
 		break;
@@ -477,7 +522,7 @@ ModelObject *RendererScene::loadModelObject(const PropertySet &p_properties)
 
 		// The newly added object in the pool
 		newObject = m_shaderObjPool.getLastRawObject();
-		newObject->m_rendererData.m_shader->loadToMemory();
+		newObject->getRenderableObjectData().m_shader->loadToMemory();
 	}
 	else
 	{
@@ -499,19 +544,19 @@ ModelObject *RendererScene::loadModelObject(const PropertySet &p_properties)
 			switch(p_properties[i].getPropertyID())
 			{
 			case Properties::OffsetPosition:
-				newObject->m_baseObjectData.m_offsetPosition = p_properties[i].getVec3f();
+				newObject->setOffsetPosition(p_properties[i].getVec3f());
 				break;
 			case Properties::OffsetRotation:
-				newObject->m_baseObjectData.m_offsetRotation = p_properties[i].getVec3f();
+				newObject->setOffsetRotation(p_properties[i].getVec3f());
 				break;
 			case Properties::Position:
-				newObject->m_baseObjectData.m_position = p_properties[i].getVec3f();
+				newObject->setPosition(p_properties[i].getVec3f());
 				break;
 			case Properties::Rotation:
-				newObject->m_baseObjectData.m_rotation = p_properties[i].getVec3f();
+				newObject->setRotation(p_properties[i].getVec3f());
 				break;
 			case Properties::Scale:
-				newObject->m_baseObjectData.m_scale = p_properties[i].getVec3f();
+				newObject->setScale(p_properties[i].getVec3f());
 				break;
 			case Properties::Lighting:
 				newObject->setLighting(p_properties[i].getBool());
@@ -519,6 +564,9 @@ ModelObject *RendererScene::loadModelObject(const PropertySet &p_properties)
 			case Properties::AlphaThreshold:
 				newObject->setAlphaThreshold(p_properties[i].getFloat());
 				break;
+			case Properties::HeightScale:
+				newObject->setHeightScale(p_properties[i].getFloat());
+				break;
 			case Properties::TextureTilingFactor:
 				newObject->setTextureTilingFactor(p_properties[i].getFloat());
 				break;
@@ -526,30 +574,28 @@ ModelObject *RendererScene::loadModelObject(const PropertySet &p_properties)
 		}
 
 		// Adjust the position and rotation by offset
-		newObject->m_baseObjectData.m_position += newObject->m_baseObjectData.m_offsetPosition;
-		newObject->m_baseObjectData.m_rotation += newObject->m_baseObjectData.m_offsetRotation;
+		newObject->setPosition(newObject->getBaseObjectData().m_position + newObject->getBaseObjectData().m_offsetPosition);
+		newObject->setRotation(newObject->getBaseObjectData().m_rotation + newObject->getBaseObjectData().m_offsetRotation);
 
 		// Get material parent property
 		auto &materialProperty = p_properties.getPropertySetByID(Properties::Materials);
 
 		// Get material properties
-		const PropertySet *materials[Model::NumOfModelMaterials];
-		materials[Model::ModelMat_diffuse] = &materialProperty.getPropertySetByID(Properties::Diffuse);
-		materials[Model::ModelMat_normal] = &materialProperty.getPropertySetByID(Properties::Normal);
-		materials[Model::ModelMat_emissive] = &materialProperty.getPropertySetByID(Properties::Emissive);
-		materials[Model::ModelMat_specular] = &materialProperty.getPropertySetByID(Properties::Specular);
-		materials[Model::ModelMat_gloss] = &materialProperty.getPropertySetByID(Properties::Gloss);
-		materials[Model::ModelMat_height] = &materialProperty.getPropertySetByID(Properties::Height);
+		const PropertySet *materials[MaterialType_NumOfTypes];
+		materials[MaterialType_Diffuse] = &materialProperty.getPropertySetByID(Properties::Diffuse);
+		materials[MaterialType_Normal] = &materialProperty.getPropertySetByID(Properties::Normal);
+		materials[MaterialType_Emissive] = &materialProperty.getPropertySetByID(Properties::Emissive);
+		materials[MaterialType_Combined] = &materialProperty.getPropertySetByID(Properties::RMHAO);
 		
 		// Process all materials
 		// For every type of material
-		for(unsigned int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+		for(unsigned int matType = 0; matType < MaterialType_NumOfTypes; matType++)
 			// Check if material property is valid
 			if(*materials[matType])
 				// For every property set in the material property
 				for(decltype(materials[matType]->getNumPropertySets()) i = 0, size = materials[matType]->getNumPropertySets(); i < size; i++)
 					// Add the material to the new object
-					newObject->addMaterial(static_cast<Model::ModelMaterialType>(matType),
+					newObject->addMaterial(static_cast<MaterialType>(matType),
 										   materials[matType]->getPropertySet(i).getPropertyByID(Properties::Filename).getString(),
 										   materials[matType]->getPropertySet(i).getPropertyByID(Properties::Index).getInt());
 	
@@ -559,18 +605,16 @@ ModelObject *RendererScene::loadModelObject(const PropertySet &p_properties)
 		if(defaultMaterials)
 		{
 			// Get individual default materials
-			const PropertySet *defaulMaterials[Model::NumOfModelMaterials];
-			defaulMaterials[Model::ModelMat_diffuse] = &defaultMaterials.getPropertySetByID(Properties::Diffuse);
-			defaulMaterials[Model::ModelMat_normal] = &defaultMaterials.getPropertySetByID(Properties::Normal);
-			defaulMaterials[Model::ModelMat_emissive] = &defaultMaterials.getPropertySetByID(Properties::Emissive);
-			defaulMaterials[Model::ModelMat_specular] = &defaultMaterials.getPropertySetByID(Properties::Specular);
-			defaulMaterials[Model::ModelMat_gloss] = &defaultMaterials.getPropertySetByID(Properties::Gloss);
-			defaulMaterials[Model::ModelMat_height] = &defaultMaterials.getPropertySetByID(Properties::Height);
+			const PropertySet *defaulMaterials[MaterialType_NumOfTypes];
+			defaulMaterials[MaterialType_Diffuse] = &defaultMaterials.getPropertySetByID(Properties::Diffuse);
+			defaulMaterials[MaterialType_Normal] = &defaultMaterials.getPropertySetByID(Properties::Normal);
+			defaulMaterials[MaterialType_Emissive] = &defaultMaterials.getPropertySetByID(Properties::Emissive);
+			defaulMaterials[MaterialType_Combined] = &defaultMaterials.getPropertySetByID(Properties::RMHAO);
 
 			// Process default materials by assigning them to the model object
-			for(unsigned int matType = 0; matType < Model::NumOfModelMaterials; matType++)
+			for(unsigned int matType = 0; matType < MaterialType_NumOfTypes; matType++)
 				if(*defaulMaterials[matType])
-					newObject->m_defaultMaterials[matType] = defaulMaterials[matType]->getPropertyByID(Properties::Filename).getString();
+					newObject->setDefaultMaterial(matType, defaulMaterials[matType]->getPropertyByID(Properties::Filename).getString());
 		}
 
 		return newObject;
@@ -593,101 +637,39 @@ CameraObject *RendererScene::loadCameraObject(const PropertySet & p_properties)
 	
 	return m_camera;
 }
-ShaderModelGraphicsObject *RendererScene::loadShaderModelObject(const PropertySet & p_properties)
+EnvironmentMapStatic *RendererScene::loadEnvMapStatic(const PropertySet &p_properties)
 {
-	// Get model properties
-	auto &models = p_properties.getPropertySetByID(Properties::Models);
-	auto &shaderProperty = p_properties.getPropertySetByID(Properties::Shaders);
+	EnvironmentMapStatic *newObject = nullptr;
 
-	// Try to add a new object to the pool
-	ErrorCode objPoolError = m_shaderObjPool.add(
-		this, p_properties.getPropertyByID(Properties::Name).getString(),
-		Loaders::model().load(models.getPropertyByID(Properties::Filename).getString(), false),
-		Loaders::shader().load(shaderProperty));
-	
-	// If adding a new object was successful, continue to load data
-	if(objPoolError == ErrorCode::Success)
-	{
-		// The newly added object in the pool
-		auto *newObject = m_shaderObjPool.getLastRawObject();
+	auto &materials = p_properties.getPropertySetByID(Properties::Materials);
 
-		// Load property data
-		for(decltype(p_properties.getNumProperties()) i = 0, size = p_properties.getNumProperties(); i < size; i++)
-		{
-			switch(p_properties[i].getPropertyID())
-			{
-			case Properties::Lighting:
-				newObject->m_affectedByLighting = p_properties[i].getBool();
-				break;
-			case Properties::Position:
-				newObject->m_baseObjectData.m_position = p_properties[i].getVec3f();
-				break;
-			case Properties::Rotation:
-				newObject->m_baseObjectData.m_rotation = p_properties[i].getVec3f();
-				break;
-			case Properties::Scale:
-				newObject->m_baseObjectData.m_scale = p_properties[i].getVec3f();
-				break;
-			case Properties::PostProcess:
-				newObject->m_affectedByLighting = p_properties[i].getBool();;
-				break;
-			case Properties::AlphaThreshold:
-				newObject->setAlphaThreshold(p_properties[i].getFloat());
-				break;
-			}
-		}
+	std::string filenames[CubemapFace_NumOfFaces];
 
-		// Get material parent property
-		auto &materialProperty = p_properties.getPropertySetByID(Properties::Materials);
-
-		// Get material properties
-		const PropertySet *materials[Model::NumOfModelMaterials];
-		materials[Model::ModelMat_diffuse] = &materialProperty.getPropertySetByID(Properties::Diffuse);
-		materials[Model::ModelMat_normal] =	&materialProperty.getPropertySetByID(Properties::Normal);
-		materials[Model::ModelMat_emissive] = &materialProperty.getPropertySetByID(Properties::Emissive);
-		materials[Model::ModelMat_specular] = &materialProperty.getPropertySetByID(Properties::Specular);
-		materials[Model::ModelMat_gloss] = &materialProperty.getPropertySetByID(Properties::Gloss);
-		materials[Model::ModelMat_height] = &materialProperty.getPropertySetByID(Properties::Height);
+	if(materials.getNumPropertySets() >= CubemapFace_NumOfFaces)
+		for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+			filenames[face] = materials.getPropertySet(face).getPropertyByID(Properties::Filename).getString();
 
-		// Process all materials
-		// For every type of material
-		for(unsigned int matType = 0; matType < Model::NumOfModelMaterials; matType++)
-			// Check if material property is valid
-			if(*materials[matType])
-				// For every property set in the material property
-				for(decltype(materials[matType]->getNumPropertySets()) i = 0, size = materials[matType]->getNumPropertySets(); i < size; i++)
-					// Add the material to the new object
-					newObject->addMaterial(static_cast<Model::ModelMaterialType>(matType),
-										   materials[matType]->getPropertySet(i).getPropertyByID(Properties::Filename).getString(),
-										   materials[matType]->getPropertySet(i).getPropertyByID(Properties::Index).getInt());
+	newObject = new EnvironmentMapStatic(this,
+										 p_properties.getPropertyByID(Properties::Name).getString(),
+										 Loaders::textureCubemap().load(filenames, false));
 
-		// Get default material properties
-		// Default materials replace any missing materials from the model file
-		auto &defaultMaterials = materialProperty.getPropertySetByID(Properties::Default);
-		if(defaultMaterials)
+	// Load property data
+	for(decltype(p_properties.getNumProperties()) i = 0, size = p_properties.getNumProperties(); i < size; i++)
+	{
+		switch(p_properties[i].getPropertyID())
 		{
-			// Get individual default materials
-			const PropertySet *defaulMaterials[Model::NumOfModelMaterials];
-			defaulMaterials[Model::ModelMat_diffuse] = &defaultMaterials.getPropertySetByID(Properties::Diffuse);
-			defaulMaterials[Model::ModelMat_normal] = &defaultMaterials.getPropertySetByID(Properties::Normal);
-			defaulMaterials[Model::ModelMat_emissive] = &defaultMaterials.getPropertySetByID(Properties::Emissive);
-			defaulMaterials[Model::ModelMat_specular] = &defaultMaterials.getPropertySetByID(Properties::Specular);
-			defaulMaterials[Model::ModelMat_gloss] = &defaultMaterials.getPropertySetByID(Properties::Gloss);
-
-			// Process default materials by assigning them to the model object
-			for(unsigned int matType = 0; matType < Model::NumOfModelMaterials; matType++)
-				if(*defaulMaterials[matType])
-					newObject->m_defaultMaterials[matType] = defaulMaterials[matType]->getPropertyByID(Properties::Filename).getString();
+		case Properties::Position:
+			newObject->setPosition(p_properties[i].getVec3f());
+			break;
 		}
-
-		return nullptr;
-	}
-	// If adding a new object failed, log an error and return a nullptr
-	else
-	{
-		ErrHandlerLoc::get().log(objPoolError, ErrorSource::Source_SceneLoader);
-		return nullptr;
 	}
+
+	newObject->loadToMemory();
+	newObject->loadToVideoMemory();
+
+	m_skybox = newObject;
+
+	return newObject;
 }
 DirectionalLightObject *RendererScene::loadDirectionalLight(const PropertySet &p_properties)
 {
@@ -704,19 +686,20 @@ DirectionalLightObject *RendererScene::loadDirectionalLight(const PropertySet &p
 		switch(p_properties[i].getPropertyID())
 		{
 		case Properties::Color:
-			m_directionalLight->m_lightDataSet.m_color = p_properties[i].getVec3f();
+			m_directionalLight->setColor(p_properties[i].getVec3f());
 			break;
+
 		case Properties::Direction:
-			m_directionalLight->m_lightDataSet.m_direction = p_properties[i].getVec3f();
+			// Need to normalize the light direction
+			m_directionalLight->setDirection(Math::normalize(p_properties[i].getVec3f()));
 			break;
+
 		case Properties::Intensity:
-			m_directionalLight->m_lightDataSet.m_intensity = p_properties[i].getFloat();
+			m_directionalLight->setIntensity(p_properties[i].getFloat());
 			break;
 		}
 	}
 
-	m_directionalLight->m_lightDataSet.m_direction.normalize();
-
 	return m_directionalLight;
 }
 PointLightObject *RendererScene::loadPointLight(const PropertySet &p_properties)
@@ -740,25 +723,29 @@ PointLightObject *RendererScene::loadPointLight(const PropertySet &p_properties)
 			switch(p_properties[i].getPropertyID())
 			{
 			case Properties::Attenuation:
-				newObject->m_lightDataSet.m_attenuation = p_properties[i].getVec3f();
+				newObject->setAttenuation(p_properties[i].getVec3f());
 				break;
+
 			case Properties::Color:
-				newObject->m_lightDataSet.m_color = p_properties[i].getVec3f();
+				newObject->setColor(p_properties[i].getVec3f());
 				break;
+
 			case Properties::Intensity:
-				newObject->m_lightDataSet.m_intensity = p_properties[i].getFloat();
+				newObject->setIntensity(p_properties[i].getFloat());
 				break;
+
 			case Properties::OffsetPosition:
-				newObject->m_offsetPosition = p_properties[i].getVec3f();
+				newObject->setOffsetPosition(p_properties[i].getVec3f());
 				break;
+
 			case Properties::Position:
-				newObject->m_lightDataSet.m_position = p_properties[i].getVec3f();
+				newObject->setPosition(p_properties[i].getVec3f());
 				break;
 			}
 		}
 
 		// Adjust the position and rotation by offset
-		newObject->m_lightDataSet.m_position += newObject->m_offsetPosition;
+		newObject->setPosition(newObject->getLightDataSet().m_position + newObject->getOffsetPosition());
 	}
 	// If adding a new object failed, log an error and return a nullptr
 	else
@@ -790,37 +777,44 @@ SpotLightObject *RendererScene::loadSpotLight(const PropertySet &p_properties)
 			switch(p_properties[i].getPropertyID())
 			{
 			case Properties::Attenuation:
-				newObject->m_lightDataSet.m_attenuation = p_properties[i].getVec3f();
+				newObject->setAttenuation(p_properties[i].getVec3f());
 				break;
+
 			case Properties::CutoffAngle:
 				// Convert to radians
-				newObject->m_lightDataSet.m_cutoffAngle = cosf(Math::toRadian(p_properties[i].getFloat()));
+				newObject->setCutoffAngle(cosf(Math::toRadian(p_properties[i].getFloat())));
 				break;
+
 			case Properties::Color:
-				newObject->m_lightDataSet.m_color = p_properties[i].getVec3f();
+				newObject->setColor(p_properties[i].getVec3f());
 				break;
+
 			case Properties::Direction:
-				newObject->m_lightDataSet.m_direction = p_properties[i].getVec3f();
+				newObject->setDirection(p_properties[i].getVec3f());
 				break;
+
 			case Properties::Intensity:
-				newObject->m_lightDataSet.m_intensity = p_properties[i].getFloat();
+				newObject->setIntensity(p_properties[i].getFloat());
 				break;
+
 			case Properties::OffsetPosition:
-				newObject->m_offsetPosition = p_properties[i].getVec3f();
+				newObject->setOffsetPosition(p_properties[i].getVec3f());
 				break;
+
 			case Properties::OffsetRotation:
-				newObject->m_offsetRotation = p_properties[i].getVec3f();
+				newObject->setOffsetRotation(p_properties[i].getVec3f());
 				break;
+
 			case Properties::Position:
-				newObject->m_lightDataSet.m_position = p_properties[i].getVec3f();
+				newObject->setPosition(p_properties[i].getVec3f());
 				break;
 			}
 		}
 
 		// Adjust the position and rotation by offset (and normalize the direction)
-		newObject->m_lightDataSet.m_position += newObject->m_offsetPosition;
-		newObject->m_lightDataSet.m_direction.rotate(newObject->m_offsetRotation);
-		newObject->m_lightDataSet.m_direction.normalize();
+
+		newObject->setPosition(newObject->getLightDataSet().m_position + newObject->getOffsetPosition());
+		newObject->setDirection(Math::normalize(newObject->getLightDataSet().m_direction + newObject->getOffsetRotation()));
 	}
 	// If adding a new object failed, log an error and return a nullptr
 	else

+ 39 - 8
Praxis3D/Source/RendererScene.h

@@ -5,6 +5,7 @@
 // and creates arrays of objects to be rendered. From here, they should be sent to the renderer.
 
 #include "CameraGraphicsObject.h"
+#include "EnvironmentMapObjects.h"
 #include "GraphicsDataSets.h"
 #include "LightingGraphicsObjects.h"
 #include "Loaders.h"
@@ -22,6 +23,7 @@ struct SceneObjects
 	SceneObjects() : m_camera(nullptr) { }
 
 	const CameraObject *m_camera;
+	EnvironmentMapStatic *m_staticSkybox;
 	const DirectionalLightDataSet *m_directionalLight;
 
 	std::vector<RenderableObjectData*> m_modelObjects;
@@ -73,10 +75,10 @@ public:
 	
 private:
 	// Used to hold info on objects that are being loaded in a background thread
-	struct LoadableObjectAndIndex
+	struct LoadableGraphicsObjectAndIndex
 	{
-		LoadableObjectAndIndex() : m_loadableObject(nullptr), m_index(0), m_activateAfterLoading(true) { }
-		LoadableObjectAndIndex(LoadableGraphicsObject *p_loadableObject, size_t p_index)
+		LoadableGraphicsObjectAndIndex() : m_loadableObject(nullptr), m_index(0), m_activateAfterLoading(true) { }
+		LoadableGraphicsObjectAndIndex(LoadableGraphicsObject *p_loadableObject, size_t p_index)
 			: m_loadableObject(p_loadableObject), m_index(p_index), m_activateAfterLoading(true) { }
 
 		// The actual object that's being loaded
@@ -89,8 +91,33 @@ private:
 		size_t m_index;
 	};
 
+	struct LoadableMiscObjectAndIndex
+	{
+		LoadableMiscObjectAndIndex(EnvironmentMapStatic *p_staticEnvMap) :
+			m_miscObject(p_staticEnvMap),
+			m_objectType(MiscLoadObj_StaticEnvMap),
+			m_index(0), 
+			m_activateAfterLoading(true) { }
+
+		union MiscObject
+		{
+			MiscObject(EnvironmentMapStatic *p_staticEnvMap) : m_staticEnvMap(p_staticEnvMap) { }
+
+			EnvironmentMapStatic *m_staticEnvMap;
+		};
+
+		// This should always be true, unless object was set to be removed before loading completed
+		bool m_activateAfterLoading;
+
+		// Unique index of the object in corresponding pool (used for fast access)
+		size_t m_index;
+
+		MiscObject m_miscObject;
+		MiscLoadObjectType m_objectType;
+	};
+
 	// Removes an object from a pool, by iterating checking each pool for matched index and name
-	inline void removeObjectFromPool(LoadableObjectAndIndex *p_objectAndIndex)
+	inline void removeObjectFromPool(LoadableGraphicsObjectAndIndex *p_objectAndIndex)
 	{
 		// Remove object from the pool determined by object's type
 		switch(p_objectAndIndex->m_loadableObject->getObjectType())
@@ -112,7 +139,7 @@ private:
 	}
 	
 	// Checks if an object is allocated in an object pool
-	inline bool checkIfAllocated(const LoadableObjectAndIndex &p_objectAndIndex)
+	inline bool checkIfAllocated(const LoadableGraphicsObjectAndIndex &p_objectAndIndex)
 	{
 		// Remove object from the pool determined by object's type
 		switch(p_objectAndIndex.m_loadableObject->getObjectType())
@@ -127,7 +154,7 @@ private:
 	}
 
 	// Finds a match in the currently being loaded object array; returns null pointer if no match is found
-	inline LoadableObjectAndIndex *getCurrentlyLoadingObject(LoadableGraphicsObject *p_loadableObject)
+	inline LoadableGraphicsObjectAndIndex *getCurrentlyLoadingObject(LoadableGraphicsObject *p_loadableObject)
 	{
 		// Iterate over currently loading objects
 		for(decltype(m_objectsBeingLoaded.size()) i = 0, size = m_objectsBeingLoaded.size(); i < size;)
@@ -144,7 +171,7 @@ private:
 	// Object creators (factories)
 	ModelObject *loadModelObject(const PropertySet &p_properties);
 	CameraObject *loadCameraObject(const PropertySet &p_properties);
-	ShaderModelGraphicsObject *loadShaderModelObject(const PropertySet &p_properties);	// Obsolete (ModelObjects handle custom shaders)
+	EnvironmentMapStatic *loadEnvMapStatic(const PropertySet &p_properties);
 	DirectionalLightObject *loadDirectionalLight(const PropertySet &p_properties);
 	PointLightObject *loadPointLight(const PropertySet &p_properties);
 	SpotLightObject *loadSpotLight(const PropertySet &p_properties);
@@ -154,9 +181,13 @@ private:
 	ObjectPool<ModelObject> m_shaderObjPool;
 	ObjectPool<PointLightObject> m_pointLightPool;
 	ObjectPool<SpotLightObject> m_spotLightPool;
+	ObjectPool<EnvironmentMapStatic> m_envMapPool;
 	
 	// Stores objects that are currently being loaded to memory in background thread
-	std::vector<LoadableObjectAndIndex> m_objectsBeingLoaded;
+	std::vector<LoadableGraphicsObjectAndIndex> m_objectsBeingLoaded;
+	std::vector<LoadableMiscObjectAndIndex> m_miscObjectsBeingLoaded;
+	
+	EnvironmentMapStatic *m_skybox;
 
 	// Only one camera present at a time
 	CameraObject *m_camera;

+ 3 - 15
Praxis3D/Source/RendererSystem.cpp

@@ -5,7 +5,6 @@
 
 RendererSystem::RendererSystem()
 {
-	m_renderer = new DeferredRenderer();
 	m_rendererScene = nullptr;
 }
 
@@ -17,23 +16,12 @@ RendererSystem::~RendererSystem()
 ErrorCode RendererSystem::init()
 {
 	ErrorCode returnCode = ErrorCode::Success;
-
+	
 	// Initialize the renderer
-	ErrorCode rendererError = m_renderer->init();
+	returnCode = m_renderer.init();
 
 	// Check if the renderer initialization was successful
-	// If it failed, assign a new null renderer
-	if(rendererError != ErrorCode::Success)
-	{
-		ErrHandlerLoc::get().log(rendererError);
-
-		// Delete the failed renderer and assign the base class as a null renderer
-		// It will not draw anything on screen, but the rest of the engine will still work,
-		// if the error type for this error code wasn't set to fatal (for example when debugging)
-		delete m_renderer;
-		m_renderer = new Renderer();
-	}
-	else
+	if(returnCode == ErrorCode::Success)
 	{
 		ErrHandlerLoc::get().log(ErrorType::Info, ErrorSource::Source_Renderer, "Renderer has been initialized");
 	}

+ 3 - 3
Praxis3D/Source/RendererSystem.h

@@ -1,7 +1,7 @@
 #pragma once
 
-#include "DeferredRenderer.h"
 #include "Loaders.h"
+#include "RendererFrontend.h"
 #include "System.h"
 
 class RendererScene;
@@ -28,10 +28,10 @@ public:
 
 	virtual SystemScene *getScene();
 
-	Renderer *getRenderer() { return m_renderer; }
+	RendererFrontend &getRenderer() { return m_renderer; }
 
 protected:
-	Renderer *m_renderer;
+	RendererFrontend m_renderer;
 	RendererScene *m_rendererScene;
 };
 

+ 72 - 89
Praxis3D/Source/SceneLoader.cpp

@@ -7,122 +7,105 @@
 
 ErrorCode SceneLoader::loadFromFile(const std::string &p_filename)
 {
-	if(!p_filename.empty())
-	{
-		m_filename = p_filename;
+	// Load properties from file
+	PropertyLoader loadedProperties(Config::filepathVar().map_path + p_filename);
+	ErrorCode loaderError = loadedProperties.loadFromFile();
 
-		// Load properties from file
-		PropertyLoader loadedProperties(Config::filepathVar().map_path + m_filename);
-		ErrorCode loaderError = loadedProperties.loadFromFile();
+	// Check if loading was successful, return an error, if not
+	if(loaderError != ErrorCode::Success)
+		return loaderError;
 
-		// Check if loading was successful, return an error, if not
-		if(loaderError != ErrorCode::Success)
-			return loaderError;
+	std::vector<std::pair<const std::string&, SystemObject*>> createdObjects;
 
-		// Get systems property set
-		auto &systemProperties = loadedProperties.getPropertySet().getPropertySetByID(Properties::Systems);
+	// Get systems property set
+	auto &systemProperties = loadedProperties.getPropertySet().getPropertySetByID(Properties::Systems);
 
-		// Iterate over each system property set
-		for(decltype(systemProperties.getNumPropertySets()) propIndex = 0, propSize = systemProperties.getNumPropertySets(); propIndex < propSize; propIndex++)
+	// Iterate over each system property set
+	for(decltype(systemProperties.getNumPropertySets()) propIndex = 0, propSize = systemProperties.getNumPropertySets(); propIndex < propSize; propIndex++)
+	{
+		// Iterate over all systems scenes
+		for(int sysIndex = 0; sysIndex < Systems::NumberOfSystems; sysIndex++)
 		{
-			// Iterate over all systems scenes
-			for(int sysIndex = 0; sysIndex < Systems::NumberOfSystems; sysIndex++)
+			// If system scene name and property set name match
+			if(Systems::SystemNames[m_systemScenes[sysIndex]->getSystemType()]
+			   == GetString(systemProperties.getPropertySetUnsafe(propIndex).getPropertyID()))
 			{
-				// If system scene name and property set name match
-				if(Systems::SystemNames[m_systemScenes[sysIndex]->getSystemType()]
-				   == GetString(systemProperties.getPropertySetUnsafe(propIndex).getPropertyID()))
-				{
-					// Pass the 'scene' property set to the matched system scene
-					m_systemScenes[sysIndex]->setup(systemProperties.getPropertySetUnsafe(propIndex).getPropertySetByID(Properties::Scene));
+				// Pass the 'scene' property set to the matched system scene
+				m_systemScenes[sysIndex]->setup(systemProperties.getPropertySetUnsafe(propIndex).getPropertySetByID(Properties::Scene));
 
-					// Get 'objects' property set
-					auto &objectProperties = systemProperties.getPropertySetUnsafe(propIndex).getPropertySetByID(Properties::Objects);
+				// Get 'objects' property set
+				auto &objectProperties = systemProperties.getPropertySetUnsafe(propIndex).getPropertySetByID(Properties::Objects);
 
-					// Iterate over all object property sets
-					for(decltype(objectProperties.getNumPropertySets()) objIndex = 0, objSize = objectProperties.getNumPropertySets(); objIndex < objSize; objIndex++)
-					{
-						// Create a new system object (by pasting the object property set)
-						auto *newObject = m_systemScenes[sysIndex]->createObject(objectProperties.getPropertySetUnsafe(objIndex));
+				// Iterate over all object property sets
+				for(decltype(objectProperties.getNumPropertySets()) objIndex = 0, objSize = objectProperties.getNumPropertySets(); objIndex < objSize; objIndex++)
+				{
+					// Create a new system object (by pasting the object property set)
+					auto *newObject = m_systemScenes[sysIndex]->createObject(objectProperties.getPropertySetUnsafe(objIndex));
 
-						// Save the newly created object for later linking
-						m_createdObjects[sysIndex].push_back(std::pair<const std::string&, SystemObject*>(newObject->getName(), newObject));
-					}
+					// Save the newly created object for later linking
+					createdObjects.push_back(std::pair<const std::string&, SystemObject*>(newObject->getName(), newObject));
 				}
 			}
 		}
+	}
 
-		// Get the object link property sets
-		auto &objLinkProperties = loadedProperties.getPropertySet().getPropertySetByID(Properties::ObjectLinks);
+	// Get the object link property sets
+	auto &objLinkProperties = loadedProperties.getPropertySet().getPropertySetByID(Properties::ObjectLinks);
 
-		// Iterate over all object link property sets
-		for(decltype(objLinkProperties.getNumPropertySets()) linkIndex = 0, linkSize = objLinkProperties.getNumPropertySets(); linkIndex < linkSize; linkIndex++)
+	// Iterate over all object link property sets
+	for(decltype(objLinkProperties.getNumPropertySets()) linkIndex = 0, linkSize = objLinkProperties.getNumPropertySets(); linkIndex < linkSize; linkIndex++)
+	{
+		// Get subject name
+		const auto &subjectName = objLinkProperties.getPropertySetUnsafe(linkIndex).getPropertyByID(Properties::Subject).getString();
+		if(subjectName.empty()) // Make sure subject's name is not empty
+			continue;
+
+		// Get observer name
+		const auto &observerName = objLinkProperties.getPropertySetUnsafe(linkIndex).getPropertyByID(Properties::Observer).getString();
+		if(observerName.empty()) // Make sure observer's name is not empty
+			continue;
+
+		// Iterate over created objects and match subject's name
+		for(decltype(createdObjects.size()) subjIndex = 0, subjSize = createdObjects.size(); subjIndex < subjSize; subjIndex++)
 		{
-			// Get subject name
-			const auto &subjectName = objLinkProperties.getPropertySetUnsafe(linkIndex).getPropertyByID(Properties::Subject).getString();
-			if(subjectName.empty()) // Make sure subject's name is not empty
-				continue;
-
-			// Get observer name
-			const auto &observerName = objLinkProperties.getPropertySetUnsafe(linkIndex).getPropertyByID(Properties::Observer).getString();
-			if(observerName.empty()) // Make sure observer's name is not empty
-				continue;
-
-			// Iterate over created objects and match subject's name
-			for(int subjSysIndex = 0; subjSysIndex < Systems::NumberOfSystems; subjSysIndex++)
+			// Compare subject name
+			if(createdObjects[subjIndex].first == subjectName)
 			{
-				for(decltype(m_createdObjects[subjSysIndex].size()) subjIndex = 0, subjSize = m_createdObjects[subjSysIndex].size(); subjIndex < subjSize; subjIndex++)
+				// Iterate over created objects and match observer's name
+				for(decltype(createdObjects.size()) observIndex = 0, observSize = createdObjects.size(); observIndex < observSize; observIndex++)
 				{
-					// Compare subject name
-					if(m_createdObjects[subjSysIndex][subjIndex].first == subjectName)
+					// Compare observer name
+					if(createdObjects[observIndex].first == observerName)
 					{
-						// Iterate over created objects and match observer's name
-						for(int observSysIndex = 0; observSysIndex < Systems::NumberOfSystems; observSysIndex++)
-						{
-							for(decltype(m_createdObjects[observSysIndex].size()) observIndex = 0, observSize = m_createdObjects[observSysIndex].size(); observIndex < observSize; observIndex++)
-							{
-								// Compare observer name
-								if(m_createdObjects[observSysIndex][observIndex].first == observerName)
-								{
-									// Create object link between subject and observer in the change controller
-									m_changeController->createObjectLink(m_createdObjects[subjSysIndex][subjIndex].second, m_createdObjects[observSysIndex][observIndex].second);
-
-									// Exit the inner loop
-									break;
-								}
-							}
-						}
-
-						// Exit the outer loop
+						// Create object link between subject and observer in the change controller
+						m_changeController->createObjectLink(createdObjects[subjIndex].second, createdObjects[observIndex].second);
+						
+						// Exit the inner loop
 						break;
 					}
 				}
-			}
-		}
-
-		// Get flag telling if the objects should be loaded in parallel
-		m_loadInBackground = loadedProperties.getPropertySet().getPropertyByID(Properties::LoadInBackground).getBool();
 
-		// If the objects should be loaded in background threads
-		if(m_loadInBackground)
-		{
-			// Start loading in background threads in all scenes
-			for(int i = 0; i < Systems::NumberOfSystems; i++)
-				m_systemScenes[i]->loadInBackground();
-		}
-		else
-		{
-			// Preload all scenes sequentially
-			for(int i = 0; i < Systems::NumberOfSystems; i++)
-				m_systemScenes[i]->preload();
+				// Exit the outer loop
+				break;
+			}
 		}
+	}
 
-		ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_PropertyLoader, "Map file has been loaded: " + m_filename);
 
-		return ErrorCode::Success;
+	if(loadedProperties.getPropertySet().getPropertyByID(Properties::LoadInBackground).getBool())
+	{
+		// Start loading in background threads in all scenes
+		for(int i = 0; i < Systems::NumberOfSystems; i++)
+			m_systemScenes[i]->loadInBackground();
+	}
+	else
+	{
+		// Preload all scenes sequentially
+		for(int i = 0; i < Systems::NumberOfSystems; i++)
+			m_systemScenes[i]->preload();
 	}
 
-	// TODO ERROR empty filename
-	return ErrorCode::Failure;
+	return ErrorCode::Success;
 }
 
 ErrorCode SceneLoader::saveToFile(const std::string p_filename)

+ 6 - 0
Praxis3D/Source/ScriptingScene.cpp

@@ -189,12 +189,18 @@ FreeCamera *ScriptingScene::loadFreeCamera(const PropertySet & p_properties)
 		case Properties::Angle:
 			freeCamera->setAngles(p_properties[i].getVec2f());
 			break;
+		case Properties::LowerLimit:
+			freeCamera->setLowerLimit(p_properties[i].getFloat());
+			break;
 		case Properties::Speed:
 			freeCamera->setSpeed(p_properties[i].getFloat());
 			break;
 		case Properties::SprintSpeed:
 			freeCamera->setFasterSpeed(p_properties[i].getFloat());
 			break;
+		case Properties::UpperLimit:
+			freeCamera->setUpperLimit(p_properties[i].getFloat());
+			break;
 		}
 	}
 

+ 3 - 3
Praxis3D/Source/ShaderGraphicsObjects.h

@@ -44,14 +44,14 @@ public:
 		ErrorCode error;
 
 		// Load shader, check if it loaded successfully
-		if(!ErrHandlerLoc::get().ifSuccessful(m_shader->loadToVideoMemory(), error))
-		{
+		//if(!ErrHandlerLoc::get().ifSuccessful(m_shader->loadToVideoMemory(), error))
+		//{
 			// Log an error on failure
 			ErrHandlerLoc::get().log(error);
 
 			// Replace the shader with a default one
 			m_shader = Loaders::shader().load();
-		}
+		//}
 
 		// Load all other data by calling parent class; log an error on failure
 		if(!ErrHandlerLoc::get().ifSuccessful(ModelObject::loadToVideoMemory(), error))

+ 14 - 533
Praxis3D/Source/ShaderLoader.cpp

@@ -5,359 +5,6 @@
 #include "ShaderUniformUpdater.h"
 #include "Utilities.h"
 
-/*
-ShaderLoader::ShaderProgram::BaseShader()
-{
-	m_loaded = false;
-	m_fileName = "";
-	m_programHandle = 0;
-	m_uniformUpdater = nullptr;
-}
-ShaderLoader::ShaderProgram::BaseShader(const std::string &p_filename) : BaseShader()
-{
-	m_fileName = p_filename;
-}
-ShaderLoader::ShaderProgram::~BaseShader()
-{
-	glDeleteProgram(m_programHandle);
-
-	if(m_uniformUpdater != nullptr)
-		delete m_uniformUpdater;
-}
-
-ErrorCode ShaderLoader::ShaderProgram::loadToVideoMemory()
-{
-	// Proceed only if it hasn't been loaded already
-	if(!m_loaded)
-	{
-		m_loaded = true;
-		//m_uniformUpdater = new ShaderUniformUpdater(*this);
-	}
-	return ErrorCode::Success;
-}
-
-ErrorCode ShaderLoader::ShaderProgram::loadFromFile(const std::string &p_fileName, std::string &p_source)
-{
-	p_source = "";
-
-	// Load shader's source code from a file
-	std::ifstream sourceStream(Config::PathsVariables().shader_path + p_fileName, std::ios::in);
-
-	// Check if it was loaded successfully
-	if(sourceStream.is_open())
-	{
-		std::string singleLine = "";
-		while(std::getline(sourceStream, singleLine))
-			p_source += "\n" + singleLine;
-
-		sourceStream.close();
-	}
-	else
-	{
-		ErrHandlerLoc::get().log(ErrorCode::Ifstream_failed, ErrorSource::Source_ShaderLoader, p_fileName);
-		return ErrorCode::Ifstream_failed;
-	}
-
-	return ErrorCode::Success;
-}
-ErrorCode ShaderLoader::ShaderProgram::compileFromSource(GLuint p_shaderHandle, const std::string &p_shaderSource)
-{
-	ErrorCode returnError = ErrorCode::Success;
-
-	// Pass shader source code and compile it
-	const char *shaderSource = p_shaderSource.c_str();
-	glShaderSource(p_shaderHandle, 1, &shaderSource, NULL);
-	glCompileShader(p_shaderHandle);
-
-	// Check for shader compilation errors
-	GLint shaderCompileResult = 0;
-	glGetShaderiv(p_shaderHandle, GL_COMPILE_STATUS, &shaderCompileResult);
-	if(!shaderCompileResult)
-	{
-		// Assign an error
-		returnError = ErrorCode::Shader_compile_failed;
-
-		int shaderCompileLogLength;
-		glGetShaderiv(p_shaderHandle, GL_INFO_LOG_LENGTH, &shaderCompileLogLength);
-
-		// Get the actual error message
-		std::vector<char> shaderCompileErrorMessage(shaderCompileLogLength);
-		glGetShaderInfoLog(p_shaderHandle, shaderCompileLogLength, NULL, &shaderCompileErrorMessage[0]);
-
-		// Convert vector of chars to a string
-		std::string errorMessageTemp;
-		for(int i = 0; shaderCompileErrorMessage[i]; i++)
-			errorMessageTemp += shaderCompileErrorMessage[i];
-
-		// Log an error with a shader info log
-		ErrHandlerLoc::get().log(returnError, ErrorSource::Source_ShaderLoader, errorMessageTemp);
-	}
-
-	return returnError;
-}
-ErrorCode ShaderLoader::ShaderProgram::attachShader(GLuint p_shaderHandle)
-{
-	// Attach shader to the program handle
-	glAttachShader(m_programHandle, p_shaderHandle);
-
-	// Check for errors
-	GLenum glError = glGetError();
-	if(glError != GL_NO_ERROR)
-	{
-		// Log an error and pass a filename
-		ErrHandlerLoc::get().log(ErrorCode::Shader_attach_failed, ErrorSource::Source_ShaderLoader, 
-								 Utilities::toString(glError) + " | Filename - " + getFileName());
-		return ErrorCode::Shader_attach_failed;
-	}
-
-	return ErrorCode::Success;
-}
-ErrorCode ShaderLoader::ShaderProgram::linkProgram()
-{
-	GLint shaderLinkingResult;
-	glLinkProgram(m_programHandle);
-
-	// Check for linking errors. If an error has occured, get the error message and throw an exception
-	glGetProgramiv(m_programHandle, GL_LINK_STATUS, &shaderLinkingResult);
-	if(!shaderLinkingResult)
-	{
-		int shaderLinkLogLength = 0;
-		std::string errorMessageTemp = "Couldn't retrieve the error";
-		glGetShaderiv(m_programHandle, GL_INFO_LOG_LENGTH, &shaderLinkLogLength);
-
-		// Sometimes opengl cannot retrieve the error string, so check that just in case
-		if(shaderLinkLogLength > 0)
-		{
-			// Get the actual error message
-			std::vector<char> shaderLinkErrorMessage(shaderLinkLogLength);
-			glGetShaderInfoLog(m_programHandle, shaderLinkLogLength, NULL, &shaderLinkErrorMessage[0]);
-
-			// Convert vector of chars to a string
-			for(int i = 0; shaderLinkErrorMessage[i]; i++)
-				errorMessageTemp += shaderLinkErrorMessage[i];
-		}
-
-		// Log an error and pass shader info log
-		ErrHandlerLoc::get().log(ErrorCode::Shader_link_failed, ErrorSource::Source_ShaderLoader, errorMessageTemp);
-		return ErrorCode::Shader_link_failed;
-	}
-
-	return ErrorCode::Success;
-}
-
-ShaderLoader::VertFragShader::VertFragShader(const std::string &p_vertexShaderFileName, const std::string &p_fragmentShaderFileName)
-	: m_vertFileName(p_vertexShaderFileName), m_fragFileName(p_fragmentShaderFileName)
-{
-	// Create the uniform updater
-	//m_uniformUpdater = new ShaderUniformUpdater(*this);
-}
-ShaderLoader::VertFragShader::~VertFragShader()
-{
-
-}
-
-ErrorCode ShaderLoader::VertFragShader::loadToVideoMemory()
-{
-	ErrorCode returnError = ErrorCode::Success;
-
-	// Proceed only if it hasn't been loaded already
-	if(!m_loaded)
-	{
-		m_loaded = true;
-
-		// Shader name is made by combining individual filenames separated by a comma and a space
-		m_fileName = m_vertFileName + ", " + m_fragFileName;
-
-		// Create shader program handle
-		m_programHandle = glCreateProgram();
-
-		// Create shader handles
-		m_vertShaderHandle = glCreateShader(GL_VERTEX_SHADER);
-		m_fragShaderHandle = glCreateShader(GL_FRAGMENT_SHADER);
-
-		// Check for errors
-		GLenum glError = glGetError();
-		if(glError != GL_NO_ERROR)
-		{
-			returnError = ErrorCode::Shader_creation_failed;
-			ErrHandlerLoc::get().log(returnError, ErrorSource::Source_ShaderLoader, Utilities::toString(glError) + " | Filename - " + getFileName());
-		}
-		else
-		{
-			std::string shaderSource;
-
-			// Parse vertex shader source code from file and check for errors
-			if(ErrHandlerLoc::get().ifSuccessful(loadFromFile(m_vertFileName, shaderSource), returnError))
-			{
-				// Compile vertex shader and check for errors
-				if(ErrHandlerLoc::get().ifSuccessful(compileFromSource(m_vertShaderHandle, shaderSource), returnError))
-				{
-					// Attach vertex shader to the shader program
-					if(ErrHandlerLoc::get().ifSuccessful(attachShader(m_vertShaderHandle), returnError))
-					{
-						// Parse fragment shader source code from file and check for errors
-						if(ErrHandlerLoc::get().ifSuccessful(loadFromFile(m_fragFileName, shaderSource), returnError))
-						{
-							// Compile fragment shader and check for errors
-							if(ErrHandlerLoc::get().ifSuccessful(compileFromSource(m_fragShaderHandle, shaderSource), returnError))
-							{
-								// Attach fragment shader to the shader program
-								if(ErrHandlerLoc::get().ifSuccessful(attachShader(m_fragShaderHandle), returnError))
-								{
-									returnError = linkProgram();
-								}
-							}
-						}
-					}
-				}
-			}
-
-			// Log an error if it occurred
-			if(returnError != ErrorCode::Success)
-				ErrHandlerLoc::get().log(returnError, ErrorSource::Source_ShaderLoader);
-			else
-			{
-				// Generate the uniform updater and check if it was successful
-				if(ErrHandlerLoc::get().ifSuccessful(m_uniformUpdater->generateUpdateList(), returnError))
-					ErrHandlerLoc::get().log(ErrorType::Info, ErrorSource::Source_ShaderLoader,
-											 "Vertex (" + m_vertFileName + ") and Fragment (" + m_fragFileName + ") shaders were loaded successfully");
-				else
-					ErrHandlerLoc::get().log(returnError, ErrorSource::Source_ShaderLoader);
-			}
-		}
-	}
-
-	return returnError;
-}
-ErrorCode ShaderLoader::VertFragShader::releaseShaderHandles()
-{
-	// Delete compiled shaders (usually linking them to the shader program)
-	glDeleteShader(m_vertShaderHandle);
-	glDeleteShader(m_fragShaderHandle);
-
-	return ErrorCode::Success;
-}
-
-ShaderLoader::GeomVertFragShader::GeomVertFragShader(const std::string &p_geometryShaderFileName, const std::string &p_vertexShaderFileName, const std::string &p_fragmentShaderFileName)
-	: VertFragShader(p_vertexShaderFileName, p_fragmentShaderFileName), m_geomFileName(p_geometryShaderFileName)
-{
-
-}
-ShaderLoader::GeomVertFragShader::~GeomVertFragShader()
-{
-
-}
-
-ErrorCode ShaderLoader::GeomVertFragShader::loadToVideoMemory()
-{
-	ErrorCode returnError = ErrorCode::Success;
-
-	// Proceed only if it hasn't been loaded already
-	if(!m_loaded)
-	{
-		m_loaded = true;
-
-		// Shader name is made by combining individual filenames separated by a comma and a space
-		m_fileName = m_geomFileName + ", " + m_vertFileName + ", " + m_fragFileName;
-
-		// Create shader program handle
-		m_programHandle = glCreateProgram();
-
-		// Create shader handles
-		m_vertShaderHandle = glCreateShader(GL_VERTEX_SHADER);
-		m_fragShaderHandle = glCreateShader(GL_FRAGMENT_SHADER);
-		m_geomShaderHandle = glCreateShader(GL_GEOMETRY_SHADER);
-
-		// Check for errors
-		GLenum glError = glGetError();
-		if(glError != GL_NO_ERROR)
-		{
-			returnError = ErrorCode::Shader_creation_failed;
-			ErrHandlerLoc::get().log(returnError, ErrorSource::Source_ShaderLoader, glError + " | Filename - " + getFileName());
-		}
-		else
-		{
-			std::string shaderSource;
-
-			//
-			// GEOMETRY SHADER
-			// _______________________________________________________________
-			// Parse geometry shader source code from file and check for errors
-			if(ErrHandlerLoc::get().ifSuccessful(loadFromFile(m_geomFileName, shaderSource), returnError))
-			{
-				// Compile geometry shader and check for errors
-				if(ErrHandlerLoc::get().ifSuccessful(compileFromSource(m_geomShaderHandle, shaderSource), returnError))
-				{
-					// Attach geometry shader to the shader program
-					if(ErrHandlerLoc::get().ifSuccessful(attachShader(m_geomShaderHandle), returnError))
-					{
-
-						//
-						// VERTEX SHADER
-						// _____________________________________________________________
-						// Parse vertex shader source code from file and check for errors
-						if(ErrHandlerLoc::get().ifSuccessful(loadFromFile(m_vertFileName, shaderSource), returnError))
-						{
-							// Compile vertex shader and check for errors
-							if(ErrHandlerLoc::get().ifSuccessful(compileFromSource(m_vertShaderHandle, shaderSource), returnError))
-							{
-								// Attach vertex shader to the shader program
-								if(ErrHandlerLoc::get().ifSuccessful(attachShader(m_vertShaderHandle), returnError))
-								{
-
-									//
-									// FRAMGENT SHADER
-									// _______________________________________________________________
-									// Parse fragment shader source code from file and check for errors
-									if(ErrHandlerLoc::get().ifSuccessful(loadFromFile(m_fragFileName, shaderSource), returnError))
-									{
-										// Compile fragment shader and check for errors
-										if(ErrHandlerLoc::get().ifSuccessful(compileFromSource(m_fragShaderHandle, shaderSource), returnError))
-										{
-											// Attach fragment shader to the shader program
-											if(ErrHandlerLoc::get().ifSuccessful(attachShader(m_fragShaderHandle), returnError))
-											{
-												returnError = linkProgram();
-											}
-										}
-									}
-								}
-							}
-						}
-					}
-				}
-			}
-
-			// Log an error if it occurred
-			if(returnError != ErrorCode::Success)
-				ErrHandlerLoc::get().log(returnError, ErrorSource::Source_ShaderLoader);
-			else
-			{
-				// Create the uniform updater
-				//m_uniformUpdater = new ShaderUniformUpdater(*this);
-
-				// Generate the uniform updater and check if it was successful
-				if(ErrHandlerLoc::get().ifSuccessful(m_uniformUpdater->generateUpdateList(), returnError))
-					ErrHandlerLoc::get().log(ErrorType::Info, ErrorSource::Source_ShaderLoader,
-											 "Geometry (" + m_geomFileName + "), Vertex (" + m_vertFileName + ") and Fragment (" + m_fragFileName + ") shaders were loaded successfully");
-				else
-					ErrHandlerLoc::get().log(returnError, ErrorSource::Source_ShaderLoader);
-			}
-		}
-	}
-	return returnError;
-}
-ErrorCode ShaderLoader::GeomVertFragShader::releaseShaderHandles()
-{
-	// Delete compiled shaders (usually linking them to the shader program)
-	glDeleteShader(m_geomShaderHandle);
-	glDeleteShader(m_vertShaderHandle);
-	glDeleteShader(m_fragShaderHandle);
-
-	return ErrorCode::Success;
-}
-*/
-
 unsigned int ShaderLoader::ShaderProgram::m_defaultProgramHandle = 0;
 
 ShaderLoader::ShaderLoader()
@@ -378,7 +25,6 @@ ErrorCode ShaderLoader::init()
 {
 	// Initialize default shader program
 	m_defaultProgram.loadToMemory();
-	m_defaultProgram.loadToVideoMemory();
 
 	// Reserve space in the program pool, to speed up push_backs
 	m_shaderPrograms.reserve(Config::rendererVar().shader_pool_size);
@@ -393,7 +39,7 @@ ShaderLoader::ShaderProgram *ShaderLoader::load(const PropertySet &p_properties)
 	if(p_properties)
 	{
 		// Create shader filename array
-		std::string shaderFilename[ArrayNumOfTypes];
+		std::string shaderFilename[ShaderType_NumOfTypes];
 		std::string programName;
 
 		// Iterate over all passed properties
@@ -406,23 +52,23 @@ ShaderLoader::ShaderProgram *ShaderLoader::load(const PropertySet &p_properties)
 				break;
 
 			case Properties::FragmentShader:
-				shaderFilename[ArrayFragment] = p_properties[i].getString();
+				shaderFilename[ShaderType_Fragment] = p_properties[i].getString();
 				break;
 
 			case Properties::VertexShader:
-				shaderFilename[ArrayVertex] = p_properties[i].getString();
+				shaderFilename[ShaderType_Vertex] = p_properties[i].getString();
 				break;
 
 			case Properties::GeometryShader:
-				shaderFilename[ArrayGeometry] = p_properties[i].getString();
+				shaderFilename[ShaderType_Geometry] = p_properties[i].getString();
 				break;
 
 			case Properties::TessControlShader:
-				shaderFilename[ArrayTessControl] = p_properties[i].getString();
+				shaderFilename[ShaderType_TessControl] = p_properties[i].getString();
 				break;
 
 			case Properties::TessEvaluationShader:
-				shaderFilename[ArrayTessEvaluation] = p_properties[i].getString();
+				shaderFilename[ShaderType_TessEvaluation] = p_properties[i].getString();
 				break;
 			}
 		}
@@ -431,7 +77,7 @@ ShaderLoader::ShaderProgram *ShaderLoader::load(const PropertySet &p_properties)
 		if(programName.empty())
 		{
 			// For every shader filename, if it's not empty, add it to the program name
-			for(unsigned int shaderType = 0; shaderType < ArrayNumOfTypes; shaderType++)
+			for(unsigned int shaderType = 0; shaderType < ShaderType_NumOfTypes; shaderType++)
 				if(!shaderFilename[shaderType].empty())
 					programName += shaderFilename[shaderType] + ", ";
 
@@ -454,7 +100,7 @@ ShaderLoader::ShaderProgram *ShaderLoader::load(const PropertySet &p_properties)
 		// Iterate over all shader programs and match hash key and name; if match is found, return it
 		for(decltype(m_shaderPrograms.size()) i = 0, size = m_shaderPrograms.size(); i < size; i++)
 			if(m_shaderPrograms[i].m_filenameHash == programHashkey)
-				if(m_shaderPrograms[i].m_filename == programName)
+				if(m_shaderPrograms[i].m_combinedFilename == programName)
 					return &m_shaderPrograms[i];
 
 		// Add the new program to the array
@@ -462,181 +108,16 @@ ShaderLoader::ShaderProgram *ShaderLoader::load(const PropertySet &p_properties)
 		ShaderProgram *newProgram = &m_shaderPrograms[m_shaderPrograms.size() - 1];
 
 		// Iterate over shader types
-		for(unsigned int shaderType = 0; shaderType < ArrayNumOfTypes; shaderType++)
+		for(unsigned int shaderType = 0; shaderType < ShaderType_NumOfTypes; shaderType++)
 			// If shader filename is valid
 			if(!shaderFilename[shaderType].empty())
-				newProgram->addShader(static_cast<ShaderArrayTypes>(shaderType), shaderFilename[shaderType]);
+				newProgram->addShader(static_cast<ShaderType>(shaderType), shaderFilename[shaderType]);
+
+		// Create a uniform updater for the new shader
+		newProgram->m_uniformUpdater = new ShaderUniformUpdater(*newProgram);
 
 		return newProgram;
 	}
 
 	return &m_defaultProgram;
-
-		/*/ Iterate over shader types
-		for(unsigned int shaderType = 0; shaderType < ArrayNumOfTypes; shaderType++)
-		{
-			// If shader filename is valid
-			if(!shaderFilename[shaderType].empty())
-			{
-				// Calculate a filename hash key
-				unsigned int hashkey = Utilities::getHashKey(shaderFilename[shaderType]);
-
-				// Iterate over all shaders of this type; if hash key and filename matches, add it to the new program
-				for(decltype(m_shaders[shaderType].size()) i = 0, size = m_shaders[shaderType].size(); i < size; i++)
-					if(m_shaders[shaderType][i].m_filenameHash == hashkey)
-						if(m_shaders[shaderType][i].m_filename == shaderFilename[shaderType])
-							newProgram->addShader(m_shaders[shaderType][i]);
-			}
-		}
-
-		newProgram->loadToMemory();
-
-		unsigned int fragHashkey = Utilities::getHashKey(fragFilename);
-
-		for(decltype(m_fragmentShaders.size()) i = 0, size = m_fragmentShaders.size(); i < size; i++)
-			if(m_fragmentShaders[i].m_filenameHash == fragHashkey)
-				if(m_fragmentShaders[i].m_filename == fragFilename)
-					return;
-	}
-
-	return nullptr;*/
-}
-/*
-ShaderLoader::ShaderProgram *ShaderLoader::load(const std::string &p_vertexShaderFileName, const std::string &p_fragmentShaderFileName)
-{
-	// If any of the filenames are empty, return default shader
-	if(p_vertexShaderFileName.empty() || p_fragmentShaderFileName.empty())
-		return &m_defaultShader;
-
-	// Shader name is made by combining individual filenames separated by a comma and a space
-	std::string shaderName = p_vertexShaderFileName + ", " + p_fragmentShaderFileName;
-	
-	// Halt concurrency before starting the search in the shader pool
-	SpinWait::Lock lock(m_vertFragMutex);
-
-	// Iterate over all shaders, compare names, if they match, return it (so no duplicates are loaded)
-	for(decltype(m_vertFragShaders.size()) i = 0, size = m_vertFragShaders.size(); i < size; i++)
-		if(m_vertFragShaders[i]->getFileName() == shaderName)
-			return m_vertFragShaders[i];
-
-	// Create new vertex / fragment shader
-	BaseShader *returnShader = new VertFragShader(p_vertexShaderFileName, p_fragmentShaderFileName);
-	
-	m_vertFragShaders.push_back(returnShader);
-
-	return returnShader;
-}
-ShaderLoader::ShaderProgram *ShaderLoader::load(const std::string &p_geometryShaderFileName, const std::string &p_vertexShaderFileName, const std::string &p_fragmentShaderFileName)
-{
-	// If geometry shader filename is empty, try to load a vertex-fragment shader instead
-	if(p_geometryShaderFileName.empty())
-		return load(p_vertexShaderFileName, p_fragmentShaderFileName);
-
-	// If any of the filenames are empty, return default shader
-	if(p_vertexShaderFileName.empty() || p_fragmentShaderFileName.empty())
-		return &m_defaultShader;
-
-	// Shader name is made by combining individual filenames separated by a comma and a space
-	std::string shaderName = p_geometryShaderFileName + ", " + p_vertexShaderFileName + ", " + p_fragmentShaderFileName;
-
-	// Halt concurrency before starting the search in the shader pool
-	SpinWait::Lock lock(m_geomMutex);
-
-	// Iterate over all shaders, compare names, if they match, return it (so no duplicates are loaded)
-	for(decltype(m_geomShaders.size()) i = 0, size = m_geomShaders.size(); i < size; i++)
-		if(m_geomShaders[i]->getFileName() == shaderName)
-			return m_geomShaders[i];
-
-	// Create new geometry / vertex / fragment shader
-	BaseShader *returnShader = new GeomVertFragShader(p_geometryShaderFileName, p_vertexShaderFileName, p_fragmentShaderFileName);
-
-	m_geomShaders.push_back(returnShader);
-
-	return returnShader;
-}
-*/
-
-ErrorCode ShaderLoader::ShaderProgram::loadToVideoMemory()
-{
-	ErrorCode individualError = ErrorCode::Success;
-	ErrorCode returnError = ErrorCode::Success;
-
-	if(!m_loadedToVideoMemory)
-	{
-		m_loadedToVideoMemory = true;
-		bool shadersPresent = false;
-
-		// Create shader program handle
-		m_programHandle = glCreateProgram();
-
-		// Iterate over all shaders and load them to video memory
-		for(unsigned int i = 0; i < ShaderNumOfTypes; i++)
-		{
-			// If shader is valid
-			if(m_shaders[i] != nullptr)
-			{
-				// Load to video memory
-				individualError = m_shaders[i]->loadToVideoMemory();
-
-				// If it was successful, attach the shader
-				if(individualError == ErrorCode::Success)
-				{
-					attachShader(m_shaders[i]);
-					shadersPresent = true;
-				}
-				else
-					returnError = individualError;
-			}
-		}
-
-		if(shadersPresent)
-		{
-			GLint shaderLinkingResult;
-			glLinkProgram(m_programHandle);
-
-			// Check for linking errors. If an error has occurred, get the error message and throw an exception
-			glGetProgramiv(m_programHandle, GL_LINK_STATUS, &shaderLinkingResult);
-
-			if(!shaderLinkingResult)
-			{
-				GLsizei shaderLinkLogLength = 0;
-				std::string errorMessageTemp = "Couldn't retrieve the error";
-				glGetShaderiv(m_programHandle, GL_INFO_LOG_LENGTH, &shaderLinkLogLength);
-
-				// Sometimes OpenGL cannot retrieve the error string, so check that just in case
-				if(shaderLinkLogLength > 0)
-				{
-					// Get the actual error message
-					std::vector<char> shaderLinkErrorMessage(shaderLinkLogLength);
-					glGetShaderInfoLog(m_programHandle, shaderLinkLogLength, NULL, &shaderLinkErrorMessage[0]);
-
-					// Convert vector of chars to a string
-					for(int i = 0; shaderLinkErrorMessage[i]; i++)
-						errorMessageTemp += shaderLinkErrorMessage[i];
-				}
-
-				// Log an error and pass shader info log
-				returnError = ErrorCode::Shader_link_failed;
-				ErrHandlerLoc::get().log(returnError, ErrorSource::Source_ShaderLoader, errorMessageTemp);
-			}
-
-			// Iterate over all shaders and detach them
-			for(unsigned int i = 0; i < ShaderNumOfTypes; i++)
-			{
-				// If shader is valid
-				if(m_shaders[i] != nullptr)
-				{
-					glDetachShader(m_programHandle, m_shaders[i]->m_shaderHandle);
-					//delete m_shaders[i];
-				}
-			}
-
-			// Create the uniform updater
-			m_uniformUpdater = new ShaderUniformUpdater(*this);
-			m_uniformUpdater->generateUpdateList();
-		}
-		else
-			m_uniformUpdater = new ShaderUniformUpdater(*this);
-	}
-	return returnError;
-}
+}

+ 73 - 95
Praxis3D/Source/ShaderLoader.h

@@ -7,6 +7,7 @@
 #include <sstream>
 #include <string>
 
+#include "CommonDefinitions.h"
 #include "ErrorCodes.h"
 #include "PropertySet.h"
 #include "SpinWait.h"
@@ -16,31 +17,22 @@ class ShaderUniformUpdater;
 class ShaderLoader
 {
 	friend class ShaderProgram;
-public:
-	enum ShaderType : unsigned int
-	{
-		ShaderNull = 0,
-		ShaderFragment = GL_FRAGMENT_SHADER,
-		ShaderGeometry = GL_GEOMETRY_SHADER,
-		ShaderVertex = GL_VERTEX_SHADER,
-		ShaderTessControl = GL_TESS_CONTROL_SHADER,
-		ShaderTessEvaluation = GL_TESS_EVALUATION_SHADER,
-		ShaderNumOfTypes = 5
-	};
-
-	enum ShaderArrayTypes : unsigned int
-	{
-		ArrayFragment,
-		ArrayGeometry,
-		ArrayVertex,
-		ArrayTessControl,
-		ArrayTessEvaluation,
-		ArrayNumOfTypes = ShaderNumOfTypes
-	};
 public:
 	class Shader
 	{
 		friend class ShaderLoader;
+	private:
+		enum ShaderType : unsigned int
+		{
+			ShaderNull = 0,
+			ShaderFragment,
+			ShaderGeometry,
+			ShaderVertex,
+			ShaderTessControl,
+			ShaderTessEvaluation,
+			ShaderNumOfTypes = 5
+		};
+
 	public:
 		Shader(const std::string &p_filename, const ShaderType p_shaderType)
 		{
@@ -71,7 +63,7 @@ public:
 				}
 				else
 				{
-					ErrHandlerLoc::get().log(ErrorCode::Ifstream_failed, ErrorSource::Source_ShaderLoader, m_filename);
+					ErrHandlerLoc::get().log(ErrorCode::Ifstream_failed, ErrorSource::Source_ShaderLoader, "(Filename - \"" + m_filename + "\"): ");
 					return ErrorCode::Ifstream_failed;
 				}
 			}
@@ -80,6 +72,9 @@ public:
 		}
 		inline ErrorCode loadToVideoMemory()
 		{
+			// Clear error queue
+			glGetError();
+
 			// Create a shader handle
 			m_shaderHandle = glCreateShader(m_shaderType);
 
@@ -87,7 +82,7 @@ public:
 			GLenum glError = glGetError();
 			if(glError != GL_NO_ERROR)
 			{
-				ErrHandlerLoc::get().log(Shader_creation_failed, ErrorSource::Source_ShaderLoader, Utilities::toString(glError) + " | Filename - " + m_filename);
+				ErrHandlerLoc::get().log(Shader_creation_failed, ErrorSource::Source_ShaderLoader, "(Filename - \"" + m_filename + "\"): " + Utilities::toString(glError));
 				return ErrorCode::Shader_creation_failed;
 			}
 			else
@@ -121,7 +116,7 @@ public:
 						errorMessageTemp += shaderCompileErrorMessage[i];
 
 					// Log an error with a shader info log
-					ErrHandlerLoc::get().log(ErrorCode::Shader_compile_failed, ErrorSource::Source_ShaderLoader, errorMessageTemp);
+					ErrHandlerLoc::get().log(ErrorCode::Shader_compile_failed, ErrorSource::Source_ShaderLoader, "(Filename - \"" + m_filename + "\"): " + errorMessageTemp);
 					return ErrorCode::Shader_compile_failed;
 				}
 			}
@@ -147,9 +142,11 @@ public:
 	};
 	class ShaderProgram
 	{
+		friend class CommandBuffer;
 		friend class ShaderLoader;
+		friend class RendererFrontend;
 	public:
-		inline void addShader(Shader *p_shader)
+		/*inline void addShader(Shader *p_shader)
 		{
 			if(p_shader != nullptr)
 			{
@@ -200,53 +197,69 @@ public:
 					break;
 				}
 			}
-		}
+		}*/
 
-		inline void bind() { glUseProgram(m_programHandle); }
+		inline void addShader(ShaderType p_shaderType, const std::string &p_filename)
+		{
+			m_shaderFilename[p_shaderType] = p_filename;
+		}
 
 		// Loads shader source code to memory
 		inline ErrorCode loadToMemory()
 		{
-			ErrorCode individualError = ErrorCode::Success;
 			ErrorCode returnError = ErrorCode::Success;
 
+			// Check if the shader hasn't been already loaded
 			if(!m_loadedToMemory)
 			{
 				m_loadedToMemory = true;
+				m_defaultShader = true;
 
-				// Iterate over all shaders and load them to memory
-				for(unsigned int i = 0; i < ShaderNumOfTypes; i++)
+				for(unsigned int i = 0; i < ShaderType_NumOfTypes; i++)
 				{
-					// If shader is valid
-					if(m_shaders[i] != nullptr)
+					if(!m_shaderFilename[i].empty())
 					{
-						// Load to memory
-						individualError = m_shaders[i]->loadToMemory();
-
-						// If it failed, assign a return error
-						if(individualError != ErrorCode::Success)
-							returnError = individualError;
+						// Load shader's source code from a file
+						std::ifstream sourceStream(Config::PathsVariables().shader_path + m_shaderFilename[i], std::ios::in);
+
+						// Check if it was loaded successfully
+						if(sourceStream.is_open())
+						{
+							std::string singleLine = "";
+							while(std::getline(sourceStream, singleLine))
+								m_shaderSource[i] += "\n" + singleLine;
+
+							sourceStream.close();
+
+							m_defaultShader = false;
+						}
+						else
+						{
+							ErrHandlerLoc::get().log(ErrorCode::Ifstream_failed, ErrorSource::Source_ShaderLoader, "(Filename - \"" + m_shaderFilename[i] + "\"): ");
+							
+							// TODO Check if error works without exiting from here
+							//return ErrorCode::Ifstream_failed;
+							returnError = ErrorCode::Ifstream_failed;
+						}
 					}
 				}
 			}
 
 			return returnError;
 		}
-		// Compile and attach, shaders, create and link program, populate uniform updaters
-		ErrorCode loadToVideoMemory();
 
 		// Returns true if the program contains any tessellation shaders
 		const inline bool isTessellated() const { return m_tessellated; }
 
 		// Getters
-		const inline std::string &getFilename() const { return m_filename; }
+		const inline std::string &getCombinedFilename() const { return m_combinedFilename; }
 		const inline unsigned int getShaderHandle() const { return m_programHandle; }
-		const inline ShaderUniformUpdater &getUniformUpdater() const { return *m_uniformUpdater; }
-
-		const inline bool isDefaultProgram() const { return m_programHandle == m_defaultProgramHandle; }
+		inline ShaderUniformUpdater &getUniformUpdater() const { return *m_uniformUpdater; }
 
+		const inline bool isDefaultProgram() const { return m_defaultShader; }
+		
 		// Comparator operators
-		const inline bool operator==(const std::string &p_filename) const { return (m_filename == p_filename); }
+		const inline bool operator==(const std::string &p_filename) const { return (m_combinedFilename == p_filename); }
 		const inline bool operator==(const unsigned int p_programHandle) const { return (m_programHandle == p_programHandle); }
 		const inline bool operator==(const ShaderProgram &p_shaderProgram) const { return (m_filenameHash == p_shaderProgram.m_filenameHash); }
 	
@@ -254,8 +267,8 @@ public:
 		const inline bool shaderPresent(const unsigned int p_shaderType)
 		{
 			// Check if the shader type passed is valid (in bounds) and return true if the shader is not null
-			if(p_shaderType >= 0 && p_shaderType < ShaderNumOfTypes)
-				return (m_shaders[p_shaderType] != nullptr);
+			//if(p_shaderType >= 0 && p_shaderType < ShaderType_NumOfTypes)
+			//	return (m_shaders[p_shaderType] != nullptr);
 
 			return false;
 		}
@@ -264,10 +277,10 @@ public:
 		const inline std::string getShaderFilename(const unsigned int p_shaderType)
 		{
 			// Check if the shader type passed is valid (in bounds)
-			if(p_shaderType >= 0 && p_shaderType < ShaderNumOfTypes + 1)
+			//if(p_shaderType >= 0 && p_shaderType < ShaderType_NumOfTypes + 1)
 				// If the shader is valid, return its filename, otherwise return an empty string
-				if(m_shaders[p_shaderType] != nullptr)
-					return m_shaders[p_shaderType]->getFilename();
+				//if(m_shaders[p_shaderType] != nullptr)
+				//	return m_shaders[p_shaderType]->getFilename();
 
 			return std::string();
 		}
@@ -276,43 +289,28 @@ public:
 		// Constructors aren't public, to allow them to be created only by the ShaderLoader class (makes it act as a factory)
 		ShaderProgram(const std::string &p_filename = "", unsigned int p_filenameHashkey = 0)
 		{
-			m_filename = p_filename;
+			m_combinedFilename = p_filename;
 			m_filenameHash = p_filenameHashkey > 0 ? p_filenameHashkey : Utilities::getHashKey(p_filename);
 			m_tessellated = false;
+			m_defaultShader = false;
 			m_loadedToMemory = false;
 			m_loadedToVideoMemory = false;
 			m_programHandle = 0;
 			m_uniformUpdater = nullptr;
-
-			for(unsigned int i = 0; i < ShaderNumOfTypes; i++)
-				m_shaders[i] = nullptr;
 		}
-		inline ErrorCode attachShader(Shader *p_shader)
-		{
-			// Attach shader to the program handle
-			glAttachShader(m_programHandle, p_shader->m_shaderHandle);
 
-			// Check for errors
-			GLenum glError = glGetError();
-			if(glError != GL_NO_ERROR)
-			{
-				// Log an error and pass a filename
-				ErrHandlerLoc::get().log(ErrorCode::Shader_attach_failed, ErrorSource::Source_ShaderLoader,
-										 Utilities::toString(glError) + " | Filename - " + p_shader->m_filename);
-				return ErrorCode::Shader_attach_failed;
-			}
-
-			return ErrorCode::Success;
-		}
-
-		bool	m_loadedToMemory,
+		bool	m_defaultShader, 
+				m_loadedToMemory,
 				m_loadedToVideoMemory,
 				m_tessellated;
 
-		std::string m_filename;
+		std::string m_combinedFilename;
+		std::string m_shaderFilename[ShaderType_NumOfTypes];
+		std::string m_shaderSource[ShaderType_NumOfTypes];
+		ErrorMessage m_errorMessages[ShaderType_NumOfTypes];
+
 		unsigned int m_filenameHash;
 		unsigned int m_programHandle;
-		Shader *m_shaders[ShaderNumOfTypes];
 
 		ShaderUniformUpdater *m_uniformUpdater;
 		
@@ -330,34 +328,14 @@ public:
 	inline ShaderProgram *load() { return &m_defaultProgram; }
 	ShaderProgram *load(const PropertySet &p_properties);
 
-	// Returns a default (empty) shader
-	//BaseShader *load() { return &m_defaultShader; }
-	//BaseShader *load(const std::string &p_vertexShaderFileName, const std::string &p_fragmentShaderFileName);
-	//BaseShader *load(const std::string &p_geometryShaderFileName, const std::string &p_vertexShaderFileName, const std::string &p_fragmentShaderFileName);
-
 private:
 	SpinWait	m_vertFragMutex,
 				m_geomMutex;
 
-	//BaseShader m_defaultShader;
 	ShaderProgram m_defaultProgram;
-
-	//std::vector<BaseShader*> m_vertFragShaders;
-	//std::vector<BaseShader*> m_geomShaders;
-
+	
 	// Mutex used to block calls from other threads while operation is in progress
 	SpinWait m_mutex;
 
-	//std::vector<Shader> m_shaders[ArrayNumOfTypes];
 	std::vector<ShaderProgram> m_shaderPrograms;
-
-	// Assign shader types, so they could be resolved from array type; order dependent
-	/*const static ShaderType m_shaderTypes[ArrayNumOfTypes] =
-	{
-		ShaderFragment,
-		ShaderGeometry,
-		ShaderVertex,
-		ShaderTessControl,
-		ShaderTessEvaluation
-	};*/
 };

+ 45 - 13
Praxis3D/Source/ShaderUniformUpdater.cpp

@@ -1,7 +1,12 @@
 
 #include "ErrorHandlerLocator.h"
+#include "ShaderUniforms.h"
 #include "ShaderUniformUpdater.h"
 
+const UniformObjectData ShaderUniformUpdater::m_defaultObjectData;
+const UniformFrameData ShaderUniformUpdater::m_defaultFrameData;
+const UniformData ShaderUniformUpdater::m_defaultUniformData = UniformData(ShaderUniformUpdater::m_defaultObjectData, ShaderUniformUpdater::m_defaultFrameData);
+
 ErrorCode ShaderUniformUpdater::generateUpdateList()
 {
 	ErrorCode returnError = ErrorCode::Success;
@@ -13,15 +18,17 @@ ErrorCode ShaderUniformUpdater::generateUpdateList()
 	returnError = generatePerFrameList();
 	returnError = generatePerModelList();
 	returnError = generatePerMeshList();
+	returnError = generateUniformBlockList();
 
 	m_numUpdatesPerFrame = m_updatesPerFrame.size();
 	m_numUpdatesPerModel = m_updatesPerModel.size();
 	m_numUpdatesPerMesh = m_updatesPerMesh.size();
 	m_numTextureUpdates = m_textureUpdates.size();
+	m_numUniformBlockUpdates = m_uniformBlockUpdates.size();
 
 	// Check for errors, and cache it if it exists, since we are returning the error to higher layer
 	if(returnError != ErrorCode::Success)
-		ErrHandlerLoc::get().log(returnError, ErrorSource::Source_ShaderLoader, m_shader.getFilename());
+		ErrHandlerLoc::get().log(returnError, ErrorSource::Source_ShaderLoader, m_shader.getCombinedFilename());
 
 	return returnError;
 }
@@ -34,26 +41,30 @@ ErrorCode ShaderUniformUpdater::generateTextureUpdateList()
 	std::vector<BaseUniform*> uniformList;
 
 	// Framebuffer texture uniforms
-	uniformList.push_back(new PositionBufferUniform(m_shaderHandle));
-	uniformList.push_back(new DiffuseBufferUniform(m_shaderHandle));
-	uniformList.push_back(new NormalBufferUniform(m_shaderHandle));
-	uniformList.push_back(new EmissiveBufferUniform(m_shaderHandle));
-	uniformList.push_back(new BlurBufferUniform(m_shaderHandle));
-
+	uniformList.push_back(new PositionMapUniform(m_shaderHandle));
+	uniformList.push_back(new DiffuseMapUniform(m_shaderHandle));
+	uniformList.push_back(new NormalMapUniform(m_shaderHandle));
+	uniformList.push_back(new EmissiveMapUniform(m_shaderHandle));
+	uniformList.push_back(new MatPropertiesMapUniform(m_shaderHandle));
+	uniformList.push_back(new BlurMapUniform(m_shaderHandle));
+	uniformList.push_back(new FinalMapUniform(m_shaderHandle));
+
+	// Cubemap texture uniforms
+	uniformList.push_back(new DynamicEnvironmentMapUniform(m_shaderHandle));
+	uniformList.push_back(new StaticEnvironmentMapUniform(m_shaderHandle));
+	
 	// Skydome texture uniforms
 	uniformList.push_back(new SunGlowTextureUniform(m_shaderHandle));
 	uniformList.push_back(new SkyMapTextureUniform(m_shaderHandle));
 
-	// Shadow map deph texture uniforms
+	// Shadow map depth texture uniforms
 	uniformList.push_back(new DirShadowMapTextureUniform(m_shaderHandle));
 
 	// Geometry pass textures
 	uniformList.push_back(new DiffuseTextureUniform(m_shaderHandle));
 	uniformList.push_back(new NormalTextureUniform(m_shaderHandle));
-	uniformList.push_back(new SpecularTextureUniform(m_shaderHandle));
 	uniformList.push_back(new EmissiveTextureUniform(m_shaderHandle));
-	uniformList.push_back(new GlossTextureUniform(m_shaderHandle));
-	uniformList.push_back(new HeightTextureUniform(m_shaderHandle));
+	uniformList.push_back(new CombinedTextureUniform(m_shaderHandle));
 	
 	// Go through each uniform and check if it is valid
 	// If it is, add it to the update list, if not, delete it
@@ -102,7 +113,6 @@ ErrorCode ShaderUniformUpdater::generatePerFrameList()
 	// Misc
 	uniformList.push_back(new ElapsedTimeUniform(m_shaderHandle));
 	uniformList.push_back(new GammaUniform(m_shaderHandle));
-	uniformList.push_back(new ParallaxHeightScaleUniform(m_shaderHandle));
 
 	// Go through each uniform and check if it is valid
 	// If it is, add it to the update list, if not, delete it
@@ -134,6 +144,7 @@ ErrorCode ShaderUniformUpdater::generatePerModelList()
 	uniformList.push_back(new AlphaCullingUniform(m_shaderHandle));
 	uniformList.push_back(new AlphaThresholdUniform(m_shaderHandle));
 	uniformList.push_back(new EmissiveThresholdUniform(m_shaderHandle));
+	uniformList.push_back(new HeightScaleUniform(m_shaderHandle));
 	uniformList.push_back(new TextureTilingFactorUniform(m_shaderHandle));
 
 	// Test uniforms, used for debugging, etc
@@ -154,4 +165,25 @@ ErrorCode ShaderUniformUpdater::generatePerModelList()
 ErrorCode ShaderUniformUpdater::generatePerMeshList()
 {
 	return ErrorCode::Success;
-}
+}
+ErrorCode ShaderUniformUpdater::generateUniformBlockList()
+{
+	ErrorCode returnError = ErrorCode::Success;
+
+	// Make a vector of uniform classes and populate it
+	std::vector<BaseUniformBlock*> uniformBlockList;
+
+	// Light buffers
+	uniformBlockList.push_back(new PointLightBufferUniform(m_shaderHandle));
+	uniformBlockList.push_back(new SpotLightBufferUniform(m_shaderHandle));
+
+	// Go through each uniform and check if it is valid
+	// If it is, add it to the update list, if not, delete it
+	for(decltype(uniformBlockList.size()) i = 0, size = uniformBlockList.size(); i < size; i++)
+		if(uniformBlockList[i]->isValid())
+			m_uniformBlockUpdates.push_back(uniformBlockList[i]);
+		else
+			delete uniformBlockList[i];
+
+	return returnError;
+}

+ 45 - 20
Praxis3D/Source/ShaderUniformUpdater.h

@@ -4,16 +4,23 @@
 #include "ShaderLoader.h"
 #include "ShaderUniforms.h"
 
+//class BaseUniform;
+//class BaseUniformBlock;
+
+// Automatically generates arrays of available uniforms in the specific shader
+// All uniforms are updates through this class
+// Should only be accessible by the renderer backend, since this class deals directly with GPU
 class ShaderUniformUpdater
 {
+	friend class RendererBackend;
 public:
-	//ShaderUniformUpdater(unsigned int p_shaderHandle) : m_shaderHandle(p_shaderHandle) { }
 	ShaderUniformUpdater(ShaderLoader::ShaderProgram &p_shader) : m_shader(p_shader)
 	{
 		m_numUpdatesPerFrame = 0;
 		m_numUpdatesPerModel = 0;
 		m_numUpdatesPerMesh = 0;
 		m_numTextureUpdates = 0;
+		m_numUniformBlockUpdates = 0;
 	}
 	~ShaderUniformUpdater()
 	{
@@ -21,57 +28,75 @@ public:
 		m_updatesPerModel.clear();
 		m_updatesPerMesh.clear();
 		m_textureUpdates.clear();
+		m_uniformBlockUpdates.clear();
 	}
 
+	inline size_t getNumUpdatesPerFrame() const	{ return m_numUpdatesPerFrame;		}
+	inline size_t getNumUpdatesPerModel() const { return m_numUpdatesPerModel;		}
+	inline size_t getNumUpdatesPerMesh() const	{ return m_numUpdatesPerMesh;		}
+	inline size_t getNumTextureUpdates() const	{ return m_numTextureUpdates;		}
+	inline size_t getNumUniformBlocks() const	{ return m_numUniformBlockUpdates;	}
+
+private:
 	// Checks which uniforms are used in the shader, and generates a list of valid ones
 	ErrorCode generateUpdateList();
 
 	// Should be called once per frame
-	const inline void updateFrame(RendererState &p_rendererState) const
+	const inline void updateFrame(const UniformData &p_uniformData = m_defaultUniformData) const
 	{
-		for(decltype(m_updatesPerFrame.size()) i = 0, size = m_updatesPerFrame.size(); i < size; i++)
-			m_updatesPerFrame[i]->update(p_rendererState);
+		for(decltype(m_numUpdatesPerFrame) i = 0; i < m_numUpdatesPerFrame; i++)
+			m_updatesPerFrame[i]->update(p_uniformData);
 	}
 	// Should be called once per model
-	const inline void updateModel(RendererState &p_rendererState) const
+	const inline void updateModel(const UniformData &p_uniformData = m_defaultUniformData) const
 	{
-		for(decltype(m_updatesPerModel.size()) i = 0, size = m_updatesPerModel.size(); i < size; i++)
-			m_updatesPerModel[i]->update(p_rendererState);
+		for(decltype(m_numUpdatesPerModel) i = 0; i < m_numUpdatesPerModel; i++)
+			m_updatesPerModel[i]->update(p_uniformData);
 	}
 	// Should be called once per mesh
-	const inline void updateMesh(RendererState &p_rendererState) const
+	const inline void updateMesh(const UniformData &p_uniformData = m_defaultUniformData) const
 	{
-		for(decltype(m_updatesPerMesh.size()) i = 0, size = m_updatesPerMesh.size(); i < size; i++)
-			m_updatesPerMesh[i]->update(p_rendererState);
+		for(decltype(m_numUpdatesPerMesh) i = 0; i < m_numUpdatesPerMesh; i++)
+			m_updatesPerMesh[i]->update(p_uniformData);
 	}
 	// Should be called when texture handles need updating
-	const inline void updateTextureUniforms(RendererState &p_rendererState) const
+	const inline void updateTextureUniforms(const UniformData &p_uniformData = m_defaultUniformData) const
 	{
-		for(decltype(m_textureUpdates.size()) i = 0, size = m_textureUpdates.size(); i < size; i++)
-			m_textureUpdates[i]->update(p_rendererState);
+		for(decltype(m_numTextureUpdates) i = 0; i < m_numTextureUpdates; i++)
+			m_textureUpdates[i]->update(p_uniformData);
+	}
+	// Should never be called, unless a binding point for a uniform block has changed
+	// (Does not update the data in the uniform block, only updates the binding point)
+	const inline void updateBlockBindingPoints(const UniformData &p_uniformData = m_defaultUniformData) const
+	{
+		for(decltype(m_numUniformBlockUpdates) i = 0; i < m_numUniformBlockUpdates; i++)
+			m_uniformBlockUpdates[i]->update(p_uniformData);
 	}
 
-	inline size_t getNumUpdatesPerFrame() const	{ return m_numUpdatesPerFrame;	}
-	inline size_t getNumUpdatesPerModel() const { return m_numUpdatesPerModel;	}
-	inline size_t getNumUpdatesPerMesh() const	{ return m_numUpdatesPerMesh;	}
-	inline size_t getNumTextureUpdates() const	{ return m_numTextureUpdates;	}
-
-private:
 	ErrorCode generateTextureUpdateList();
 	ErrorCode generatePerFrameList();
 	ErrorCode generatePerModelList();
 	ErrorCode generatePerMeshList();
+	ErrorCode generateUniformBlockList();
 
 	std::vector<BaseUniform*>	m_updatesPerFrame,
 								m_updatesPerModel,
 								m_updatesPerMesh,
 								m_textureUpdates;
 
+	std::vector<BaseUniformBlock*> m_uniformBlockUpdates;
+
 	size_t	m_numUpdatesPerFrame,
 			m_numUpdatesPerModel,
 			m_numUpdatesPerMesh,
-			m_numTextureUpdates;
+			m_numTextureUpdates,
+			m_numUniformBlockUpdates;
 
 	unsigned int m_shaderHandle;
 	ShaderLoader::ShaderProgram &m_shader;
+
+	// (Quick, but safe hack) Used to enable calling uniform updates without any arguments
+	const static UniformObjectData m_defaultObjectData;
+	const static UniformFrameData m_defaultFrameData;
+	const static UniformData m_defaultUniformData;
 };

+ 292 - 234
Praxis3D/Source/ShaderUniforms.h

@@ -3,8 +3,11 @@
 #include <GL/glew.h>
 #include <string>
 
+#include "ClockLocator.h"
+#include "CommonDefinitions.h"
 #include "Config.h"
-#include "Renderer.h"
+#include "GeometryBuffer.h"
+#include "UniformData.h"
 
 // A class (derived from BaseUniform) per each uniform in a shader.
 // Designed to be adaptive, and update all the uniforms that are being used in a shader.
@@ -13,28 +16,67 @@
 class BaseUniform
 {
 public:
-	BaseUniform(std::string p_name, unsigned int p_shaderHandle) : m_name(p_name)
+	BaseUniform(const std::string &p_name, const unsigned int p_shaderHandle) : m_name(p_name)
 	{
+		// Get uniform location (returns -1 in case it is not present in the shader)
 		m_uniformHandle = glGetUniformLocation(p_shaderHandle, p_name.c_str());
 	}
 
-	const inline bool isValid() { return (m_uniformHandle != -1); }
+	// Returns true if the uniform is present in the shader
+	const inline bool isValid() const { return (m_uniformHandle != -1); }
 
-	virtual void update(RendererState &p_rendererState) = 0;
+	// Updates the uniform
+	virtual void update(const UniformData &p_uniformData) = 0;
 
 protected:
-	std::string m_name;
+	const std::string m_name;
 	unsigned int m_uniformHandle;
 };
+class BaseUniformBlock
+{
+public:
+	BaseUniformBlock(const std::string &p_name, const unsigned int p_shaderHandle)
+		: m_name(p_name), m_shaderHandle(p_shaderHandle)
+	{
+		// Get the uniform location (returns -1 in case it is not present in the shader)
+		m_uniformHandle = glGetUniformBlockIndex(m_shaderHandle, p_name.c_str());
+	}
+
+	// Returns true if the uniform is present in the shader
+	const inline bool isValid() const { return (m_uniformHandle != -1); }
+	const inline int getBlockSize() const 
+	{ 
+		int blockSize = 0;
+
+		// Get the uniform block size
+		glGetActiveUniformBlockiv(m_shaderHandle, m_uniformHandle, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
+
+		return blockSize;
+	}
+
+	// Updates the uniform block binding index
+	virtual void update(const UniformData &p_uniformData) = 0;
+
+protected:
+	const inline void updateBlockBinding(const unsigned int p_bindingPoint) const
+	{
+		// Bind the uniform buffer at the specified binding point
+		glUniformBlockBinding(m_shaderHandle, m_uniformHandle, p_bindingPoint);
+	}
+
+	const std::string m_name;
+	unsigned int m_uniformHandle;
+	const unsigned int m_shaderHandle;
+};
 
 class ModelMatUniform : public BaseUniform
 {
 public:
 	ModelMatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().modelMatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getModelMatrix().m[0]);
+		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.m_objectData.m_modelMat.m[0]);
 	}
 };
 class ViewMatUniform : public BaseUniform
@@ -42,9 +84,9 @@ class ViewMatUniform : public BaseUniform
 public:
 	ViewMatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().viewMatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getViewMatrix().m[0]);
+		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.m_frameData.m_viewMatrix.m[0]);
 	}
 };
 class ProjectionMatUniform : public BaseUniform
@@ -52,9 +94,9 @@ class ProjectionMatUniform : public BaseUniform
 public:
 	ProjectionMatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().projectionMatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getProjectionMatrix().m[0]);
+		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.m_frameData.m_projMatrix.m[0]);
 	}
 };
 class ViewProjectionMatUniform : public BaseUniform
@@ -62,9 +104,9 @@ class ViewProjectionMatUniform : public BaseUniform
 public:
 	ViewProjectionMatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().viewProjectionMatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getViewProjMatrix().m[0]);
+		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.m_frameData.m_viewProjMatrix.m[0]);
 	}
 };
 class ModelViewMatUniform : public BaseUniform
@@ -72,9 +114,12 @@ class ModelViewMatUniform : public BaseUniform
 public:
 	ModelViewMatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().modelViewMatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getModelViewMatrix().m[0]);
+		// TODO
+		// Quick hack, for convenience when testing, should not be used, because it's slow
+		Math::Mat4f modelViewMat = p_uniformData.m_frameData.m_viewMatrix * p_uniformData.m_objectData.m_modelMat;
+		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &modelViewMat.m[0]);
 	}
 };
 class ModelViewProjectionMatUniform : public BaseUniform
@@ -82,9 +127,13 @@ class ModelViewProjectionMatUniform : public BaseUniform
 public:
 	ModelViewProjectionMatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().modelViewProjectionMatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getModelViewProjMatrix().m[0]);
+		// TODO
+		// Quick hack, for convenience when testing, should not be used, because it's slow
+		Math::Mat4f MVP = p_uniformData.m_frameData.m_projMatrix * p_uniformData.m_frameData.m_viewMatrix * p_uniformData.m_objectData.m_modelMat;
+		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &MVP.m[0]);
+		//glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.m_objectData.m_modelViewProjMatrix.m[0]);
 	}
 };
 
@@ -93,10 +142,11 @@ class ScreenSizeUniform : public BaseUniform
 public:
 	ScreenSizeUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().screenSizeUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		auto &screenSize = p_rendererState.getScreenSize();
-		glUniform2i(m_uniformHandle, screenSize.x, screenSize.y);
+		glUniform2i(m_uniformHandle, 
+					p_uniformData.m_frameData.m_screenSize.x, 
+					p_uniformData.m_frameData.m_screenSize.y);
 	}
 };
 class ElapsedTimeUniform : public BaseUniform
@@ -104,9 +154,9 @@ class ElapsedTimeUniform : public BaseUniform
 public:
 	ElapsedTimeUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().elapsedTimeUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1f(m_uniformHandle, p_rendererState.getElapsedTime());
+		glUniform1f(m_uniformHandle, ClockLocator::get().getElapsedSecondsF());
 	}
 };
 class GammaUniform : public BaseUniform
@@ -114,7 +164,7 @@ class GammaUniform : public BaseUniform
 public:
 	GammaUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().gammaUniform, p_shaderHandle), m_currentGamma(0.0f) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
 		// Gamma will rarely be modified, so checking two floats will be faster than updating a uniform
 		if(m_currentGamma != Config::graphicsVar().gamma)
@@ -132,11 +182,9 @@ class AlphaCullingUniform : public BaseUniform
 public:
 	AlphaCullingUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().alphaCullingUniform, p_shaderHandle), m_currentCullingState(false) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		float alphaThreshold = p_rendererState.getAlphaThreshold();
-
-		bool state = p_rendererState.getAlphaThreshold() > 0.0 ? true : false;
+		bool state = p_uniformData.m_objectData.m_alphaThreshold > 0.0 ? true : false;
 
 		if(m_currentCullingState != state)
 		{
@@ -157,15 +205,14 @@ class AlphaThresholdUniform : public BaseUniform
 public:
 	AlphaThresholdUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().alphaThresholdUniform, p_shaderHandle), m_currentAlphaThreshold(-1.0) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		float alphaThreshold = p_rendererState.getAlphaThreshold();
-
-		if(m_currentAlphaThreshold != alphaThreshold)
+		// Check if the same value is not already assigned (a small optimization)
+		if(m_currentAlphaThreshold != p_uniformData.m_objectData.m_alphaThreshold)
 		{
-			glUniform1f(m_uniformHandle, alphaThreshold);
+			m_currentAlphaThreshold = p_uniformData.m_objectData.m_alphaThreshold;
 
-			m_currentAlphaThreshold = alphaThreshold;
+			glUniform1f(m_uniformHandle, m_currentAlphaThreshold);
 		}
 	}
 
@@ -177,31 +224,31 @@ class EmissiveThresholdUniform : public BaseUniform
 public:
 	EmissiveThresholdUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().emissiveThresholdUniform, p_shaderHandle), m_currentEmissiveThreshold(-1.0) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		float emissiveThreshold = p_rendererState.getEmissiveThreshold();
-
-		if(m_currentEmissiveThreshold != emissiveThreshold)
+		// Check if the same value is not already assigned (a small optimization)
+		if(m_currentEmissiveThreshold != p_uniformData.m_objectData.m_emissiveThreshold)
 		{
-			glUniform1f(m_uniformHandle, emissiveThreshold);
+			m_currentEmissiveThreshold = p_uniformData.m_objectData.m_emissiveThreshold;
 
-			m_currentEmissiveThreshold = emissiveThreshold;
+			glUniform1f(m_uniformHandle, m_currentEmissiveThreshold);
 		}
 	}
 
 private:
 	float m_currentEmissiveThreshold;
 };
-class ParallaxHeightScaleUniform : public BaseUniform
+class HeightScaleUniform : public BaseUniform
 {
 public:
-	ParallaxHeightScaleUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().parallaxHeightScale, p_shaderHandle), m_currentHeightScale(-1.0) { }
+	HeightScaleUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().heightScaleUniform, p_shaderHandle), m_currentHeightScale(-1.0) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		if(m_currentHeightScale != Config::graphicsVar().parallax_height_scale)
+		// Check if the same value is not already assigned (a small optimization)
+		if(m_currentHeightScale != p_uniformData.m_objectData.m_heightScale)
 		{
-			m_currentHeightScale = Config::graphicsVar().parallax_height_scale;
+			m_currentHeightScale = p_uniformData.m_objectData.m_heightScale;
 
 			glUniform1f(m_uniformHandle, m_currentHeightScale);
 		}
@@ -215,15 +262,14 @@ class TextureTilingFactorUniform : public BaseUniform
 public:
 	TextureTilingFactorUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().textureTilingFactorUniform, p_shaderHandle), m_currentTexTillingFactor(0.0) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		float texTilingFactor = p_rendererState.getTextureTilingFactor();
-
-		if(m_currentTexTillingFactor != texTilingFactor)
+		// Check if the same value is not already assigned (a small optimization)
+		if(m_currentTexTillingFactor != p_uniformData.m_objectData.m_textureTilingFactor)
 		{
-			glUniform1f(m_uniformHandle, texTilingFactor);
+			m_currentTexTillingFactor = p_uniformData.m_objectData.m_textureTilingFactor;
 
-			m_currentTexTillingFactor = texTilingFactor;
+			glUniform1f(m_uniformHandle, m_currentTexTillingFactor);
 		}
 	}
 
@@ -236,10 +282,10 @@ class DirLightColorUniform : public BaseUniform
 public:
 	DirLightColorUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().dirLightColor, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		auto &cameraPosVec = p_rendererState.getDirLightColor();
-		glUniform3f(m_uniformHandle, cameraPosVec.x, cameraPosVec.y, cameraPosVec.z);
+		auto &dirLightColor = p_uniformData.m_frameData.m_dirLightColor;
+		glUniform3f(m_uniformHandle, dirLightColor.x, dirLightColor.y, dirLightColor.z);
 	}
 };
 class DirLightDirectionUniform : public BaseUniform
@@ -247,12 +293,10 @@ class DirLightDirectionUniform : public BaseUniform
 public:
 	DirLightDirectionUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().dirLightDirection, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		auto cameraPosVec = p_rendererState.getDirLightDirection();
-		// Normalize the direction here one per frame instead of once per fragment in the shader
-		cameraPosVec.normalize();
-		glUniform3f(m_uniformHandle, cameraPosVec.x, cameraPosVec.y, cameraPosVec.z);
+		auto lightDirection = p_uniformData.m_frameData.m_dirLightDirection;
+		glUniform3f(m_uniformHandle, lightDirection.x, lightDirection.y, lightDirection.z);
 	}
 };
 class DirLightIntensityUniform : public BaseUniform
@@ -260,9 +304,9 @@ class DirLightIntensityUniform : public BaseUniform
 public:
 	DirLightIntensityUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().dirLightIntensity, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1f(m_uniformHandle, p_rendererState.getDirLightintensity());
+		glUniform1f(m_uniformHandle, p_uniformData.m_frameData.m_dirLightIntensity);
 	}
 };
 class NumPointLightsUniform : public BaseUniform
@@ -270,9 +314,9 @@ class NumPointLightsUniform : public BaseUniform
 public:
 	NumPointLightsUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().numPointLightsUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getNumPointLights());
+		glUniform1i(m_uniformHandle, p_uniformData.m_frameData.m_numPointLights);
 	}
 };
 class NumSpotLightsUniform : public BaseUniform
@@ -280,60 +324,60 @@ class NumSpotLightsUniform : public BaseUniform
 public:
 	NumSpotLightsUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().numSpotLightsUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getNumSpotLights());
+		glUniform1i(m_uniformHandle, p_uniformData.m_frameData.m_numSpotLights);
 	}
 };
-class PointLightViewProjectionMatUniform : public BaseUniform
+/* Unused */ class PointLightViewProjectionMatUniform : public BaseUniform
 {
 public:
 	PointLightViewProjectionMatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().pointLightViewProjectionMatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getModelViewProjMatrix().m[0]);
+		//glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.getModelViewProjMatrix().m[0]);
 	}
 };
-class SpotLightViewProjectionMatUniform : public BaseUniform
+/* Unused */ class SpotLightViewProjectionMatUniform : public BaseUniform
 {
 public:
 	SpotLightViewProjectionMatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().spotLightViewProjectionMatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getModelViewProjMatrix().m[0]);
+		//glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.getModelViewProjMatrix().m[0]);
 	}
 };
-class StencilPassViewProjectionMatUniform : public BaseUniform
+/* Unused */ class StencilPassViewProjectionMatUniform : public BaseUniform
 {
 public:
 	StencilPassViewProjectionMatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().stencilPassViewProjectionMatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getModelViewProjMatrix().m[0]);
+		//glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.getModelViewProjMatrix().m[0]);
 	}
 };
 
-class DirShadowMapMVPUniform : public BaseUniform
+/* Unused */ class DirShadowMapMVPUniform : public BaseUniform
 {
 public:
 	DirShadowMapMVPUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().dirShadowMapMVPUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getModelViewProjMatrix().m[0]);
+		//glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.getModelViewProjMatrix().m[0]);
 	}
 };
-class DirShadowMapBiasMVPUniform : public BaseUniform
+/* Unused */ class DirShadowMapBiasMVPUniform : public BaseUniform
 {
 public:
 	DirShadowMapBiasMVPUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().dirShadowMapBiasMVPUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getModelViewProjMatrix().m[0]);
+		//glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.getModelViewProjMatrix().m[0]);
 	}
 };
 
@@ -342,136 +386,158 @@ class CameraPosVecUniform : public BaseUniform
 public:
 	CameraPosVecUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().cameraPosVecUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		auto &cameraPosVec = p_rendererState.getCameraPosition();
-		glUniform3f(m_uniformHandle, cameraPosVec.x, cameraPosVec.y, cameraPosVec.z);
+		glUniform3f(m_uniformHandle, 
+					p_uniformData.m_frameData.m_cameraPosition.x, 
+					p_uniformData.m_frameData.m_cameraPosition.y,
+					p_uniformData.m_frameData.m_cameraPosition.z);
 	}
 };
-class CameraTargetVecUniform : public BaseUniform
+/* Unused */ class CameraTargetVecUniform : public BaseUniform
 {
 public:
 	CameraTargetVecUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().cameraTargetVecUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		auto &cameraPosVec = p_rendererState.getCameraTarget();
-		glUniform3f(m_uniformHandle, cameraPosVec.x, cameraPosVec.y, cameraPosVec.z);
+		//auto &cameraPosVec = p_uniformData.getCameraTarget();
+		//glUniform3f(m_uniformHandle, cameraPosVec.x, cameraPosVec.y, cameraPosVec.z);
 	}
 };
-class CameraUpVecUniform : public BaseUniform // Unused
+/* Unused */ class CameraUpVecUniform : public BaseUniform // Unused
 {
 public:
 	CameraUpVecUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().cameraUpVecUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		//auto &cameraUpVec = p_rendererState.getCameraUpVec();
+		//auto &cameraUpVec = p_uniformData.getCameraUpVec();
 		//glUniform3f(m_uniformHandle, cameraUpVec.x, cameraUpVec.y, cameraUpVec.z);
 	}
 };
-class CameraRightVecUniform : public BaseUniform // Unused
+/* Unused */ class CameraRightVecUniform : public BaseUniform // Unused
 {
 public:
 	CameraRightVecUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().cameraRightVecUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		//auto &cameraRightVec = p_rendererState.getCameraRightVec();
+		//auto &cameraRightVec = p_uniformData.getCameraRightVec();
 		//glUniform3f(m_uniformHandle, cameraRightVec.x, cameraRightVec.y, cameraRightVec.z);
 	}
 };
-class CameraAngleUniform : public BaseUniform
+/* Unused */ class CameraAngleUniform : public BaseUniform
 {
 public:
 	CameraAngleUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().cameraPosVecUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		auto &cameraAngle = p_rendererState.getCameraAngle();
-		glUniform2f(m_uniformHandle, cameraAngle.x, cameraAngle.y);
+		//auto &cameraAngle = p_uniformData.getCameraAngle();
+		//glUniform2f(m_uniformHandle, cameraAngle.x, cameraAngle.y);
 	}
 };
 
-class PositionBufferUniform : public BaseUniform
+class PositionMapUniform : public BaseUniform
+{
+public:
+	PositionMapUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().positionMapUniform, p_shaderHandle) { }
+
+	void update(const UniformData &p_uniformData)
+	{
+		glUniform1i(m_uniformHandle, GeometryBuffer::GBufferTextureType::GBufferPosition);
+	}
+};
+class DiffuseMapUniform : public BaseUniform
+{
+public:
+	DiffuseMapUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().diffuseMapUniform, p_shaderHandle) { }
+
+	void update(const UniformData &p_uniformData)
+	{
+		glUniform1i(m_uniformHandle, GeometryBuffer::GBufferTextureType::GBufferDiffuse);
+	}
+};
+class NormalMapUniform : public BaseUniform
 {
 public:
-	PositionBufferUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().positionMapUniform, p_shaderHandle) { }
+	NormalMapUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().normalMapUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getPositionBufferPos());
+		glUniform1i(m_uniformHandle, GeometryBuffer::GBufferTextureType::GBufferNormal);
 	}
 };
-class DiffuseBufferUniform : public BaseUniform
+class EmissiveMapUniform : public BaseUniform
 {
 public:
-	DiffuseBufferUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().diffuseMapUniform, p_shaderHandle) { }
+	EmissiveMapUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().emissiveMapUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getDiffuseBufferPos());
+		glUniform1i(m_uniformHandle, GeometryBuffer::GBufferTextureType::GBufferEmissive);
 	}
 };
-class NormalBufferUniform : public BaseUniform
+class MatPropertiesMapUniform : public BaseUniform
 {
 public:
-	NormalBufferUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().normalMapUniform, p_shaderHandle) { }
+	MatPropertiesMapUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().matPropertiesMapUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getNormalBufferPos());
+		glUniform1i(m_uniformHandle, GeometryBuffer::GBufferTextureType::GBufferMatProperties);
 	}
 };
-class EmissiveBufferUniform : public BaseUniform
+class BlurMapUniform : public BaseUniform
 {
 public:
-	EmissiveBufferUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().emissiveMapUniform, p_shaderHandle) { }
+	BlurMapUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().blurMapUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getEmissiveBufferPos());
+		glUniform1i(m_uniformHandle, GeometryBuffer::GBufferTextureType::GBufferBlur);
 	}
 };
-class BlurBufferUniform : public BaseUniform
+class FinalMapUniform : public BaseUniform
 {
 public:
-	BlurBufferUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().blurMapUniform, p_shaderHandle) { }
+	FinalMapUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().finalMapUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getBlurBufferPos());
+		//glUniform1i(m_uniformHandle, GeometryBuffer::GBufferTextureType::GBufferDiffuse);
 	}
 };
 
-class SunGlowTextureUniform : public BaseUniform
+/* Unused */ class SunGlowTextureUniform : public BaseUniform
 {
 public:
 	SunGlowTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().sunGlowTextureUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getDiffuseTexturePos());
+		//glUniform1i(m_uniformHandle, p_uniformData.getDiffuseTexturePos());
 	}
 };
-class SkyMapTextureUniform : public BaseUniform
+/* Unused */ class SkyMapTextureUniform : public BaseUniform
 {
 public:
 	SkyMapTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().skyMapTextureUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getDiffuseTexturePos());
+		//glUniform1i(m_uniformHandle, p_uniformData.getDiffuseTexturePos());
 	}
 };
-class DirShadowMapTextureUniform : public BaseUniform
+/* Unused */ class DirShadowMapTextureUniform : public BaseUniform
 {
 public:
 	DirShadowMapTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().dirShadowMapTextureUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getDiffuseTexturePos());
+		//glUniform1i(m_uniformHandle, p_uniformData.getDiffuseTexturePos());
 	}
 };
 class DiffuseTextureUniform : public BaseUniform
@@ -479,9 +545,10 @@ class DiffuseTextureUniform : public BaseUniform
 public:
 	DiffuseTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().diffuseTextureUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getDiffuseTexturePos());
+		//glUniform1i(m_uniformHandle, p_uniformData.getDiffuseTexturePos());
+		glUniform1i(m_uniformHandle, MaterialType_Diffuse);
 	}
 };
 class NormalTextureUniform : public BaseUniform
@@ -489,188 +556,179 @@ class NormalTextureUniform : public BaseUniform
 public:
 	NormalTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().normalTextureUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getNormalTexturePos());
+		//glUniform1i(m_uniformHandle, p_uniformData.getNormalTexturePos());
+		glUniform1i(m_uniformHandle, MaterialType_Normal);
 	}
 };
-class SpecularTextureUniform : public BaseUniform
+class EmissiveTextureUniform : public BaseUniform
 {
 public:
-	SpecularTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().specularTextureUniform, p_shaderHandle) { }
+	EmissiveTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().emissiveTextureUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getSpecularTexturePos());
+		glUniform1i(m_uniformHandle, MaterialType_Emissive);
 	}
 };
-class EmissiveTextureUniform : public BaseUniform
+class CombinedTextureUniform : public BaseUniform
 {
 public:
-	EmissiveTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().emissiveTextureUniform, p_shaderHandle) { }
+	CombinedTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().combinedTextureUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getEmissiveTexturePos());
+		//glUniform1i(m_uniformHandle, p_uniformData.getCombinedTexturePos());
+		glUniform1i(m_uniformHandle, MaterialType_Combined);
 	}
 };
-class GlossTextureUniform : public BaseUniform
+
+class DynamicEnvironmentMapUniform : public BaseUniform
+{
+public:
+	DynamicEnvironmentMapUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().dynamicEnvMapUniform, p_shaderHandle) { }
+
+	void update(const UniformData &p_uniformData)
+	{
+		//glUniform1i(m_uniformHandle, p_uniformData.getDynamicEnvMapPos());
+	}
+};
+class StaticEnvironmentMapUniform : public BaseUniform
+{
+public:
+	StaticEnvironmentMapUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().staticEnvMapUniform, p_shaderHandle) { }
+
+	void update(const UniformData &p_uniformData)
+	{
+		//glUniform1i(m_uniformHandle, p_uniformData.getStaticEnvMapPos());
+	}
+};
+
+// Unused (old shading model)
+/* Unused */ class SpecularTextureUniform : public BaseUniform
+{
+public:
+	SpecularTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().specularTextureUniform, p_shaderHandle) { }
+
+	void update(const UniformData &p_uniformData)
+	{
+		//glUniform1i(m_uniformHandle, p_uniformData.getSpecularTexturePos());
+	}
+};
+/* Unused */ class GlossTextureUniform : public BaseUniform
 {
 public:
 	GlossTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().glossTextureUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getGlossTexturePos());
+		//glUniform1i(m_uniformHandle, p_uniformData.getGlossTexturePos());
 	}
 };
-class HeightTextureUniform : public BaseUniform
+/* Unused */ class HeightTextureUniform : public BaseUniform
 {
 public:
 	HeightTextureUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().heightTextureUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, p_rendererState.getHeightTexturePos());
+		//glUniform1i(m_uniformHandle, p_uniformData.getHeightTexturePos());
 	}
 };
 
-class FogDensityUniform : public BaseUniform
+/* Unused */ class FogDensityUniform : public BaseUniform
 {
 public:
 	FogDensityUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().fogDensityUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1f(m_uniformHandle, p_rendererState.getFogDensity());
+		//glUniform1f(m_uniformHandle, p_uniformData.getFogDensity());
 	}
 };
-class FogColorUniform : public BaseUniform
+/* Unused */ class FogColorUniform : public BaseUniform
 {
 public:
 	FogColorUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().fogColorUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		auto &fogColor = p_rendererState.getFogColor();
-		glUniform3f(m_uniformHandle, fogColor.x, fogColor.y, fogColor.z);
+		//auto &fogColor = p_uniformData.getFogColor();
+		//glUniform3f(m_uniformHandle, fogColor.x, fogColor.y, fogColor.z);
 	}
 };
 
-class BillboardScaleUniform : public BaseUniform
+/* Unused */ class BillboardScaleUniform : public BaseUniform
 {
 public:
 	BillboardScaleUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().billboardScaleUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1f(m_uniformHandle, 1.0f);
+		//glUniform1f(m_uniformHandle, 1.0f);
 	}
 };
-class DepthTypeUniform : public BaseUniform
+/* Unused */ class DepthTypeUniform : public BaseUniform
 {
 public:
 	DepthTypeUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().depthTypeUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniform1i(m_uniformHandle, 0);
+		//glUniform1i(m_uniformHandle, 0);
 	}
 };
 
-class TestMatUniform : public BaseUniform
+/* Unused */ class TestMatUniform : public BaseUniform
 {
 public:
 	TestMatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().testMatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_rendererState.getTestMat().m[0]);
+		//glUniformMatrix4fv(m_uniformHandle, 1, GL_FALSE, &p_uniformData.getTestMat().m[0]);
 	}
 };
-class TestVecUniform : public BaseUniform
+/* Unused */ class TestVecUniform : public BaseUniform
 {
 public:
 	TestVecUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().testVecUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
+	void update(const UniformData &p_uniformData)
 	{
-		auto &testVec = p_rendererState.getTestVec();
-		glUniform4f(m_uniformHandle, testVec.x, testVec.y, testVec.z, testVec.w);
+		//auto &testVec = p_uniformData.getTestVec();
+		//glUniform4f(m_uniformHandle, testVec.x, testVec.y, testVec.z, testVec.w);
 	}
 };
-class TestFloatUniform : public BaseUniform
+/* Unused */ class TestFloatUniform : public BaseUniform
 {
 public:
 	TestFloatUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().testFloatUniform, p_shaderHandle) { }
 
-	void update(RendererState &p_rendererState)
-	{
-		glUniform1f(m_uniformHandle, p_rendererState.getTestFloat());
-	}
-};
-
-/*modelMatUniform
-viewMatUniform
-projectionMatUniform
-ViewProjectionMatUniform
-ModelViewMatUniform
-ModelViewProjectionMatUniform
-ScreenSizeUniform
-NumPointLightsUniform
-NumSpotLightsUniform
-PointLightViewProjectionMatUniform
-SpotLightViewProjectionMatUniform
-StencilPassViewProjectionMatUniform
-DirLightMatUniform
-DirLightProjectionMatUniform*/
-
-/*directionalLightBaseColorUniform
-directionalLightBaseAmbientIntensityUniform
-directionalLightDirectionUniform
-directionalLightDiffuseIntensityUniform
-directionalLightMinGradientUniform
-
-pointLightBaseColorUniform
-pointLightAmbientIntensityUniform
-pointLightPositionUniform
-pointLightBaseDiffuseIntensityUniform
-pointLightAttenuationConstantUniform
-pointLightAttenuationLinearUniform
-pointLightAttenuationExponentialUniform
-
-spotLightBaseColorUniform
-spotLightPositionUniform
-spotLightAmbientIntensityUniform
-spotLightBaseDiffuseIntensityUniform
-spotLightAttenuationConstantUniform
-spotLightAttenuationLinearUniform
-spotLightAttenuationExponentialUniform
-spotLightDirectionUniform
-spotLightCutoffUniform*/
-
-/*DirShadowMapMVPUniform
-DirShadowMapBiasMVPUniform
-
-CameraPosVecUniform
-CameraUpVecUniform
-CameraRightVecUniform
-
-PositionMapUniform
-DiffuseMapUniform
-NormalMapUniform
-EmissiveMapUniform
-BlurMapUniform
-
-SunGlowTextureUniform
-SkyMapTextureUniform
-DirShadowMapTextureUniform
-DiffuseTextureUniform
-NormalTextureUniform
-SpecularTextureUniform
-EmissiveTextureUniform
-
-FogDensityUniform
-FogColorUniform
-BillboardScaleUniform
-DepthTypeUniform*/
+	void update(const UniformData &p_uniformData)
+	{
+		//glUniform1f(m_uniformHandle, p_uniformData.getTestFloat());
+	}
+};
+
+class PointLightBufferUniform : public BaseUniformBlock
+{
+public:
+	PointLightBufferUniform(unsigned int p_shaderHandle) : BaseUniformBlock(Config::shaderVar().pointLightBuffer, p_shaderHandle) { }
+
+	void update(const UniformData &p_uniformData)
+	{
+		updateBlockBinding(LightBufferBinding_PointLight);
+	}
+};
+class SpotLightBufferUniform : public BaseUniformBlock
+{
+public:
+	SpotLightBufferUniform(unsigned int p_shaderHandle) : BaseUniformBlock(Config::shaderVar().spotLightBuffer, p_shaderHandle) { }
+
+	void update(const UniformData &p_uniformData)
+	{
+		updateBlockBinding(LightBufferBinding_SpotLight);
+	}
+};

+ 1 - 1
Praxis3D/Source/SolarTimeScript.h

@@ -95,7 +95,7 @@ public:
 
 		m_sunPosition = (-m_sunDirection * m_offsetPosition) + m_originPosition;
 
-		postChanges(Systems::Changes::Spacial::Position | Systems::Changes::Spacial::Rotation);
+		//postChanges(Systems::Changes::Spacial::Position | Systems::Changes::Spacial::Rotation);
 	}
 
 	virtual BitMask getDesiredSystemChanges() { return Systems::Changes::Spacial::All; }

+ 28 - 26
Praxis3D/Source/TaskManager.cpp

@@ -52,7 +52,7 @@ namespace TaskManagerGlobal
 
 			m_callback(m_callbackParam);
 
-			if (InterlockedDecrement(&m_callbacksCount) == 0)
+			if(InterlockedDecrement(&m_callbacksCount) == 0)
 			{
 				SetEvent(m_allCallbacksInvokedEvent);
 			}
@@ -87,11 +87,11 @@ namespace TaskManagerGlobal
 
 		tbb::task *execute()
 		{
-			if (m_taskManager->isPrimaryThread())
+			if(m_taskManager->isPrimaryThread())
 			{
 				// Cannot stall a primary task, so stall some other task
 				m_taskManager->addStallTask();
-				
+
 				// Wait a bit to give some time for some thread to pick up the stall task
 				// TODO change hardcoded value
 				tbb::this_tbb_thread::sleep(tbb::tick_count::interval_t(0.1));
@@ -138,7 +138,7 @@ TaskManager::TaskManager()
 	m_stallPoolParent = nullptr;
 	m_systemTasksRoot = nullptr;
 	m_tbbScheduler = nullptr;
-	
+
 	m_timeToQuit = false;
 	m_deltaTime = 0.0f;
 	m_stallPoolSemaphore = nullptr;
@@ -214,7 +214,7 @@ void TaskManager::setNumberOfThreads(unsigned int p_numOfThreads)
 {
 	unsigned int targetNumberOfThreads = p_numOfThreads;
 
-	if (targetNumberOfThreads > m_numOfMaxThreads || targetNumberOfThreads == 0)
+	if(targetNumberOfThreads > m_numOfMaxThreads || targetNumberOfThreads == 0)
 		targetNumberOfThreads = m_numOfMaxThreads;
 
 	m_numOfTargetThreads = targetNumberOfThreads;
@@ -225,16 +225,16 @@ void TaskManager::waitForSystemTasks(SystemTask **p_tasks, unsigned int p_count)
 	assert(isPrimaryThread());
 	assert(p_count > 0);
 	assert(p_count <= Systems::Types::Max);
-	
+
 	// Execute the tasks we are waiting, now
 	// Save the tasks we aren't waiting, for next time
 
 	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
 
-	for (std::vector<SystemTask*>::iterator iterator = m_primaryThreadSystemTaskList.begin(); iterator != m_primaryThreadSystemTaskList.end(); iterator++)
+	for(std::vector<SystemTask*>::iterator iterator = m_primaryThreadSystemTaskList.begin(); iterator != m_primaryThreadSystemTaskList.end(); iterator++)
 	{
 		// Check if we are waiting for this thread
-		if (std::find(p_tasks, p_tasks + p_count, *iterator))
+		if(std::find(p_tasks, p_tasks + p_count, *iterator))
 		{
 			// If we are, execute it on the primary thread
 			(*iterator)->update(m_deltaTime);
@@ -258,7 +258,7 @@ void TaskManager::nonStandardPerThreadCallback(JobFunct p_callback, void *p_data
 	SpinWait::Lock lock(m_syncedCallbackMutex);
 
 	unsigned int numOfThreads = m_numOfThreads;
-	if (numOfThreads != m_numOfMaxThreads)
+	if(numOfThreads != m_numOfMaxThreads)
 	{
 		m_numOfTargetThreads = m_numOfMaxThreads;
 		updateThreadPoolSize();
@@ -274,7 +274,7 @@ void TaskManager::nonStandardPerThreadCallback(JobFunct p_callback, void *p_data
 	broadcastParent->set_ref_count(m_numOfMaxThreads + 1);
 
 	tbb::task_list taskList;
-	for (unsigned int i = 0; i < m_numOfMaxThreads; i++)
+	for(unsigned int i = 0; i < m_numOfMaxThreads; i++)
 	{
 		// Add a SynchronizeTask to each thread in the TBB pool (workers and master)
 		tbb::task *newTask = new(broadcastParent->allocate_child()) TaskManagerGlobal::SynchronizeTask;
@@ -287,7 +287,7 @@ void TaskManager::nonStandardPerThreadCallback(JobFunct p_callback, void *p_data
 	broadcastParent->spawn_and_wait_for_all(taskList);
 	broadcastParent->destroy(*broadcastParent);
 
-	if (numOfThreads != m_numOfMaxThreads)
+	if(numOfThreads != m_numOfMaxThreads)
 	{
 		m_numOfTargetThreads = numOfThreads;
 		updateThreadPoolSize();
@@ -298,7 +298,7 @@ void TaskManager::issueJobsForSystemTasks(SystemTask **p_tasks, unsigned int p_c
 	//TODO ERROR
 	assert(isPrimaryThread());
 	assert(p_count > 0);
-	
+
 	m_deltaTime = p_deltaTime;
 
 	updateThreadPoolSize();
@@ -311,25 +311,27 @@ void TaskManager::issueJobsForSystemTasks(SystemTask **p_tasks, unsigned int p_c
 	// Schedule tasks based on their performance hint order
 	tbb::task_list taskList;
 	unsigned int affinityCount = (unsigned int)m_affinityIDs.size();
-	
-	for (unsigned int perfHint = 0, currentTask = 0; perfHint < PerformanceHint::Task_MAX; perfHint++)
-	{
-		for (currentTask = 0; currentTask < p_count; currentTask++)
+
+	// TODO: implement performance hint
+
+	//for(unsigned int perfHint = 0, currentTask = 0; perfHint < PerformanceHint::Task_MAX; perfHint++)
+	//{
+		for(unsigned int currentTask = 0; currentTask < p_count; currentTask++)
 		{
-			if (p_tasks[currentTask]->isPrimaryThreadOnly())
+			if(p_tasks[currentTask]->isPrimaryThreadOnly())
 			{
 				// Put this task on the list of tasks to be run on the primary thread
 				// only do this during the first outer loop
 				//if (perfHint == 0)
 				//{
-					m_primaryThreadSystemTaskList.push_back(p_tasks[currentTask]);
+				m_primaryThreadSystemTaskList.push_back(p_tasks[currentTask]);
 				//}
 			}
 			else
 			{
 				// Check if it's time to dispatch this task
-				if (getPerformanceHint(p_tasks[currentTask]) == (PerformanceHint)perfHint)
-				{
+				//if(getPerformanceHint(p_tasks[currentTask]) == (PerformanceHint)perfHint)
+				//{
 					// This task can be run on an arbitrary thread - allocate it 
 					TaskManagerGlobal::GenericCallbackTask<TaskManager::JobFunct> *systemTask
 						= new(m_systemTasksRoot->allocate_additional_child_of(*m_systemTasksRoot))
@@ -342,20 +344,20 @@ void TaskManager::issueJobsForSystemTasks(SystemTask **p_tasks, unsigned int p_c
 					// to a unique thread, regardless of PerformanceHint
 					systemTask->set_affinity(m_affinityIDs[currentTask % affinityCount]);
 					taskList.push_back(*systemTask);
-				}
+				//}
 			}
 		}
 
 		// We only spawn system tasks here. They in their turn will spawn descendant tasks.
 		// Waiting for the whole bunch completion happens in WaitForSystemTasks.
 		m_systemTasksRoot->spawn(taskList);
-	}
+	//}
 }
 void TaskManager::parallelFor(SystemTask *p_systemTask, ParallelForFunc p_jobFunc, void *p_param, unsigned int p_begin, unsigned int p_end, unsigned int p_minGrainSize)
 {
 	TaskManagerGlobal::ParallelFor parallelForBody(p_jobFunc, p_param);
 
-	if (m_numOfThreads != 1)
+	if(m_numOfThreads != 1)
 	{
 		tbb::parallel_for(tbb::blocked_range<unsigned int>(p_begin, p_end, p_minGrainSize), parallelForBody, tbb::auto_partitioner());
 	}
@@ -375,13 +377,13 @@ void TaskManager::updateThreadPoolSize()
 {
 	// Change the number of threads if needed, by creating some tasks which do not complete until signaled
 
-	if (m_numOfTargetThreads != m_numOfThreads)
+	if(m_numOfTargetThreads != m_numOfThreads)
 	{
 		unsigned int numOfThreadsToWait = (m_numOfMaxThreads - m_numOfTargetThreads);
 		unsigned int numOfThreadsToFree = (m_numOfMaxThreads - m_numOfThreads);
 
 		// Free up all the threads
-		if (m_stallPoolParent)
+		if(m_stallPoolParent)
 		{
 			ReleaseSemaphore(m_stallPoolSemaphore, numOfThreadsToFree, NULL);
 
@@ -399,7 +401,7 @@ void TaskManager::updateThreadPoolSize()
 		m_stallPoolParent->set_ref_count(numOfThreadsToWait + 1);
 
 		tbb::task_list taskList;
-		for (unsigned int i = 0; i < numOfThreadsToWait; i++)
+		for(unsigned int i = 0; i < numOfThreadsToWait; i++)
 		{
 			tbb::task *stallTask = new(m_stallPoolParent->allocate_child()) TaskManagerGlobal::StallTask(this, m_stallPoolSemaphore);
 			// TODO ERROR

+ 98 - 97
Praxis3D/Source/TaskManager.h

@@ -6,6 +6,7 @@
 #include <tbb/task_scheduler_init.h>
 #include <tbb/tbb_thread.h>
 #include <vector>
+#include "Window.h"
 
 #include "System.h"
 #include "SpinWait.h"
@@ -37,8 +38,8 @@ public:
 		SIMD_INT
 	};
 
-	typedef void (*JobFunct)(void*);
-	typedef void (*ParallelForFunc)(void *p_param, unsigned int p_begin, unsigned int p_end);
+	typedef void(*JobFunct)(void*);
+	typedef void(*ParallelForFunc)(void *p_param, unsigned int p_begin, unsigned int p_end);
 
 	TaskManager();
 	~TaskManager();
@@ -66,19 +67,19 @@ public:
 
 	// TBB paralle_for wrapper for job tasks
 	void parallelFor(SystemTask *p_systemTask, ParallelForFunc p_jobFunc, void *p_param, unsigned int p_begin, unsigned int p_end, unsigned int p_minGrainSize = 1);
-	
+
 	// Passed function is executed in a parallel thread; returns before the passed function has been completed
 	template<typename Function>
 	inline void startBackgroundThread(const Function& p_func)
 	{
 		// If multi-threading is enabled 
-		#ifdef SETTING_MULTITHREADING_ENABLED
+#ifdef SETTING_MULTITHREADING_ENABLED
 		m_backgroundTaskGroup.run(p_func);
 
-		#else
+#else
 		p_func();
 
-		#endif
+#endif
 	}
 
 	// Wrapper for a TBB parallel_for function; executed the given set of functions in parallel
@@ -87,14 +88,14 @@ public:
 	inline void parallelFor(Index p_first, Index p_last, Index p_step, const Function& p_func)
 	{
 		// If multi-threading is enabled 
-		#ifdef SETTING_MULTITHREADING_ENABLED
+#ifdef SETTING_MULTITHREADING_ENABLED
 		tbb::parallel_for(p_first, p_last, p_step, p_func);
 
-		#else
+#else
 		for(Index i = p_first; i < p_last; i += p_step)
 			p_func(i);
 
-		#endif
+#endif
 	}
 
 	unsigned int getNumberOfThreads() { return m_numOfThreads; }
@@ -174,141 +175,141 @@ class TaskSet;
 class TaskManager
 {
 public:
-	TaskManager();
-	~TaskManager();
+TaskManager();
+~TaskManager();
 
-	void init();
-	void shutdown();
+void init();
+void shutdown();
 
-	bool createTaskSet(TaskSetFunc p_func, void *p_arg, unsigned int p_taskCount, TaskSetHandle *p_depends,
-		unsigned int p_dependsCount, OPTIONAL char* p_name, OUT TaskSetHandle *p_outHandle);
+bool createTaskSet(TaskSetFunc p_func, void *p_arg, unsigned int p_taskCount, TaskSetHandle *p_depends,
+unsigned int p_dependsCount, OPTIONAL char* p_name, OUT TaskSetHandle *p_outHandle);
 
-	void releaseHandle(TaskSetHandle p_taskSet);
-	void releaseHandles(TaskSetHandle *p_taskSetList, unsigned int p_taskSetCount);
+void releaseHandle(TaskSetHandle p_taskSet);
+void releaseHandles(TaskSetHandle *p_taskSetList, unsigned int p_taskSetCount);
 
-	void waitForSet(TaskSetHandle p_taskSet);
-	void waitForAll();
+void waitForSet(TaskSetHandle p_taskSet);
+void waitForAll();
 
-	bool isSetComplete(TaskSetHandle p_set);
+bool isSetComplete(TaskSetHandle p_set);
 
 private:
-	friend class GenericTask;
+friend class GenericTask;
 
-	TaskSetHandle allocateTaskSet();
+TaskSetHandle allocateTaskSet();
 
-	void completeTaskSet(TaskSetHandle p_set);
+void completeTaskSet(TaskSetHandle p_set);
 
-	TaskSet			*m_taskSets[MAX_TASKSETS];
-	TbbContextId	*m_tbbContextId;
-	void			*m_tbbInit;
-	unsigned int	m_nextFreeSet;
+TaskSet			*m_taskSets[MAX_TASKSETS];
+TbbContextId	*m_tbbContextId;
+void			*m_tbbInit;
+unsigned int	m_nextFreeSet;
 };
 
 class TbbContextId : public tbb::task_scheduler_observer
 {
-	void on_scheduler_entry(bool)
-	{
-		INT context = g_contextIdCount.fetch_and_increment();
-		g_contextId.local() = context;
-	}
+void on_scheduler_entry(bool)
+{
+INT context = g_contextIdCount.fetch_and_increment();
+g_contextId.local() = context;
+}
 
 public:
-	TbbContextId()
-	{
-		g_contextIdCount = 0;
-		observe(true);
-	}
+TbbContextId()
+{
+g_contextIdCount = 0;
+observe(true);
+}
 };
 
 class SpinLock
 {
 public:
-	SpinLock() : m_lock(0)	{ }
-	~SpinLock()				{ }
+SpinLock() : m_lock(0)	{ }
+~SpinLock()				{ }
 
-	void lock()
-	{
-		while (_InterlockedCompareExchange((long*)&m_lock, 1, 0) == 1)
-		{
+void lock()
+{
+while (_InterlockedCompareExchange((long*)&m_lock, 1, 0) == 1)
+{
 
-		}
-	}
+}
+}
 
-	void unlock()
-	{
-		m_lock = 0;
-	}
+void unlock()
+{
+m_lock = 0;
+}
 
 private:
-	volatile unsigned int m_lock;
+volatile unsigned int m_lock;
 };
 
 class GenericTask : public tbb::task
 {
 public:
-	GenericTask();
-	GenericTask(TaskSetFunc p_func, void* p_arg, unsigned int p_id, unsigned int p_size, char* p_setName, TaskSetHandle p_taskSet) :
-		m_func(p_func), m_arg(p_arg), m_id(p_id), m_size(p_size), m_setName(p_setName), m_taskSet(p_taskSet)
-	{
+GenericTask();
+GenericTask(TaskSetFunc p_func, void* p_arg, unsigned int p_id, unsigned int p_size, char* p_setName, TaskSetHandle p_taskSet) :
+m_func(p_func), m_arg(p_arg), m_id(p_id), m_size(p_size), m_setName(p_setName), m_taskSet(p_taskSet)
+{
 
-	}
+}
 
-	task* execute();
-	//{
-	//	m_func(m_arg, g_contextId.local(), m_id, m_size);
-	//	g_taskManager.completeTaskSet(m_taskSet);
-	//}
+task* execute();
+//{
+//	m_func(m_arg, g_contextId.local(), m_id, m_size);
+//	g_taskManager.completeTaskSet(m_taskSet);
+//}
 
 private:
-	TaskSetFunc		m_func;
-	void*			m_arg;
-	unsigned int	m_id;
-	unsigned int	m_size;
-	char*			m_setName;
-	TaskSetHandle		m_taskSet;
+TaskSetFunc		m_func;
+void*			m_arg;
+unsigned int	m_id;
+unsigned int	m_size;
+char*			m_setName;
+TaskSetHandle		m_taskSet;
 };
 
 class TaskSet : public tbb::task
 {
 public:
-	TaskSet() :
-		m_func(NULL),
-		m_arg(0),
-		m_size(0),
-		m_taskSet(TASKSETHANDLE_INVALID),
-		m_hasBeenWaitedOn(false)
-	{
-		m_setName[0] = 0;
-		memset(m_successors, 0, sizeof(m_successors));
-	}
+TaskSet() :
+m_func(NULL),
+m_arg(0),
+m_size(0),
+m_taskSet(TASKSETHANDLE_INVALID),
+m_hasBeenWaitedOn(false)
+{
+m_setName[0] = 0;
+memset(m_successors, 0, sizeof(m_successors));
+}
 
-	~TaskSet() { }
+~TaskSet() { }
 
-	task* execute()
-	{
-		set_ref_count(m_size + 1);
+task* execute()
+{
+set_ref_count(m_size + 1);
 
-		for (unsigned int i = 0; i < m_size; i++)
-		{
-			spawn(*new(allocate_child()) GenericTask(m_func, m_arg, i, m_size, m_setName, m_taskSet));
-		}
+for (unsigned int i = 0; i < m_size; i++)
+{
+spawn(*new(allocate_child()) GenericTask(m_func, m_arg, i, m_size, m_setName, m_taskSet));
+}
 
-		return NULL;
-	}
+return NULL;
+}
 
-	TaskSet			*m_successors[MAX_SUCCESSORS];
-	TaskSetHandle	m_taskSet;
-	bool			m_hasBeenWaitedOn;
+TaskSet			*m_successors[MAX_SUCCESSORS];
+TaskSetHandle	m_taskSet;
+bool			m_hasBeenWaitedOn;
 
-	TaskSetFunc	m_func;
-	void		*m_arg;
+TaskSetFunc	m_func;
+void		*m_arg;
 
-	volatile unsigned int	m_startCount;
-	volatile unsigned int	m_completionCount;
-	volatile unsigned int	m_refCount;
+volatile unsigned int	m_startCount;
+volatile unsigned int	m_completionCount;
+volatile unsigned int	m_refCount;
 
-	unsigned int	m_size;
-	SpinLock		m_successorsLock;
+unsigned int	m_size;
+SpinLock		m_successorsLock;
 
-	char	m_setName[MAX_TASKSETNAMELENGTH];
+char	m_setName[MAX_TASKSETNAMELENGTH];
 };*/

+ 4 - 4
Praxis3D/Source/TaskScheduler.cpp

@@ -5,10 +5,10 @@
 // TODO DATA DRIVEN
 const float TaskScheduler::m_defaultClockFrequency = 1.0f / 120.0f;      // Set the timer to 120Hz
 
-TaskScheduler::TaskScheduler(TaskManager *p_taskManager) :	m_taskManager(p_taskManager), 
-															m_clockFrequency(m_defaultClockFrequency), 
-															m_executionTimer(nullptr),
-															m_multithreadingEnabled(true) // TODO DATA DRIVEN
+TaskScheduler::TaskScheduler(TaskManager *p_taskManager) : m_taskManager(p_taskManager),
+m_clockFrequency(m_defaultClockFrequency),
+m_executionTimer(nullptr),
+m_multithreadingEnabled(true) // TODO DATA DRIVEN
 {
 	m_multithreadingEnabled = (p_taskManager != nullptr);
 }

+ 156 - 19
Praxis3D/Source/TextureLoader.cpp

@@ -7,7 +7,7 @@
 #include "TextureLoader.h"
 #include "Utilities.h"
 
-TextureLoader::TextureLoader()
+TextureLoader2D::TextureLoader2D()
 {
 	m_default2DTexture = new Texture2D(this, Config::textureVar().default_texture, m_objectPool.size(), 0);
 	m_defaultEmissive = new Texture2D(this, Config::textureVar().default_emissive_texture, m_objectPool.size(), 0);
@@ -15,12 +15,12 @@ TextureLoader::TextureLoader()
 	m_defaultNormal = new Texture2D(this, Config::textureVar().default_normal_texture, m_objectPool.size(), 0);
 }
 
-TextureLoader::~TextureLoader()
+TextureLoader2D::~TextureLoader2D()
 {
 
 }
 
-ErrorCode TextureLoader::init()
+ErrorCode TextureLoader2D::init()
 {
 	// If the default texture filename changed upon loading the configuration
 	if(m_default2DTexture->m_filename != Config::textureVar().default_texture)
@@ -46,16 +46,16 @@ ErrorCode TextureLoader::init()
 	
 	// Load default textures to memory and video memory
 	m_default2DTexture->loadToMemory();
-	m_default2DTexture->loadToVideoMemory();
+	//m_default2DTexture->loadToVideoMemory();
 
 	m_defaultEmissive->loadToMemory();
-	m_defaultEmissive->loadToVideoMemory();
+	//m_defaultEmissive->loadToVideoMemory();
 
 	m_defaultHeight->loadToMemory();
-	m_defaultHeight->loadToVideoMemory();
+	//m_defaultHeight->loadToVideoMemory();
 
 	m_defaultNormal->loadToMemory();
-	m_defaultNormal->loadToVideoMemory();
+	//m_defaultNormal->loadToVideoMemory();
 
 	// Add default textures to the texture pool
 	m_objectPool.push_back(m_default2DTexture);
@@ -66,7 +66,7 @@ ErrorCode TextureLoader::init()
 	return ErrorCode::Success;
 }
 
-TextureLoader::Texture2DHandle TextureLoader::load2D(const std::string &p_filename, Model::ModelMaterialType p_materialType, bool p_startBackgroundLoading)
+TextureLoader2D::Texture2DHandle TextureLoader2D::load(const std::string &p_filename, MaterialType p_materialType, bool p_startBackgroundLoading)
 {
 	Texture2D *returnTexture;
 
@@ -80,19 +80,20 @@ TextureLoader::Texture2DHandle TextureLoader::load2D(const std::string &p_filena
 	{
 		switch(p_materialType)
 		{
-		case Model::ModelMat_normal:
+		case MaterialType_Normal:
 			returnTexture = m_defaultNormal;
 			break;
-		case Model::ModelMat_emissive:
+		case MaterialType_Emissive:
 			returnTexture = m_defaultEmissive;
 			break;
-		case Model::ModelMat_height:
+		case MaterialType_Height:
 			returnTexture = m_defaultHeight;
 			break;
-		case Model::ModelMat_diffuse:
-		case Model::ModelMat_specular:
-		case Model::ModelMat_gloss:
-		case Model::NumOfModelMaterials:
+		case MaterialType_Diffuse:
+		case MaterialType_Combined:
+		case MaterialType_Roughness:
+		case MaterialType_Metalness:
+		case MaterialType_AmbientOcclusion:
 		default:
 			returnTexture = m_default2DTexture;
 			break;
@@ -104,13 +105,13 @@ TextureLoader::Texture2DHandle TextureLoader::load2D(const std::string &p_filena
 		unsigned int defaultTextureHandle = m_default2DTexture->m_handle;
 		switch(p_materialType)
 		{
-		case Model::ModelMat_normal:
+		case MaterialType_Normal:
 			defaultTextureHandle = m_defaultNormal->m_handle;
 			break;
-		case Model::ModelMat_emissive:
+		case MaterialType_Emissive:
 			defaultTextureHandle = m_defaultEmissive->m_handle;
 			break;
-		case Model::ModelMat_height:
+		case MaterialType_Height:
 			defaultTextureHandle = m_defaultHeight->m_handle;
 			break;
 		}
@@ -142,7 +143,7 @@ TextureLoader::Texture2DHandle TextureLoader::load2D(const std::string &p_filena
 	// Return the new texture
 	return Texture2DHandle(returnTexture);
 }
-TextureLoader::Texture2DHandle TextureLoader::load2D(const std::string &p_filename, unsigned int p_textureHandle)
+TextureLoader2D::Texture2DHandle TextureLoader2D::load(const std::string &p_filename, unsigned int p_textureHandle)
 {
 	Texture2D *returnTexture;
 
@@ -177,3 +178,139 @@ TextureLoader::Texture2DHandle TextureLoader::load2D(const std::string &p_filena
 	// Return the new texture
 	return Texture2DHandle(returnTexture);
 }
+
+TextureLoaderCubemap::TextureLoaderCubemap()
+{
+	std::string defaultFilenames[CubemapFace_NumOfFaces];
+	for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+		defaultFilenames[face] = Config::textureVar().default_texture;
+
+	m_defaultCubemap = new TextureCubemap(this, Config::textureVar().default_texture, defaultFilenames, m_objectPool.size(), 0);
+}
+
+TextureLoaderCubemap::~TextureLoaderCubemap()
+{
+}
+
+ErrorCode TextureLoaderCubemap::init()
+{
+	// If the default texture filename changed upon loading the configuration
+	// (don't need to compare all filenames, since the default cubemap will have the same texture for all faces)
+	if(m_defaultCubemap->m_filenames[CubemapFace_PositiveX] != Config::textureVar().default_texture)
+	{
+		delete m_defaultCubemap;
+
+		std::string defaultFilenames[CubemapFace_NumOfFaces];
+		for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+			defaultFilenames[face] = Config::textureVar().default_texture;
+
+		m_defaultCubemap = new TextureCubemap(this, Config::textureVar().default_texture, defaultFilenames, m_objectPool.size(), 0);
+	}
+
+	// Load default texture to memory and video memory
+	m_defaultCubemap->loadToMemory();
+	//m_defaultCubemap->loadToVideoMemory();
+
+	// Add default texture to the texture pool
+	m_objectPool.push_back(m_defaultCubemap);
+
+	return ErrorCode::Success;
+}
+
+TextureLoaderCubemap::TextureCubemapHandle TextureLoaderCubemap::load(const std::string & p_filenamePosX, const std::string & p_filenameNegX, const std::string & p_filenamePosY, const std::string & p_filenameNegY, const std::string & p_filenamePosZ, const std::string & p_filenameNegZ, bool p_startBackgroundLoading)
+{
+	std::string filenames[CubemapFace_NumOfFaces];
+
+	filenames[CubemapFace_PositiveX] = p_filenamePosX;
+	filenames[CubemapFace_NegativeX] = p_filenameNegX;
+	filenames[CubemapFace_PositiveY] = p_filenamePosY;
+	filenames[CubemapFace_NegativeY] = p_filenameNegY;
+	filenames[CubemapFace_PositiveZ] = p_filenamePosZ;
+	filenames[CubemapFace_NegativeZ] = p_filenameNegZ;
+
+	return load(filenames, p_startBackgroundLoading);
+}
+
+TextureLoaderCubemap::TextureCubemapHandle TextureLoaderCubemap::load(const std::string(&p_filenames)[CubemapFace_NumOfFaces], bool p_startBackgroundLoading)
+{
+	TextureCubemap *returnTexture;
+
+	// Make sure calls from other threads are locked, while current call is in progress
+	// This is needed to as the object that is being requested might be currently loading /
+	// being added to the pool. Mutex prevents duplicates being loaded, and same data being changed.
+	SpinWait::Lock lock(m_mutex);
+
+	// If any of the filenames are empty, return a default texture instead
+	for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+		if(p_filenames[face].empty())
+			return m_defaultCubemap;
+
+	// Combine the filenames of individual faces into one
+	std::string combinedFilename;
+	for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+		combinedFilename += p_filenames[face] + ", ";
+
+	// Remove the last comma and space 
+	combinedFilename.pop_back();
+	combinedFilename.pop_back();
+
+	// Go through the texture pool and check if the texture hasn't been already loaded (to avoid duplicates)
+	for(decltype(m_objectPool.size()) size = m_objectPool.size(), i = 0; i < size; i++)
+	{
+		if(*m_objectPool[i] == combinedFilename)
+			return TextureCubemapHandle(m_objectPool[i]);
+	}
+
+	// Texture wasn't loaded before, so create a new one
+	// Assign default handle (as a placeholder to be used before the texture is loaded from HDD)
+	returnTexture = new TextureCubemap(this, combinedFilename, p_filenames, m_objectPool.size(), m_defaultCubemap->m_handle);
+
+	if(p_startBackgroundLoading)
+	{
+		// Start loading the texture from file, in a background thread
+		TaskManagerLocator::get().startBackgroundThread(
+			std::bind((ErrorCode(TextureCubemap::*)(void))&TextureCubemap::loadToMemory, returnTexture));
+	}
+
+	// Add the new texture to the list
+	m_objectPool.push_back(returnTexture);
+
+	// Return the new texture
+	return TextureCubemapHandle(returnTexture);
+}
+
+TextureLoaderCubemap::TextureCubemapHandle TextureLoaderCubemap::load(const std::string & p_filename, unsigned int p_textureHandle)
+{
+	TextureCubemap *returnTexture;
+
+	// Make sure calls from other threads are locked, while current call is in progress
+	// This is needed to as the object that is being requested might be currently loading /
+	// being added to the pool. Mutex prevents duplicates being loaded, and same data being changed.
+	SpinWait::Lock lock(m_mutex);
+
+	// If the filename is empty, return a default texture instead
+	if(p_filename == "")
+	{
+		returnTexture = m_defaultCubemap;
+	}
+	else
+	{
+		// Go through the texture pool and check if the texture hasn't been already loaded (to avoid duplicates)
+		for(decltype(m_objectPool.size()) size = m_objectPool.size(), i = 0; i < size; i++)
+		{
+			if(*m_objectPool[i] == p_filename && m_objectPool[i]->m_handle == p_textureHandle)
+				return TextureCubemapHandle(m_objectPool[i]);
+		}
+
+		returnTexture = new TextureCubemap(this, p_filename, m_objectPool.size(), p_textureHandle);
+
+		// Set the loaded flag to true, because we have already provided the texture handle
+		returnTexture->setLoadedToVideoMemory(true);
+
+		// Add the new texture to the list
+		m_objectPool.push_back(returnTexture);
+	}
+
+	// Return the new texture
+	return TextureCubemapHandle(returnTexture);
+}

+ 497 - 114
Praxis3D/Source/TextureLoader.h

@@ -19,24 +19,43 @@ enum TextureColorChannelOffset : unsigned int
 	ColorOffset_Alpha	= 3,
 	ColorOffset_NumChannels
 };
+enum TextureCubemapFaces : unsigned int
+{
+	CubemapFace_PositiveX = 0,
+	CubemapFace_NegativeX = 1,
+	CubemapFace_PositiveY = 2,
+	CubemapFace_NegativeY = 3,
+	CubemapFace_PositiveZ = 4,
+	CubemapFace_NegativeZ = 5,
+	CubemapFace_NumOfFaces
+};
+enum TextureWrapMode
+{
+	Repeat = GL_REPEAT,
+	ClampToEdge = GL_CLAMP_TO_EDGE,
+	ClampToBorder = GL_CLAMP_TO_BORDER,
+	MirroredRepeat = GL_MIRRORED_REPEAT
+};
 
-class TextureLoader;
+class TextureLoader2D;
+class TextureLoaderCubemap;
 enum ModelMaterialType : unsigned int;
 
-class Texture2D : public LoaderBase<TextureLoader, Texture2D>::UniqueObject
+class Texture2D : public LoaderBase<TextureLoader2D, Texture2D>::UniqueObject
 {
-	friend class TextureLoader;
+	friend class RendererFrontend;
+	friend class TextureLoader2D;
 	friend class Texture2DHandle;
-	friend class LoaderBase<TextureLoader, Texture2D>::UniqueObject;
+	friend class LoaderBase<TextureLoader2D, Texture2D>::UniqueObject;
 protected:
-	Texture2D(LoaderBase<TextureLoader, Texture2D> *p_loaderBase, std::string p_filename, size_t p_uniqueID, unsigned int p_handle) : UniqueObject(p_loaderBase, p_uniqueID, p_filename), m_handle(p_handle)
+	Texture2D(LoaderBase<TextureLoader2D, Texture2D> *p_loaderBase, std::string p_filename, size_t p_uniqueID, unsigned int p_handle) : UniqueObject(p_loaderBase, p_uniqueID, p_filename), m_handle(p_handle)
 	{
+		m_mipmapLevel = 0;
 		m_textureWidth = 0;
 		m_textureHeight = 0;
 		m_pixelData = nullptr;
-
-		// Since the texture handle has been provided, set loaded to video memory flag to true
-		//setLoadedToVideoMemory(true);
+		m_bitmap = nullptr;
+		m_textureFormat = TextureFormat_RGBA;
 	}
 
 	// Loads pixel data (using the filename) from HDD to RAM, re-factors it
@@ -56,10 +75,26 @@ protected:
 			
 			// Read the actual texture
 			m_bitmap = FreeImage_Load(imageFormat, (Config::PathsVariables().texture_path + m_filename).c_str());
-			m_bitmap = FreeImage_ConvertTo32Bits(m_bitmap);
-
+			
 			if(m_bitmap)
 			{
+				// Calculate the number of bytes per pixel
+				unsigned int bytesPerPixel = FreeImage_GetLine(m_bitmap) / FreeImage_GetWidth(m_bitmap);
+				// Calculate the number of samples per pixel
+				unsigned int samplesPerPixel = bytesPerPixel / sizeof(BYTE);
+
+				// Only supporting 24bits or 32bits per pixel
+				if(samplesPerPixel == 3)
+				{
+					m_textureFormat = TextureFormat_RGB;
+					m_bitmap = FreeImage_ConvertTo24Bits(m_bitmap);
+				}
+				else
+				{
+					m_textureFormat = TextureFormat_RGBA;
+					m_bitmap = FreeImage_ConvertTo32Bits(m_bitmap);
+				}
+
 				// Get texture width, height and size
 				m_textureWidth = FreeImage_GetWidth(m_bitmap);
 				m_textureHeight = FreeImage_GetHeight(m_bitmap);
@@ -71,13 +106,15 @@ protected:
 				// Temp variable for swapping color channels
 				unsigned char blue = 0;
 
+				// Define number of channels per pixel
+				const unsigned int numChan = m_textureFormat == TextureFormat_RGB ? 3 : 4;
+
 				// FreeImage loads in BGR format, therefore swap of bytes is needed (Or usage of GL_BGR)
 				for(unsigned int i = 0; i < m_size; i++)
 				{
-					blue = m_pixelData[i * 4 + 0];
-
-					m_pixelData[i * 4 + 0] = m_pixelData[i * 4 + 2];	// Red
-					m_pixelData[i * 4 + 2] = blue;						// Blue
+					blue = m_pixelData[i * numChan + 0];						 // Store blue
+					m_pixelData[i * numChan + 0] = m_pixelData[i * numChan + 2]; // Set red
+					m_pixelData[i * numChan + 2] = blue;						 // Set blue
 				}
 
 				setLoadedToMemory(true);
@@ -93,111 +130,77 @@ protected:
 		return returnError;
 	}
 	
-	// Load pixel data from RAM to Video RAM
-	ErrorCode loadToVideoMemory()
+	// Deletes pixel data stored in RAM. Does not delete the texture that is loaded on GPU VRAM
+	ErrorCode unloadMemory()
 	{
 		ErrorCode returnError = ErrorCode::Success;
 
+		// Release memory if it hasn't been freed already
 		if(m_bitmap)
 		{
-			auto oldHandle = m_handle;
-
-			// Generate, bind and upload the texture
-			glGenTextures(1, &m_handle);
-			glBindTexture(GL_TEXTURE_2D, m_handle);
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_textureWidth, m_textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)m_pixelData);
-
-			// Generate  mipmaps if they are enabled
-			if(Config::textureVar().generate_mipmaps)
-				glGenerateMipmap(GL_TEXTURE_2D);
-
-			// Texture filtering mode, when image is minimized
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Config::textureVar().gl_texture_minification);
-			// Texture filtering mode, when image is magnified
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Config::textureVar().gl_texture_magnification);
-			// Texture anisotropic filtering
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, Config::textureVar().gl_texture_anisotropy);
-
-			if(m_handle == 0)
-				m_handle = oldHandle;
-
-			// Release memory
 			FreeImage_Unload(m_bitmap);
-			m_pixelData = nullptr;
 			m_bitmap = nullptr;
-		}
-		else
-		{
-			returnError = ErrorCode::Texture_not_found;
+			m_pixelData = nullptr;
 		}
 
-		setLoadedToVideoMemory(true);
-
-		return returnError;
-	}
-
-	// Deletes pixel data stored in RAM. Does not delete the texture that is loaded on GPU VRAM
-	ErrorCode unloadMemory()
-	{
-		ErrorCode returnError = ErrorCode::Success;
-		glDeleteTextures(1, &m_handle);
 		return returnError;
 	}
 
 	// Deletes texture from GPU VRAM
-	ErrorCode unloadVideoMemory()
+	/*ErrorCode unloadVideoMemory()
 	{
 		ErrorCode returnError = ErrorCode::Success;
-
-		// Release memory if it hasn't been freed already
-		if(m_bitmap)
-		{
-			FreeImage_Unload(m_bitmap);
-			m_bitmap = nullptr;
-			m_pixelData = nullptr;
-		}
-
+		glDeleteTextures(1, &m_handle);
 		return returnError;
-	}
+	}*/
 
 	// Copies the pixel data from source channel from passed texture, to the destination channel
 	// Repeats the texture, if the passed texture size does not match
 	void setColorChannel(const GLubyte *p_pixelData, unsigned int p_textureWidth, unsigned int p_textureHeight, TextureColorChannelOffset p_destChannel, TextureColorChannelOffset p_sourceChannel)
-	{		
-		// Loop through the 1D array in a 2D fashion, to make the texture-repeat easier
-		// Loop through the width of the texture
-		for(unsigned int destWidth = 0, srcWidth = 0; destWidth < m_textureWidth; destWidth++, srcWidth++)
+	{
+		// TODO: add support for RGB format as well
+		if(m_textureFormat == TextureFormat_RGBA)
 		{
-			// If the width index exceeds the passed texture width, clamp it back to 0, so it repeats
-			if(srcWidth >= p_textureWidth)
-				srcWidth = 0;
-
-			// Loop through the height of the texture
-			for(unsigned int destHeight = 0, srcHeight = 0; destHeight < m_textureHeight; destHeight++, srcHeight++)
+			// Loop through the 1D array in a 2D fashion, to make the texture-repeat easier
+			// Loop through the width of the texture
+			for(unsigned int destWidth = 0, srcWidth = 0; destWidth < m_textureWidth; destWidth++, srcWidth++)
 			{
-				// If the height index exceeds the passed texture height, clamp it back to 0, so it repeats
-				if(srcHeight >= p_textureHeight)
-					srcHeight = 0;
-				
-				// Copy the pixel data
-				// Width-index * texture-width + height-index is the translation from 2D array indices to 1D
-				// Multiply the indices by 4, because textures contain RGBA channels, and add the channel offset
-				m_pixelData[(destWidth * m_textureWidth + destHeight) * 4 + p_destChannel] =
-					p_pixelData[(srcWidth * p_textureWidth + srcHeight) * 4 + p_sourceChannel];
+				// If the width index exceeds the passed texture width, clamp it back to 0, so it repeats
+				if(srcWidth >= p_textureWidth)
+					srcWidth = 0;
+
+				// Loop through the height of the texture
+				for(unsigned int destHeight = 0, srcHeight = 0; destHeight < m_textureHeight; destHeight++, srcHeight++)
+				{
+					// If the height index exceeds the passed texture height, clamp it back to 0, so it repeats
+					if(srcHeight >= p_textureHeight)
+						srcHeight = 0;
+
+					// Copy the pixel data
+					// Width-index * texture-width + height-index is the translation from 2D array indices to 1D
+					// Multiply the indices by 4, because textures contain RGBA channels, and add the channel offset
+					m_pixelData[(destWidth * m_textureWidth + destHeight) * 4 + p_destChannel] =
+						p_pixelData[(srcWidth * p_textureWidth + srcHeight) * 4 + p_sourceChannel];
+				}
 			}
 		}
 	}
 
+	// Returns a void pointer to the pixel data
+	const inline void *getData() { return (void*)m_pixelData; }
+
 protected:
-	unsigned int m_size;
-	unsigned int m_handle;
-	unsigned int m_textureWidth;
-	unsigned int m_textureHeight;
-	unsigned char *m_pixelData;
+	TextureFormat m_textureFormat;
+	int m_mipmapLevel;
+
 	FIBITMAP* m_bitmap;
+	unsigned char *m_pixelData;
+	unsigned int m_size,
+				 m_handle,
+				 m_textureWidth,
+				 m_textureHeight;
 };
-
-class TextureLoader : public LoaderBase<TextureLoader, Texture2D>
+class TextureLoader2D : public LoaderBase<TextureLoader2D, Texture2D>
 {
 protected:
 	Texture2D *m_default2DTexture;
@@ -206,21 +209,13 @@ protected:
 	Texture2D *m_defaultNormal;
 
 public:
-	enum TextureWrapMode
-	{
-		Repeat = GL_REPEAT,
-		ClampToEdge = GL_CLAMP_TO_EDGE,
-		ClampToBorder = GL_CLAMP_TO_BORDER,
-		MirroredRepeat = GL_MIRRORED_REPEAT
-	};
 	class Texture2DHandle
 	{
-		friend class TextureLoader;
+		friend class CommandBuffer;
+		friend class TextureLoader2D;
+		friend class RendererFrontend;
 	public:
-		~Texture2DHandle() { 
-			m_textureData->decRefCounter();
-			//std::cout << m_textureData->m_filename << ": dtor Reference Counter: " << m_textureData->m_refCounter << std::endl;
-		}
+		~Texture2DHandle() { m_textureData->decRefCounter(); }
 
 		// Bind texture for rendering if it is loaded
 		// Load the texture to GPU memory instead if it's not loaded
@@ -242,9 +237,9 @@ public:
 					handle = m_textureData->m_handle;
 
 					// If loading to memory failed, log an error
-					ErrorCode error = m_textureData->loadToVideoMemory();
-					if(error != ErrorCode::Success)
-						ErrHandlerLoc::get().log(error, ErrorSource::Source_TextureLoader, m_textureData->getFilename());
+					//ErrorCode error = m_textureData->loadToVideoMemory();
+					//if(error != ErrorCode::Success)
+					//	ErrHandlerLoc::get().log(error, ErrorSource::Source_TextureLoader, m_textureData->getFilename());
 
 					// Set loaded to video memory flag to true even if loading failed.
 					// This way, the failed loading attempt is not repeated every frame.
@@ -273,7 +268,7 @@ public:
 			{
 				if(m_textureData->loadedToMemory())
 				{
-					returnError = m_textureData->loadToVideoMemory();
+				//	returnError = m_textureData->loadToVideoMemory();
 					m_textureData->setLoadedToVideoMemory(true);
 				}
 				else
@@ -282,7 +277,7 @@ public:
 					if(returnError == ErrorCode::Success)
 					{
 						m_textureData->setLoadedToMemory(true);
-						returnError = m_textureData->loadToVideoMemory();
+						//returnError = m_textureData->loadToVideoMemory();
 						m_textureData->setLoadedToVideoMemory(true);
 					}
 				}
@@ -310,9 +305,9 @@ public:
 			ErrorCode returnError = ErrorCode::Success;
 
 			// If it's not loaded to video memory already, and has been loaded to memory, call load
-			if(!m_textureData->loadedToVideoMemory())
-				if(m_textureData->loadedToMemory())
-					returnError = m_textureData->loadToVideoMemory();
+			//if(!m_textureData->loadedToVideoMemory())
+				//if(m_textureData->loadedToMemory())
+				//	returnError = m_textureData->loadToVideoMemory();
 
 			return returnError;
 		}
@@ -351,21 +346,409 @@ public:
 		}
 
 		// Getters
+		inline unsigned int getTextureHeight() const { return m_textureData->m_textureHeight; }
+		inline unsigned int getTextureWidth() const { return m_textureData->m_textureWidth; }
 		inline unsigned int getHandle() const { return m_textureData->m_handle; }
+		inline int getMipmapLevel() const { return m_textureData->m_mipmapLevel; }
 		inline std::string getFilename() const { return m_textureData->m_filename; }
+		inline TextureFormat getTextureFormat() const { return m_textureData->m_textureFormat; }
 
 	private:
 		// Increment the reference counter when creating a handle
 		Texture2DHandle(Texture2D *p_textureData) : m_textureData(p_textureData) { m_textureData->incRefCounter(); }
 
+		inline unsigned int &getHandleRef() { return m_textureData->m_handle; }
+
+		// Returns a void pointer to the pixel data
+		const inline void *getData() { return m_textureData->getData(); }
+
 		Texture2D *m_textureData;
 	};
+		
+	TextureLoader2D();
+	~TextureLoader2D();
+
+	ErrorCode init();
+
+	Texture2DHandle load(const std::string &p_filename, MaterialType p_materialType, bool p_startBackgroundLoading = true);
+	Texture2DHandle load(const std::string &p_filename, unsigned int p_textureHandle);
+};
+
+class TextureCubemap : public LoaderBase<TextureLoaderCubemap, TextureCubemap>::UniqueObject
+{
+	friend class TextureLoaderCubemap;
+	friend class Texture2DHandle;
+	friend class LoaderBase<TextureLoaderCubemap, TextureCubemap>::UniqueObject;
+protected:
+	TextureCubemap(LoaderBase<TextureLoaderCubemap, TextureCubemap> *p_loaderBase, std::string p_combinedName, const std::string(&p_filenames)[CubemapFace_NumOfFaces], size_t p_uniqueID, unsigned int p_handle) : UniqueObject(p_loaderBase, p_uniqueID, p_combinedName), m_handle(p_handle)
+	{
+		m_mipmapLevel = 0;
+		m_textureWidth = 0;
+		m_textureHeight = 0;
+		m_textureFormat = TextureFormat_RGBA;
+
+		for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+		{
+			m_filenames[face] = p_filenames[face];
+			m_pixelData[face] = nullptr;
+			m_bitmap[face] = nullptr;
+		}
+
+		// Since the texture handle has been provided, set loaded to video memory flag to true
+		//setLoadedToVideoMemory(true);
+	}
+	TextureCubemap(LoaderBase<TextureLoaderCubemap, TextureCubemap> *p_loaderBase, std::string p_combinedName, size_t p_uniqueID, unsigned int p_handle) : UniqueObject(p_loaderBase, p_uniqueID, p_combinedName), m_handle(p_handle)
+	{
+		m_mipmapLevel = 0;
+		m_textureWidth = 0;
+		m_textureHeight = 0;
+		m_textureFormat = TextureFormat_RGBA;
+
+		for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+		{
+			m_filenames[face] = Utilities::toString(face);
+			m_pixelData[face] = nullptr;
+			m_bitmap[face] = nullptr;
+		}
+
+		// Since the texture handle has been provided, set loaded to video memory flag to true
+		//setLoadedToVideoMemory(true);
+	}
+
+	// Loads pixel data (using the filename) from HDD to RAM, re-factors it
+	ErrorCode loadToMemory()
+	{
+		ErrorCode returnError = ErrorCode::Success;
+
+		// If the same texture is being used in multiple objects, loadToMemory might be called
+		// from multiple threads at the same time. Use a spin wait to deal with it
+		SpinWait::Lock lock(m_mutex);
+
+		// Texture might have already been loaded when called from a different thread. Check if it was
+		if(!loadedToMemory())
+		{
+			for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+			{
+				// Read the format of the texture
+				FREE_IMAGE_FORMAT imageFormat = FreeImage_GetFileType((Config::PathsVariables().texture_path + m_filenames[face]).c_str(), 0);
+
+				// Read the actual texture
+				m_bitmap[face] = FreeImage_Load(imageFormat, (Config::PathsVariables().texture_path + m_filenames[face]).c_str());
+				m_bitmap[face] = FreeImage_ConvertTo32Bits(m_bitmap[face]);
+
+				if(m_bitmap[face])
+				{
+					// Calculate the number of bytes per pixel
+					unsigned int bytesPerPixel = FreeImage_GetLine(m_bitmap[face]) / FreeImage_GetWidth(m_bitmap[face]);
+					// Calculate the number of samples per pixel
+					unsigned int samplesPerPixel = bytesPerPixel / sizeof(BYTE);
+
+					// Only supporting 24bits or 32bits per pixel
+					if (samplesPerPixel == 3)
+					{
+						m_textureFormat = TextureFormat_RGB;
+						m_bitmap[face] = FreeImage_ConvertTo24Bits(m_bitmap[face]);
+					}
+					else
+					{
+						m_textureFormat = TextureFormat_RGBA;
+						m_bitmap[face] = FreeImage_ConvertTo32Bits(m_bitmap[face]);
+					}
+
+					// Get texture width, height and size
+					m_textureWidth = FreeImage_GetWidth(m_bitmap[face]);
+					m_textureHeight = FreeImage_GetHeight(m_bitmap[face]);
+					m_size = m_textureWidth * m_textureHeight;
+
+					// Texture data passed to the GPU must be in an unsigned char array format
+					m_pixelData[face] = (unsigned char*)FreeImage_GetBits(m_bitmap[face]);
+
+					// Temp variable for swapping color channels
+					unsigned char blue = 0;
+
+					// FreeImage loads in BGR format, therefore swap of bytes is needed (Or usage of GL_BGR)
+					for(unsigned int i = 0; i < m_size; i++)
+					{
+						blue = m_pixelData[face][i * 4 + 0];							// Store blue
+						m_pixelData[face][i * 4 + 0] = m_pixelData[face][i * 4 + 2];	// Red
+						m_pixelData[face][i * 4 + 2] = blue;							// Blue
+					}
+				}
+				else
+				{
+					ErrHandlerLoc::get().log(ErrorCode::Texture_not_found, ErrorSource::Source_TextureLoader, m_filename);
+					returnError = ErrorCode::Texture_not_found;
+				}
+			}
+
+			if(returnError == ErrorCode::Success)
+			{
+				setLoadedToMemory(true);
+				setLoadedToVideoMemory(false);
+			}
+		}
+
+		return returnError;
+	}
+
+	/*/ Load pixel data from RAM to Video RAM
+	ErrorCode loadToVideoMemory()
+	{
+		ErrorCode returnError = ErrorCode::Success;
+
+		// Make sure that every texture is valid
+		for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+			if(!m_bitmap[face])
+				return ErrorCode::Texture_not_found;
+
+		auto oldHandle = m_handle;
+
+		// Generate, bind and upload the texture
+		glGenTextures(1, &m_handle);
+		glBindTexture(GL_TEXTURE_CUBE_MAP, m_handle);
+
+		for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+		{
+			glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA, m_textureWidth, m_textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)m_pixelData[face]);
+
+			// Release memory
+			FreeImage_Unload(m_bitmap[face]);
+			m_pixelData[face] = nullptr;
+			m_bitmap[face] = nullptr;
+		}
+
+		glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+
+		// Generate  mipmaps if they are enabled
+		if(Config::textureVar().generate_mipmaps)
+			glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+
+		// Texture filtering mode, when image is minimized
+		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+		// Texture filtering mode, when image is magnified
+		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		// Texture anisotropic filtering
+		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, Config::textureVar().gl_texture_anisotropy);
+
+		if(m_handle == 0)
+			m_handle = oldHandle;
+
+		setLoadedToVideoMemory(true);
+
+		return returnError;
+	}*/
+
+	// Deletes pixel data stored in RAM. Does not delete the texture that is loaded on GPU VRAM
+	ErrorCode unloadMemory()
+	{
+		ErrorCode returnError = ErrorCode::Success;
+		glDeleteTextures(1, &m_handle);
+		return returnError;
+	}
+
+	/*/ Deletes texture from GPU VRAM
+	ErrorCode unloadVideoMemory()
+	{
+		ErrorCode returnError = ErrorCode::Success;
+
+		for(unsigned int face = CubemapFace_PositiveX; face < CubemapFace_NumOfFaces; face++)
+		{
+			// Release memory if it hasn't been freed already
+			if(m_bitmap[face])
+			{
+				FreeImage_Unload(m_bitmap[face]);
+				m_bitmap[face] = nullptr;
+				m_pixelData[face] = nullptr;
+			}
+		}
+
+		return returnError;
+	}*/
+
+	// Returns a void pointer to the pixel data array
+	const inline void **getData() { return (const void**)m_pixelData; }
+
+protected:
+	int m_mipmapLevel;
+	unsigned int m_size;
+	unsigned int m_handle;
+	unsigned int m_textureWidth;
+	unsigned int m_textureHeight;
+	TextureFormat m_textureFormat;
+	unsigned char *m_pixelData[CubemapFace_NumOfFaces];
+
+	FIBITMAP* m_bitmap[CubemapFace_NumOfFaces];
+
+	std::string m_filenames[CubemapFace_NumOfFaces];
+};
+class TextureLoaderCubemap : public LoaderBase<TextureLoaderCubemap, TextureCubemap>
+{
+protected:
+	TextureCubemap *m_defaultCubemap;
+
+public:
+	class TextureCubemapHandle
+	{
+		friend class CommandBuffer;
+		friend class RendererFrontend;
+		friend class TextureLoaderCubemap;
+	public:
+		~TextureCubemapHandle() { m_textureData->decRefCounter(); }
+
+		/*/ Bind texture for rendering if it is loaded
+		// Load the texture to GPU memory instead if it's not loaded
+		void bind(unsigned int p_activeTextureID = GL_TEXTURE0)
+		{
+			// Declare the handle to bind at the start here, and bind it at the end of the function,
+			// so there is only one path to bind function and the branch can be predicted easier on CPU
+			decltype(m_textureData->m_handle) handle = m_textureData->m_handle;
+
+			// If the texture is already loaded (to GPU), just bind it (the handle is already assigned).
+			// Otherwise load it to GPU. This way, the texture loading is hidden away,
+			// so graphics system doesn't have to deal with it. The thread that calls bind
+			// on a texture is guaranteed to be rendering thread, so it is save to load it.
+			if(!m_textureData->loadedToVideoMemory())
+			{
+				if(m_textureData->loadedToMemory())
+				{
+					// Reassign the handle, since it has been changed while loading to video memory
+					handle = m_textureData->m_handle;
+
+					// If loading to memory failed, log an error
+					ErrorCode error = m_textureData->loadToVideoMemory();
+					if(error != ErrorCode::Success)
+						ErrHandlerLoc::get().log(error, ErrorSource::Source_TextureLoader, m_textureData->getFilename());
+
+					// Set loaded to video memory flag to true even if loading failed.
+					// This way, the failed loading attempt is not repeated every frame.
+					// (And since loaded to memory flag is already true, it is not the cause,
+					// and it will not "fix" itself)
+					m_textureData->setLoadedToVideoMemory(true);
+				}
+				else
+				{
+					// Set handle to zero if the texture is not yet ready to be used
+					handle = 0;
+				}
+			}
+
+			// Set the active texture position and bind the handle
+			glActiveTexture(GL_TEXTURE0 + p_activeTextureID);
+			glBindTexture(GL_TEXTURE_CUBE_MAP, handle);
+		}
+
+		// Upload the texture to GPU memory
+		ErrorCode preload()
+		{
+			ErrorCode returnError = ErrorCode::Success;
+
+			if(!m_textureData->loadedToVideoMemory())
+			{
+				if(m_textureData->loadedToMemory())
+				{
+					returnError = m_textureData->loadToVideoMemory();
+					m_textureData->setLoadedToVideoMemory(true);
+				}
+				else
+				{
+					returnError = m_textureData->loadToMemory();
+					if(returnError == ErrorCode::Success)
+					{
+						m_textureData->setLoadedToMemory(true);
+						returnError = m_textureData->loadToVideoMemory();
+						m_textureData->setLoadedToVideoMemory(true);
+					}
+				}
+			}
+
+			return returnError;
+		}*/
+
+		// Loads data from HDD to RAM and restructures it to be used to fill buffers later
+		ErrorCode loadToMemory()
+		{
+			ErrorCode returnError = ErrorCode::Success;
+
+			// If it's not loaded to memory already, call load
+			if(!m_textureData->loadedToMemory())
+			{
+				returnError = m_textureData->loadToMemory();
+				m_textureData->setLoadedToVideoMemory(false);
+			}
+
+			return returnError;
+		}
+
+		/*/ Loads data from RAM to buffer and uploads them to VRAM
+		// WARNING: should probably only be called from rendering thread, since this code deals with graphics API
+		ErrorCode loadToVideoMemory()
+		{
+			ErrorCode returnError = ErrorCode::Success;
+
+			// If it's not loaded to video memory already, and has been loaded to memory, call load
+			if(!m_textureData->loadedToVideoMemory())
+				if(m_textureData->loadedToMemory())
+					returnError = m_textureData->loadToVideoMemory();
+
+			return returnError;
+		}
+
+		void setWrapMode(TextureWrapMode p_wrapMode)
+		{
+			bind();
+			glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, p_wrapMode);
+			glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, p_wrapMode);
+		}*/
+
+		// Assignment operator
+		TextureCubemapHandle &operator=(const TextureCubemapHandle &p_textureHandle)
+		{
+			m_textureData->decRefCounter();
+			m_textureData = p_textureHandle.m_textureData;
+			m_textureData->incRefCounter();
+			return *this;
+		}
+
+		// Getters
+		inline unsigned int getTextureHeight() const { return m_textureData->m_textureHeight; }
+		inline unsigned int getTextureWidth() const { return m_textureData->m_textureWidth; }
+		inline unsigned int getHandle() const { return m_textureData->m_handle; }
+		inline std::string getCombinedFilename() const { return m_textureData->m_filename; }
+		inline std::string getFaceFilename(unsigned int p_face) const
+		{
+			// Make sure the passed index is within bounds
+			if(p_face >= CubemapFace_PositiveX && p_face < CubemapFace_NumOfFaces)
+				return m_textureData->m_filenames[p_face];
+
+			return std::string();
+		}
+		inline int getMipmapLevel() const { return m_textureData->m_mipmapLevel; }
+		inline TextureFormat getTextureFormat() const { return m_textureData->m_textureFormat; }
+
+
+	private:
+		// Increment the reference counter when creating a handle
+		TextureCubemapHandle(TextureCubemap *p_textureData) : m_textureData(p_textureData) { m_textureData->incRefCounter(); }
+
+		inline unsigned int &getHandleRef() { return m_textureData->m_handle; }
+
+		// Returns a void pointer to the pixel data array
+		const inline void **getData() { return m_textureData->getData(); }
+
+		TextureCubemap *m_textureData;
+	};
 
-	TextureLoader();
-	~TextureLoader();
+	TextureLoaderCubemap();
+	~TextureLoaderCubemap();
 
 	ErrorCode init();
 
-	virtual Texture2DHandle load2D(const std::string &p_filename, Model::ModelMaterialType p_materialType, bool p_startBackgroundLoading = true);
-	virtual Texture2DHandle load2D(const std::string &p_filename, unsigned int p_textureHandle);
+	TextureCubemapHandle load(	const std::string &p_filenamePosX, const std::string &p_filenameNegX, 
+								const std::string &p_filenamePosY, const std::string &p_filenameNegY, 
+								const std::string &p_filenamePosZ, const std::string &p_filenameNegZ, 
+								bool p_startBackgroundLoading = true);
+
+	TextureCubemapHandle load(const std::string (&p_filenames)[CubemapFace_NumOfFaces], bool p_startBackgroundLoading = true);
+
+	TextureCubemapHandle load(const std::string &p_filename, unsigned int p_textureHandle);
 };

+ 81 - 0
Praxis3D/Source/UniformData.h

@@ -0,0 +1,81 @@
+#pragma once
+
+#include "Math.h"
+
+struct UniformFrameData
+{
+	UniformFrameData()
+	{
+		m_numPointLights = 0;
+		m_numSpotLights = 0;
+	}
+
+	// Framebuffer size (can be different from the window size)
+	Math::Vec2i m_screenSize;
+
+	// Camera's position in the scene
+	Math::Vec3f m_cameraPosition;
+
+	// Matrices that can only change once per frame
+	Math::Mat4f m_projMatrix,
+				m_viewMatrix,
+				m_viewProjMatrix;
+
+	// Parameters of direction light, since there can be only one of it
+	Math::Vec3f m_dirLightColor,
+				m_dirLightDirection;
+	float		m_dirLightIntensity;
+
+	// Current number of lights in the light buffers
+	unsigned int m_numPointLights,
+				 m_numSpotLights;
+};
+
+struct UniformObjectData
+{
+	UniformObjectData()
+	{
+		m_heightScale = 0.0f;
+		m_alphaThreshold = 0.0f;
+		m_emissiveThreshold = 0.0f;
+		m_textureTilingFactor = 1.0f;
+	}
+
+	UniformObjectData(const Math::Mat4f &p_modelMat,
+					  const Math::Mat4f &p_modelViewProjMatrix,
+					  //const unsigned int (&p_materials)[MaterialType_NumOfTypes],
+					  float	p_heightScale = 0.0f,
+					  float p_alphaThreshold = 0.0f,
+					  float p_emissiveThreshold = 0.0f,
+					  float p_textureTilingFactor = 1.0f)
+	{
+		m_heightScale = p_heightScale;
+		m_alphaThreshold = p_alphaThreshold;
+		m_emissiveThreshold = p_emissiveThreshold;
+		m_textureTilingFactor = p_textureTilingFactor;
+
+		m_modelMat = p_modelMat;
+		m_modelViewProjMatrix = p_modelViewProjMatrix;
+
+		//memcpy(m_materials, p_materials, sizeof(m_materials));
+	}
+
+	Math::Mat4f m_modelMat,
+				m_modelViewProjMatrix;
+
+	float	m_heightScale,
+			m_alphaThreshold,
+			m_emissiveThreshold,
+			m_textureTilingFactor;
+
+	//unsigned int m_materials[MaterialType_NumOfTypes];
+};
+
+struct UniformData
+{
+	UniformData(const UniformObjectData &p_objectData, const UniformFrameData &p_frameData)
+		: m_objectData(p_objectData), m_frameData(p_frameData) { }
+
+	const UniformObjectData &m_objectData;
+	const UniformFrameData &m_frameData;
+};

+ 2 - 2
Praxis3D/Source/Universal.h

@@ -31,8 +31,8 @@ public:
 	void sendChange(SystemObject *p_subject, SystemObject *p_observer, BitMask p_changedBits)
 	{
 		// Check if any changes have been done
-		if(p_changedBits)
-			m_objectChangeController->oneTimeChange(p_subject, p_observer, p_changedBits);
+		//if(p_changedBits)
+		//	m_objectChangeController->oneTimeChange(p_subject, p_observer, p_changedBits);
 	}
 
 	virtual void changeOccurred(ObservedSubject *p_subject, BitMask p_changes);

+ 23 - 10
Praxis3D/Source/Utilities.h

@@ -59,16 +59,6 @@ namespace Utilities
 			return stringstream_ret.str() + ".0f";
 		else
 			return stringstream_ret.str() + "f";
-
-		/*for(decltype(floatString.size()) i = 0, size = floatString.size(); i < size; i++)
-			if(floatString[i] == '.')
-			{
-				floatString += "f";
-				return floatString;
-			}
-
-		floatString += ".0f";
-		return floatString;*/
 	}
 	
 
@@ -103,4 +93,27 @@ namespace Utilities
 		}
 		return hash;
 	}
+
+
+	// Template std::pair comparator, only compares the first element
+	template <class T1, class T2, class Pred = std::less<T2>>
+	struct sort_pair_first 
+	{
+		bool operator()(const std::pair<T1, T2>&left, const std::pair<T1, T2>&right) 
+		{
+			Pred p;
+			return p(left.first, right.first);
+		}
+	};
+
+	// Template std::pair comparator, only compares the second element
+	template <class T1, class T2, class Pred = std::less<T2>>
+	struct sort_pair_second 
+	{
+		bool operator()(const std::pair<T1, T2>&left, const std::pair<T1, T2>&right) 
+		{
+			Pred p;
+			return p(left.second, right.second);
+		}
+	};
 }

+ 17 - 17
Praxis3D/Source/Window.cpp

@@ -146,8 +146,19 @@ void Window::handleEvents()
 	// Process queued up changes
 	processChanges();
 
-	// Get current relative mouse location
-	SDL_GetRelativeMouseState(&m_mouseInfo.m_movementCurrentFrameX, &m_mouseInfo.m_movementCurrentFrameY);
+	SDL_Event SDLEvent;
+	while(SDL_PollEvent(&SDLEvent))
+	{
+		if(SDLEvent.type == SDL_QUIT)
+		{
+			Config::setEngineVar().running = false;
+			break;
+		}
+		else
+		{
+			handleSDLEvent(SDLEvent);
+		}
+	}
 
 	// If filtering is enabled, interpolate mouse location over current and previous frame; otherwise use current frame data
 	if(Config::inputVar().mouse_filter)
@@ -164,20 +175,6 @@ void Window::handleEvents()
 		m_mouseInfo.m_movementX = (float)m_mouseInfo.m_movementCurrentFrameX;
 		m_mouseInfo.m_movementY = (float)m_mouseInfo.m_movementCurrentFrameY;
 	}
-
-	SDL_Event SDLEvent;
-	while(SDL_PollEvent(&SDLEvent))
-	{
-		if(SDLEvent.type == SDL_QUIT)
-		{
-			Config::setEngineVar().running = false;
-			break;
-		}
-		else
-		{
-			handleSDLEvent(SDLEvent);
-		}
-	}
 }
 
 void Window::handleSDLEvent(const SDL_Event &p_SDLEvent)
@@ -262,7 +259,10 @@ void Window::handleSDLEvent(const SDL_Event &p_SDLEvent)
 
 	case SDL_MOUSEMOTION:
 	{
-		// Currently unused, as the mouse position is retrieved every frame, independently of the motion
+		// Get the relative mouse location
+		m_mouseInfo.m_movementCurrentFrameX += p_SDLEvent.motion.xrel;
+		m_mouseInfo.m_movementCurrentFrameY += p_SDLEvent.motion.yrel;
+
 		break;
 	}
 

+ 6 - 6
Praxis3D/Source/WorldEditObject.h

@@ -173,18 +173,18 @@ public:
 				// If save key is active, spawn a message box asking if the scene should be exported
 				if(m_saveKey.isActivated())
 				{
-					if(WindowLocator::get().spawnYesNoErrorBox("World Editor", "Export the scene to \"test.pmap\"?"))
-						m_sceneLoader->saveToFile();
-
 					// Deactivate key here manually, to not cause re-triggering for multiple frames
-					m_saveKey.deactivate();
 					m_modifierKey.deactivate();
+					m_saveKey.deactivate();
+
+					if(WindowLocator::get().spawnYesNoErrorBox("World Editor", "Export the scene to \"test.pmap\"?"))
+						m_sceneLoader->saveToFile();
 				}
 			}
 
 			// If an object is selected, update the its data
-			if(m_selectedObject != nullptr)
-				m_sceneLoader->getChangeController()->sendChange(this, m_selectedObject, Systems::Changes::Spacial::Position);
+			//if(m_selectedObject != nullptr)
+			//	m_sceneLoader->getChangeController()->sendChange(this, m_selectedObject, Systems::Changes::Spacial::Position);
 		}
 	}
 

BIN
Praxis3D/x64/Debug 64bit/Praxis3D.tlog/CL.command.1.tlog


BIN
Praxis3D/x64/Debug 64bit/Praxis3D.tlog/CL.read.1.tlog


BIN
Praxis3D/x64/Debug 64bit/Praxis3D.tlog/CL.write.1.tlog


+ 1 - 1
Praxis3D/x64/Debug 64bit/Praxis3D.tlog/Praxis3D.lastbuildstate

@@ -1,2 +1,2 @@
 #TargetFrameworkVersion=v4.0:PlatformToolSet=v140:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit:WindowsTargetPlatformVersion=8.1
-Debug 64bit|x64|C:\Users\Paul\Documents\Visual Studio 2015\Projects\Praxis3D - Copy - Copy\|
+Debug 64bit|x64|C:\Users\Paul\Documents\Visual Studio 2015\Projects\Praxis3D\|

BIN
Praxis3D/x64/Debug 64bit/Praxis3D.tlog/link.command.1.tlog


BIN
Praxis3D/x64/Debug 64bit/Praxis3D.tlog/link.read.1.tlog


Some files were not shown because too many files changed in this diff