Эх сурвалжийг харах

Merge branch 'data-separation' of github.com:Almamu/linux-wallpaperengine into data-separation

# Conflicts:
#	CMakeLists.txt
#	src/WallpaperEngine/Core/Objects/Particles/Initializers/CRotationRandom.cpp
#	src/WallpaperEngine/Core/Objects/Particles/Initializers/CRotationRandom.h
#	src/WallpaperEngine/Core/Projects/CProperty.cpp
#	src/WallpaperEngine/Render/CScene.cpp
#	src/WallpaperEngine/Render/Objects/CSound.cpp
#	src/WallpaperEngine/Render/Objects/CSound.h

Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Alexis Maiquez Murcia 6 жил өмнө
parent
commit
79e9ead2ee
100 өөрчлөгдсөн 3345 нэмэгдсэн , 1473 устгасан
  1. 58 5
      CMakeLists.txt
  2. 110 0
      CMakeModules/FindFFmpeg.cmake
  3. 1 0
      README.md
  4. 96 230
      main.cpp
  5. 52 49
      src/WallpaperEngine/Core/CObject.cpp
  6. 15 9
      src/WallpaperEngine/Core/CObject.h
  7. 26 27
      src/WallpaperEngine/Core/CProject.cpp
  8. 9 10
      src/WallpaperEngine/Core/CProject.h
  9. 45 154
      src/WallpaperEngine/Core/CScene.cpp
  10. 26 28
      src/WallpaperEngine/Core/CScene.h
  11. 17 0
      src/WallpaperEngine/Core/CVideo.cpp
  12. 36 0
      src/WallpaperEngine/Core/CVideo.h
  13. 18 0
      src/WallpaperEngine/Core/CWallpaper.cpp
  14. 33 0
      src/WallpaperEngine/Core/CWallpaper.h
  15. 26 14
      src/WallpaperEngine/Core/Core.cpp
  16. 3 0
      src/WallpaperEngine/Core/Core.h
  17. 201 97
      src/WallpaperEngine/Core/Objects/CEffect.cpp
  18. 17 3
      src/WallpaperEngine/Core/Objects/CEffect.h
  19. 10 15
      src/WallpaperEngine/Core/Objects/CImage.cpp
  20. 3 2
      src/WallpaperEngine/Core/Objects/CImage.h
  21. 15 35
      src/WallpaperEngine/Core/Objects/CParticle.cpp
  22. 4 4
      src/WallpaperEngine/Core/Objects/CParticle.h
  23. 5 10
      src/WallpaperEngine/Core/Objects/CSound.cpp
  24. 2 2
      src/WallpaperEngine/Core/Objects/CSound.h
  25. 29 0
      src/WallpaperEngine/Core/Objects/Effects/CBind.cpp
  26. 27 0
      src/WallpaperEngine/Core/Objects/Effects/CBind.h
  27. 40 0
      src/WallpaperEngine/Core/Objects/Effects/CFBO.cpp
  28. 28 0
      src/WallpaperEngine/Core/Objects/Effects/CFBO.h
  29. 8 0
      src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.cpp
  30. 20 0
      src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.h
  31. 17 0
      src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantFloat.cpp
  32. 21 0
      src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantFloat.h
  33. 17 0
      src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantInteger.cpp
  34. 21 0
      src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantInteger.h
  35. 17 0
      src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantVector3.cpp
  36. 21 0
      src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantVector3.h
  37. 50 14
      src/WallpaperEngine/Core/Objects/Images/CMaterial.cpp
  38. 18 6
      src/WallpaperEngine/Core/Objects/Images/CMaterial.h
  39. 141 0
      src/WallpaperEngine/Core/Objects/Images/Materials/CPass.cpp
  40. 51 0
      src/WallpaperEngine/Core/Objects/Images/Materials/CPass.h
  41. 0 131
      src/WallpaperEngine/Core/Objects/Images/Materials/CPassess.cpp
  42. 0 32
      src/WallpaperEngine/Core/Objects/Images/Materials/CPassess.h
  43. 6 13
      src/WallpaperEngine/Core/Objects/Particles/CControlPoint.cpp
  44. 4 3
      src/WallpaperEngine/Core/Objects/Particles/CControlPoint.h
  45. 14 46
      src/WallpaperEngine/Core/Objects/Particles/CEmitter.cpp
  46. 7 6
      src/WallpaperEngine/Core/Objects/Particles/CEmitter.h
  47. 4 9
      src/WallpaperEngine/Core/Objects/Particles/CInitializer.cpp
  48. 4 3
      src/WallpaperEngine/Core/Objects/Particles/CInitializer.h
  49. 4 14
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CAlphaRandom.cpp
  50. 4 3
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CAlphaRandom.h
  51. 6 18
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CAngularVelocityRandom.cpp
  52. 4 3
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CAngularVelocityRandom.h
  53. 6 18
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CColorRandom.cpp
  54. 4 3
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CColorRandom.h
  55. 4 14
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CLifeTimeRandom.cpp
  56. 4 3
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CLifeTimeRandom.h
  57. 4 4
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CRotationRandom.cpp
  58. 2 2
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CRotationRandom.h
  59. 4 14
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CSizeRandom.cpp
  60. 4 3
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CSizeRandom.h
  61. 6 18
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CVelocityRandom.cpp
  62. 4 3
      src/WallpaperEngine/Core/Objects/Particles/Initializers/CVelocityRandom.h
  63. 33 44
      src/WallpaperEngine/Core/Projects/CProperty.cpp
  64. 7 7
      src/WallpaperEngine/Core/Projects/CProperty.h
  65. 4 5
      src/WallpaperEngine/Core/Projects/CPropertyColor.cpp
  66. 3 1
      src/WallpaperEngine/Core/Projects/CPropertyColor.h
  67. 12 28
      src/WallpaperEngine/Core/Scenes/CCamera.cpp
  68. 5 4
      src/WallpaperEngine/Core/Scenes/CCamera.h
  69. 4 15
      src/WallpaperEngine/Core/Scenes/CProjection.cpp
  70. 4 3
      src/WallpaperEngine/Core/Scenes/CProjection.h
  71. 17 15
      src/WallpaperEngine/FileSystem/FileSystem.cpp
  72. 1 1
      src/WallpaperEngine/FileSystem/FileSystem.h
  73. 231 6
      src/WallpaperEngine/Irrlicht/CContext.cpp
  74. 41 0
      src/WallpaperEngine/Irrlicht/CContext.h
  75. 20 0
      src/WallpaperEngine/Irrlicht/CEventReceiver.cpp
  76. 18 0
      src/WallpaperEngine/Irrlicht/CEventReceiver.h
  77. 96 98
      src/WallpaperEngine/Irrlicht/CFileList.cpp
  78. 24 2
      src/WallpaperEngine/Irrlicht/CImageLoaderTEX.cpp
  79. 11 10
      src/WallpaperEngine/Render/CCamera.cpp
  80. 6 6
      src/WallpaperEngine/Render/CCamera.h
  81. 9 1
      src/WallpaperEngine/Render/CObject.cpp
  82. 4 2
      src/WallpaperEngine/Render/CObject.h
  83. 16 49
      src/WallpaperEngine/Render/CScene.cpp
  84. 13 13
      src/WallpaperEngine/Render/CScene.h
  85. 165 0
      src/WallpaperEngine/Render/CVideo.cpp
  86. 52 0
      src/WallpaperEngine/Render/CVideo.h
  87. 40 0
      src/WallpaperEngine/Render/CWallpaper.cpp
  88. 45 0
      src/WallpaperEngine/Render/CWallpaper.h
  89. 94 0
      src/WallpaperEngine/Render/Objects/CEffect.cpp
  90. 47 0
      src/WallpaperEngine/Render/Objects/CEffect.h
  91. 319 48
      src/WallpaperEngine/Render/Objects/CImage.cpp
  92. 19 4
      src/WallpaperEngine/Render/Objects/CImage.h
  93. 47 27
      src/WallpaperEngine/Render/Objects/CSound.cpp
  94. 9 7
      src/WallpaperEngine/Render/Objects/CSound.h
  95. 34 0
      src/WallpaperEngine/Render/Objects/Effects/CFBO.cpp
  96. 25 0
      src/WallpaperEngine/Render/Objects/Effects/CFBO.h
  97. 60 0
      src/WallpaperEngine/Render/Objects/Effects/CMaterial.cpp
  98. 52 0
      src/WallpaperEngine/Render/Objects/Effects/CMaterial.h
  99. 264 0
      src/WallpaperEngine/Render/Objects/Effects/CPass.cpp
  100. 41 0
      src/WallpaperEngine/Render/Objects/Effects/CPass.h

+ 58 - 5
CMakeLists.txt

@@ -15,8 +15,9 @@ find_package(Irrlicht REQUIRED)
 find_package(SDL REQUIRED)
 find_package(SDL_mixer REQUIRED)
 find_package(LZ4 REQUIRED)
+find_package(FFmpeg REQUIRED)
 
-include_directories(${X11_INCLUDE_DIR} ${XRANDR_INCLUDE_DIR} ${IRRLICHT_INCLUDE_DIR} ${LZ4_INCLUDE_DIR} ${SDL_INCLUDE_DIRS} ${SDL_MIXER_INCLUDE_DIRS} src include)
+include_directories(${X11_INCLUDE_DIR} ${XRANDR_INCLUDE_DIR} ${IRRLICHT_INCLUDE_DIR} ${LZ4_INCLUDE_DIR} ${SDL_INCLUDE_DIRS} ${SDL_MIXER_INCLUDE_DIRS} ${FFMPEG_INCLUDE_DIR} src include)
 
 add_executable(
         wallengine
@@ -25,11 +26,33 @@ add_executable(
         src/WallpaperEngine/Core/Core.h
         src/WallpaperEngine/Core/Core.cpp
 
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariable.h
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariable.cpp
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableFloat.h
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableFloat.cpp
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableInteger.h
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableInteger.cpp
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector2.h
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector2.cpp
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector3.h
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector3.cpp
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector4.h
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector4.cpp
+
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableFloatPointer.h
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableFloatPointer.cpp
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector2Pointer.h
+        src/WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector2Pointer.cpp
+
         src/WallpaperEngine/Render/Shaders/Compiler.h
         src/WallpaperEngine/Render/Shaders/Compiler.cpp
 
+        src/WallpaperEngine/Render/CWallpaper.h
+        src/WallpaperEngine/Render/CWallpaper.cpp
         src/WallpaperEngine/Render/CScene.h
         src/WallpaperEngine/Render/CScene.cpp
+        src/WallpaperEngine/Render/CVideo.h
+        src/WallpaperEngine/Render/CVideo.cpp
         src/WallpaperEngine/Render/CCamera.h
         src/WallpaperEngine/Render/CCamera.cpp
         src/WallpaperEngine/Render/CObject.h
@@ -37,12 +60,23 @@ add_executable(
 
         src/WallpaperEngine/Render/Objects/CImage.h
         src/WallpaperEngine/Render/Objects/CImage.cpp
-        src/WallpaperEngine/Render/Objects/CSound.cpp
         src/WallpaperEngine/Render/Objects/CSound.h
+        src/WallpaperEngine/Render/Objects/CSound.cpp
+        src/WallpaperEngine/Render/Objects/CEffect.h
+        src/WallpaperEngine/Render/Objects/CEffect.cpp
+
+        src/WallpaperEngine/Render/Objects/Effects/CFBO.h
+        src/WallpaperEngine/Render/Objects/Effects/CFBO.cpp
+        src/WallpaperEngine/Render/Objects/Effects/CPass.h
+        src/WallpaperEngine/Render/Objects/Effects/CPass.cpp
+        src/WallpaperEngine/Render/Objects/Effects/CMaterial.h
+        src/WallpaperEngine/Render/Objects/Effects/CMaterial.cpp
 
         src/WallpaperEngine/FileSystem/FileSystem.cpp
         src/WallpaperEngine/FileSystem/FileSystem.h
 
+        src/WallpaperEngine/Irrlicht/CEventReceiver.h
+        src/WallpaperEngine/Irrlicht/CEventReceiver.cpp
         src/WallpaperEngine/Irrlicht/CContext.h
         src/WallpaperEngine/Irrlicht/CContext.cpp
         src/WallpaperEngine/Irrlicht/CImageLoaderTEX.h
@@ -54,8 +88,12 @@ add_executable(
 
         src/WallpaperEngine/Core/CProject.cpp
         src/WallpaperEngine/Core/CProject.h
+        src/WallpaperEngine/Core/CWallpaper.cpp
+        src/WallpaperEngine/Core/CWallpaper.h
         src/WallpaperEngine/Core/CScene.cpp
         src/WallpaperEngine/Core/CScene.h
+        src/WallpaperEngine/Core/CVideo.cpp
+        src/WallpaperEngine/Core/CVideo.h
         src/WallpaperEngine/Core/CObject.cpp
         src/WallpaperEngine/Core/CObject.h
 
@@ -80,6 +118,20 @@ add_executable(
         src/WallpaperEngine/Core/Objects/CParticle.cpp
         src/WallpaperEngine/Core/Objects/CParticle.h
 
+        src/WallpaperEngine/Core/Objects/Effects/CFBO.h
+        src/WallpaperEngine/Core/Objects/Effects/CFBO.cpp
+        src/WallpaperEngine/Core/Objects/Effects/CBind.h
+        src/WallpaperEngine/Core/Objects/Effects/CBind.cpp
+
+        src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.h
+        src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.cpp
+        src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantFloat.h
+        src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantFloat.cpp
+        src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantVector3.h
+        src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantVector3.cpp
+        src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantInteger.h
+        src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantInteger.cpp
+
         src/WallpaperEngine/Core/Objects/Particles/CControlPoint.cpp
         src/WallpaperEngine/Core/Objects/Particles/CControlPoint.h
         src/WallpaperEngine/Core/Objects/Particles/CEmitter.cpp
@@ -107,7 +159,8 @@ add_executable(
         src/WallpaperEngine/Core/Objects/Images/CMaterial.cpp
         src/WallpaperEngine/Core/Objects/Images/CMaterial.h
 
-        src/WallpaperEngine/Core/Objects/Images/Materials/CPassess.cpp
-        src/WallpaperEngine/Core/Objects/Images/Materials/CPassess.h)
+        src/WallpaperEngine/Core/Objects/Images/Materials/CPass.cpp
+        src/WallpaperEngine/Core/Objects/Images/Materials/CPass.h
+)
 
-target_link_libraries(wallengine ${X11_LIBRARIES} ${XRANDR_LIBRARIES} ${X11_Xxf86vm_LIB} ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ${ZLIB_LIBRARIES} ${IRRLICHT_LIBRARY} ${LZ4_LIBRARY} ${SDL_LIBRARY} ${SDL_MIXER_LIBRARIES})
+target_link_libraries(wallengine ${X11_LIBRARIES} ${XRANDR_LIBRARIES} ${X11_Xxf86vm_LIB} ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ${ZLIB_LIBRARIES} ${IRRLICHT_LIBRARY} ${LZ4_LIBRARY} ${SDL_LIBRARY} ${SDL_MIXER_LIBRARIES} ${FFMPEG_LIBRARIES})

+ 110 - 0
CMakeModules/FindFFmpeg.cmake

@@ -0,0 +1,110 @@
+# - Try to find ffmpeg libraries (libavcodec, libavformat, libavutil and libswscale)
+# Once done this will define
+#
+# FFMPEG_FOUND - system has ffmpeg or libav
+# FFMPEG_INCLUDE_DIR - the ffmpeg include directory
+# FFMPEG_LIBRARIES - Link these to use ffmpeg
+# FFMPEG_LIBAVCODEC
+# FFMPEG_LIBAVFORMAT
+# FFMPEG_LIBAVUTIL
+# FFMPEG_LIBSWSCALE
+#
+# Copyright (c) 2008 Andreas Schneider <mail@cynapses.org>
+# Modified for other libraries by Lasse Kärkkäinen <tronic>
+# Modified for Hedgewars by Stepik777
+# Modified for FFmpeg-example Tuukka Pasanen 2018
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+#
+
+include(FindPackageHandleStandardArgs)
+
+    find_package_handle_standard_args(FFMPEG
+        FOUND_VAR FFMPEG_FOUND
+        REQUIRED_VARS
+            FFMPEG_LIBRARY
+            FFMPEG_INCLUDE_DIR
+        VERSION_VAR FFMPEG_VERSION
+    )
+
+if(FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
+  # in cache already
+  set(FFMPEG_FOUND TRUE)
+else()
+  # use pkg-config to get the directories and then use these values
+  # in the FIND_PATH() and FIND_LIBRARY() calls
+  find_package(PkgConfig)
+  if(PKG_CONFIG_FOUND)
+    pkg_check_modules(_FFMPEG_AVCODEC libavcodec)
+    pkg_check_modules(_FFMPEG_AVFORMAT libavformat)
+    pkg_check_modules(_FFMPEG_AVUTIL libavutil)
+    pkg_check_modules(_FFMPEG_SWSCALE libswscale)
+  endif()
+
+  find_path(FFMPEG_AVCODEC_INCLUDE_DIR
+    NAMES libavcodec/avcodec.h
+    PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS}
+      /usr/include
+      /usr/local/include
+      /opt/local/include
+      /sw/include
+    PATH_SUFFIXES ffmpeg libav)
+
+  find_library(FFMPEG_LIBAVCODEC
+    NAMES avcodec
+    PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS}
+      /usr/lib
+      /usr/local/lib
+      /opt/local/lib
+      /sw/lib)
+
+  find_library(FFMPEG_LIBAVFORMAT
+    NAMES avformat
+    PATHS ${_FFMPEG_AVFORMAT_LIBRARY_DIRS}
+      /usr/lib
+      /usr/local/lib
+      /opt/local/lib
+      /sw/lib)
+
+  find_library(FFMPEG_LIBAVUTIL
+    NAMES avutil
+    PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS}
+      /usr/lib
+      /usr/local/lib
+      /opt/local/lib
+      /sw/lib)
+
+   find_library(FFMPEG_LIBSWSCALE
+    NAMES swscale
+    PATHS ${_FFMPEG_SWSCALE_LIBRARY_DIRS}
+      /usr/lib
+      /usr/local/lib
+      /opt/local/lib
+      /sw/lib)
+
+  if(FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVFORMAT)
+    set(FFMPEG_FOUND TRUE)
+  endif()
+
+  if(FFMPEG_FOUND)
+    set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR})
+    set(FFMPEG_LIBRARIES
+      ${FFMPEG_LIBAVCODEC}
+      ${FFMPEG_LIBAVFORMAT}
+      ${FFMPEG_LIBAVUTIL}
+      ${FFMPEG_LIBSWSCALE})
+  endif()
+
+  if(FFMPEG_FOUND)
+    if(NOT FFMPEG_FIND_QUIETLY)
+      message(STATUS
+      "Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}")
+    endif()
+  else()
+    if(FFMPEG_FIND_REQUIRED)
+      message(FATAL_ERROR
+      "Could not find libavcodec or libavformat or libavutil or libswscale")
+    endif()
+  endif()
+endif()

+ 1 - 0
README.md

@@ -15,6 +15,7 @@ Wallpaper Engine is a software designed by [Kristjan Skutta](https://store.steam
 - ZLIB
 - SDL
 - SDL_mixer
+- FFmpeg
 - X11
 - Xrandr
 

+ 96 - 230
main.cpp

@@ -1,153 +1,24 @@
 #include <iostream>
 #include <irrlicht/irrlicht.h>
-#include <sstream>
-#include <WallpaperEngine/Irrlicht/CPkgReader.h>
 #include <getopt.h>
 #include <SDL_mixer.h>
 #include <SDL.h>
 
-#include <X11/Xlib.h>
-#include <X11/extensions/Xrandr.h>
-
-#include "WallpaperEngine/Render/Shaders/Compiler.h"
-#include "WallpaperEngine/Irrlicht/CImageLoaderTEX.h"
-
 #include "WallpaperEngine/Core/CProject.h"
 #include "WallpaperEngine/Irrlicht/CContext.h"
+#include "WallpaperEngine/Render/CWallpaper.h"
 #include "WallpaperEngine/Render/CScene.h"
+#include "WallpaperEngine/Render/CVideo.h"
 
-bool IsRootWindow = false;
-std::vector<std::string> Screens;
-std::vector<irr::core::rect<irr::s32>> Viewports;
-
-irr::SIrrlichtCreationParameters _irr_params;
-
-irr::f32 g_Time = 0;
-
-WallpaperEngine::Irrlicht::CContext* IrrlichtContext;
-void initialize_viewports ()
-{
-    if (IsRootWindow == false || Screens.size () == 0)
-        return;
-
-    Display* display = XOpenDisplay (NULL);
-    int xrandr_result, xrandr_error;
-
-    if (!XRRQueryExtension (display, &xrandr_result, &xrandr_error))
-    {
-        std::cerr << "XRandr is not present, cannot detect specified screens, running in window mode" << std::endl;
-        return;
-    }
-
-    XRRScreenResources* screenResources = XRRGetScreenResources (display, DefaultRootWindow (display));
-
-    // there are some situations where xrandr returns null (like screen not using the extension)
-    if (screenResources == nullptr)
-        return;
-
-    for (int i = 0; i < screenResources->noutput; i ++)
-    {
-        XRROutputInfo* info = XRRGetOutputInfo (display, screenResources, screenResources->outputs [i]);
-
-        // there are some situations where xrandr returns null (like screen not using the extension)
-        if (info == nullptr)
-            continue;
-
-        std::vector<std::string>::iterator cur = Screens.begin ();
-        std::vector<std::string>::iterator end = Screens.end ();
-
-        for (; cur != end; cur ++)
-        {
-            if (info->connection == RR_Connected && strcmp (info->name, (*cur).c_str ()) == 0)
-            {
-                XRRCrtcInfo* crtc = XRRGetCrtcInfo (display, screenResources, info->crtc);
-
-                std::cout << "Found requested screen: " << info->name << " -> " << crtc->x << "x" << crtc->y << ":" << crtc->width << "x" << crtc->height << std::endl;
-
-                irr::core::rect<irr::s32> viewport;
-
-                viewport.UpperLeftCorner.X = crtc->x;
-                viewport.UpperLeftCorner.Y = crtc->y;
-                viewport.LowerRightCorner.X = crtc->x + crtc->width;
-                viewport.LowerRightCorner.Y = crtc->y + crtc->height;
-
-                Viewports.push_back (viewport);
-
-                XRRFreeCrtcInfo (crtc);
-            }
-        }
-
-        XRRFreeOutputInfo (info);
-    }
-
-    XRRFreeScreenResources (screenResources);
-
-    _irr_params.WindowId = reinterpret_cast<void*> (DefaultRootWindow (display));
-}
-
-int init_irrlicht()
+enum BACKGROUND_RUN_MODE
 {
-    IrrlichtContext = new WallpaperEngine::Irrlicht::CContext ();
-
-    // prepare basic configuration for irrlicht
-    _irr_params.AntiAlias = 8;
-    _irr_params.Bits = 16;
-    // _irr_params.DeviceType = Irrlicht::EIDT_X11;
-    _irr_params.DriverType = irr::video::EDT_OPENGL;
-    _irr_params.Doublebuffer = false;
-    _irr_params.EventReceiver = nullptr;
-    _irr_params.Fullscreen = false;
-    _irr_params.HandleSRGB = false;
-    _irr_params.IgnoreInput = true;
-    _irr_params.Stencilbuffer = true;
-    _irr_params.UsePerformanceTimer = false;
-    _irr_params.Vsync = false;
-    _irr_params.WithAlphaChannel = false;
-    _irr_params.ZBufferBits = 24;
-    _irr_params.LoggingLevel = irr::ELL_DEBUG;
-
-    initialize_viewports ();
-
-    IrrlichtContext->setDevice (irr::createDeviceEx (_irr_params));
-
-    if (IrrlichtContext->getDevice () == nullptr)
-    {
-        return 1;
-    }
-
-    IrrlichtContext->getDevice ()->setWindowCaption (L"Test game");
-
-    // check for ps and vs support
-    if (
-            IrrlichtContext->getDevice ()->getVideoDriver()->queryFeature (irr::video::EVDF_PIXEL_SHADER_1_1) == false &&
-            IrrlichtContext->getDevice ()->getVideoDriver()->queryFeature (irr::video::EVDF_ARB_FRAGMENT_PROGRAM_1) == false)
-    {
-        IrrlichtContext->getDevice ()->getLogger ()->log ("WARNING: Pixel shaders disabled because of missing driver/hardware support");
-    }
+    RUN_MODE_UNKNOWN = 0,
+    RUN_MODE_HELP = 1,
+    RUN_MODE_DIRECTORY = 2,
+    RUN_MODE_PACKAGE = 3
+};
 
-    if (
-            IrrlichtContext->getDevice ()->getVideoDriver()->queryFeature (irr::video::EVDF_VERTEX_SHADER_1_1) == false &&
-            IrrlichtContext->getDevice ()->getVideoDriver()->queryFeature (irr::video::EVDF_ARB_VERTEX_PROGRAM_1) == false)
-    {
-        IrrlichtContext->getDevice ()->getLogger ()->log ("WARNING: Vertex shaders disabled because of missing driver/hardware support");
-    }
-
-    return 0;
-}
-
-void preconfigure_wallpaper_engine ()
-{
-    // load the assets from wallpaper engine
-    IrrlichtContext->getDevice ()->getFileSystem ()->addFileArchive ("assets.zip", true, false);
-
-    // register custom loaders
-    IrrlichtContext->getDevice ()->getVideoDriver()->addExternalImageLoader (
-        new WallpaperEngine::Irrlicht::CImageLoaderTex (IrrlichtContext)
-    );
-    IrrlichtContext->getDevice ()->getFileSystem ()->addArchiveLoader (
-        new WallpaperEngine::Irrlicht::CArchiveLoaderPkg (IrrlichtContext)
-    );
-}
+WallpaperEngine::Irrlicht::CContext* IrrlichtContext = nullptr;
 
 void print_help (const char* route)
 {
@@ -176,21 +47,24 @@ std::string stringPathFixes(const std::string& s){
 
 int main (int argc, char* argv[])
 {
-    int mode = 0;
-    int max_fps = 30;
-    bool audio_support = true;
+    std::vector <std::string> screens;
+    bool isRootWindow = false;
+
+    int mode = RUN_MODE_UNKNOWN;
+    int maximumFPS = 30;
+    bool shouldEnableAudio = true;
     std::string path;
 
     int option_index = 0;
 
     static struct option long_options [] = {
-            {"screen-root", required_argument, 0, 'r'},
-            {"pkg",         required_argument, 0, 'p'},
-            {"dir",         required_argument, 0, 'd'},
-            {"silent",      no_argument,       0, 's'},
-            {"help",        no_argument,       0, 'h'},
-            {"fps",         required_argument, 0, 'f'},
-            {nullptr,              0, 0,   0}
+        {"screen-root", required_argument, 0, 'r'},
+        {"pkg",         required_argument, 0, 'p'},
+        {"dir",         required_argument, 0, 'd'},
+        {"silent",      no_argument,       0, 's'},
+        {"help",        no_argument,       0, 'h'},
+        {"fps",         required_argument, 0, 'f'},
+        {nullptr,              0, 0,   0}
     };
 
     while (true)
@@ -203,30 +77,32 @@ int main (int argc, char* argv[])
         switch (c)
         {
             case 'r':
-                IsRootWindow = true;
-                Screens.push_back (optarg);
+                isRootWindow = true;
+                screens.emplace_back (optarg);
                 break;
 
             case 'p':
-                mode = 1;
+                if (mode == RUN_MODE_UNKNOWN)
+                    mode = RUN_MODE_PACKAGE;
                 path = optarg;
                 break;
 
             case 'd':
-                mode = 2;
+                if (mode == RUN_MODE_UNKNOWN)
+                    mode = RUN_MODE_DIRECTORY;
                 path = optarg;
                 break;
 
             case 's':
-                audio_support = false;
+                shouldEnableAudio = false;
                 break;
 
             case 'h':
-                print_help (argv [0]);
-                return 0;
+                mode = RUN_MODE_HELP;
+                break;
 
             case 'f':
-                max_fps = atoi (optarg);
+                maximumFPS = atoi (optarg);
                 break;
 
             default:
@@ -234,55 +110,52 @@ int main (int argc, char* argv[])
         }
     }
 
-    if (init_irrlicht ())
+    if (mode == RUN_MODE_UNKNOWN || mode == RUN_MODE_HELP)
     {
-        return 1;
+        print_help (argv [0]);
+        return 0;
     }
 
-    preconfigure_wallpaper_engine ();
-
-    irr::io::path wallpaper_path;
-    irr::io::path project_path;
-    irr::io::path scene_path;
-
-    switch (mode)
+    try
     {
-        case 0:
-            print_help (argv [0]);
-            return 0;
-
-        // pkg mode
-        case 1:
-            path = stringPathFixes(path);
-            wallpaper_path = IrrlichtContext->getDevice ()->getFileSystem ()->getAbsolutePath (path.c_str ());
-            project_path = wallpaper_path + "project.json";
-            scene_path = wallpaper_path + "scene.pkg";
-
-            IrrlichtContext->getDevice ()->getFileSystem ()->addFileArchive (scene_path, true, false); // add the pkg file to the lookup list
-            break;
+        IrrlichtContext = new WallpaperEngine::Irrlicht::CContext (screens, isRootWindow);
+        IrrlichtContext->initializeContext ();
+    }
+    catch (std::runtime_error& ex)
+    {
+        std::cerr << ex.what () << std::endl;
 
-        // folder mode
-        case 2:
-            path = stringPathFixes(path);
-            wallpaper_path = IrrlichtContext->getDevice ()->getFileSystem ()->getAbsolutePath (path.c_str ());
-            project_path = wallpaper_path + "project.json";
+        return 1;
+    }
 
-            // set our working directory
-            IrrlichtContext->getDevice ()->getFileSystem ()->changeWorkingDirectoryTo (wallpaper_path);
-            break;
+    path = stringPathFixes (path);
 
-        default:
-            break;
+    irr::io::path wallpaper_path = IrrlichtContext->getDevice ()->getFileSystem ()->getAbsolutePath (path.c_str ());
+    irr::io::path project_path = wallpaper_path + "project.json";
+
+    if (mode == RUN_MODE_PACKAGE)
+    {
+        irr::io::path scene_path = wallpaper_path + "scene.pkg";
+        // add the package file to the lookup list
+        IrrlichtContext->getDevice ()->getFileSystem ()->addFileArchive (scene_path, true, false);
+    }
+    else if (mode == RUN_MODE_DIRECTORY)
+    {
+        project_path = wallpaper_path + "project.json";
+        // set the working directory to the project folder
+        IrrlichtContext->getDevice ()->getFileSystem ()->changeWorkingDirectoryTo (wallpaper_path);
     }
 
-    if (audio_support == true)
+    if (shouldEnableAudio == true)
     {
         int mixer_flags = MIX_INIT_MP3 | MIX_INIT_FLAC | MIX_INIT_OGG;
 
         if (SDL_Init (SDL_INIT_AUDIO) < 0 || mixer_flags != Mix_Init (mixer_flags))
         {
-            IrrlichtContext->getDevice ()->getLogger ()->log ("Cannot initialize SDL audio system", irr::ELL_ERROR);
-            return -1;
+            // Mix_GetError is an alias for SDL_GetError, so calling it directly will yield the correct result
+            // it doesn't matter if SDL_Init or Mix_Init failed, both report the errors through the same functions
+            IrrlichtContext->getDevice ()->getLogger ()->log ("Cannot initialize SDL audio system", SDL_GetError(),irr::ELL_ERROR);
+            return 2;
         }
 
         // initialize audio engine
@@ -290,51 +163,44 @@ int main (int argc, char* argv[])
     }
 
     WallpaperEngine::Core::CProject* project = WallpaperEngine::Core::CProject::fromFile (project_path);
-    WallpaperEngine::Render::CScene* sceneRender = new WallpaperEngine::Render::CScene (project, IrrlichtContext);
-
-    irr::u32 lastTime = 0;
-    irr::u32 minimumTime = 1000 / max_fps;
-    irr::u32 currentTime = 0;
+    WallpaperEngine::Render::CWallpaper* wallpaper;
 
+    if (project->getType () == "scene")
+    {
+        WallpaperEngine::Core::CScene* scene = project->getWallpaper ()->as <WallpaperEngine::Core::CScene> ();
+        wallpaper = new WallpaperEngine::Render::CScene (scene, IrrlichtContext);
+        IrrlichtContext->getDevice ()->getSceneManager ()->setAmbientLight (
+                    scene->getAmbientColor ().toSColor ()
+        );
+    }
+    else if (project->getType () == "video")
+    {
+        wallpaper = new WallpaperEngine::Render::CVideo (
+                    project->getWallpaper ()->as <WallpaperEngine::Core::CVideo> (),
+                    IrrlichtContext
+        );
+    }
+    else
+    {
+        throw std::runtime_error ("Unsupported wallpaper type");
+    }
+    
+    irr::u32 minimumTime = 1000 / maximumFPS;
     irr::u32 startTime = 0;
     irr::u32 endTime = 0;
 
     while (IrrlichtContext && IrrlichtContext->getDevice () && IrrlichtContext->getDevice ()->run ())
     {
-        // if (device->isWindowActive ())
-        {
-            currentTime = startTime = IrrlichtContext->getDevice ()->getTimer ()->getTime ();
-            g_Time = currentTime / 1000.0f;
-
-            if (Viewports.size () > 0)
-            {
-                std::vector<irr::core::rect<irr::s32>>::iterator cur = Viewports.begin ();
-                std::vector<irr::core::rect<irr::s32>>::iterator end = Viewports.end ();
-
-                for (; cur != end; cur ++)
-                {
-                    // change viewport to render to the correct portion of the display
-                    IrrlichtContext->getDevice ()->getVideoDriver ()->setViewPort (*cur);
-
-                    if (IrrlichtContext->getDevice ()->getVideoDriver () == nullptr)
-                        continue;
-
-                    IrrlichtContext->getDevice ()->getVideoDriver ()->beginScene(false, true, irr::video::SColor(0, 0, 0, 0));
-                    IrrlichtContext->getDevice ()->getSceneManager ()->drawAll ();
-                    IrrlichtContext->getDevice ()->getVideoDriver ()->endScene ();
-                }
-            }
-            else
-            {
-                IrrlichtContext->getDevice ()->getVideoDriver ()->beginScene(false, true, irr::video::SColor(0, 0, 0, 0));
-                IrrlichtContext->getDevice ()->getSceneManager ()->drawAll ();
-                IrrlichtContext->getDevice ()->getVideoDriver ()->endScene ();
-            }
-
-            endTime = IrrlichtContext->getDevice ()->getTimer ()->getTime ();
-
-            IrrlichtContext->getDevice ()->sleep (minimumTime - (endTime - startTime), false);
-        }
+        if (IrrlichtContext->getDevice ()->getVideoDriver () == nullptr)
+            continue;
+
+        startTime = IrrlichtContext->getDevice ()->getTimer ()->getTime ();
+
+        IrrlichtContext->renderFrame (wallpaper);
+
+        endTime = IrrlichtContext->getDevice ()->getTimer ()->getTime ();
+
+        IrrlichtContext->getDevice ()->sleep (minimumTime - (endTime - startTime), false);
     }
 
     SDL_Quit ();

+ 52 - 49
src/WallpaperEngine/Core/CObject.cpp

@@ -5,8 +5,6 @@
 #include "WallpaperEngine/Core/Objects/CSound.h"
 #include "WallpaperEngine/Core/Objects/CParticle.h"
 
-#include "Core.h"
-
 using namespace WallpaperEngine::Core;
 
 CObject::CObject (
@@ -29,42 +27,17 @@ CObject::CObject (
 
 CObject* CObject::fromJSON (json data)
 {
-    json::const_iterator id_it = data.find ("id");
-    json::const_iterator visible_it = data.find ("visible");
-    json::const_iterator origin_it = data.find ("origin");
-    json::const_iterator scale_it = data.find ("scale");
-    json::const_iterator size_it = data.find ("size");
-    json::const_iterator angles_it = data.find ("angles");
-    json::const_iterator name_it = data.find ("name");
-    json::const_iterator effects_it = data.find ("effects");
+    auto id_it = jsonFindRequired (data, "id", "Objects must have id");
+    auto visible_it = data.find ("visible");
+    auto origin_it = jsonFindRequired (data, "origin", "Objects must have origin point");
+    auto scale_it = jsonFindRequired (data, "scale", "Objects must have scale");
+    auto angles_it = jsonFindRequired (data, "angles", "Objects must have angles");
+    auto name_it = jsonFindRequired (data, "name", "Objects must have name");
+    auto effects_it = data.find ("effects");
+    auto dependencies_it = data.find ("dependencies");
 
     bool visible = true;
 
-    if (id_it == data.end ())
-    {
-        throw std::runtime_error ("Objects must have id");
-    }
-
-    if (origin_it == data.end ())
-    {
-        throw std::runtime_error ("Objects must have origin point");
-    }
-
-    if (scale_it == data.end ())
-    {
-        throw std::runtime_error ("Objects must have scale");
-    }
-
-    if (angles_it == data.end ())
-    {
-        throw std::runtime_error ("Objects must have angles");
-    }
-
-    if (name_it == data.end ())
-    {
-        throw std::runtime_error ("Objects must have name");
-    }
-
     // visibility is optional
     if (visible_it != data.end ())
     {
@@ -80,9 +53,9 @@ CObject* CObject::fromJSON (json data)
         }
     }
 
-    json::const_iterator image_it = data.find ("image");
-    json::const_iterator sound_it = data.find ("sound");
-    json::const_iterator particle_it = data.find ("particle");
+    auto image_it = data.find ("image");
+    auto sound_it = data.find ("sound");
+    auto particle_it = data.find ("particle");
 
     CObject* object = nullptr;
 
@@ -127,8 +100,8 @@ CObject* CObject::fromJSON (json data)
 
     if (effects_it != data.end () && (*effects_it).is_array () == true)
     {
-        json::const_iterator cur = (*effects_it).begin ();
-        json::const_iterator end = (*effects_it).end ();
+        auto cur = (*effects_it).begin ();
+        auto end = (*effects_it).end ();
 
         for (; cur != end; cur ++)
         {
@@ -138,30 +111,56 @@ CObject* CObject::fromJSON (json data)
         }
     }
 
+    if (dependencies_it != data.end () && (*dependencies_it).is_array () == true)
+    {
+        auto cur = (*dependencies_it).begin ();
+        auto end = (*dependencies_it).end ();
+
+        for (; cur != end; cur ++)
+        {
+            object->insertDependency (*cur);
+        }
+    }
+
     return object;
 }
 
-irr::core::vector3df* CObject::getOrigin ()
+const irr::core::vector3df& CObject::getOrigin () const
+{
+    return this->m_origin;
+}
+
+const irr::core::vector3df& CObject::getScale () const
 {
-    return &this->m_origin;
+    return this->m_scale;
 }
 
-irr::core::vector3df* CObject::getScale ()
+const irr::core::vector3df& CObject::getAngles () const
 {
-    return &this->m_scale;
+    return this->m_angles;
 }
 
-irr::core::vector3df* CObject::getAngles ()
+const std::string& CObject::getName () const
 {
-    return &this->m_angles;
+    return this->m_name;
 }
 
-std::vector<Objects::CEffect*>* CObject::getEffects ()
+const std::vector<Objects::CEffect*>& CObject::getEffects () const
 {
-    return &this->m_effects;
+    return this->m_effects;
 }
 
-int CObject::getId ()
+const std::vector<irr::u32>& CObject::getDependencies () const
+{
+    return this->m_dependencies;
+}
+
+bool CObject::isVisible ()
+{
+    return this->m_visible;
+}
+
+const int CObject::getId () const
 {
     return this->m_id;
 }
@@ -169,4 +168,8 @@ int CObject::getId ()
 void CObject::insertEffect (Objects::CEffect* effect)
 {
     this->m_effects.push_back (effect);
+}
+void CObject::insertDependency (irr::u32 dependency)
+{
+    this->m_dependencies.push_back (dependency);
 }

+ 15 - 9
src/WallpaperEngine/Core/CObject.h

@@ -1,8 +1,9 @@
 #pragma once
 
-#include <nlohmann/json.hpp>
 #include <irrlicht/irrlicht.h>
 
+#include "Core.h"
+
 #include "WallpaperEngine/Core/Objects/CEffect.h"
 
 namespace WallpaperEngine::Core::Objects
@@ -19,18 +20,21 @@ namespace WallpaperEngine::Core
     public:
         static CObject* fromJSON (json data);
 
-        template<class T> const T* As () const { assert (Is<T> ()); return (const T*) this; }
-        template<class T> T* As () { assert (Is<T> ()); return (T*) this; }
+        template<class T> const T* as () const { assert (is <T> ()); return (const T*) this; }
+        template<class T> T* as () { assert (is <T> ()); return (T*) this; }
 
-        template<class T> bool Is () { return this->m_type == T::Type; }
+        template<class T> bool is () { return this->m_type == T::Type; }
 
-        std::vector<Objects::CEffect*>* getEffects ();
-        int getId ();
+        const std::vector<Objects::CEffect*>& getEffects () const;
+        const std::vector<irr::u32>& getDependencies () const;
+        const int getId () const;
 
-        irr::core::vector3df* getOrigin ();
-        irr::core::vector3df* getScale ();
-        irr::core::vector3df* getAngles ();
+        const irr::core::vector3df& getOrigin () const;
+        const irr::core::vector3df& getScale () const;
+        const irr::core::vector3df& getAngles () const;
+        const std::string& getName () const;
 
+        bool isVisible ();
     protected:
         CObject (
             bool visible,
@@ -43,6 +47,7 @@ namespace WallpaperEngine::Core
         );
 
         void insertEffect (Objects::CEffect* effect);
+        void insertDependency (irr::u32 dependency);
     private:
         std::string m_type;
 
@@ -54,5 +59,6 @@ namespace WallpaperEngine::Core
         irr::core::vector3df m_angles;
 
         std::vector<Objects::CEffect*> m_effects;
+        std::vector<irr::u32> m_dependencies;
     };
 };

+ 26 - 27
src/WallpaperEngine/Core/CProject.cpp

@@ -1,55 +1,54 @@
 #include <WallpaperEngine/FileSystem/FileSystem.h>
 
 #include "CProject.h"
+#include "CScene.h"
+#include "CVideo.h"
 
 using namespace WallpaperEngine::Core;
 
-CProject::CProject (std::string title, std::string type, CScene *scene) :
+CProject::CProject (std::string title, std::string type, CWallpaper* wallpaper) :
     m_title (std::move (title)),
     m_type (std::move (type)),
-    m_scene (scene)
+    m_wallpaper (wallpaper)
 {
-    this->m_scene->setProject (this);
+    this->m_wallpaper->setProject (this);
 }
 
 CProject* CProject::fromFile (const irr::io::path& filename)
 {
     json content = json::parse (WallpaperEngine::FileSystem::loadFullFile (filename));
 
-    json::const_iterator title = content.find ("title");
-    json::const_iterator type = content.find ("type");
-    json::const_iterator file = content.find ("file");
-    json::const_iterator general = content.find ("general");
+    auto title = jsonFindRequired (content, "title", "Project title missing");
+    auto type = jsonFindRequired (content, "type", "Project type missing");
+    auto file = jsonFindRequired (content, "file", "Project's main file missing");
+    auto general = content.find ("general");
+    CWallpaper* wallpaper;
 
-    if (title == content.end ())
+    if (strcmp ((*type).get <std::string> ().c_str (), "scene") == 0)
     {
-        throw std::runtime_error ("Project title missing");
+        wallpaper = CScene::fromFile ((*file).get <std::string> ().c_str ());
     }
-
-    if (type == content.end ())
-    {
-        throw std::runtime_error ("Project type missing");
-    }
-
-    if (file == content.end ())
+    else if (strcmp ((*type).get <std::string> ().c_str (), "video") == 0)
     {
-        throw std::runtime_error ("Project's main file missing");
+        wallpaper = new CVideo ((*file).get <std::string> ().c_str ());
     }
+    else
+        throw std::runtime_error ("Unsupported wallpaper type");
 
     CProject* project = new CProject (
         *title,
         *type,
-        CScene::fromFile ((*file).get <std::string> ().c_str ())
+        wallpaper
     );
 
     if (general != content.end ())
     {
-        json::const_iterator properties = (*general).find ("properties");
+        auto properties = (*general).find ("properties");
 
         if (properties != (*general).end ())
         {
-            json::const_iterator cur = (*properties).begin ();
-            json::const_iterator end = (*properties).end ();
+            auto cur = (*properties).begin ();
+            auto end = (*properties).end ();
 
             for (; cur != end; cur ++)
             {
@@ -63,24 +62,24 @@ CProject* CProject::fromFile (const irr::io::path& filename)
     return project;
 }
 
-CScene* CProject::getScene ()
+CWallpaper* CProject::getWallpaper () const
 {
-    return this->m_scene;
+    return this->m_wallpaper;
 }
 
-std::string CProject::getTitle ()
+const std::string& CProject::getTitle () const
 {
     return this->m_title;
 }
 
-std::string CProject::getType ()
+const std::string& CProject::getType () const
 {
     return this->m_type;
 }
 
-std::vector<Projects::CProperty*>* CProject::getProperties ()
+const std::vector<Projects::CProperty*>& CProject::getProperties () const
 {
-    return &this->m_properties;
+    return this->m_properties;
 }
 
 void CProject::insertProperty (Projects::CProperty* property)

+ 9 - 10
src/WallpaperEngine/Core/CProject.h

@@ -1,30 +1,30 @@
 #pragma once
 
 #include <irrlicht/irrlicht.h>
-#include <nlohmann/json.hpp>
 
-#include "CScene.h"
+#include "CWallpaper.h"
+#include "WallpaperEngine/Core/Core.h"
 #include "WallpaperEngine/Core/Projects/CProperty.h"
 
 namespace WallpaperEngine::Core
 {
     using json = nlohmann::json;
 
-    class CScene;
+    class CWallpaper;
 
     class CProject
     {
     public:
         static CProject* fromFile (const irr::io::path& filename);
 
-        CScene* getScene ();
+        CWallpaper* getWallpaper () const;
 
-        std::string getTitle ();
-        std::string getType ();
-        std::vector<Projects::CProperty*>* getProperties ();
+        const std::string& getTitle () const;
+        const std::string& getType () const;
+        const std::vector<Projects::CProperty*>& getProperties () const;
 
     protected:
-        CProject (std::string title, std::string type, CScene* scene);
+        CProject (std::string title, std::string type, CWallpaper* wallpaper);
 
         void insertProperty (Projects::CProperty* property);
     private:
@@ -32,7 +32,6 @@ namespace WallpaperEngine::Core
 
         std::string m_title;
         std::string m_type;
-        CScene* m_scene;
+        CWallpaper* m_wallpaper;
     };
 };
-

+ 45 - 154
src/WallpaperEngine/Core/CScene.cpp

@@ -1,7 +1,6 @@
 #include "CScene.h"
 #include "CProject.h"
 
-#include "Core.h"
 #include "WallpaperEngine/FileSystem/FileSystem.h"
 
 using namespace WallpaperEngine::Core;
@@ -25,6 +24,7 @@ CScene::CScene (
         irr::video::SColorf clearColor,
         Scenes::CProjection* orthogonalProjection,
         irr::video::SColorf skylightColor) :
+    CWallpaper (Type),
     m_camera (camera),
     m_ambientColor (ambientColor),
     m_bloom (bloom),
@@ -50,127 +50,27 @@ CScene* CScene::fromFile (const irr::io::path& filename)
 {
     json content = json::parse (WallpaperEngine::FileSystem::loadFullFile (filename));
 
-    json::const_iterator camera_it = content.find ("camera");
-    json::const_iterator general_it = content.find ("general");
-    json::const_iterator objects_it = content.find ("objects");
-
-    if (camera_it == content.end ())
-    {
-        throw std::runtime_error ("Scenes must have a defined camera");
-    }
-
-    if (general_it == content.end ())
-    {
-        throw std::runtime_error ("Scenes must have a general section");
-    }
-
-    if (objects_it == content.end ())
-    {
-        throw std::runtime_error ("Scenes must have a list of objects to display");
-    }
-
-    json::const_iterator ambientcolor_it = (*general_it).find ("ambientcolor");
-    json::const_iterator bloom_it = (*general_it).find ("bloom");
-    json::const_iterator bloomstrength_it = (*general_it).find ("bloomstrength");
-    json::const_iterator bloomthreshold_it = (*general_it).find ("bloomthreshold");
-    json::const_iterator camerafade_it = (*general_it).find ("camerafade");
-    json::const_iterator cameraparallax_it = (*general_it).find ("cameraparallax");
-    json::const_iterator cameraparallaxamount_it = (*general_it).find ("cameraparallaxamount");
-    json::const_iterator cameraparallaxdelay_it = (*general_it).find ("cameraparallaxdelay");
-    json::const_iterator cameraparallaxmouseinfluence_it = (*general_it).find ("cameraparallaxmouseinfluence");
-    json::const_iterator camerapreview_it = (*general_it).find ("camerapreview");
-    json::const_iterator camerashake_it = (*general_it).find ("camerashake");
-    json::const_iterator camerashakeamplitude_it = (*general_it).find ("camerashakeamplitude");
-    json::const_iterator camerashakeroughness_it = (*general_it).find ("camerashakeroughness");
-    json::const_iterator camerashakespeed_it = (*general_it).find ("camerashakespeed");
-    json::const_iterator clearcolor_it = (*general_it).find ("clearcolor");
-    json::const_iterator orthogonalprojection_it = (*general_it).find ("orthogonalprojection");
-    json::const_iterator skylightcolor_it = (*general_it).find ("skylightcolor");
-
-    if (ambientcolor_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have ambient color");
-    }
-
-    if (bloom_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have bloom flag");
-    }
-
-    if (bloomstrength_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have bloom strength");
-    }
-
-    if (bloomthreshold_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have bloom threshold");
-    }
-
-    if (camerafade_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have camera fade");
-    }
-
-    if (cameraparallax_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have camera parallax");
-    }
-
-    if (cameraparallaxamount_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have camera parallax amount");
-    }
-
-    if (cameraparallaxdelay_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have camera parallax delay");
-    }
-
-    if (cameraparallaxmouseinfluence_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have camera parallax mouse influence");
-    }
-
-    if (camerapreview_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have camera preview");
-    }
-
-    if (camerashake_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have camera shake");
-    }
-
-    if (camerashakeamplitude_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have camera shake amplitude");
-    }
-
-    if (camerashakeroughness_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have camera shake roughness");
-    }
-
-    if (camerashakespeed_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have camera shake speed");
-    }
-
-    if (clearcolor_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have clear color");
-    }
-
-    if (orthogonalprojection_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have orthogonal projection info");
-    }
-
-    if (skylightcolor_it == (*general_it).end ())
-    {
-        throw std::runtime_error ("General section must have skylight color");
-    }
+    auto camera_it = jsonFindRequired (content, "camera", "Scenes must have a defined camera");
+    auto general_it = jsonFindRequired (content, "general", "Scenes must have a general section");
+    auto objects_it = jsonFindRequired (content, "objects", "Scenes must have a list of objects to display");
+
+    auto ambientcolor_it = jsonFindRequired (*general_it, "ambientcolor", "General section must have ambient color");
+    auto bloom_it = jsonFindRequired (*general_it, "bloom", "General section must have bloom flag");
+    auto bloomstrength_it = jsonFindRequired (*general_it, "bloomstrength", "General section must have bloom strength");
+    auto bloomthreshold_it = jsonFindRequired (*general_it, "bloomthreshold", "General section must have bloom threshold");
+    auto camerafade_it = jsonFindRequired (*general_it, "camerafade", "General section must have camera fade");
+    auto cameraparallax_it = jsonFindRequired (*general_it, "cameraparallax", "General section must have camera parallax");
+    auto cameraparallaxamount_it = jsonFindRequired (*general_it, "cameraparallaxamount", "General section must have camera parallax amount");
+    auto cameraparallaxdelay_it = jsonFindRequired (*general_it, "cameraparallaxdelay", "General section must have camera parallax delay");
+    auto cameraparallaxmouseinfluence_it = jsonFindRequired (*general_it, "cameraparallaxmouseinfluence", "General section must have camera parallax mouse influence");
+    auto camerapreview_it = jsonFindRequired (*general_it, "camerapreview", "General section must have camera preview");
+    auto camerashake_it = jsonFindRequired (*general_it, "camerashake", "General section must have camera shake");
+    auto camerashakeamplitude_it = jsonFindRequired (*general_it, "camerashakeamplitude", "General section must have camera shake amplitude");
+    auto camerashakeroughness_it = jsonFindRequired (*general_it, "camerashakeroughness", "General section must have camera shake roughness");
+    auto camerashakespeed_it = jsonFindRequired (*general_it, "camerashakespeed", "General section must have camera shake speed");
+    auto clearcolor_it = jsonFindRequired (*general_it, "clearcolor", "General section must have clear color");
+    auto orthogonalprojection_it = jsonFindRequired (*general_it, "orthogonalprojection", "General section must have orthogonal projection info");
+    auto skylightcolor_it = jsonFindRequired (*general_it, "skylightcolor", "General section must have skylight color");
 
     CScene* scene = new CScene (
             Scenes::CCamera::fromJSON (*camera_it),
@@ -193,8 +93,8 @@ CScene* CScene::fromFile (const irr::io::path& filename)
             WallpaperEngine::Core::atoSColorf (*skylightcolor_it)
     );
 
-    json::const_iterator cur = (*objects_it).begin ();
-    json::const_iterator end = (*objects_it).end ();
+    auto cur = (*objects_it).begin ();
+    auto end = (*objects_it).end ();
 
     for (; cur != end; cur ++)
     {
@@ -206,10 +106,9 @@ CScene* CScene::fromFile (const irr::io::path& filename)
     return scene;
 }
 
-
-std::vector<CObject*>* CScene::getObjects ()
+const std::vector<CObject*>& CScene::getObjects () const
 {
-    return &this->m_objects;
+    return this->m_objects;
 }
 
 void CScene::insertObject (CObject* object)
@@ -217,17 +116,7 @@ void CScene::insertObject (CObject* object)
     this->m_objects.push_back (object);
 }
 
-CProject* CScene::getProject ()
-{
-    return this->m_project;
-}
-
-void CScene::setProject (CProject* project)
-{
-    this->m_project = project;
-}
-
-Scenes::CCamera* CScene::getCamera ()
+const Scenes::CCamera* CScene::getCamera () const
 {
     return this->m_camera;
 }
@@ -237,82 +126,84 @@ const irr::video::SColorf &CScene::getAmbientColor() const
     return this->m_ambientColor;
 }
 
-bool CScene::isBloom () const
+const bool CScene::isBloom () const
 {
     return this->m_bloom;
 }
 
-irr::f64 CScene::getBloomStrength () const
+const irr::f64 CScene::getBloomStrength () const
 {
     return this->m_bloomStrength;
 }
 
-irr::f64 CScene::getBloomThreshold () const
+const irr::f64 CScene::getBloomThreshold () const
 {
     return this->m_bloomThreshold;
 }
 
-bool CScene::isCameraFade () const
+const bool CScene::isCameraFade () const
 {
     return this->m_cameraFade;
 }
 
-bool CScene::isCameraParallax () const
+const bool CScene::isCameraParallax () const
 {
     return this->m_cameraParallax;
 }
 
-irr::f64 CScene::getCameraParallaxAmount () const
+const irr::f64 CScene::getCameraParallaxAmount () const
 {
     return this->m_cameraParallaxAmount;
 }
 
-irr::f64 CScene::getCameraParallaxDelay () const
+const irr::f64 CScene::getCameraParallaxDelay () const
 {
     return this->m_cameraParallaxDelay;
 }
 
-irr::f64 CScene::getCameraParallaxMouseInfluence () const
+const irr::f64 CScene::getCameraParallaxMouseInfluence () const
 {
     return this->m_cameraParallaxMouseInfluence;
 }
 
-bool CScene::isCameraPreview () const
+const bool CScene::isCameraPreview () const
 {
     return this->m_cameraPreview;
 }
 
-bool CScene::isCameraShake () const
+const bool CScene::isCameraShake () const
 {
     return this->m_cameraShake;
 }
 
-irr::f64 CScene::getCameraShakeAmplitude () const
+const irr::f64 CScene::getCameraShakeAmplitude () const
 {
     return this->m_cameraShakeAmplitude;
 }
 
-irr::f64 CScene::getCameraShakeRoughness () const
+const irr::f64 CScene::getCameraShakeRoughness () const
 {
     return this->m_cameraShakeRoughness;
 }
 
-irr::f64 CScene::getCameraShakeSpeed () const
+const irr::f64 CScene::getCameraShakeSpeed () const
 {
     return this->m_cameraShakeSpeed;
 }
 
-const irr::video::SColorf &CScene::getClearColor () const
+const irr::video::SColorf& CScene::getClearColor () const
 {
     return this->m_clearColor;
 }
 
-Scenes::CProjection* CScene::getOrthogonalProjection () const
+const Scenes::CProjection* CScene::getOrthogonalProjection () const
 {
     return this->m_orthogonalProjection;
 }
 
-const irr::video::SColorf &CScene::getSkylightColor () const
+const irr::video::SColorf& CScene::getSkylightColor () const
 {
     return this->m_skylightColor;
 }
+
+const std::string CScene::Type = "scene";

+ 26 - 28
src/WallpaperEngine/Core/CScene.h

@@ -1,10 +1,11 @@
 #pragma once
 
 #include <irrlicht/irrlicht.h>
-#include <nlohmann/json.hpp>
 
-#include "CProject.h"
 #include "CObject.h"
+#include "CWallpaper.h"
+
+#include "Core.h"
 
 #include "WallpaperEngine/Core/Scenes/CCamera.h"
 #include "WallpaperEngine/Core/Scenes/CProjection.h"
@@ -13,40 +14,36 @@ namespace WallpaperEngine::Core
 {
     using json = nlohmann::json;
 
-    class CProject;
     class CObject;
 
-    class CScene
+    class CScene : public CWallpaper
     {
     public:
         static CScene* fromFile (const irr::io::path& filename);
 
-        CProject* getProject ();
-        std::vector<CObject*>* getObjects ();
+        const std::vector<CObject*>& getObjects () const;
 
-        const irr::video::SColorf &getAmbientColor() const;
-        bool isBloom() const;
-        irr::f64 getBloomStrength() const;
-        irr::f64 getBloomThreshold() const;
-        bool isCameraFade() const;
-        bool isCameraParallax() const;
-        irr::f64 getCameraParallaxAmount() const;
-        irr::f64 getCameraParallaxDelay() const;
-        irr::f64 getCameraParallaxMouseInfluence() const;
-        bool isCameraPreview() const;
-        bool isCameraShake() const;
-        irr::f64 getCameraShakeAmplitude() const;
-        irr::f64 getCameraShakeRoughness() const;
-        irr::f64 getCameraShakeSpeed() const;
-        const irr::video::SColorf &getClearColor() const;
-        Scenes::CProjection *getOrthogonalProjection() const;
-        const irr::video::SColorf &getSkylightColor() const;
-        Scenes::CCamera* getCamera ();
+        const irr::video::SColorf& getAmbientColor() const;
+        const bool isBloom() const;
+        const irr::f64 getBloomStrength() const;
+        const irr::f64 getBloomThreshold() const;
+        const bool isCameraFade() const;
+        const bool isCameraParallax() const;
+        const irr::f64 getCameraParallaxAmount() const;
+        const irr::f64 getCameraParallaxDelay() const;
+        const irr::f64 getCameraParallaxMouseInfluence() const;
+        const bool isCameraPreview() const;
+        const bool isCameraShake() const;
+        const irr::f64 getCameraShakeAmplitude() const;
+        const irr::f64 getCameraShakeRoughness() const;
+        const irr::f64 getCameraShakeSpeed() const;
+        const irr::video::SColorf& getClearColor() const;
+        const Scenes::CProjection* getOrthogonalProjection() const;
+        const irr::video::SColorf& getSkylightColor() const;
+        const Scenes::CCamera* getCamera () const;
 
     protected:
-        friend class CProject;
-
-        void setProject (CProject* project);
+        friend class CWallpaper;
 
         CScene (
                 Scenes::CCamera* camera,
@@ -69,9 +66,10 @@ namespace WallpaperEngine::Core
                 irr::video::SColorf skylightColor
         );
 
+        static const std::string Type;
+
         void insertObject (CObject* object);
     private:
-        CProject* m_project;
         Scenes::CCamera* m_camera;
 
         // data from general section on the json

+ 17 - 0
src/WallpaperEngine/Core/CVideo.cpp

@@ -0,0 +1,17 @@
+#include "CVideo.h"
+
+using namespace WallpaperEngine::Core;
+
+CVideo::CVideo (
+        const irr::io::path& filename) :
+        CWallpaper (Type),
+        m_filename (filename)
+{
+}
+
+const irr::io::path CVideo::getFilename ()
+{
+    return this->m_filename;
+}
+
+const std::string CVideo::Type = "video";

+ 36 - 0
src/WallpaperEngine/Core/CVideo.h

@@ -0,0 +1,36 @@
+#pragma once
+
+#include <irrlicht/irrlicht.h>
+
+#include "Core.h"
+#include "CWallpaper.h"
+
+extern "C"
+{
+    #include <libavcodec/avcodec.h>
+    #include <libavformat/avformat.h>
+    #include <libavutil/imgutils.h>
+    #include <libswscale/swscale.h>
+}
+
+namespace WallpaperEngine::Core
+{
+    class CVideo : public CWallpaper
+    {
+    public:
+        CVideo (
+                const irr::io::path& filename
+        );
+
+        const irr::io::path getFilename ();
+
+    protected:
+        friend class CWallpaper;
+
+        const irr::io::path m_filename;
+
+        static const std::string Type;
+
+    private:
+    };
+};

+ 18 - 0
src/WallpaperEngine/Core/CWallpaper.cpp

@@ -0,0 +1,18 @@
+#include "CWallpaper.h"
+
+using namespace WallpaperEngine::Core;
+
+CWallpaper::CWallpaper (std::string type) :
+    m_type (type)
+{
+}
+
+CProject* CWallpaper::getProject ()
+{
+    return this->m_project;
+}
+
+void CWallpaper::setProject (CProject* project)
+{
+    this->m_project = project;
+}

+ 33 - 0
src/WallpaperEngine/Core/CWallpaper.h

@@ -0,0 +1,33 @@
+#pragma once
+
+#include <assert.h>
+
+#include "CProject.h"
+
+namespace WallpaperEngine::Core
+{
+    class CProject;
+
+    class CWallpaper
+    {
+    public:
+        template<class T> const T* as () const { assert (is <T> ()); return (const T*) this; }
+        template<class T> T* as () { assert (is <T> ()); return (T*) this; }
+
+        template<class T> bool is () { return this->m_type == T::Type; }
+
+        CWallpaper (std::string type);
+
+        CProject* getProject ();
+
+    protected:
+        friend class CProject;
+
+        void setProject (CProject* project);
+
+    private:
+        CProject* m_project;
+
+        std::string m_type;
+    };
+}

+ 26 - 14
src/WallpaperEngine/Core/Core.cpp

@@ -1,7 +1,9 @@
 #include <irrlicht/irrlicht.h>
 #include "Core.h"
 
-irr::core::vector3df WallpaperEngine::Core::ato3vf(const char *str)
+using namespace WallpaperEngine;
+
+irr::core::vector3df Core::ato3vf(const char *str)
 {
     irr::f32 x = irr::core::fast_atof (str, &str); while (*str == ' ') str ++;
     irr::f32 y = irr::core::fast_atof (str, &str); while (*str == ' ') str ++;
@@ -10,7 +12,7 @@ irr::core::vector3df WallpaperEngine::Core::ato3vf(const char *str)
     return irr::core::vector3df (x, y, z);
 }
 
-irr::core::vector2df WallpaperEngine::Core::ato2vf (const char *str)
+irr::core::vector2df Core::ato2vf (const char *str)
 {
     irr::f32 x = irr::core::fast_atof (str, &str); while (*str == ' ') str ++;
     irr::f32 y = irr::core::fast_atof (str, &str);
@@ -18,19 +20,19 @@ irr::core::vector2df WallpaperEngine::Core::ato2vf (const char *str)
     return irr::core::vector2df (x, y);
 }
 
-irr::core::vector3df WallpaperEngine::Core::ato3vf (const std::string& str)
+irr::core::vector3df Core::ato3vf (const std::string& str)
 {
-    return WallpaperEngine::Core::ato3vf (str.c_str ());
+    return Core::ato3vf (str.c_str ());
 }
 
-irr::core::vector2df WallpaperEngine::Core::ato2vf (const std::string& str)
+irr::core::vector2df Core::ato2vf (const std::string& str)
 {
-    return WallpaperEngine::Core::ato2vf (str.c_str ());
+    return Core::ato2vf (str.c_str ());
 }
 
-irr::video::SColorf WallpaperEngine::Core::atoSColorf (const char *str)
+irr::video::SColorf Core::atoSColorf (const char *str)
 {
-    irr::core::vector3df vector = WallpaperEngine::Core::ato3vf (str);
+    irr::core::vector3df vector = Core::ato3vf (str);
 
     return irr::video::SColorf (
             vector.X,
@@ -39,12 +41,12 @@ irr::video::SColorf WallpaperEngine::Core::atoSColorf (const char *str)
     );
 }
 
-irr::video::SColorf WallpaperEngine::Core::atoSColorf (const std::string& str)
+irr::video::SColorf Core::atoSColorf (const std::string& str)
 {
-    return WallpaperEngine::Core::atoSColorf (str.c_str ());
+    return Core::atoSColorf (str.c_str ());
 }
 
-irr::video::SColor WallpaperEngine::Core::atoSColor (const char *str)
+irr::video::SColor Core::atoSColor (const char *str)
 {
     irr::f32 r = irr::core::strtoul10 (str, &str); while (*str == ' ') str ++;
     irr::f32 g = irr::core::strtoul10 (str, &str); while (*str == ' ') str ++;
@@ -53,7 +55,17 @@ irr::video::SColor WallpaperEngine::Core::atoSColor (const char *str)
     return irr::video::SColor (255, r, g, b);
 }
 
-irr::video::SColor WallpaperEngine::Core::atoSColor (const std::string& str)
+irr::video::SColor Core::atoSColor (const std::string& str)
 {
-    return WallpaperEngine::Core::atoSColor (str.c_str ());
-}
+    return Core::atoSColor (str.c_str ());
+}
+
+nlohmann::json::iterator Core::jsonFindRequired (nlohmann::json& data, const char *key, const char *notFoundMsg)
+{
+    auto value = data.find (key);
+    if (value == data.end ())
+    {
+        throw std::runtime_error (notFoundMsg);
+    }
+    return value;
+}

+ 3 - 0
src/WallpaperEngine/Core/Core.h

@@ -2,6 +2,7 @@
 
 #include <string>
 #include <irrlicht/irrlicht.h>
+#include <nlohmann/json.hpp>
 
 namespace WallpaperEngine::Core
 {
@@ -16,4 +17,6 @@ namespace WallpaperEngine::Core
 
     irr::video::SColor atoSColor (const char *str);
     irr::video::SColor atoSColor (const std::string& str);
+
+    nlohmann::json::iterator jsonFindRequired (nlohmann::json& data, const char *key, const char *notFoundMsg);
 };

+ 201 - 97
src/WallpaperEngine/Core/Objects/CEffect.cpp

@@ -3,6 +3,11 @@
 #include <utility>
 
 #include "WallpaperEngine/Core/Objects/CImage.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantFloat.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantVector3.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantInteger.h"
+
 #include "WallpaperEngine/FileSystem/FileSystem.h"
 
 using namespace WallpaperEngine;
@@ -24,152 +29,246 @@ CEffect::CEffect (
 
 CEffect* CEffect::fromJSON (json data, Core::CObject* object)
 {
-    json::const_iterator file_it = data.find ("file");
-    json::const_iterator effectpasses_it = data.find ("passes");
-
-    if (file_it == data.end ())
-    {
-        throw std::runtime_error ("Object effect must have a file");
-    }
+    auto file_it = jsonFindRequired (data, "file", "Object effect must have a file");
+    auto effectpasses_it = data.find ("passes");
 
     json content = json::parse (WallpaperEngine::FileSystem::loadFullFile ((*file_it).get <std::string> ().c_str ()));
 
-    json::const_iterator name_it = content.find ("name");
-    json::const_iterator description_it = content.find ("description");
-    json::const_iterator group_it = content.find ("group");
-    json::const_iterator preview_it = content.find ("preview");
-    json::const_iterator passes_it = content.find ("passes");
-    json::const_iterator dependencies_it = content.find ("dependencies");
+    auto name_it = jsonFindRequired (content, "name", "Effect must have a name");
+    auto description_it = jsonFindRequired (content, "description", "Effect must have a description");
+    auto group_it = jsonFindRequired (content, "group", "Effect must have a group");
+    auto preview_it = jsonFindRequired (content, "preview", "Effect must have a preview");
+    auto passes_it = jsonFindRequired (content, "passes", "Effect must have a pass list");
+    auto dependencies_it = jsonFindRequired (content, "dependencies", "");
+    auto fbos_it = content.find ("fbos");
 
-    if (name_it == content.end ())
-    {
-        throw std::runtime_error ("Effect must have a name");
-    }
+    CEffect* effect = new CEffect (
+        *name_it,
+        *description_it,
+        *group_it,
+        *preview_it,
+        object
+    );
 
-    if (description_it == content.end ())
-    {
-        throw std::runtime_error ("Effect must have a description");
-    }
+    CEffect::materialsFromJSON (passes_it, effect);
+    CEffect::dependencyFromJSON (dependencies_it, effect);
 
-    if (group_it == content.end ())
+    if (fbos_it != content.end ())
     {
-        throw std::runtime_error ("Effect must have a group");
+        CEffect::fbosFromJSON (fbos_it, effect);
     }
 
-    if (preview_it == content.end ())
+    if (effectpasses_it != data.end ())
     {
-        throw std::runtime_error ("Effect must have a preview");
-    }
+        auto cur = (*effectpasses_it).begin ();
+        auto end = (*effectpasses_it).end ();
 
-    if (passes_it == content.end ())
-    {
-        throw std::runtime_error ("Effect must have a pass list");
+        for (int passNumber = 0; cur != end; cur ++, passNumber ++)
+        {
+            auto constants_it = (*cur).find ("constantshadervalues");
+            auto combos_it = (*cur).find ("combos");
+            auto textures_it = (*cur).find ("textures");
+
+            if (constants_it == (*cur).end () && combos_it == (*cur).end () && textures_it == (*cur).end ())
+                continue;
+
+            Images::CMaterial* material = effect->getMaterials ().at (passNumber);
+
+            auto passCur = material->getPasses ().begin ();
+            auto passEnd = material->getPasses ().end ();
+
+            for (; passCur != passEnd; passCur ++)
+            {
+                if (textures_it != (*cur).end ())
+                {
+                    auto texturesCur = (*textures_it).begin ();
+                    auto texturesEnd = (*textures_it).end ();
+
+                    for (int textureNumber = 0; texturesCur != texturesEnd; texturesCur ++)
+                    {
+                        std::string texture;
+
+                        if ((*texturesCur).is_null () == true)
+                        {
+                            if (object->is <CImage> () == false)
+                            {
+                                throw std::runtime_error ("unexpected null texture for non-image object");
+                            }
+
+                            CImage* image = object->as <CImage> ();
+
+                            texture = (*(*image->getMaterial ()->getPasses ().begin ())->getTextures ().begin ());
+                        }
+                        else
+                        {
+                            texture = *texturesCur;
+                        }
+
+                        std::vector<std::string> passTextures = (*passCur)->getTextures ();
+
+                        if (textureNumber < passTextures.size ())
+                            (*passCur)->setTexture (textureNumber, texture);
+                        else
+                            (*passCur)->insertTexture (texture);
+
+                        textureNumber ++;
+                    }
+                }
+
+                if (combos_it != (*cur).end ())
+                {
+                    CEffect::combosFromJSON (combos_it, *passCur);
+                }
+
+                if (constants_it != (*cur).end ())
+                {
+                    CEffect::constantsFromJSON (constants_it, *passCur);
+                }
+            }
+        }
     }
 
-    if (dependencies_it == content.end ())
+    return effect;
+}
+
+void CEffect::combosFromJSON (json::const_iterator combos_it, Core::Objects::Images::Materials::CPass* pass)
+{
+    auto cur = (*combos_it).begin ();
+    auto end = (*combos_it).end ();
+
+    for (; cur != end; cur ++)
     {
-        throw std::runtime_error ("Effect must have dependencies");
+        pass->insertCombo (cur.key (), *cur);
     }
+}
 
-    CEffect* effect = new CEffect (
-        *name_it,
-        *description_it,
-        *group_it,
-        *preview_it,
-        object
-    );
-
-    json::const_iterator cur = (*passes_it).begin ();
-    json::const_iterator end = (*passes_it).end ();
+void CEffect::constantsFromJSON (json::const_iterator constants_it, Core::Objects::Images::Materials::CPass* pass)
+{
+    auto cur = (*constants_it).begin ();
+    auto end = (*constants_it).end ();
 
     for (; cur != end; cur ++)
     {
-        json::const_iterator materialfile = (*cur).find ("material");
+        Effects::Constants::CShaderConstant* constant = nullptr;
 
-        if (materialfile == (*cur).end ())
+        if ((*cur).is_number_float () == true)
         {
-            throw std::runtime_error ("Effect pass must have a material file");
+            constant = new Effects::Constants::CShaderConstantFloat ((*cur).get <irr::f32> ());
+        }
+        else if ((*cur).is_number_integer () == true)
+        {
+            constant = new Effects::Constants::CShaderConstantInteger ((*cur).get <irr::s32> ());
+        }
+        else if ((*cur).is_string () == true)
+        {
+            constant = new Effects::Constants::CShaderConstantVector3 (WallpaperEngine::Core::ato3vf (*cur));
+        }
+        else
+        {
+            throw std::runtime_error ("unknown shader constant type");
         }
 
-        effect->insertMaterial (
-                Images::CMaterial::fromFile ((*materialfile).get <std::string> ().c_str ())
+        pass->insertConstant (cur.key (), constant);
+    }
+}
+
+void CEffect::fbosFromJSON (json::const_iterator fbos_it, CEffect* effect)
+{
+    auto cur = (*fbos_it).begin ();
+    auto end = (*fbos_it).end ();
+
+    for (; cur != end; cur ++)
+    {
+        effect->insertFBO (
+            Effects::CFBO::fromJSON (*cur)
         );
     }
+}
 
-    cur = (*dependencies_it).begin ();
-    end = (*dependencies_it).end ();
+void CEffect::dependencyFromJSON (json::const_iterator dependencies_it, CEffect* effect)
+{
+    auto cur = (*dependencies_it).begin ();
+    auto end = (*dependencies_it).end ();
 
     for (; cur != end; cur ++)
     {
         effect->insertDependency (*cur);
     }
+}
 
-    if (effectpasses_it != data.end ())
+void CEffect::materialsFromJSON (json::const_iterator passes_it, CEffect* effect)
+{
+    auto cur = (*passes_it).begin ();
+    auto end = (*passes_it).end ();
+
+    for (; cur != end; cur ++)
     {
-        cur = (*effectpasses_it).begin ();
-        end = (*effectpasses_it).end ();
+        auto materialfile = (*cur).find ("material");
+        auto target = (*cur).find ("target");
+        auto bind = (*cur).find ("bind");
 
-        for (int passNumber = 0; cur != end; cur ++, passNumber ++)
+        if (materialfile == (*cur).end ())
         {
-            json::const_iterator textures_it = (*cur).find ("textures");
-
-            if (textures_it == (*cur).end ())
-                continue;
-
-            Images::CMaterial* material = effect->getMaterials ()->at (passNumber);
-            std::vector<Images::Materials::CPassess*>::const_iterator materialCur = material->getPasses ()->begin ();
-            std::vector<Images::Materials::CPassess*>::const_iterator materialEnd = material->getPasses ()->end ();
-
-            for (; materialCur != materialEnd; materialCur ++)
-            {
-                json::const_iterator texturesCur = (*textures_it).begin ();
-                json::const_iterator texturesEnd = (*textures_it).end ();
-
-                for (int textureNumber = 0; texturesCur != texturesEnd; texturesCur ++)
-                {
-                    std::string texture;
-
-                    if ((*texturesCur).is_null () == true)
-                    {
-                        if (object->Is <CImage> () == false)
-                        {
-                            throw std::runtime_error ("unexpected null texture for non-image object");
-                        }
-
-                        CImage* image = object->As <CImage> ();
+            throw std::runtime_error ("Effect pass must have a material file");
+        }
 
-                        texture = (*(*image->getMaterial ()->getPasses ()->begin ())->getTextures ()->begin ());
-                    }
-                    else
-                    {
-                        texture = *texturesCur;
-                    }
+        Images::CMaterial* material = nullptr;
 
-                    std::vector<std::string>* passTextures = (*materialCur)->getTextures ();
+        if (target == (*cur).end ())
+        {
+            material = Images::CMaterial::fromFile ((*materialfile).get <std::string> ().c_str ());
+        }
+        else
+        {
+            material = Images::CMaterial::fromFile ((*materialfile).get <std::string> ().c_str (), *target);
+        }
 
-                    if (textureNumber < passTextures->size ())
-                        passTextures->at (textureNumber) = texture;
-                    else
-                        passTextures->push_back (texture);
+        if (bind != (*cur).end ())
+        {
+            auto bindCur = (*bind).begin ();
+            auto bindEnd = (*bind).end ();
 
-                    textureNumber ++;
-                }
+            for (; bindCur != bindEnd; bindCur ++)
+            {
+                material->insertTextureBind (
+                    Effects::CBind::fromJSON (*bindCur)
+                );
             }
-
         }
+
+        effect->insertMaterial (material);
     }
+}
 
-    return effect;
+const std::vector<std::string>& CEffect::getDependencies () const
+{
+    return this->m_dependencies;
+}
+
+const std::vector<Images::CMaterial*>& CEffect::getMaterials () const
+{
+    return this->m_materials;
 }
 
-std::vector<std::string>* CEffect::getDependencies ()
+const std::vector<Effects::CFBO*>& CEffect::getFbos () const
 {
-    return &this->m_dependencies;
+    return this->m_fbos;
 }
 
-std::vector<Images::CMaterial*>* CEffect::getMaterials ()
+Effects::CFBO* CEffect::findFBO (const std::string& name)
 {
-    return &this->m_materials;
+    auto cur = this->m_fbos.begin ();
+    auto end = this->m_fbos.end ();
+
+    for (; cur != end; cur ++)
+    {
+        if ((*cur)->getName () == name)
+        {
+            return (*cur);
+        }
+    }
+
+    throw std::runtime_error ("cannot find fbo named " + name);
 }
 
 void CEffect::insertDependency (const std::string& dep)
@@ -180,4 +279,9 @@ void CEffect::insertDependency (const std::string& dep)
 void CEffect::insertMaterial (Images::CMaterial* material)
 {
     this->m_materials.push_back (material);
+}
+
+void CEffect::insertFBO (Effects::CFBO* fbo)
+{
+    this->m_fbos.push_back (fbo);
 }

+ 17 - 3
src/WallpaperEngine/Core/Objects/CEffect.h

@@ -1,8 +1,10 @@
 #pragma once
 
-#include <nlohmann/json.hpp>
 #include <irrlicht/irrlicht.h>
 
+#include "WallpaperEngine/Core/Core.h"
+#include "WallpaperEngine/Core/Objects/Effects/CFBO.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.h"
 #include "WallpaperEngine/Core/CObject.h"
 #include "WallpaperEngine/Core/Objects/Images/CMaterial.h"
 
@@ -28,11 +30,22 @@ namespace WallpaperEngine::Core::Objects
 
         static CEffect* fromJSON (json data, Core::CObject* object);
 
-        std::vector<std::string>* getDependencies ();
-        std::vector<Images::CMaterial*>* getMaterials ();
+        const std::vector<std::string>& getDependencies () const;
+        const std::vector<Images::CMaterial*>& getMaterials () const;
+        const std::vector<Effects::CFBO*>& getFbos () const;
+
+        Effects::CFBO* findFBO (const std::string& name);
     protected:
+        static void constantsFromJSON (json::const_iterator constants_it, Core::Objects::Images::Materials::CPass* pass);
+        static void combosFromJSON (json::const_iterator combos_it, Core::Objects::Images::Materials::CPass* pass);
+        static void fbosFromJSON (json::const_iterator fbos_it, CEffect* effect);
+        static void dependencyFromJSON (json::const_iterator dependencies_it, CEffect* effect);
+        static void materialsFromJSON (json::const_iterator passes_it, CEffect* effect);
+
         void insertDependency (const std::string& dep);
         void insertMaterial (Images::CMaterial* material);
+        void insertFBO (Effects::CFBO* fbo);
+
     private:
         std::string m_name;
         std::string m_description;
@@ -42,5 +55,6 @@ namespace WallpaperEngine::Core::Objects
 
         std::vector<std::string> m_dependencies;
         std::vector<Images::CMaterial*> m_materials;
+        std::vector<Effects::CFBO*> m_fbos;
     };
 }

+ 10 - 15
src/WallpaperEngine/Core/Objects/CImage.cpp

@@ -1,7 +1,6 @@
 #include "CImage.h"
 #include "WallpaperEngine/Core/Objects/Images/CMaterial.h"
 
-#include "WallpaperEngine/Core/Core.h"
 #include "WallpaperEngine/FileSystem/FileSystem.h"
 
 using namespace WallpaperEngine::Core::Objects;
@@ -30,22 +29,12 @@ WallpaperEngine::Core::CObject* CImage::fromJSON (
     const irr::core::vector3df& scale,
     const irr::core::vector3df& angles)
 {
-    json::const_iterator image_it = data.find ("image");
-    json::const_iterator size_it = data.find ("size");
-
-    if (size_it == data.end ())
-    {
-        throw std::runtime_error ("Images must have size");
-    }
+    auto image_it = data.find ("image");
+    auto size_it = jsonFindRequired (data, "size", "Images must have size");
 
     json content = json::parse (WallpaperEngine::FileSystem::loadFullFile ((*image_it).get <std::string> ().c_str ()));
 
-    json::const_iterator material_it = content.find ("material");
-
-    if (material_it == content.end ())
-    {
-        throw std::runtime_error ("Image must have a material");
-    }
+    auto material_it = jsonFindRequired (content, "material", "Image must have a material");
 
     return new CImage (
         Images::CMaterial::fromFile ((*material_it).get <std::string> ().c_str ()),
@@ -59,9 +48,15 @@ WallpaperEngine::Core::CObject* CImage::fromJSON (
     );
 }
 
-Images::CMaterial* CImage::getMaterial ()
+const Images::CMaterial* CImage::getMaterial () const
 {
     return this->m_material;
 }
 
+const irr::core::vector2df& CImage::getSize () const
+{
+    return this->m_size;
+}
+
+
 const std::string CImage::Type = "image";

+ 3 - 2
src/WallpaperEngine/Core/Objects/CImage.h

@@ -1,10 +1,10 @@
 #pragma once
 
-#include <nlohmann/json.hpp>
 #include <irrlicht/irrlicht.h>
 
 #include "WallpaperEngine/Core/Objects/Images/CMaterial.h"
 
+#include "WallpaperEngine/Core/Core.h"
 #include "WallpaperEngine/Core/CObject.h"
 
 namespace WallpaperEngine::Core::Objects
@@ -26,7 +26,8 @@ namespace WallpaperEngine::Core::Objects
                 const irr::core::vector3df& angles
         );
 
-        Images::CMaterial* getMaterial ();
+        const Images::CMaterial* getMaterial () const;
+        const irr::core::vector2df& getSize () const;
 
     protected:
         CImage (

+ 15 - 35
src/WallpaperEngine/Core/Objects/CParticle.cpp

@@ -13,31 +13,11 @@ CParticle* CParticle::fromFile (
     const irr::core::vector3df& scale)
 {
     json data = json::parse (WallpaperEngine::FileSystem::loadFullFile (filename));
-    json::const_iterator controlpoint_it = data.find ("controlpoint");
-    json::const_iterator starttime_it = data.find ("starttime");
-    json::const_iterator maxcount_it = data.find ("maxcount");
-    json::const_iterator emitter_it = data.find ("emitter");
-    json::const_iterator initializer_it = data.find ("initializer");
-
-    if (starttime_it == data.end ())
-    {
-        throw std::runtime_error ("Particles must have start time");
-    }
-
-    if (maxcount_it == data.end ())
-    {
-        throw std::runtime_error ("Particles must have maximum count");
-    }
-
-    if (emitter_it == data.end ())
-    {
-        throw std::runtime_error ("Particles must have emitters");
-    }
-
-    if (initializer_it == data.end ())
-    {
-        throw std::runtime_error ("Particles must have initializers");
-    }
+    auto controlpoint_it = data.find ("controlpoint");
+    auto starttime_it = jsonFindRequired (data, "starttime", "Particles must have start time");
+    auto maxcount_it = jsonFindRequired (data, "maxcount", "Particles must have maximum count");
+    auto emitter_it = jsonFindRequired (data, "emitter", "Particles must have emitters");
+    auto initializer_it = jsonFindRequired (data, "initializer", "Particles must have initializers");
 
     CParticle* particle = new CParticle (
         *starttime_it,
@@ -50,8 +30,8 @@ CParticle* CParticle::fromFile (
 
     if (controlpoint_it != data.end ())
     {
-        json::const_iterator cur = (*controlpoint_it).begin ();
-        json::const_iterator end = (*controlpoint_it).end ();
+        auto cur = (*controlpoint_it).begin ();
+        auto end = (*controlpoint_it).end ();
 
         for (; cur != end; cur ++)
         {
@@ -61,8 +41,8 @@ CParticle* CParticle::fromFile (
         }
     }
 
-    json::const_iterator cur = (*emitter_it).begin ();
-    json::const_iterator end = (*emitter_it).end ();
+    auto cur = (*emitter_it).begin ();
+    auto end = (*emitter_it).end ();
 
     for (; cur != end; cur ++)
     {
@@ -97,19 +77,19 @@ CParticle::CParticle (
 {
 }
 
-std::vector<Particles::CEmitter*>* CParticle::getEmitters ()
+const std::vector<Particles::CEmitter*>& CParticle::getEmitters () const
 {
-    return &this->m_emitters;
+    return this->m_emitters;
 }
 
-std::vector<Particles::CControlPoint*>* CParticle::getControlPoints ()
+const std::vector<Particles::CControlPoint*>& CParticle::getControlPoints () const
 {
-    return &this->m_controlpoints;
+    return this->m_controlpoints;
 }
 
-std::vector<Particles::CInitializer*>* CParticle::getInitializers ()
+const std::vector<Particles::CInitializer*>& CParticle::getInitializers () const
 {
-    return &this->m_initializers;
+    return this->m_initializers;
 }
 
 void CParticle::insertControlPoint (Particles::CControlPoint* controlpoint)

+ 4 - 4
src/WallpaperEngine/Core/Objects/CParticle.h

@@ -1,12 +1,12 @@
 #pragma once
 
 #include <irrlicht/irrlicht.h>
-#include <nlohmann/json.hpp>
 
 #include "WallpaperEngine/Core/Objects/Particles/CControlPoint.h"
 #include "WallpaperEngine/Core/Objects/Particles/CEmitter.h"
 #include "WallpaperEngine/Core/Objects/Particles/CInitializer.h"
 
+#include "WallpaperEngine/Core/Core.h"
 #include "WallpaperEngine/Core/CObject.h"
 
 namespace WallpaperEngine::Core::Objects
@@ -26,9 +26,9 @@ namespace WallpaperEngine::Core::Objects
                 const irr::core::vector3df& scale
         );
 
-        std::vector<Particles::CEmitter*>* getEmitters ();
-        std::vector<Particles::CControlPoint*>* getControlPoints ();
-        std::vector<Particles::CInitializer*>* getInitializers ();
+        const std::vector<Particles::CEmitter*>& getEmitters () const;
+        const std::vector<Particles::CControlPoint*>& getControlPoints () const;
+        const std::vector<Particles::CInitializer*>& getInitializers () const;
 
     protected:
         CParticle (

+ 5 - 10
src/WallpaperEngine/Core/Objects/CSound.cpp

@@ -25,12 +25,7 @@ WallpaperEngine::Core::CObject* CSound::fromJSON (
         const irr::core::vector3df& scale,
         const irr::core::vector3df& angles)
 {
-    json::const_iterator sound_it = data.find ("sound");
-
-    if (sound_it == data.end ())
-    {
-        throw std::runtime_error ("Sound information not present");
-    }
+    auto sound_it = jsonFindRequired (data, "sound", "Sound information not present");
 
     if ((*sound_it).is_array () == false)
     {
@@ -46,8 +41,8 @@ WallpaperEngine::Core::CObject* CSound::fromJSON (
         angles
     );
 
-    json::const_iterator cur = (*sound_it).begin ();
-    json::const_iterator end = (*sound_it).end ();
+    auto cur = (*sound_it).begin ();
+    auto end = (*sound_it).end ();
 
     for (; cur != end; cur ++)
     {
@@ -62,9 +57,9 @@ void CSound::insertSound (std::string filename)
     this->m_sounds.push_back (filename);
 }
 
-std::vector<std::string>* CSound::getSounds ()
+const std::vector<std::string>& CSound::getSounds () const
 {
-    return &this->m_sounds;
+    return this->m_sounds;
 }
 
 const std::string CSound::Type = "sound";

+ 2 - 2
src/WallpaperEngine/Core/Objects/CSound.h

@@ -1,8 +1,8 @@
 #pragma once
 
 #include <irrlicht/irrlicht.h>
-#include <nlohmann/json.hpp>
 
+#include "WallpaperEngine/Core/Core.h"
 #include "WallpaperEngine/Core/CObject.h"
 
 namespace WallpaperEngine::Core::Objects
@@ -25,7 +25,7 @@ namespace WallpaperEngine::Core::Objects
         );
 
         void insertSound (std::string filename);
-        std::vector<std::string>* getSounds ();
+        const std::vector<std::string>& getSounds () const;
 
     protected:
         CSound (

+ 29 - 0
src/WallpaperEngine/Core/Objects/Effects/CBind.cpp

@@ -0,0 +1,29 @@
+#include "CBind.h"
+
+#include <utility>
+
+using namespace WallpaperEngine::Core::Objects::Effects;
+
+CBind::CBind (std::string name, irr::u32 index) :
+    m_name (std::move(name)),
+    m_index (index)
+{
+}
+
+CBind* CBind::fromJSON (json data)
+{
+    auto name_it = jsonFindRequired (data, "name", "bind must have texture name");
+    auto index_it = jsonFindRequired (data, "index", "bind must have index");
+
+    return new CBind (*name_it, *index_it);
+}
+
+const std::string& CBind::getName () const
+{
+    return this->m_name;
+}
+
+const irr::u32& CBind::getIndex () const
+{
+    return this->m_index;
+}

+ 27 - 0
src/WallpaperEngine/Core/Objects/Effects/CBind.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include <string>
+
+#include <irrlicht/irrlicht.h>
+
+#include "WallpaperEngine/Core/Core.h"
+
+namespace WallpaperEngine::Core::Objects::Effects
+{
+    using json = nlohmann::json;
+
+    class CBind
+    {
+    public:
+        static CBind* fromJSON (json data);
+
+        CBind (std::string name, irr::u32 index);
+
+        const std::string& getName () const;
+        const irr::u32& getIndex () const;
+
+    private:
+        std::string m_name;
+        irr::u32 m_index;
+    };
+}

+ 40 - 0
src/WallpaperEngine/Core/Objects/Effects/CFBO.cpp

@@ -0,0 +1,40 @@
+#include "CFBO.h"
+
+#include <utility>
+
+using namespace WallpaperEngine::Core::Objects::Effects;
+
+CFBO::CFBO (std::string name, irr::f32 scale, std::string format) :
+    m_name (std::move(name)),
+    m_scale (scale),
+    m_format(std::move(format))
+{
+}
+
+CFBO* CFBO::fromJSON (json data)
+{
+    auto name_it = data.find ("name");
+    auto scale_it = data.find ("scale");
+    auto format_it = data.find ("format");
+
+    return new CFBO (
+        *name_it,
+        *scale_it,
+        *format_it
+    );
+}
+
+const std::string& CFBO::getName () const
+{
+    return this->m_name;
+}
+
+const irr::f32& CFBO::getScale () const
+{
+    return this->m_scale;
+}
+
+const std::string& CFBO::getFormat () const
+{
+    return this->m_format;
+}

+ 28 - 0
src/WallpaperEngine/Core/Objects/Effects/CFBO.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include <string>
+
+#include <irrlicht/irrlicht.h>
+#include <nlohmann/json.hpp>
+
+namespace WallpaperEngine::Core::Objects::Effects
+{
+    using json = nlohmann::json;
+
+    class CFBO
+    {
+    public:
+        CFBO (std::string name, irr::f32 scale, std::string format);
+
+        static CFBO* fromJSON (json data);
+
+        const std::string& getName () const;
+        const irr::f32& getScale () const;
+        const std::string& getFormat () const;
+
+    private:
+        std::string m_name;
+        irr::f32 m_scale;
+        std::string m_format;
+    };
+}

+ 8 - 0
src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.cpp

@@ -0,0 +1,8 @@
+#include "CShaderConstant.h"
+
+using namespace WallpaperEngine::Core::Objects::Effects::Constants;
+
+CShaderConstant::CShaderConstant (std::string type) :
+    m_type (std::move(type))
+{
+}

+ 20 - 0
src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include <string>
+
+namespace WallpaperEngine::Core::Objects::Effects::Constants
+{
+    class CShaderConstant
+    {
+    public:
+        CShaderConstant (std::string  type);
+
+        template<class T> const T* as () const { assert (is <T> ()); return (const T*) this; }
+        template<class T> T* as () { assert (is <T> ()); return (T*) this; }
+
+        template<class T> bool is () { return this->m_type == T::Type; }
+
+    private:
+        std::string m_type;
+    };
+}

+ 17 - 0
src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantFloat.cpp

@@ -0,0 +1,17 @@
+#include "CShaderConstantFloat.h"
+
+using namespace WallpaperEngine::Core::Objects::Effects::Constants;
+
+
+CShaderConstantFloat::CShaderConstantFloat (irr::f32 value) :
+    CShaderConstant (Type),
+    m_value (value)
+{
+}
+
+irr::f32* CShaderConstantFloat::getValue ()
+{
+    return &this->m_value;
+}
+
+const std::string CShaderConstantFloat::Type = "float";

+ 21 - 0
src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantFloat.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include "CShaderConstant.h"
+
+#include <string>
+#include <irrlicht/irrlicht.h>
+
+namespace WallpaperEngine::Core::Objects::Effects::Constants
+{
+    class CShaderConstantFloat : public CShaderConstant
+    {
+    public:
+        CShaderConstantFloat (irr::f32 value);
+
+        irr::f32* getValue ();
+
+        static const std::string Type;
+    protected:
+        irr::f32 m_value;
+    };
+}

+ 17 - 0
src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantInteger.cpp

@@ -0,0 +1,17 @@
+#include "CShaderConstantInteger.h"
+
+using namespace WallpaperEngine::Core::Objects::Effects::Constants;
+
+
+CShaderConstantInteger::CShaderConstantInteger (irr::s32 value) :
+    CShaderConstant (Type),
+    m_value (value)
+{
+}
+
+irr::u32* CShaderConstantInteger::getValue ()
+{
+    return &this->m_value;
+}
+
+const std::string CShaderConstantInteger::Type = "integer";

+ 21 - 0
src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantInteger.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include "CShaderConstant.h"
+
+#include <string>
+#include <irrlicht/irrlicht.h>
+
+namespace WallpaperEngine::Core::Objects::Effects::Constants
+{
+    class CShaderConstantInteger : public CShaderConstant
+    {
+    public:
+        CShaderConstantInteger (irr::s32 value);
+
+        irr::u32* getValue ();
+
+        static const std::string Type;
+    protected:
+        irr::u32 m_value;
+    };
+}

+ 17 - 0
src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantVector3.cpp

@@ -0,0 +1,17 @@
+#include "CShaderConstantVector3.h"
+
+using namespace WallpaperEngine::Core::Objects::Effects::Constants;
+
+
+CShaderConstantVector3::CShaderConstantVector3 (irr::core::vector3df value) :
+    CShaderConstant (Type),
+    m_value (value)
+{
+}
+
+irr::core::vector3df* CShaderConstantVector3::getValue ()
+{
+    return &this->m_value;
+}
+
+const std::string CShaderConstantVector3::Type = "vector3";

+ 21 - 0
src/WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantVector3.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include "CShaderConstant.h"
+
+#include <string>
+#include <irrlicht/irrlicht.h>
+
+namespace WallpaperEngine::Core::Objects::Effects::Constants
+{
+    class CShaderConstantVector3 : public CShaderConstant
+    {
+    public:
+        CShaderConstantVector3 (irr::core::vector3df value);
+
+        irr::core::vector3df* getValue ();
+
+        static const std::string Type;
+    protected:
+        irr::core::vector3df m_value;
+    };
+}

+ 50 - 14
src/WallpaperEngine/Core/Objects/Images/CMaterial.cpp

@@ -5,49 +5,85 @@
 
 #include "WallpaperEngine/FileSystem/FileSystem.h"
 
+using namespace WallpaperEngine::Core::Objects;
 using namespace WallpaperEngine::Core::Objects::Images;
 
-CMaterial::CMaterial ()
+CMaterial::CMaterial () :
+    m_target ("")
 {
 }
 
-CMaterial* CMaterial::fromFile (irr::io::path filename)
+CMaterial* CMaterial::fromFile (const irr::io::path& filename)
 {
     return fromJSON (
         json::parse (WallpaperEngine::FileSystem::loadFullFile (filename))
     );
 }
+CMaterial* CMaterial::fromFile (const irr::io::path& filename, const std::string& target)
+{
+    return fromJSON (
+        json::parse (WallpaperEngine::FileSystem::loadFullFile (filename)), target
+    );
+}
 
-CMaterial* CMaterial::fromJSON (json data)
+CMaterial* CMaterial::fromJSON (json data, const std::string& target)
 {
-    json::const_iterator passes_it = data.find ("passes");
+    CMaterial* material = fromJSON (data);
 
-    if (passes_it == data.end ())
-    {
-        throw std::runtime_error ("Material must have at least one pass");
-    }
+    material->setTarget (target);
+
+    return material;
+}
+
+CMaterial* CMaterial::fromJSON (json data)
+{
+    auto passes_it = jsonFindRequired (data, "passes", "Material must have at least one pass");
 
     CMaterial* material = new CMaterial ();
 
-    json::const_iterator cur = (*passes_it).begin ();
-    json::const_iterator end = (*passes_it).end ();
+    auto cur = (*passes_it).begin ();
+    auto end = (*passes_it).end ();
 
     for (; cur != end; cur ++)
     {
         material->insertPass (
-                Materials::CPassess::fromJSON (*cur)
+            Materials::CPass::fromJSON (*cur)
         );
     }
 
     return material;
 }
 
-void CMaterial::insertPass (Materials::CPassess* mass)
+void CMaterial::insertPass (Materials::CPass* mass)
 {
     this->m_passes.push_back (mass);
 }
 
-std::vector <Materials::CPassess*>* CMaterial::getPasses ()
+void CMaterial::insertTextureBind (Effects::CBind* bind)
+{
+    this->m_textureBindings.push_back (bind);
+}
+
+void CMaterial::setTarget (const std::string& target)
+{
+    this->m_target = target;
+}
+
+const std::vector <Materials::CPass*>& CMaterial::getPasses () const
+{
+    return this->m_passes;
+}
+const std::vector <Effects::CBind*>& CMaterial::getTextureBinds () const
+{
+    return this->m_textureBindings;
+}
+
+const std::string& CMaterial::getTarget () const
+{
+    return this->m_target;
+}
+
+const bool CMaterial::hasTarget () const
 {
-    return &this->m_passes;
+    return this->m_target.empty () == false;
 }

+ 18 - 6
src/WallpaperEngine/Core/Objects/Images/CMaterial.h

@@ -1,9 +1,11 @@
 #pragma once
 
 #include <irrlicht/irrlicht.h>
-#include <nlohmann/json.hpp>
 
-#include "WallpaperEngine/Core/Objects/Images/Materials/CPassess.h"
+#include "WallpaperEngine/Core/Objects/Images/Materials/CPass.h"
+#include "WallpaperEngine/Core/Objects/Effects/CBind.h"
+
+#include "WallpaperEngine/Core/Core.h"
 
 namespace WallpaperEngine::Core::Objects::Images
 {
@@ -12,15 +14,25 @@ namespace WallpaperEngine::Core::Objects::Images
     class CMaterial
     {
     public:
-        static CMaterial* fromFile (irr::io::path filename);
+        static CMaterial* fromFile (const irr::io::path& filename);
         static CMaterial* fromJSON (json data);
+        static CMaterial* fromFile (const irr::io::path& filename, const std::string& target);
+        static CMaterial* fromJSON (json data, const std::string& target);
 
-        void insertPass (Materials::CPassess* mass);
+        void insertPass (Materials::CPass* mass);
+        void insertTextureBind (Effects::CBind* bind);
 
-        std::vector <Materials::CPassess*>* getPasses ();
+        const std::vector <Materials::CPass*>& getPasses () const;
+        const std::vector <Effects::CBind*>& getTextureBinds () const;
+        const std::string& getTarget () const;
+        const bool hasTarget () const;
     protected:
         CMaterial ();
+
+        void setTarget (const std::string& target);
     private:
-        std::vector <Materials::CPassess*> m_passes;
+        std::vector <Materials::CPass*> m_passes;
+        std::vector <Effects::CBind*> m_textureBindings;
+        std::string m_target;
     };
 };

+ 141 - 0
src/WallpaperEngine/Core/Objects/Images/Materials/CPass.cpp

@@ -0,0 +1,141 @@
+#include "CPass.h"
+
+using namespace WallpaperEngine::Core::Objects::Effects::Constants;
+using namespace WallpaperEngine::Core::Objects::Images::Materials;
+
+CPass::CPass (std::string blending, std::string cullmode, std::string depthtest, std::string depthwrite, std::string shader) :
+    m_blending (std::move(blending)),
+    m_cullmode (std::move(cullmode)),
+    m_depthtest (std::move(depthtest)),
+    m_depthwrite (std::move(depthwrite)),
+    m_shader (std::move(shader))
+{
+}
+
+CPass* CPass::fromJSON (json data)
+{
+    auto blending_it = jsonFindRequired (data, "blending", "Material pass must have blending specified");
+    auto cullmode_it = jsonFindRequired (data, "cullmode", "Material pass must have cullmode specified");
+    auto depthtest_it = jsonFindRequired (data, "depthtest", "Material pass must have depthtest specified");
+    auto depthwrite_it = jsonFindRequired (data, "depthwrite", "Material pass must have depthwrite specified");
+    auto shader_it = jsonFindRequired (data, "shader", "Material pass must have shader specified");
+    auto textures_it = data.find ("textures");
+    auto combos_it = data.find ("combos");
+
+    if (textures_it != data.end ())
+    {
+        // TODO: FETCH THIS FROM CImage TO MAKE IT COMPATIBLE WITH OLDER WALLPAPERS
+        if ((*textures_it).is_array () == false)
+        {
+            throw std::runtime_error ("Textures for material must be a list");
+        }
+    }
+
+    CPass* pass = new CPass (
+        *blending_it,
+        *cullmode_it,
+        *depthtest_it,
+        *depthwrite_it,
+        *shader_it
+    );
+
+    if (textures_it != data.end ())
+    {
+        auto cur = (*textures_it).begin ();
+        auto end = (*textures_it).end ();
+
+        for (;cur != end; cur ++)
+        {
+            if ((*cur).is_null () == true)
+            {
+                pass->insertTexture ("");
+            }
+            else
+            {
+                pass->insertTexture (*cur);
+            }
+        }
+    }
+
+    if (combos_it != data.end ())
+    {
+        auto cur = (*combos_it).begin ();
+        auto end = (*combos_it).end ();
+
+        for (; cur != end; cur ++)
+        {
+            std::string name = cur.key ();
+
+            if ((*cur).is_number_integer () == true)
+            {
+                pass->insertCombo (name, *cur);
+            }
+            else
+            {
+                throw std::runtime_error ("unexpected non-integer combo");
+            }
+        }
+    }
+
+    return pass;
+}
+
+void CPass::insertTexture (const std::string& texture)
+{
+    this->m_textures.push_back (texture);
+}
+
+void CPass::setTexture (int index, const std::string& texture)
+{
+    this->m_textures.at (index) = texture;
+}
+
+void CPass::insertCombo (const std::string& name, int value)
+{
+    this->m_combos.insert (std::pair <std::string, int> (name, value));
+}
+
+const std::vector<std::string>& CPass::getTextures () const
+{
+    return this->m_textures;
+}
+
+const std::map<std::string, CShaderConstant*>& CPass::getConstants () const
+{
+    return this->m_constants;
+}
+
+const std::map<std::string, int>& CPass::getCombos () const
+{
+    return this->m_combos;
+}
+
+const std::string& CPass::getShader () const
+{
+    return this->m_shader;
+}
+
+const std::string& CPass::getBlendingMode () const
+{
+    return this->m_blending;
+}
+
+const std::string& CPass::getCullingMode () const
+{
+    return this->m_cullmode;
+}
+
+const std::string& CPass::getDepthTest () const
+{
+    return this->m_depthtest;
+}
+
+const std::string& CPass::getDepthWrite ()const
+{
+    return this->m_depthwrite;
+}
+
+void CPass::insertConstant (const std::string& name, CShaderConstant* constant)
+{
+    this->m_constants.insert (std::pair <std::string, CShaderConstant*> (name, constant));
+}

+ 51 - 0
src/WallpaperEngine/Core/Objects/Images/Materials/CPass.h

@@ -0,0 +1,51 @@
+#pragma once
+
+#include "WallpaperEngine/Core/Core.h"
+
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.h"
+
+namespace WallpaperEngine::Core::Objects
+{
+    class CEffect;
+};
+
+namespace WallpaperEngine::Core::Objects::Images::Materials
+{
+    using json = nlohmann::json;
+
+    class CPass
+    {
+        friend class Core::Objects::CEffect;
+    public:
+        static CPass* fromJSON (json data);
+
+        const std::vector<std::string>& getTextures () const;
+        const std::map<std::string, Effects::Constants::CShaderConstant*>& getConstants () const;
+
+        const std::map<std::string, int>& getCombos () const;
+        const std::string& getShader () const;
+        const std::string& getBlendingMode () const;
+        const std::string& getCullingMode () const;
+        const std::string& getDepthTest () const;
+        const std::string& getDepthWrite () const;
+
+        void insertCombo (const std::string& name, int value);
+        void insertConstant (const std::string& name, Effects::Constants::CShaderConstant* constant);
+
+    protected:
+        CPass (std::string blending, std::string cullmode, std::string depthtest, std::string depthwrite, std::string shader);
+
+        void insertTexture (const std::string& texture);
+        void setTexture (int index, const std::string& texture);
+
+    private:
+        std::string m_blending;
+        std::string m_cullmode;
+        std::string m_depthtest;
+        std::string m_depthwrite;
+        std::string m_shader;
+        std::vector<std::string> m_textures;
+        std::map<std::string, int> m_combos;
+        std::map<std::string, Core::Objects::Effects::Constants::CShaderConstant*> m_constants;
+    };
+}

+ 0 - 131
src/WallpaperEngine/Core/Objects/Images/Materials/CPassess.cpp

@@ -1,131 +0,0 @@
-#include "CPassess.h"
-
-using namespace WallpaperEngine::Core::Objects::Images::Materials;
-
-CPassess::CPassess (std::string blending, std::string cullmode, std::string depthtest, std::string depthwrite, std::string shader) :
-    m_blending (std::move(blending)),
-    m_cullmode (std::move(cullmode)),
-    m_depthtest (std::move(depthtest)),
-    m_depthwrite (std::move(depthwrite)),
-    m_shader (std::move(shader))
-{
-}
-
-std::vector<std::string>* CPassess::getTextures ()
-{
-    return &this->m_textures;
-}
-
-CPassess* CPassess::fromJSON (json data)
-{
-    json::const_iterator blending_it = data.find ("blending");
-    json::const_iterator cullmode_it = data.find ("cullmode");
-    json::const_iterator depthtest_it = data.find ("depthtest");
-    json::const_iterator depthwrite_it = data.find ("depthwrite");
-    json::const_iterator shader_it = data.find ("shader");
-    json::const_iterator textures_it = data.find ("textures");
-    json::const_iterator combos_it = data.find ("combos");
-
-    if (blending_it == data.end ())
-    {
-        throw std::runtime_error ("Material pass must have blending specified");
-    }
-
-    if (cullmode_it == data.end ())
-    {
-        throw std::runtime_error ("Material pass must have cullmode specified");
-    }
-
-    if (depthtest_it == data.end ())
-    {
-        throw std::runtime_error ("Material pass must have depthtest specified");
-    }
-
-    if (depthwrite_it == data.end ())
-    {
-        throw std::runtime_error ("Material pass must have depthwrite specified");
-    }
-
-    if (shader_it == data.end ())
-    {
-        throw std::runtime_error ("Material pass must have shader specified");
-    }
-
-    if (textures_it != data.end ())
-    {
-        // TODO: FETCH THIS FROM CImage TO MAKE IT COMPATIBLE WITH OLDER WALLPAPERS
-        if ((*textures_it).is_array () == false)
-        {
-            throw std::runtime_error ("Textures for material must be a list");
-        }
-    }
-
-    CPassess* pass = new CPassess (
-        *blending_it,
-        *cullmode_it,
-        *depthtest_it,
-        *depthwrite_it,
-        *shader_it
-    );
-
-    if (textures_it != data.end ())
-    {
-        json::const_iterator cur = (*textures_it).begin ();
-        json::const_iterator end = (*textures_it).end ();
-
-        for (;cur != end; cur ++)
-        {
-            if ((*cur).is_null () == true)
-            {
-                pass->insertTexture ("");
-            }
-            else
-            {
-                pass->insertTexture (*cur);
-            }
-        }
-    }
-
-    if (combos_it != data.end ())
-    {
-        json::const_iterator cur = (*combos_it).begin ();
-        json::const_iterator end = (*combos_it).end ();
-
-        for (; cur != end; cur ++)
-        {
-            std::string name = cur.key ();
-
-            if ((*cur).is_number_integer () == true)
-            {
-                pass->insertCombo (name, *cur);
-            }
-            else
-            {
-                throw std::runtime_error ("unexpected non-integer combo");
-            }
-        }
-    }
-
-    return pass;
-}
-
-
-void CPassess::insertTexture (const std::string& texture)
-{
-    this->m_textures.push_back (texture);
-}
-
-void CPassess::insertCombo (const std::string& name, int value)
-{
-    this->m_combos.insert (std::pair <std::string, int> (name, value));
-}
-
-std::map<std::string, int>* CPassess::getCombos ()
-{
-    return &this->m_combos;
-}
-
-std::string CPassess::getShader ()
-{
-    return this->m_shader;
-}

+ 0 - 32
src/WallpaperEngine/Core/Objects/Images/Materials/CPassess.h

@@ -1,32 +0,0 @@
-#pragma once
-
-#include <nlohmann/json.hpp>
-
-namespace WallpaperEngine::Core::Objects::Images::Materials
-{
-    using json = nlohmann::json;
-
-    class CPassess
-    {
-    public:
-        static CPassess* fromJSON (json data);
-
-        std::vector<std::string>* getTextures ();
-        std::map<std::string, int>* getCombos ();
-        std::string getShader ();
-    protected:
-        CPassess (std::string blending, std::string cullmode, std::string depthtest, std::string depthwrite, std::string shader);
-
-        void insertTexture (const std::string& texture);
-        void insertCombo (const std::string& name, int value);
-
-    private:
-        std::string m_blending;
-        std::string m_cullmode;
-        std::string m_depthtest;
-        std::string m_depthwrite;
-        std::string m_shader;
-        std::vector<std::string> m_textures;
-        std::map<std::string, int> m_combos;
-    };
-}

+ 6 - 13
src/WallpaperEngine/Core/Objects/Particles/CControlPoint.cpp

@@ -1,19 +1,12 @@
 #include "CControlPoint.h"
 
-#include "WallpaperEngine/Core/Core.h"
-
 using namespace WallpaperEngine::Core::Objects::Particles;
 
 CControlPoint* CControlPoint::fromJSON (json data)
 {
-    json::const_iterator flags_it = data.find ("flags");
-    json::const_iterator id_it = data.find ("id");
-    json::const_iterator offset_it = data.find ("offset");
-
-    if (id_it == data.end ())
-    {
-        throw std::runtime_error ("Particle's control point must have id");
-    }
+    auto flags_it = data.find ("flags");
+    auto id_it = jsonFindRequired (data, "id", "Particle's control point must have id");
+    auto offset_it = data.find ("offset");
 
     CControlPoint* controlpoint = new CControlPoint (*id_it, 0);
 
@@ -47,12 +40,12 @@ void CControlPoint::setFlags (irr::u32 flags)
     this->m_flags = flags;
 }
 
-irr::core::vector3df* CControlPoint::getOffset ()
+const irr::core::vector3df& CControlPoint::getOffset () const
 {
-    return &this->m_offset;
+    return this->m_offset;
 }
 
-irr::u32 CControlPoint::getFlags ()
+const irr::u32 CControlPoint::getFlags () const
 {
     return this->m_flags;
 }

+ 4 - 3
src/WallpaperEngine/Core/Objects/Particles/CControlPoint.h

@@ -1,8 +1,9 @@
 #pragma once
 
-#include <nlohmann/json.hpp>
 #include <irrlicht/irrlicht.h>
 
+#include "WallpaperEngine/Core/Core.h"
+
 namespace WallpaperEngine::Core::Objects::Particles
 {
     using json = nlohmann::json;
@@ -12,8 +13,8 @@ namespace WallpaperEngine::Core::Objects::Particles
     public:
         static CControlPoint* fromJSON (json data);
 
-        irr::core::vector3df* getOffset ();
-        irr::u32 getFlags ();
+        const irr::core::vector3df& getOffset () const;
+        const irr::u32 getFlags () const;
     protected:
         CControlPoint (irr::u32 id, irr::u32 flags = 0);
 

+ 14 - 46
src/WallpaperEngine/Core/Objects/Particles/CEmitter.cpp

@@ -1,48 +1,16 @@
 #include "CEmitter.h"
 
-#include "WallpaperEngine/Core/Core.h"
-
 using namespace WallpaperEngine::Core::Objects::Particles;
 
 CEmitter* CEmitter::fromJSON (json data)
 {
-    json::const_iterator directions_it = data.find ("directions");
-    json::const_iterator distancemax_it = data.find ("distancemax");
-    json::const_iterator distancemin_it = data.find ("distancemin");
-    json::const_iterator id_it = data.find ("id");
-    json::const_iterator name_it = data.find ("name");
-    json::const_iterator origin_it = data.find ("origin");
-    json::const_iterator rate_it = data.find ("rate");
-
-    if (directions_it == data.end ())
-    {
-        throw std::runtime_error ("Particle emitter must have direction specified");
-    }
-
-    if (distancemax_it == data.end ())
-    {
-        throw std::runtime_error ("Particle emitter must have maximum distance");
-    }
-
-    if (distancemin_it == data.end ())
-    {
-        throw std::runtime_error ("Particle emitter must have minimum distance");
-    }
-
-    if (name_it == data.end ())
-    {
-        throw std::runtime_error ("Particle emitter must have a name");
-    }
-
-    if (origin_it == data.end ())
-    {
-        throw std::runtime_error ("Particle emitter must have an origin");
-    }
-
-    if (rate_it == data.end ())
-    {
-        throw std::runtime_error ("Particle emitter must have a rate");
-    }
+    auto directions_it = jsonFindRequired (data, "directions", "Particle emitter must have direction specified");
+    auto distancemax_it = jsonFindRequired (data, "distancemax", "Particle emitter must have maximum distance");
+    auto distancemin_it = jsonFindRequired (data, "distancemin", "Particle emitter must have minimum distance");
+    auto id_it = data.find ("id");
+    auto name_it = jsonFindRequired (data, "name", "Particle emitter must have a name");
+    auto origin_it = jsonFindRequired (data, "origin", "Particle emitter must have an origin");
+    auto rate_it = jsonFindRequired (data, "rate", "Particle emitter must have a rate");
 
     return new CEmitter (
             WallpaperEngine::Core::ato3vf (*directions_it),
@@ -79,27 +47,27 @@ const std::string& CEmitter::getName () const
     return this->m_name;
 }
 
-irr::u32 CEmitter::getDistanceMax () const
+const irr::u32 CEmitter::getDistanceMax () const
 {
     return this->m_distancemax;
 }
 
-irr::u32 CEmitter::getDistanceMin () const
+const irr::u32 CEmitter::getDistanceMin () const
 {
     return this->m_distancemin;
 }
 
-irr::core::vector3df* CEmitter::getDirections ()
+const irr::core::vector3df& CEmitter::getDirections () const
 {
-    return &this->m_directions;
+    return this->m_directions;
 }
 
-irr::core::vector3df* CEmitter::getOrigin ()
+const irr::core::vector3df& CEmitter::getOrigin () const
 {
-    return &this->m_origin;
+    return this->m_origin;
 }
 
-irr::f64 CEmitter::getRate () const
+const irr::f64 CEmitter::getRate () const
 {
     return this->m_rate;
 }

+ 7 - 6
src/WallpaperEngine/Core/Objects/Particles/CEmitter.h

@@ -1,8 +1,9 @@
 #pragma once
 
-#include <nlohmann/json.hpp>
 #include <irrlicht/irrlicht.h>
 
+#include "WallpaperEngine/Core/Core.h"
+
 namespace WallpaperEngine::Core::Objects::Particles
 {
     using json = nlohmann::json;
@@ -13,11 +14,11 @@ namespace WallpaperEngine::Core::Objects::Particles
         static CEmitter* fromJSON (json data);
 
         const std::string& getName () const;
-        irr::u32 getDistanceMax () const;
-        irr::u32 getDistanceMin () const;
-        irr::core::vector3df* getDirections ();
-        irr::core::vector3df* getOrigin ();
-        irr::f64 getRate () const;
+        const irr::u32 getDistanceMax () const;
+        const irr::u32 getDistanceMin () const;
+        const irr::core::vector3df& getDirections () const;
+        const irr::core::vector3df& getOrigin () const;
+        const irr::f64 getRate () const;
     protected:
         CEmitter (
             const irr::core::vector3df& directions,

+ 4 - 9
src/WallpaperEngine/Core/Objects/Particles/CInitializer.cpp

@@ -13,15 +13,10 @@ using namespace WallpaperEngine::Core::Objects::Particles;
 
 CInitializer* CInitializer::fromJSON (json data)
 {
-    json::const_iterator id_it = data.find ("id");
-    json::const_iterator name_it = data.find ("name");
+    auto id_it = data.find ("id");
+    auto name_it = jsonFindRequired (data, "name", "Particle's initializer must have a name");
     irr::u32 id = ((id_it == data.end ()) ? 0 : (irr::u32) (*id_it));
 
-    if (name_it == data.end ())
-    {
-        throw std::runtime_error ("Particle's initializer must have a name");
-    }
-
     if (*name_it == "lifetimerandom")
     {
         return Initializers::CLifeTimeRandom::fromJSON (data, id);
@@ -68,12 +63,12 @@ CInitializer::CInitializer (irr::u32 id, std::string name) :
 }
 
 
-std::string& CInitializer::getName ()
+const std::string& CInitializer::getName () const
 {
     return this->m_name;
 }
 
-irr::u32 CInitializer::getId ()
+const irr::u32 CInitializer::getId () const
 {
     return this->m_id;
 }

+ 4 - 3
src/WallpaperEngine/Core/Objects/Particles/CInitializer.h

@@ -1,8 +1,9 @@
 #pragma once
 
-#include <nlohmann/json.hpp>
 #include <irrlicht/irrlicht.h>
 
+#include "WallpaperEngine/Core/Core.h"
+
 namespace WallpaperEngine::Core::Objects::Particles
 {
     using json = nlohmann::json;
@@ -12,8 +13,8 @@ namespace WallpaperEngine::Core::Objects::Particles
     public:
         static CInitializer* fromJSON (json data);
 
-        std::string& getName ();
-        irr::u32 getId ();
+        const std::string& getName () const;
+        const irr::u32 getId () const;
     protected:
         CInitializer (irr::u32 id, std::string name);
     private:

+ 4 - 14
src/WallpaperEngine/Core/Objects/Particles/Initializers/CAlphaRandom.cpp

@@ -4,18 +4,8 @@ using namespace WallpaperEngine::Core::Objects::Particles::Initializers;
 
 CAlphaRandom* CAlphaRandom::fromJSON (json data, irr::u32 id)
 {
-    json::const_iterator min_it = data.find ("min");
-    json::const_iterator max_it = data.find ("max");
-
-    if (min_it == data.end ())
-    {
-        throw std::runtime_error ("Alpharandom initializer must have a minimum value");
-    }
-
-    if (max_it == data.end ())
-    {
-        throw std::runtime_error ("Alpharandom initializer must have a maximum value");
-    }
+    auto min_it = jsonFindRequired (data, "min", "Alpharandom initializer must have a minimum value");
+    auto max_it = jsonFindRequired (data, "max", "Alpharandom initializer must have a maximum value");
 
     return new CAlphaRandom (id, *min_it, *max_it);
 }
@@ -27,12 +17,12 @@ CAlphaRandom::CAlphaRandom (irr::u32 id, irr::f64 min, irr::f64 max) :
 {
 }
 
-irr::f64 CAlphaRandom::getMinimum ()
+const irr::f64 CAlphaRandom::getMinimum () const
 {
     return this->m_min;
 }
 
-irr::f64 CAlphaRandom::getMaximum ()
+const irr::f64 CAlphaRandom::getMaximum () const
 {
     return this->m_max;
 }

+ 4 - 3
src/WallpaperEngine/Core/Objects/Particles/Initializers/CAlphaRandom.h

@@ -2,7 +2,8 @@
 
 #include "WallpaperEngine/Core/Objects/Particles/CInitializer.h"
 
-#include <nlohmann/json.hpp>
+#include "WallpaperEngine/Core/Core.h"
+
 #include <irrlicht/irrlicht.h>
 
 namespace WallpaperEngine::Core::Objects::Particles::Initializers
@@ -10,8 +11,8 @@ namespace WallpaperEngine::Core::Objects::Particles::Initializers
     class CAlphaRandom : CInitializer
     {
     public:
-        irr::f64 getMinimum ();
-        irr::f64 getMaximum ();
+        const irr::f64 getMinimum () const;
+        const irr::f64 getMaximum () const;
     protected:
         friend class CInitializer;
 

+ 6 - 18
src/WallpaperEngine/Core/Objects/Particles/Initializers/CAngularVelocityRandom.cpp

@@ -1,23 +1,11 @@
 #include "CAngularVelocityRandom.h"
 
-#include "WallpaperEngine/Core/Core.h"
-
 using namespace WallpaperEngine::Core::Objects::Particles::Initializers;
 
 CAngularVelocityRandom* CAngularVelocityRandom::fromJSON (json data, irr::u32 id)
 {
-    json::const_iterator min_it = data.find ("min");
-    json::const_iterator max_it = data.find ("max");
-
-    if (min_it == data.end ())
-    {
-        throw std::runtime_error ("Angularvelocityrandom initializer must have a minimum value");
-    }
-
-    if (max_it == data.end ())
-    {
-        throw std::runtime_error ("Angularvelocityrandom initializer must have a maximum value");
-    }
+    auto min_it = jsonFindRequired (data, "min", "Angularvelocityrandom initializer must have a minimum value");
+    auto max_it = jsonFindRequired (data, "max", "Angularvelocityrandom initializer must have a maximum value");
 
     return new CAngularVelocityRandom (
             id,
@@ -34,12 +22,12 @@ CAngularVelocityRandom::CAngularVelocityRandom (irr::u32 id, irr::core::vector3d
 {
 }
 
-irr::core::vector3df* CAngularVelocityRandom::getMinimum ()
+const irr::core::vector3df& CAngularVelocityRandom::getMinimum () const
 {
-    return &this->m_min;
+    return this->m_min;
 }
 
-irr::core::vector3df* CAngularVelocityRandom::getMaximum ()
+const irr::core::vector3df& CAngularVelocityRandom::getMaximum () const
 {
-    return &this->m_max;
+    return this->m_max;
 }

+ 4 - 3
src/WallpaperEngine/Core/Objects/Particles/Initializers/CAngularVelocityRandom.h

@@ -2,7 +2,8 @@
 
 #include "WallpaperEngine/Core/Objects/Particles/CInitializer.h"
 
-#include <nlohmann/json.hpp>
+#include "WallpaperEngine/Core/Core.h"
+
 #include <irrlicht/irrlicht.h>
 
 namespace WallpaperEngine::Core::Objects::Particles::Initializers
@@ -10,8 +11,8 @@ namespace WallpaperEngine::Core::Objects::Particles::Initializers
     class CAngularVelocityRandom : CInitializer
     {
     public:
-        irr::core::vector3df* getMinimum ();
-        irr::core::vector3df* getMaximum ();
+        const irr::core::vector3df& getMinimum () const;
+        const irr::core::vector3df& getMaximum () const;
     protected:
         friend class CInitializer;
 

+ 6 - 18
src/WallpaperEngine/Core/Objects/Particles/Initializers/CColorRandom.cpp

@@ -1,23 +1,11 @@
 #include "CColorRandom.h"
 
-#include "WallpaperEngine/Core/Core.h"
-
 using namespace WallpaperEngine::Core::Objects::Particles::Initializers;
 
 CColorRandom* CColorRandom::fromJSON (json data, irr::u32 id)
 {
-    json::const_iterator min_it = data.find ("min");
-    json::const_iterator max_it = data.find ("max");
-
-    if (min_it == data.end ())
-    {
-        throw std::runtime_error ("Colorrandom initializer must have a minimum value");
-    }
-
-    if (max_it == data.end ())
-    {
-        throw std::runtime_error ("Colorrandom initializer must have a maximum value");
-    }
+    auto min_it = jsonFindRequired (data, "min", "Colorrandom initializer must have a minimum value");
+    auto max_it = jsonFindRequired (data, "max", "Colorrandom initializer must have a maximum value");
 
     return new CColorRandom (
             id,
@@ -34,12 +22,12 @@ CColorRandom::CColorRandom (irr::u32 id, irr::video::SColor min, irr::video::SCo
 {
 }
 
-irr::video::SColor* CColorRandom::getMinimum ()
+const irr::video::SColor& CColorRandom::getMinimum () const
 {
-    return &this->m_min;
+    return this->m_min;
 }
 
-irr::video::SColor* CColorRandom::getMaximum ()
+const irr::video::SColor& CColorRandom::getMaximum () const
 {
-    return &this->m_max;
+    return this->m_max;
 }

+ 4 - 3
src/WallpaperEngine/Core/Objects/Particles/Initializers/CColorRandom.h

@@ -2,7 +2,8 @@
 
 #include "WallpaperEngine/Core/Objects/Particles/CInitializer.h"
 
-#include <nlohmann/json.hpp>
+#include "WallpaperEngine/Core/Core.h"
+
 #include <irrlicht/irrlicht.h>
 
 namespace WallpaperEngine::Core::Objects::Particles::Initializers
@@ -10,8 +11,8 @@ namespace WallpaperEngine::Core::Objects::Particles::Initializers
     class CColorRandom : CInitializer
     {
     public:
-        irr::video::SColor* getMinimum ();
-        irr::video::SColor* getMaximum ();
+        const irr::video::SColor& getMinimum () const;
+        const irr::video::SColor& getMaximum () const;
     protected:
         friend class CInitializer;
 

+ 4 - 14
src/WallpaperEngine/Core/Objects/Particles/Initializers/CLifeTimeRandom.cpp

@@ -4,18 +4,8 @@ using namespace WallpaperEngine::Core::Objects::Particles::Initializers;
 
 CLifeTimeRandom* CLifeTimeRandom::fromJSON (json data, irr::u32 id)
 {
-    json::const_iterator min_it = data.find ("min");
-    json::const_iterator max_it = data.find ("max");
-
-    if (min_it == data.end ())
-    {
-        throw std::runtime_error ("Lifetimerandom initializer must have a minimum value");
-    }
-
-    if (max_it == data.end ())
-    {
-        throw std::runtime_error ("Lifetimerandom initializer must have a maximum value");
-    }
+    auto min_it = jsonFindRequired (data, "min", "Lifetimerandom initializer must have a minimum value");
+    auto max_it = jsonFindRequired (data, "max", "Lifetimerandom initializer must have a maximum value");
 
     return new CLifeTimeRandom (id, *min_it, *max_it);
 }
@@ -28,12 +18,12 @@ CLifeTimeRandom::CLifeTimeRandom (irr::u32 id, irr::u32 min, irr::u32 max) :
 {
 }
 
-irr::u32 CLifeTimeRandom::getMinimum ()
+const irr::u32 CLifeTimeRandom::getMinimum () const
 {
     return this->m_min;
 }
 
-irr::u32 CLifeTimeRandom::getMaximum ()
+const irr::u32 CLifeTimeRandom::getMaximum () const
 {
     return this->m_max;
 }

+ 4 - 3
src/WallpaperEngine/Core/Objects/Particles/Initializers/CLifeTimeRandom.h

@@ -2,7 +2,8 @@
 
 #include "WallpaperEngine/Core/Objects/Particles/CInitializer.h"
 
-#include <nlohmann/json.hpp>
+#include "WallpaperEngine/Core/Core.h"
+
 #include <irrlicht/irrlicht.h>
 
 namespace WallpaperEngine::Core::Objects::Particles::Initializers
@@ -10,8 +11,8 @@ namespace WallpaperEngine::Core::Objects::Particles::Initializers
     class CLifeTimeRandom : CInitializer
     {
     public:
-        irr::u32 getMinimum ();
-        irr::u32 getMaximum ();
+        const irr::u32 getMinimum () const;
+        const irr::u32 getMaximum () const;
     protected:
         friend class CInitializer;
 

+ 4 - 4
src/WallpaperEngine/Core/Objects/Particles/Initializers/CRotationRandom.cpp

@@ -6,8 +6,8 @@ using namespace WallpaperEngine::Core::Objects::Particles::Initializers;
 
 CRotationRandom* CRotationRandom::fromJSON (json data, irr::u32 id)
 {
-    json::const_iterator min_it = data.find ("min");
-    json::const_iterator max_it = data.find ("max");
+    auto min_it = data.find ("min");
+    auto max_it = data.find ("max");
 
     irr::core::vector3df min = irr::core::vector3df ();
     irr::core::vector3df max = irr::core::vector3df ();
@@ -32,12 +32,12 @@ CRotationRandom::CRotationRandom (irr::u32 id, irr::core::vector3df min, irr::co
 {
 }
 
-irr::core::vector3df CRotationRandom::getMinimum ()
+const irr::core::vector3df CRotationRandom::getMinimum () const
 {
     return this->m_min;
 }
 
-irr::core::vector3df CRotationRandom::getMaximum ()
+const irr::core::vector3df CRotationRandom::getMaximum () const
 {
     return this->m_max;
 }

+ 2 - 2
src/WallpaperEngine/Core/Objects/Particles/Initializers/CRotationRandom.h

@@ -10,8 +10,8 @@ namespace WallpaperEngine::Core::Objects::Particles::Initializers
     class CRotationRandom : CInitializer
     {
     public:
-        irr::core::vector3df getMinimum ();
-        irr::core::vector3df getMaximum ();
+        const irr::core::vector3df getMinimum () const;
+        const irr::core::vector3df getMaximum () const;
     protected:
         friend class CInitializer;
 

+ 4 - 14
src/WallpaperEngine/Core/Objects/Particles/Initializers/CSizeRandom.cpp

@@ -4,18 +4,8 @@ using namespace WallpaperEngine::Core::Objects::Particles::Initializers;
 
 CSizeRandom* CSizeRandom::fromJSON (json data, irr::u32 id)
 {
-    json::const_iterator min_it = data.find ("min");
-    json::const_iterator max_it = data.find ("max");
-
-    if (min_it == data.end ())
-    {
-        throw std::runtime_error ("Sizerandom initializer must have a minimum value");
-    }
-
-    if (max_it == data.end ())
-    {
-        throw std::runtime_error ("Sizerandom initializer must have a maximum value");
-    }
+    auto min_it = jsonFindRequired (data, "min", "Sizerandom initializer must have a minimum value");
+    auto max_it = jsonFindRequired (data, "max", "Sizerandom initializer must have a maximum value");
 
     return new CSizeRandom (id, *min_it, *max_it);
 }
@@ -27,12 +17,12 @@ CSizeRandom::CSizeRandom (irr::u32 id, irr::u32 min, irr::u32 max) :
 {
 }
 
-irr::u32 CSizeRandom::getMinimum ()
+const irr::u32 CSizeRandom::getMinimum () const
 {
     return this->m_min;
 }
 
-irr::u32 CSizeRandom::getMaximum ()
+const irr::u32 CSizeRandom::getMaximum () const
 {
     return this->m_max;
 }

+ 4 - 3
src/WallpaperEngine/Core/Objects/Particles/Initializers/CSizeRandom.h

@@ -2,7 +2,8 @@
 
 #include "WallpaperEngine/Core/Objects/Particles/CInitializer.h"
 
-#include <nlohmann/json.hpp>
+#include "WallpaperEngine/Core/Core.h"
+
 #include <irrlicht/irrlicht.h>
 
 namespace WallpaperEngine::Core::Objects::Particles::Initializers
@@ -10,8 +11,8 @@ namespace WallpaperEngine::Core::Objects::Particles::Initializers
     class CSizeRandom : CInitializer
     {
     public:
-        irr::u32 getMinimum ();
-        irr::u32 getMaximum ();
+        const irr::u32 getMinimum () const;
+        const irr::u32 getMaximum () const;
     protected:
         friend class CInitializer;
 

+ 6 - 18
src/WallpaperEngine/Core/Objects/Particles/Initializers/CVelocityRandom.cpp

@@ -1,23 +1,11 @@
 #include "CVelocityRandom.h"
 
-#include "WallpaperEngine/Core/Core.h"
-
 using namespace WallpaperEngine::Core::Objects::Particles::Initializers;
 
 CVelocityRandom* CVelocityRandom::fromJSON (json data, irr::u32 id)
 {
-    json::const_iterator min_it = data.find ("min");
-    json::const_iterator max_it = data.find ("max");
-
-    if (min_it == data.end ())
-    {
-        throw std::runtime_error ("Velocityrandom initializer must have a minimum value");
-    }
-
-    if (max_it == data.end ())
-    {
-        throw std::runtime_error ("Velocityrandom initializer must have a maximum value");
-    }
+    auto min_it = jsonFindRequired (data, "min", "Velocityrandom initializer must have a minimum value");
+    auto max_it = jsonFindRequired (data, "max", "Velocityrandom initializer must have a maximum value");
 
     return new CVelocityRandom (
             id,
@@ -34,12 +22,12 @@ CVelocityRandom::CVelocityRandom (irr::u32 id, irr::core::vector3df min, irr::co
 {
 }
 
-irr::core::vector3df* CVelocityRandom::getMinimum ()
+const irr::core::vector3df& CVelocityRandom::getMinimum () const
 {
-    return &this->m_min;
+    return this->m_min;
 }
 
-irr::core::vector3df* CVelocityRandom::getMaximum ()
+const irr::core::vector3df& CVelocityRandom::getMaximum () const
 {
-    return &this->m_max;
+    return this->m_max;
 }

+ 4 - 3
src/WallpaperEngine/Core/Objects/Particles/Initializers/CVelocityRandom.h

@@ -2,7 +2,8 @@
 
 #include "WallpaperEngine/Core/Objects/Particles/CInitializer.h"
 
-#include <nlohmann/json.hpp>
+#include "WallpaperEngine/Core/Core.h"
+
 #include <irrlicht/irrlicht.h>
 
 namespace WallpaperEngine::Core::Objects::Particles::Initializers
@@ -10,8 +11,8 @@ namespace WallpaperEngine::Core::Objects::Particles::Initializers
     class CVelocityRandom : CInitializer
     {
     public:
-        irr::core::vector3df* getMinimum ();
-        irr::core::vector3df* getMaximum ();
+        const irr::core::vector3df& getMinimum () const;
+        const irr::core::vector3df& getMaximum () const;
     protected:
         friend class CInitializer;
 

+ 33 - 44
src/WallpaperEngine/Core/Projects/CProperty.cpp

@@ -2,56 +2,45 @@
 #include "CPropertyColor.h"
 #include "CPropertyBoolean.h"
 
-namespace WallpaperEngine::Core::Projects
+using namespace WallpaperEngine::Core::Projects;
+
+CProperty* CProperty::fromJSON (json data, const std::string& name)
 {
-    CProperty* CProperty::fromJSON (json data, const std::string& name)
-    {
-        json::const_iterator type = data.find ("type");
-        json::const_iterator value = data.find ("value");
-        json::const_iterator text = data.find ("text");
-
-        if (value == data.end ())
-        {
-            throw std::runtime_error ("Project properties must have the value field");
-        }
-
-        if (type == data.end ())
-        {
-            throw std::runtime_error ("Project properties must have the type field");
-        }
-
-        if (*type == CPropertyColor::Type)
-        {
-            return CPropertyColor::fromJSON (data, name);
-        }
-
-        if (*type == CPropertyBoolean::Type)
-        {
-            return CPropertyBoolean::fromJSON (data, name);
-        }
-
-        throw std::runtime_error ("Unexpected type for property");
-    }
+    auto type = jsonFindRequired (data, "type", "Project properties must have the type field");
+    auto value = jsonFindRequired (data, "value", "Project properties must have the value field");
+    auto text = data.find ("text");
 
-    CProperty::CProperty (std::string name, std::string type, std::string text) :
-        m_name (std::move(name)),
-        m_type (std::move(type)),
-        m_text (std::move(text))
+    if (*type == CPropertyColor::Type)
     {
+        return CPropertyColor::fromJSON (data, name);
     }
 
-    std::string& CProperty::getName ()
+    if (*type == CPropertyBoolean::Type)
     {
-        return this->m_name;
+        return CPropertyBoolean::fromJSON (data, name);
     }
 
-    std::string& CProperty::getType ()
-    {
-        return this->m_type;
-    }
+    throw std::runtime_error ("Unexpected type for property");
+}
 
-    std::string& CProperty::getText ()
-    {
-        return this->m_text;
-    }
-};
+CProperty::CProperty (std::string name, std::string type, std::string text) :
+    m_name (std::move(name)),
+    m_type (std::move(type)),
+    m_text (std::move(text))
+{
+}
+
+const std::string& CProperty::getName () const
+{
+    return this->m_name;
+}
+
+const std::string& CProperty::getType () const
+{
+    return this->m_type;
+}
+
+const std::string& CProperty::getText () const
+{
+    return this->m_text;
+}

+ 7 - 7
src/WallpaperEngine/Core/Projects/CProperty.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include <nlohmann/json.hpp>
+#include "WallpaperEngine/Core/Core.h"
 
 namespace WallpaperEngine::Core::Projects
 {
@@ -13,14 +13,14 @@ namespace WallpaperEngine::Core::Projects
     public:
         static CProperty* fromJSON (json data, const std::string& name);
 
-        template<class T> const T* As () const { assert (Is<T> ()); return (const T*) this; }
-        template<class T> T* As () { assert (Is<T> ()); return (T*) this; }
+        template<class T> const T* as () const { assert (is <T> ()); return (const T*) this; }
+        template<class T> T* as () { assert (is <T> ()); return (T*) this; }
 
-        template<class T> bool Is () { return this->m_type == T::Type; }
+        template<class T> bool is () { return this->m_type == T::Type; }
 
-        std::string& getName ();
-        std::string& getType ();
-        std::string& getText ();
+        const std::string& getName () const;
+        const std::string& getType () const;
+        const std::string& getText () const;
     protected:
         CProperty (std::string name, std::string type, std::string text);
 

+ 4 - 5
src/WallpaperEngine/Core/Projects/CPropertyColor.cpp

@@ -1,12 +1,11 @@
 #include "CPropertyColor.h"
-#include "WallpaperEngine/Core/Core.h"
 
 using namespace WallpaperEngine::Core::Projects;
 
 CPropertyColor* CPropertyColor::fromJSON (json data, const std::string& name)
 {
-    json::const_iterator value = data.find ("value");
-    json::const_iterator text = data.find ("type");
+    auto value = data.find ("value");
+    auto text = data.find ("type");
 
     return new CPropertyColor (
         WallpaperEngine::Core::atoSColor (*value),
@@ -15,9 +14,9 @@ CPropertyColor* CPropertyColor::fromJSON (json data, const std::string& name)
     );
 }
 
-irr::video::SColor* CPropertyColor::getValue ()
+const irr::video::SColor& CPropertyColor::getValue () const
 {
-    return &this->m_color;
+    return this->m_color;
 }
 
 CPropertyColor::CPropertyColor (irr::video::SColor color, const std::string& name, const std::string& text) :

+ 3 - 1
src/WallpaperEngine/Core/Projects/CPropertyColor.h

@@ -4,6 +4,8 @@
 
 #include "CProperty.h"
 
+#include "WallpaperEngine/Core/Core.h"
+
 namespace WallpaperEngine::Core::Projects
 {
     using json = nlohmann::json;
@@ -13,7 +15,7 @@ namespace WallpaperEngine::Core::Projects
     public:
         static CPropertyColor* fromJSON (json data, const std::string& name);
 
-        irr::video::SColor* getValue ();
+        const irr::video::SColor& getValue () const;
 
         static const std::string Type;
 

+ 12 - 28
src/WallpaperEngine/Core/Scenes/CCamera.cpp

@@ -1,5 +1,4 @@
 #include "CCamera.h"
-#include "WallpaperEngine/Core/Core.h"
 
 using namespace WallpaperEngine::Core::Scenes;
 
@@ -10,45 +9,30 @@ CCamera::CCamera (irr::core::vector3df center, irr::core::vector3df eye, irr::co
 {
 }
 
-irr::core::vector3df* CCamera::getCenter ()
+const irr::core::vector3df& CCamera::getCenter () const
 {
-    return &this->m_center;
+    return this->m_center;
 }
 
-irr::core::vector3df* CCamera::getEye ()
+const irr::core::vector3df& CCamera::getEye () const
 {
-    return &this->m_eye;
+    return this->m_eye;
 }
 
-irr::core::vector3df* CCamera::getUp ()
+const irr::core::vector3df& CCamera::getUp () const
 {
-    return &this->m_up;
+    return this->m_up;
 }
 
 CCamera* CCamera::fromJSON (json data)
 {
-    json::const_iterator center_it = data.find ("center");
-    json::const_iterator eye_it = data.find ("eye");
-    json::const_iterator up_it = data.find ("up");
-
-    if (center_it == data.end ())
-    {
-        throw std::runtime_error ("Camera must have a center position");
-    }
-
-    if (eye_it == data.end ())
-    {
-        throw std::runtime_error ("Camera must have an eye position");
-    }
-
-    if (up_it == data.end ())
-    {
-        throw std::runtime_error ("Camera must have a up position");
-    }
+    auto center_it = jsonFindRequired (data, "center", "Camera must have a center position");
+    auto eye_it = jsonFindRequired (data, "eye", "Camera must have an eye position");
+    auto up_it = jsonFindRequired (data, "up", "Camera must have a up position");
 
     return new CCamera (
-            WallpaperEngine::Core::ato3vf (*center_it),
-            WallpaperEngine::Core::ato3vf (*eye_it),
-            WallpaperEngine::Core::ato3vf (*up_it)
+        WallpaperEngine::Core::ato3vf (*center_it),
+        WallpaperEngine::Core::ato3vf (*eye_it),
+        WallpaperEngine::Core::ato3vf (*up_it)
     );
 }

+ 5 - 4
src/WallpaperEngine/Core/Scenes/CCamera.h

@@ -1,8 +1,9 @@
 #pragma once
 
-#include <nlohmann/json.hpp>
 #include <irrlicht/irrlicht.h>
 
+#include "WallpaperEngine/Core/Core.h"
+
 namespace WallpaperEngine::Core::Scenes
 {
     using json = nlohmann::json;
@@ -12,9 +13,9 @@ namespace WallpaperEngine::Core::Scenes
     public:
         static CCamera* fromJSON (json data);
 
-        irr::core::vector3df* getCenter ();
-        irr::core::vector3df* getEye ();
-        irr::core::vector3df* getUp ();
+        const irr::core::vector3df& getCenter () const;
+        const irr::core::vector3df& getEye () const;
+        const irr::core::vector3df& getUp () const;
     protected:
         CCamera (irr::core::vector3df center, irr::core::vector3df eye, irr::core::vector3df up);
     private:

+ 4 - 15
src/WallpaperEngine/Core/Scenes/CProjection.cpp

@@ -1,5 +1,4 @@
 #include "CProjection.h"
-#include "WallpaperEngine/Core/Core.h"
 
 using namespace WallpaperEngine::Core::Scenes;
 
@@ -9,30 +8,20 @@ CProjection::CProjection (irr::u32 width, irr::u32 height) :
 {
 }
 
-irr::u32 CProjection::getWidth ()
+const irr::u32& CProjection::getWidth () const
 {
     return this->m_width;
 }
 
-irr::u32 CProjection::getHeight ()
+const irr::u32& CProjection::getHeight () const
 {
     return this->m_height;
 }
 
 CProjection* CProjection::fromJSON (json data)
 {
-    json::const_iterator width_it = data.find ("width");
-    json::const_iterator height_it = data.find ("height");
-
-    if (width_it == data.end ())
-    {
-        throw std::runtime_error ("Projection must have width");
-    }
-
-    if (height_it == data.end ())
-    {
-        throw std::runtime_error ("Projection must have height");
-    }
+    auto width_it = jsonFindRequired (data, "width", "Projection must have width");
+    auto height_it = jsonFindRequired (data, "height", "Projection must have height");
 
     return new CProjection (
         *width_it,

+ 4 - 3
src/WallpaperEngine/Core/Scenes/CProjection.h

@@ -1,8 +1,9 @@
 #pragma once
 
-#include <nlohmann/json.hpp>
 #include <irrlicht/irrlicht.h>
 
+#include "WallpaperEngine/Core/Core.h"
+
 namespace WallpaperEngine::Core::Scenes
 {
     using json = nlohmann::json;
@@ -12,8 +13,8 @@ namespace WallpaperEngine::Core::Scenes
     public:
         static CProjection* fromJSON (json data);
 
-        irr::u32 getWidth ();
-        irr::u32 getHeight ();
+        const irr::u32& getWidth () const;
+        const irr::u32& getHeight () const;
     protected:
         CProjection (irr::u32 width, irr::u32 height);
     private:

+ 17 - 15
src/WallpaperEngine/FileSystem/FileSystem.cpp

@@ -1,29 +1,31 @@
 // filesystem includes
 #include "FileSystem.h"
 
+#include <iostream>
+
 // engine includes
 #include "WallpaperEngine/Irrlicht/CContext.h"
 
 extern WallpaperEngine::Irrlicht::CContext* IrrlichtContext;
 
-namespace WallpaperEngine::FileSystem
+using namespace WallpaperEngine;
+
+std::string FileSystem::loadFullFile (const irr::io::path& file)
 {
-    std::string loadFullFile (irr::io::path file)
-    {
-        irr::io::IReadFile* reader = IrrlichtContext->getDevice ()->getFileSystem ()->createAndOpenFile (file);
+    std::cout << file.c_str() << std::endl;
+    irr::io::IReadFile* reader = IrrlichtContext->getDevice ()->getFileSystem ()->createAndOpenFile (file);
 
-        if (reader == NULL)
-            throw std::runtime_error ("Cannot open file " + std::string (file.c_str ()) + " for reading");
+    if (reader == nullptr)
+        throw std::runtime_error ("Cannot open file " + std::string (file.c_str ()) + " for reading");
 
-        char* filedata = new char [reader->getSize () + 1];
-        memset (filedata, 0, reader->getSize () + 1);
+    char* filedata = new char [reader->getSize () + 1];
+    memset (filedata, 0, reader->getSize () + 1);
 
-        reader->read (filedata, reader->getSize ());
-        reader->drop ();
+    reader->read (filedata, reader->getSize ());
+    reader->drop ();
 
-        std::string content = filedata;
-        delete [] filedata;
+    std::string content = filedata;
+    delete [] filedata;
 
-        return content;
-    }
-};
+    return content;
+}

+ 1 - 1
src/WallpaperEngine/FileSystem/FileSystem.h

@@ -16,5 +16,5 @@ namespace WallpaperEngine::FileSystem
      * @param file
      * @return
      */
-    std::string loadFullFile (irr::io::path file);
+    std::string loadFullFile (const irr::io::path& file);
 }

+ 231 - 6
src/WallpaperEngine/Irrlicht/CContext.cpp

@@ -1,14 +1,239 @@
+#include <iostream>
+#include <stdexcept>
+#include <utility>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.h>
+
+#include "WallpaperEngine/Irrlicht/CImageLoaderTEX.h"
+#include "WallpaperEngine/Irrlicht/CPkgReader.h"
+
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableFloatPointer.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector2Pointer.h"
+
 #include "CContext.h"
 
-namespace WallpaperEngine::Irrlicht
+using namespace WallpaperEngine;
+using namespace WallpaperEngine::Irrlicht;
+
+CContext::CContext (std::vector<std::string>  screens, bool isRootWindow) :
+    m_screens (std::move(screens)),
+    m_isRootWindow (isRootWindow)
 {
-    void CContext::setDevice (irr::IrrlichtDevice* device)
+}
+
+void CContext::setDevice (irr::IrrlichtDevice* device)
+{
+    this->m_device = device;
+}
+
+void CContext::initializeContext ()
+{
+    irr::SIrrlichtCreationParameters irrlichtCreationParameters;
+
+    // initialize event receiver first
+    this->m_eventReceiver = new CEventReceiver ();
+
+    // prepare basic configuration for irrlicht
+    irrlichtCreationParameters.AntiAlias = 8;
+    irrlichtCreationParameters.Bits = 16;
+    // _irr_params.DeviceType = Irrlicht::EIDT_X11;
+    irrlichtCreationParameters.DriverType = irr::video::EDT_OPENGL;
+    irrlichtCreationParameters.Doublebuffer = false;
+    irrlichtCreationParameters.EventReceiver = this->m_eventReceiver;
+    irrlichtCreationParameters.Fullscreen = false;
+    irrlichtCreationParameters.HandleSRGB = false;
+    irrlichtCreationParameters.IgnoreInput = false;
+    irrlichtCreationParameters.Stencilbuffer = true;
+    irrlichtCreationParameters.UsePerformanceTimer = false;
+    irrlichtCreationParameters.Vsync = false;
+    irrlichtCreationParameters.WithAlphaChannel = false;
+    irrlichtCreationParameters.ZBufferBits = 24;
+    irrlichtCreationParameters.LoggingLevel = irr::ELL_DEBUG;
+
+    this->initializeViewports (irrlichtCreationParameters);
+
+    this->setDevice (irr::createDeviceEx (irrlichtCreationParameters));
+
+    if (this->getDevice () == nullptr)
     {
-        this->m_device = device;
+        throw std::runtime_error ("Cannot create irrlicht device");
     }
 
-    irr::IrrlichtDevice* CContext::getDevice ()
+    this->getDevice ()->setWindowCaption (L"Test game");
+
+    // check for ps and vs support
+    if (
+        this->getDevice ()->getVideoDriver()->queryFeature (irr::video::EVDF_PIXEL_SHADER_2_0) == false &&
+        this->getDevice ()->getVideoDriver()->queryFeature (irr::video::EVDF_ARB_FRAGMENT_PROGRAM_1) == false)
     {
-        return this->m_device;
+        throw std::runtime_error ("Pixel Shader 2.0 not supported by your video driver/hardware");
     }
-};
+
+    if (
+        this->getDevice ()->getVideoDriver()->queryFeature (irr::video::EVDF_VERTEX_SHADER_2_0) == false &&
+        this->getDevice ()->getVideoDriver()->queryFeature (irr::video::EVDF_ARB_VERTEX_PROGRAM_1) == false)
+    {
+        throw std::runtime_error ("Vertex Shader 2.0 not supported by your video driver/hardware");
+    }
+
+    if (this->getDevice ()->getVideoDriver ()->queryFeature (irr::video::EVDF_RENDER_TO_TARGET) == false)
+    {
+        throw std::runtime_error ("Render to texture not supported by your video driver/hardware");
+    }
+
+    // load the assets from wallpaper engine
+    this->getDevice ()->getFileSystem ()->addFileArchive ("assets.zip", true, false);
+
+    // register custom loaders
+    this->getDevice ()->getVideoDriver()->addExternalImageLoader (
+            new WallpaperEngine::Irrlicht::CImageLoaderTex (this)
+    );
+    this->getDevice ()->getFileSystem ()->addArchiveLoader (
+            new WallpaperEngine::Irrlicht::CArchiveLoaderPkg (this)
+    );
+    // register time shader variable
+    this->insertShaderVariable (
+        new Render::Shaders::Variables::CShaderVariableFloatPointer (&this->m_time, "g_Time")
+    );
+    // register normalized uv position for mouse
+    this->insertShaderVariable (
+        new Render::Shaders::Variables::CShaderVariableVector2Pointer (&this->m_pointerPosition, "g_PointerPosition")
+    );
+}
+
+void CContext::initializeViewports (irr::SIrrlichtCreationParameters &irrlichtCreationParameters)
+{
+    if (this->m_isRootWindow == false || this->m_screens.empty () == true)
+        return;
+
+    Display* display = XOpenDisplay (nullptr);
+    int xrandr_result, xrandr_error;
+
+    if (!XRRQueryExtension (display, &xrandr_result, &xrandr_error))
+    {
+        std::cerr << "XRandr is not present, cannot detect specified screens, running in window mode" << std::endl;
+        return;
+    }
+
+    XRRScreenResources* screenResources = XRRGetScreenResources (display, DefaultRootWindow (display));
+
+    // there are some situations where xrandr returns null (like screen not using the extension)
+    if (screenResources == nullptr)
+        return;
+
+    for (int i = 0; i < screenResources->noutput; i ++)
+    {
+        XRROutputInfo* info = XRRGetOutputInfo (display, screenResources, screenResources->outputs [i]);
+
+        // there are some situations where xrandr returns null (like screen not using the extension)
+        if (info == nullptr)
+            continue;
+
+        auto cur = this->m_screens.begin ();
+        auto end = this->m_screens.end ();
+
+        for (; cur != end; cur ++)
+        {
+            if (info->connection == RR_Connected && strcmp (info->name, (*cur).c_str ()) == 0)
+            {
+                XRRCrtcInfo* crtc = XRRGetCrtcInfo (display, screenResources, info->crtc);
+
+                std::cout << "Found requested screen: " << info->name << " -> " << crtc->x << "x" << crtc->y << ":" << crtc->width << "x" << crtc->height << std::endl;
+
+                irr::core::rect<irr::s32> viewport;
+
+                viewport.UpperLeftCorner.X = crtc->x;
+                viewport.UpperLeftCorner.Y = crtc->y;
+                viewport.LowerRightCorner.X = crtc->x + crtc->width;
+                viewport.LowerRightCorner.Y = crtc->y + crtc->height;
+
+                this->m_viewports.push_back (viewport);
+
+                XRRFreeCrtcInfo (crtc);
+            }
+        }
+
+        XRRFreeOutputInfo (info);
+    }
+
+    XRRFreeScreenResources (screenResources);
+
+    irrlichtCreationParameters.WindowId = reinterpret_cast<void*> (DefaultRootWindow (display));
+}
+
+void CContext::renderFrame (Render::CWallpaper* wallpaper)
+{
+    this->m_time = this->getDevice ()->getTimer ()->getTime () / 1000.0f;
+    this->m_pointerPosition.X = this->m_eventReceiver->getPosition ().X / (irr::f32) this->getDevice ()->getVideoDriver ()->getScreenSize ().Width;
+    this->m_pointerPosition.Y = this->m_eventReceiver->getPosition ().Y / (irr::f32) this->getDevice ()->getVideoDriver ()->getScreenSize ().Height;
+
+    if (this->m_viewports.empty () == true)
+    {
+        this->drawWallpaper (wallpaper, true);
+    }
+    else
+    {
+        auto cur = this->m_viewports.begin ();
+        auto end = this->m_viewports.end ();
+
+        for (; cur != end; cur ++)
+        {
+            // change viewport to render to the correct portion of the display
+            this->getDevice ()->getVideoDriver ()->setViewPort (*cur);
+            this->drawWallpaper (wallpaper, false);
+        }
+    }
+}
+
+void CContext::drawWallpaper (Render::CWallpaper* wallpaper, bool backBuffer)
+{
+    // TODO: Get scene clear color
+    this->getDevice ()->getVideoDriver ()->beginScene (backBuffer, true);
+    this->getDevice ()->getSceneManager ()->drawAll ();
+    this->getDevice ()->getVideoDriver ()->endScene ();
+}
+
+void CContext::insertShaderVariable (Render::Shaders::Variables::CShaderVariable* variable)
+{
+    this->m_globalShaderVariables.push_back (variable);
+}
+
+const std::vector<Render::Shaders::Variables::CShaderVariable*>& CContext::getShaderVariables () const
+{
+    return this->m_globalShaderVariables;
+}
+
+irr::IrrlichtDevice* CContext::getDevice ()
+{
+    return this->m_device;
+}
+
+irr::io::path CContext::resolveFile (const irr::io::path& file)
+{
+    if (this->getDevice ()->getFileSystem ()->existFile (file) == false)
+    {
+        throw std::runtime_error ("Cannot find file " + std::string (file.c_str ()));
+    }
+
+    return file;
+}
+
+irr::io::path CContext::resolveMaterials (const std::string& materialName)
+{
+    return this->resolveFile (std::string ("materials/" + materialName + ".tex").c_str ());
+}
+
+irr::io::path CContext::resolveVertexShader (const std::string& vertexShader)
+{
+    return this->resolveFile (std::string ("shaders/" + vertexShader + ".vert").c_str ());
+}
+irr::io::path CContext::resolveFragmentShader (const std::string& fragmentShader)
+{
+    return this->resolveFile (std::string ("shaders/" + fragmentShader + ".frag").c_str ());
+}
+
+irr::io::path CContext::resolveIncludeShader (const std::string& includeShader)
+{
+    return this->resolveFile (std::string ("shaders/" + includeShader).c_str ());
+}

+ 41 - 0
src/WallpaperEngine/Irrlicht/CContext.h

@@ -1,16 +1,57 @@
 #pragma once
 
+#include <vector>
+#include <string>
+
 #include <irrlicht/irrlicht.h>
 
+#include "WallpaperEngine/Render/CWallpaper.h"
+
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariable.h"
+
+#include "CEventReceiver.h"
+
+namespace WallpaperEngine::Render
+{
+    class CWallpaper;
+};
+
 namespace WallpaperEngine::Irrlicht
 {
     class CContext
     {
     public:
+        CContext (std::vector<std::string>  screens, bool isRootWindow = false);
+
         void setDevice (irr::IrrlichtDevice* device);
+        void initializeContext ();
+
+        void insertShaderVariable (Render::Shaders::Variables::CShaderVariable* variable);
+        const std::vector<Render::Shaders::Variables::CShaderVariable*>& getShaderVariables () const;
+
+        void renderFrame (Render::CWallpaper* wallpaper);
 
         irr::IrrlichtDevice* getDevice ();
+        irr::io::path resolveMaterials (const std::string& materialName);
+        irr::io::path resolveVertexShader (const std::string& vertexShader);
+        irr::io::path resolveFragmentShader (const std::string& fragmentShader);
+        irr::io::path resolveIncludeShader (const std::string& includeShader);
     private:
+        void initializeViewports (irr::SIrrlichtCreationParameters& irrlichtCreationParameters);
+        void drawWallpaper (Render::CWallpaper* wallpaper, bool backBuffer);
+
+        irr::io::path resolveFile (const irr::io::path& file);
+
         irr::IrrlichtDevice* m_device;
+        CEventReceiver* m_eventReceiver;
+
+        std::vector<Render::Shaders::Variables::CShaderVariable*> m_globalShaderVariables;
+
+        irr::f32 m_time;
+        irr::core::vector2df m_pointerPosition;
+
+        std::vector<std::string> m_screens;
+        std::vector<irr::core::recti> m_viewports;
+        bool m_isRootWindow;
     };
 };

+ 20 - 0
src/WallpaperEngine/Irrlicht/CEventReceiver.cpp

@@ -0,0 +1,20 @@
+#include "CEventReceiver.h"
+
+using namespace WallpaperEngine::Irrlicht;
+
+bool CEventReceiver::OnEvent(const irr::SEvent &event)
+{
+    if (event.EventType == irr::EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == irr::EMIE_MOUSE_MOVED)
+    {
+        this->m_position.X = event.MouseInput.X;
+        this->m_position.Y = event.MouseInput.Y;
+        return true;
+    }
+
+    return false;
+}
+
+const irr::core::position2di& CEventReceiver::getPosition () const
+{
+    return this->m_position;
+}

+ 18 - 0
src/WallpaperEngine/Irrlicht/CEventReceiver.h

@@ -0,0 +1,18 @@
+#pragma once
+
+#include <irrlicht/irrlicht.h>
+
+namespace WallpaperEngine::Irrlicht
+{
+    class CEventReceiver : public irr::IEventReceiver
+    {
+    public:
+        // This is the one method that we have to implement
+        bool OnEvent(const irr::SEvent& event) override;
+
+        const irr::core::position2di& getPosition () const;
+
+    private:
+        irr::core::position2di m_position;
+    };
+}

+ 96 - 98
src/WallpaperEngine/Irrlicht/CFileList.cpp

@@ -2,135 +2,133 @@
 
 #include "CFileList.h"
 
-namespace WallpaperEngine::Irrlicht
-{
-    static const irr::io::path emptyFileListEntry;
+using namespace WallpaperEngine::Irrlicht;
+static const irr::io::path emptyFileListEntry;
 
-    CFileList::CFileList (const irr::io::path& path, bool ignoreCase, bool ignorePaths) :
-            m_ignorePaths (ignorePaths),
-            m_ignoreCase (ignoreCase),
-            m_path(path)
-    {
-        this->m_path.replace ('\\', '/');
-    }
+CFileList::CFileList (const irr::io::path& path, bool ignoreCase, bool ignorePaths) :
+        m_ignorePaths (ignorePaths),
+        m_ignoreCase (ignoreCase),
+        m_path(path)
+{
+    this->m_path.replace ('\\', '/');
+}
 
-    CFileList::~CFileList ()
-    {
-        this->m_files.clear ();
-    }
+CFileList::~CFileList ()
+{
+    this->m_files.clear ();
+}
 
-    irr::u32 CFileList::getFileCount () const
-    {
-        return this->m_files.size ();
-    }
+irr::u32 CFileList::getFileCount () const
+{
+    return this->m_files.size ();
+}
 
-    void CFileList::sort ()
-    {
-        this->m_files.sort ();
-    }
+void CFileList::sort ()
+{
+    this->m_files.sort ();
+}
 
-    const irr::io::path& CFileList::getFileName (irr::u32 index) const
-    {
-        return (index < this->m_files.size ()) ? this->m_files [index].Name : emptyFileListEntry;
-    }
+const irr::io::path& CFileList::getFileName (irr::u32 index) const
+{
+    return (index < this->m_files.size ()) ? this->m_files [index].Name : emptyFileListEntry;
+}
 
 
 //! Gets the full name of a file in the list, path included, based on an index.
-    const irr::io::path& CFileList::getFullFileName (irr::u32 index) const
-    {
-        return (index < this->m_files.size ()) ? this->m_files [index].FullName : emptyFileListEntry;
-    }
+const irr::io::path& CFileList::getFullFileName (irr::u32 index) const
+{
+    return (index < this->m_files.size ()) ? this->m_files [index].FullName : emptyFileListEntry;
+}
 
 //! adds a file or folder
-    irr::u32 CFileList::addItem (const irr::io::path& fullPath, irr::u32 offset, irr::u32 size, bool isDirectory, irr::u32 id)
+irr::u32 CFileList::addItem (const irr::io::path& fullPath, irr::u32 offset, irr::u32 size, bool isDirectory, irr::u32 id)
+{
+    SFileListEntry entry;
+    entry.ID   = id ? id : this->m_files.size ();
+    entry.Offset = offset;
+    entry.Size = size;
+    entry.Name = fullPath;
+    entry.Name.replace ('\\', '/');
+    entry.IsDirectory = isDirectory;
+
+    // remove trailing slash
+    if (entry.Name.lastChar () == '/')
     {
-        SFileListEntry entry;
-        entry.ID   = id ? id : this->m_files.size ();
-        entry.Offset = offset;
-        entry.Size = size;
-        entry.Name = fullPath;
-        entry.Name.replace ('\\', '/');
-        entry.IsDirectory = isDirectory;
-
-        // remove trailing slash
-        if (entry.Name.lastChar () == '/')
-        {
-            entry.IsDirectory = true;
-            entry.Name [entry.Name.size ()-1] = 0;
-            entry.Name.validate ();
-        }
-
-        if (this->m_ignoreCase)
-            entry.Name.make_lower ();
+        entry.IsDirectory = true;
+        entry.Name [entry.Name.size ()-1] = 0;
+        entry.Name.validate ();
+    }
 
-        entry.FullName = entry.Name;
+    if (this->m_ignoreCase)
+        entry.Name.make_lower ();
 
-        irr::core::deletePathFromFilename (entry.Name);
+    entry.FullName = entry.Name;
 
-        if (this->m_ignorePaths)
-            entry.FullName = entry.Name;
+    irr::core::deletePathFromFilename (entry.Name);
 
-        this->m_files.push_back (entry);
+    if (this->m_ignorePaths)
+        entry.FullName = entry.Name;
 
-        return this->m_files.size () - 1;
-    }
+    this->m_files.push_back (entry);
+
+    return this->m_files.size () - 1;
+}
 
 //! Returns the ID of a file in the file list, based on an index.
-    irr::u32 CFileList::getID (irr::u32 index) const
-    {
-        return (index < this->m_files.size ()) ? this->m_files [index].ID : 0;
-    }
+irr::u32 CFileList::getID (irr::u32 index) const
+{
+    return (index < this->m_files.size ()) ? this->m_files [index].ID : 0;
+}
 
-    bool CFileList::isDirectory (irr::u32 index) const
-    {
-        return (index < this->m_files.size ()) ? this->m_files [index].IsDirectory : false;
-    }
+bool CFileList::isDirectory (irr::u32 index) const
+{
+    return (index < this->m_files.size ()) ? this->m_files [index].IsDirectory : false;
+}
 
 //! Returns the size of a file
-    irr::u32 CFileList::getFileSize (irr::u32 index) const
-    {
-        return (index < this->m_files.size ()) ? this->m_files [index].Size : 0;
-    }
+irr::u32 CFileList::getFileSize (irr::u32 index) const
+{
+    return (index < this->m_files.size ()) ? this->m_files [index].Size : 0;
+}
 
 //! Returns the size of a file
-    irr::u32 CFileList::getFileOffset (irr::u32 index) const
-    {
-        return (index < this->m_files.size ()) ? this->m_files [index].Offset : 0;
-    }
+irr::u32 CFileList::getFileOffset (irr::u32 index) const
+{
+    return (index < this->m_files.size ()) ? this->m_files [index].Offset : 0;
+}
 
 
 //! Searches for a file or folder within the list, returns the index
-    irr::s32 CFileList::findFile (const irr::io::path& filename, bool isDirectory = false) const
-    {
-        SFileListEntry entry;
-        // we only need FullName to be set for the search
-        entry.FullName = filename;
-        entry.IsDirectory = isDirectory;
+irr::s32 CFileList::findFile (const irr::io::path& filename, bool isDirectory = false) const
+{
+    SFileListEntry entry;
+    // we only need FullName to be set for the search
+    entry.FullName = filename;
+    entry.IsDirectory = isDirectory;
 
-        // exchange
-        entry.FullName.replace('\\', '/');
+    // exchange
+    entry.FullName.replace('\\', '/');
 
-        // remove trailing slash
-        if (entry.FullName.lastChar () == '/')
-        {
-            entry.IsDirectory = true;
-            entry.FullName [entry.FullName.size ()-1] = 0;
-            entry.FullName.validate ();
-        }
+    // remove trailing slash
+    if (entry.FullName.lastChar () == '/')
+    {
+        entry.IsDirectory = true;
+        entry.FullName [entry.FullName.size ()-1] = 0;
+        entry.FullName.validate ();
+    }
 
-        if (this->m_ignoreCase)
-            entry.FullName.make_lower ();
+    if (this->m_ignoreCase)
+        entry.FullName.make_lower ();
 
-        if (this->m_ignorePaths)
-            irr::core::deletePathFromFilename (entry.FullName);
+    if (this->m_ignorePaths)
+        irr::core::deletePathFromFilename (entry.FullName);
 
-        return this->m_files.binary_search (entry);
-    }
+    return this->m_files.binary_search (entry);
+}
 
 
 //! Returns the base path of the file list
-    const irr::io::path& CFileList::getPath () const
-    {
-        return m_path;
-    }
-};
+const irr::io::path& CFileList::getPath () const
+{
+    return m_path;
+}

+ 24 - 2
src/WallpaperEngine/Irrlicht/CImageLoaderTEX.cpp

@@ -46,8 +46,8 @@ namespace WallpaperEngine::Irrlicht
 
     CImageLoaderTex::TextureContainer::~TextureContainer ()
     {
-        std::vector <TextureMipmap*>::const_iterator cur = this->mipmaps.begin ();
-        std::vector <TextureMipmap*>::const_iterator end = this->mipmaps.end ();
+        auto cur = this->mipmaps.begin ();
+        auto end = this->mipmaps.end ();
 
         for (; cur != end; cur ++)
         {
@@ -372,6 +372,28 @@ namespace WallpaperEngine::Irrlicht
     // https://github.com/Benjamin-Dobell/s3tc-dxt-decompression
     // ------------------------------------------------------------------------------------
 
+    /*
+     * Copyright (c) 2009 Benjamin Dobell, Glass Echidna
+     *
+     * Permission is hereby granted, free of charge, to any person obtaining a copy
+     * of this software and associated documentation files (the "Software"), to deal
+     * in the Software without restriction, including without limitation the rights
+     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+     * copies of the Software, and to permit persons to whom the Software is
+     * furnished to do so, subject to the following conditions:
+     *
+     * The above copyright notice and this permission notice shall be included in
+     * all copies or substantial portions of the Software.
+     *
+     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+     * THE SOFTWARE.
+     */
+    
     // unsigned long PackRGBA(): Helper method that packs RGBA channels into a single 4 byte pixel.
     //
     // unsigned char r:		red channel.

+ 11 - 10
src/WallpaperEngine/Render/CCamera.cpp

@@ -3,13 +3,14 @@
 using namespace WallpaperEngine;
 using namespace WallpaperEngine::Render;
 
-CCamera::CCamera (CScene* scene, Core::Scenes::CCamera* camera) :
+CCamera::CCamera (CScene* scene, const Core::Scenes::CCamera* camera) :
     m_camera (camera),
     m_scene (scene)
 {
     this->m_sceneCamera = scene->getContext ()->getDevice ()->getSceneManager ()->addCameraSceneNode (
-        scene, *this->m_camera->getCenter (), *this->m_camera->getEye (), scene->nextId ()
+        scene, this->getEye (), this->getCenter (), scene->nextId ()
     );
+    this->m_sceneCamera->setUpVector (this->getUp ());
 }
 
 CCamera::~CCamera ()
@@ -17,32 +18,32 @@ CCamera::~CCamera ()
     this->m_sceneCamera->remove ();
 }
 
-irr::core::vector3df* CCamera::getCenter ()
+const irr::core::vector3df& CCamera::getCenter () const
 {
     return this->m_camera->getCenter ();
 }
 
-irr::core::vector3df* CCamera::getEye ()
+const irr::core::vector3df& CCamera::getEye () const
 {
     return this->m_camera->getEye ();
 }
 
-irr::core::vector3df* CCamera::getUp ()
+const irr::core::vector3df& CCamera::getUp () const
 {
     return this->m_camera->getUp ();
 }
 
-void CCamera::setOrthogonalProjection (irr::u32 width, irr::u32 height)
+void CCamera::setOrthogonalProjection (irr::f32 width, irr::f32 height)
 {
     irr::core::matrix4 identity; identity.makeIdentity ();
     irr::core::matrix4 orthogonalProjection; orthogonalProjection.buildProjectionMatrixOrthoLH (
             width, height,
-            this->m_camera->getUp ()->X,
-            this->m_camera->getUp ()->Y
+            this->getCenter ().Z,
+            this->getEye ().Z
     );
 
     this->m_sceneCamera->setProjectionMatrix (orthogonalProjection);
     this->m_scene->getContext ()->getDevice ()->getVideoDriver ()->setTransform (irr::video::ETS_PROJECTION, orthogonalProjection);
-    this->m_scene->getContext ()->getDevice ()->getVideoDriver ()->setTransform (irr::video::ETS_VIEW, orthogonalProjection);
-    this->m_scene->getContext ()->getDevice ()->getVideoDriver ()->setTransform (irr::video::ETS_WORLD, orthogonalProjection);
+    this->m_scene->getContext ()->getDevice ()->getVideoDriver ()->setTransform (irr::video::ETS_VIEW, identity);
+    this->m_scene->getContext ()->getDevice ()->getVideoDriver ()->setTransform (irr::video::ETS_WORLD, identity);
 }

+ 6 - 6
src/WallpaperEngine/Render/CCamera.h

@@ -11,17 +11,17 @@ namespace WallpaperEngine::Render
     class CCamera
     {
     public:
-        CCamera (CScene* scene, Core::Scenes::CCamera* camera);
+        CCamera (CScene* scene, const Core::Scenes::CCamera* camera);
         ~CCamera ();
 
-        void setOrthogonalProjection (irr::u32 width, irr::u32 height);
+        void setOrthogonalProjection (irr::f32 width, irr::f32 height);
 
-        irr::core::vector3df* getCenter ();
-        irr::core::vector3df* getEye ();
-        irr::core::vector3df* getUp ();
+        const irr::core::vector3df& getCenter () const;
+        const irr::core::vector3df& getEye () const;
+        const irr::core::vector3df& getUp () const;
 
     private:
-        Core::Scenes::CCamera* m_camera;
+        const Core::Scenes::CCamera* m_camera;
         irr::scene::ICameraSceneNode* m_sceneCamera;
         CScene* m_scene;
     };

+ 9 - 1
src/WallpaperEngine/Render/CObject.cpp

@@ -19,7 +19,15 @@ CObject::~CObject()
 {
 }
 
-CScene* CObject::getScene ()
+CScene* CObject::getScene () const
 {
     return this->m_scene;
+}
+
+void CObject::OnRegisterSceneNode ()
+{
+    if (this->m_object->isVisible () == true)
+        SceneManager->registerNodeForRendering (this);
+
+    ISceneNode::OnRegisterSceneNode ();
 }

+ 4 - 2
src/WallpaperEngine/Render/CObject.h

@@ -21,9 +21,11 @@ namespace WallpaperEngine::Render
 
     protected:
         CObject (CScene* scene, std::string type, Core::CObject *object);
-        ~CObject ();
+        ~CObject () override;
 
-        CScene* getScene ();
+        void OnRegisterSceneNode () override;
+
+        CScene* getScene () const;
 
     private:
         std::string m_type;

+ 16 - 49
src/WallpaperEngine/Render/CScene.cpp

@@ -1,31 +1,25 @@
 #include "WallpaperEngine/Core/Objects/CImage.h"
 #include "WallpaperEngine/Core/Objects/CSound.h"
-#include "WallpaperEngine/Core/Objects/CParticle.h"
 
 #include "WallpaperEngine/Render/Objects/CImage.h"
 #include "WallpaperEngine/Render/Objects/CSound.h"
+
 #include "CScene.h"
 
 using namespace WallpaperEngine;
 using namespace WallpaperEngine::Render;
 
-CScene::CScene (Core::CProject* project, Irrlicht::CContext* context) :
-    irr::scene::ISceneNode (
-        context->getDevice ()->getSceneManager ()->getRootSceneNode (),
-        context->getDevice ()->getSceneManager ()
-    ),
-    m_project (project),
-    m_scene (project->getScene ()),
-    m_context (context)
+CScene::CScene (Core::CScene* scene, Irrlicht::CContext* context) :
+    CWallpaper (scene, Type, context)
 {
-    this->m_camera = new CCamera (this, this->m_project->getScene ()->getCamera ());
+    this->m_camera = new CCamera (this, scene->getCamera ());
     this->m_camera->setOrthogonalProjection (
-            this->m_scene->getOrthogonalProjection ()->getWidth (),
-            this->m_scene->getOrthogonalProjection ()->getHeight ()
+            scene->getOrthogonalProjection ()->getWidth (),
+            scene->getOrthogonalProjection ()->getHeight ()
     );
 
-    std::vector<Core::CObject*>::const_iterator cur = this->m_scene->getObjects ()->begin ();
-    std::vector<Core::CObject*>::const_iterator end = this->m_scene->getObjects ()->end ();
+    auto cur = scene->getObjects ().begin ();
+    auto end = scene->getObjects ().end ();
 
     int highestId = 0;
 
@@ -34,44 +28,21 @@ CScene::CScene (Core::CProject* project, Irrlicht::CContext* context) :
         if ((*cur)->getId () > highestId)
             highestId = (*cur)->getId ();
 
-        if ((*cur)->Is <Core::Objects::CImage> () == true)
-        {
-            new Objects::CImage (this, (*cur)->As <Core::Objects::CImage> ());
-        }
-        else if ((*cur)->Is <Core::Objects::CSound> () == true)
-        {
-            new Objects::CSound (this, (*cur)->As <Core::Objects::CSound> ());
-        }
-        else if ((*cur)->Is <Core::Objects::CParticle> () == true)
+        if ((*cur)->is<Core::Objects::CImage>() == true)
         {
-            this->getContext ()->getDevice ()->getLogger ()->log ("Particles disabled, not supported yet", irr::ELL_ERROR);
+            new Objects::CImage (this, (*cur)->as<Core::Objects::CImage>());
         }
-        else
+        else if ((*cur)->is<Core::Objects::CSound>() == true)
         {
-            throw std::runtime_error ("unsupported object type found");
+            new Objects::CSound (this, (*cur)->as<Core::Objects::CSound>());
         }
     }
 
     this->m_nextId = ++highestId;
     this->setAutomaticCulling (irr::scene::EAC_OFF);
-    this->m_boundingBox = irr::core::aabbox3d<irr::f32>(0, 0, 0, 0, 0, 0);
 }
 
-CScene::~CScene ()
-{
-}
-
-Irrlicht::CContext* CScene::getContext ()
-{
-    return this->m_context;
-}
-
-Core::CScene* CScene::getScene ()
-{
-    return this->m_scene;
-}
-
-CCamera* CScene::getCamera ()
+CCamera* CScene::getCamera () const
 {
     return this->m_camera;
 }
@@ -85,13 +56,9 @@ void CScene::render ()
 {
 }
 
-const irr::core::aabbox3d<irr::f32>& CScene::getBoundingBox() const
+Core::CScene* CScene::getScene ()
 {
-    return this->m_boundingBox;
+    return this->getWallpaperData ()->as<Core::CScene> ();
 }
-void CScene::OnRegisterSceneNode ()
-{
-    SceneManager->registerNodeForRendering (this);
 
-    ISceneNode::OnRegisterSceneNode ();
-}
+const std::string CScene::Type = "scene";

+ 13 - 13
src/WallpaperEngine/Render/CScene.h

@@ -2,35 +2,35 @@
 
 #include "CCamera.h"
 
-#include "WallpaperEngine/Core/CProject.h"
 #include "WallpaperEngine/Core/CScene.h"
 
+#include "WallpaperEngine/Render/CWallpaper.h"
+
 #include "WallpaperEngine/Irrlicht/CContext.h"
 
 namespace WallpaperEngine::Render
 {
     class CCamera;
 
-    class CScene : public irr::scene::ISceneNode
+    class CScene : public CWallpaper
     {
     public:
-        CScene (Core::CProject* project, Irrlicht::CContext* context);
-        ~CScene ();
+        CScene (Core::CScene* scene, WallpaperEngine::Irrlicht::CContext* context);
 
-        Irrlicht::CContext* getContext ();
-        Core::CScene* getScene ();
-        CCamera* getCamera ();
+        CCamera* getCamera () const;
         int nextId ();
 
         void render () override;
-        const irr::core::aabbox3d<irr::f32>& getBoundingBox() const override;
-        void OnRegisterSceneNode () override;
+
+        Core::CScene* getScene ();
+
+    protected:
+        friend class CWallpaper;
+
+        static const std::string Type;
+
     private:
-        Core::CProject* m_project;
-        Core::CScene* m_scene;
         CCamera* m_camera;
-        Irrlicht::CContext* m_context;
         irr::u32 m_nextId;
-        irr::core::aabbox3d<irr::f32> m_boundingBox;
     };
 }

+ 165 - 0
src/WallpaperEngine/Render/CVideo.cpp

@@ -0,0 +1,165 @@
+#include "CVideo.h"
+
+using namespace WallpaperEngine;
+
+using namespace WallpaperEngine::Render;
+
+CVideo::CVideo (Core::CVideo* video, WallpaperEngine::Irrlicht::CContext* context) :
+    CWallpaper (video, Type, context)
+{
+    if (avformat_open_input (&m_formatCtx, video->getFilename ().c_str (), NULL, NULL) < 0)
+        throw std::runtime_error ("Failed to open video file");
+
+    if (avformat_find_stream_info (m_formatCtx, NULL) < 0)
+        throw std::runtime_error ("Failed to get stream info");
+
+    // Find first video stream
+    for (int i = 0; i < m_formatCtx->nb_streams; i++)
+    {
+        if (m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
+        {
+            m_videoStream = i;
+            break;
+        }
+    }
+
+    // Find first audio stream
+    for (int i = 0; i < m_formatCtx->nb_streams; i++)
+    {
+        if (m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
+        {
+            m_audioStream = i; 
+            break;
+        }
+    }
+
+    // Only video stream is required
+    if (m_videoStream == -1)
+        throw std::runtime_error ("Failed to find video stream");
+
+    AVCodec* codec = avcodec_find_decoder (m_formatCtx->streams[m_videoStream]->codecpar->codec_id);
+    if (codec == nullptr)
+        throw std::runtime_error ("Failed to find codec");
+
+    m_codecCtx = avcodec_alloc_context3 (codec);
+    if (avcodec_parameters_to_context (m_codecCtx, m_formatCtx->streams[m_videoStream]->codecpar))
+        throw std::runtime_error ("Failed to copy codec parameters");
+
+    if (avcodec_open2 (m_codecCtx, codec, NULL) < 0)
+        throw std::runtime_error ("Failed to open codec");
+
+    m_videoFrame = av_frame_alloc ();
+    m_videoFrameRGB = av_frame_alloc ();
+    if (m_videoFrameRGB == nullptr)
+        throw std::runtime_error ("Failed to allocate video frame");
+}
+
+void CVideo::setSize (int width, int height)
+{
+    if (m_buffer != nullptr)
+        av_free (m_buffer);
+
+    if (m_swsCtx != nullptr)
+        sws_freeContext (m_swsCtx);
+
+    int numBytes = av_image_get_buffer_size (AV_PIX_FMT_RGB24, width, height, 1);
+    m_buffer = (uint8_t*)av_malloc (numBytes * sizeof (uint8_t));
+
+    av_image_fill_arrays (m_videoFrameRGB->data, m_videoFrameRGB->linesize, m_buffer, AV_PIX_FMT_RGB24, width, height, 1);
+
+    m_swsCtx = sws_getContext (m_codecCtx->width, m_codecCtx->height,
+                    m_codecCtx->pix_fmt,
+                    width, height,
+                    AV_PIX_FMT_RGB24,
+                    SWS_BILINEAR, NULL, NULL, NULL);
+}
+
+void CVideo::render ()
+{
+    irr::video::IVideoDriver* driver = m_context->getDevice ()->getVideoDriver ();
+    int width = driver->getScreenSize ().Width;
+    int height = driver->getScreenSize ().Height;
+
+    m_frameImage = m_context->getDevice ()->getVideoDriver ()->createImage (irr::video::ECOLOR_FORMAT::ECF_R8G8B8,
+                irr::core::dimension2du(width, height));
+
+    setSize (width, height);
+    getNextFrame ();
+    writeFrameToImage ();
+
+    driver->removeTexture (m_frameTexture);
+    m_frameTexture = driver->addTexture ("frameTexture", m_frameImage);
+    m_frameImage->drop ();
+
+    driver->draw2DImage (m_frameTexture, irr::core::vector2di(0));
+}
+
+void CVideo::getNextFrame ()
+{
+    bool eof = false;
+    AVPacket packet;
+    packet.data = nullptr;
+    
+    // Find video streams packet
+    do
+    {
+        if (packet.data != nullptr)
+            av_packet_unref (&packet);
+
+        int readError = av_read_frame (m_formatCtx, &packet);
+        if (readError == AVERROR_EOF)
+        {
+            eof = true;
+            break;
+        }
+        else if (readError < 0)
+        {
+            char err[AV_ERROR_MAX_STRING_SIZE];
+            throw std::runtime_error (av_make_error_string (err, AV_ERROR_MAX_STRING_SIZE, readError));
+        }
+        
+    } while (packet.stream_index != m_videoStream);
+
+    // Send video stream packet to codec
+    if (avcodec_send_packet (m_codecCtx, &packet) < 0)
+        return;
+    
+    // Receive frame from codec
+    if (avcodec_receive_frame (m_codecCtx, m_videoFrame) < 0)
+        return;
+
+    sws_scale (m_swsCtx, (uint8_t const* const*)m_videoFrame->data, m_videoFrame->linesize,
+            0, m_codecCtx->height, m_videoFrameRGB->data, m_videoFrameRGB->linesize);
+
+    av_packet_unref (&packet);
+
+    if (eof)
+        restartStream ();
+}
+
+void CVideo::writeFrameToImage ()
+{
+    uint8_t* frameData = m_videoFrameRGB->data[0];
+    if (frameData == nullptr)
+        return;
+
+    irr::u32 imgWidth = m_frameImage->getDimension().Width;
+    irr::u32 imgHeight = m_frameImage->getDimension().Height;
+    
+    unsigned char* data = (unsigned char*)m_frameImage->lock ();
+    memcpy (data, frameData, imgWidth * imgHeight * 3);
+    m_frameImage->unlock ();
+}
+
+void CVideo::restartStream ()
+{
+    av_seek_frame (m_formatCtx, m_videoStream, 0, AVSEEK_FLAG_FRAME);
+    avcodec_flush_buffers (m_codecCtx);
+}
+
+Core::CVideo* CVideo::getVideo ()
+{
+    return this->getWallpaperData ()->as<Core::CVideo> ();
+}
+
+const std::string CVideo::Type = "video";

+ 52 - 0
src/WallpaperEngine/Render/CVideo.h

@@ -0,0 +1,52 @@
+#pragma once
+
+#include <irrlicht/irrlicht.h>
+
+#include "WallpaperEngine/Core/CVideo.h"
+
+#include "WallpaperEngine/Render/CWallpaper.h"
+
+#include "WallpaperEngine/Irrlicht/CContext.h"
+
+extern "C"
+{
+    #include <libavcodec/avcodec.h>
+    #include <libavformat/avformat.h>
+    #include <libavutil/imgutils.h>
+    #include <libswscale/swscale.h>
+}
+
+namespace WallpaperEngine::Render
+{
+    class CVideo : public CWallpaper
+    {
+    public:
+        CVideo (Core::CVideo* video, WallpaperEngine::Irrlicht::CContext* context);
+
+        void render () override;
+
+        Core::CVideo* getVideo ();
+
+    protected:
+        friend class CWallpaper;
+
+        static const std::string Type;
+
+    private:
+        void setSize (int width, int height);
+        void restartStream ();
+        void getNextFrame ();
+        void writeFrameToImage ();
+
+        AVFormatContext* m_formatCtx = nullptr;
+        AVCodecContext* m_codecCtx = nullptr;
+        AVFrame* m_videoFrame = nullptr;
+        AVFrame* m_videoFrameRGB = nullptr;
+        SwsContext* m_swsCtx = nullptr;
+        uint8_t* m_buffer = nullptr;
+        int m_videoStream = -1, m_audioStream = -1;
+
+        irr::video::IImage* m_frameImage;
+        irr::video::ITexture* m_frameTexture;
+    };
+};

+ 40 - 0
src/WallpaperEngine/Render/CWallpaper.cpp

@@ -0,0 +1,40 @@
+#include "CWallpaper.h"
+
+using namespace WallpaperEngine::Render;
+
+CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, WallpaperEngine::Irrlicht::CContext* context) :
+    irr::scene::ISceneNode (
+        context->getDevice ()->getSceneManager ()->getRootSceneNode (),
+        context->getDevice ()->getSceneManager ()
+    ),
+    m_context (context),
+    m_wallpaperData (wallpaperData),
+    m_type (type)
+{
+}
+
+CWallpaper::~CWallpaper ()
+{
+}
+
+void CWallpaper::OnRegisterSceneNode ()
+{
+    SceneManager->registerNodeForRendering (this);
+
+    ISceneNode::OnRegisterSceneNode ();
+}
+
+WallpaperEngine::Irrlicht::CContext* CWallpaper::getContext () const
+{
+    return this->m_context;
+}
+
+const irr::core::aabbox3d<irr::f32>& CWallpaper::getBoundingBox () const
+{
+    return this->m_boundingBox;
+}
+
+WallpaperEngine::Core::CWallpaper* CWallpaper::getWallpaperData ()
+{
+    return this->m_wallpaperData;
+}

+ 45 - 0
src/WallpaperEngine/Render/CWallpaper.h

@@ -0,0 +1,45 @@
+#pragma once
+
+#include <irrlicht/irrlicht.h>
+
+#include "WallpaperEngine/Core/CWallpaper.h"
+#include "WallpaperEngine/Core/CScene.h"
+#include "WallpaperEngine/Core/CVideo.h"
+
+#include "WallpaperEngine/Irrlicht/CContext.h"
+
+namespace WallpaperEngine::Irrlicht
+{
+    class CContext;
+};
+
+namespace WallpaperEngine::Render
+{
+    class CWallpaper : public irr::scene::ISceneNode
+    {
+    public:
+        template<class T> const T* as () const { assert (is<T> ()); return (const T*) this; }
+        template<class T> T* as () { assert (is<T> ()); return (T*) this; }
+
+        template<class T> bool is () { return this->m_type == T::Type; }
+
+        CWallpaper (Core::CWallpaper* wallpaperData, std::string type, WallpaperEngine::Irrlicht::CContext* context);
+        ~CWallpaper () override;
+
+        void OnRegisterSceneNode () override;
+
+        WallpaperEngine::Irrlicht::CContext* getContext () const;
+        const irr::core::aabbox3d<irr::f32>& getBoundingBox () const override;
+
+    protected:
+        WallpaperEngine::Irrlicht::CContext* m_context;
+        Core::CWallpaper* m_wallpaperData;
+
+        Core::CWallpaper* getWallpaperData ();
+
+    private:
+        irr::core::aabbox3d<irr::f32> m_boundingBox = irr::core::aabbox3d<irr::f32> (0, 0, 0, 0, 0, 0);
+
+        std::string m_type;
+    };
+}

+ 94 - 0
src/WallpaperEngine/Render/Objects/CEffect.cpp

@@ -0,0 +1,94 @@
+#include "CEffect.h"
+
+using namespace WallpaperEngine::Render::Objects;
+
+CEffect::CEffect (CImage* image, Core::Objects::CEffect* effect, Irrlicht::CContext* context, irr::video::ITexture* input) :
+    m_context (context),
+    m_image (image),
+    m_effect (effect),
+    m_inputTexture (input)
+{
+    irr::core::dimension2du size = irr::core::dimension2du (
+        this->m_image->getImage ()->getSize ().X,
+        this->m_image->getImage ()->getSize ().Y
+    );
+
+    this->m_outputTexture = this->m_context->getDevice ()->getVideoDriver ()->addRenderTargetTexture (
+        size,
+        (
+            "_rt_WALLENGINELINUX_OUTPUT_" +
+            std::to_string (image->getImage ()->getId ()) + "_" +
+            std::to_string (this->m_image->getEffects ().size ()) +
+            "_effect_output"
+        ).c_str ()
+    );
+
+    this->generateFBOs ();
+    this->generatePasses ();
+}
+
+const irr::video::ITexture* CEffect::getInputTexture () const
+{
+    return this->m_inputTexture;
+}
+
+const irr::video::ITexture* CEffect::getOutputTexture () const
+{
+    return this->m_outputTexture;
+}
+
+const CImage* CEffect::getImage () const
+{
+    return this->m_image;
+}
+
+const std::vector<Effects::CMaterial*>& CEffect::getMaterials () const
+{
+    return this->m_materials;
+}
+
+Effects::CFBO* CEffect::findFBO (const std::string& name)
+{
+    auto cur = this->m_fbos.begin ();
+    auto end = this->m_fbos.end ();
+
+    for (; cur != end; cur ++)
+    {
+        if ((*cur)->getName () == name)
+        {
+            return *cur;
+        }
+    }
+
+    return nullptr;
+}
+
+void CEffect::generatePasses ()
+{
+    auto cur = this->m_effect->getMaterials ().begin ();
+    auto end = this->m_effect->getMaterials ().end ();
+    const irr::video::ITexture* inputTexture = this->getInputTexture ();
+
+    for (; cur != end; cur ++)
+    {
+        Effects::CMaterial* material = new Effects::CMaterial (this->m_context, this, *cur, inputTexture);
+
+        // next input texture will be the output texture of the material
+        inputTexture = material->getOutputTexture ();
+
+        this->m_materials.push_back (material);
+    }
+}
+
+void CEffect::generateFBOs ()
+{
+    auto cur = this->m_effect->getFbos ().begin ();
+    auto end = this->m_effect->getFbos ().end ();
+
+    for (; cur != end; cur ++)
+    {
+        this->m_fbos.push_back (
+            new Effects::CFBO (*cur, this->m_image->getImage (), this->m_context)
+        );
+    }
+}

+ 47 - 0
src/WallpaperEngine/Render/Objects/CEffect.h

@@ -0,0 +1,47 @@
+#pragma once
+
+#include <irrlicht/irrlicht.h>
+
+#include "WallpaperEngine/Irrlicht/CContext.h"
+
+#include "WallpaperEngine/Render/Objects/CImage.h"
+#include "WallpaperEngine/Render/Objects/Effects/CFBO.h"
+#include "WallpaperEngine/Render/Objects/Effects/CPass.h"
+#include "WallpaperEngine/Render/Objects/Effects/CMaterial.h"
+
+namespace WallpaperEngine::Render::Objects::Effects
+{
+    class CMaterial;
+}
+
+namespace WallpaperEngine::Render::Objects
+{
+    class CImage;
+
+    class CEffect
+    {
+    public:
+        CEffect (CImage* image, Core::Objects::CEffect* effect, Irrlicht::CContext* context, irr::video::ITexture* input);
+
+        const irr::video::ITexture* getOutputTexture () const;
+        const irr::video::ITexture* getInputTexture () const;
+        const CImage* getImage () const;
+
+        const std::vector<Effects::CMaterial*>& getMaterials () const;
+
+        Effects::CFBO* findFBO (const std::string& name);
+    private:
+        void generatePasses ();
+        void generateFBOs ();
+
+        Irrlicht::CContext* m_context;
+        CImage* m_image;
+        Core::Objects::CEffect* m_effect;
+
+        std::vector<Effects::CFBO*> m_fbos;
+        std::vector<Effects::CMaterial*> m_materials;
+
+        irr::video::ITexture* m_inputTexture;
+        irr::video::ITexture* m_outputTexture;
+    };
+};

+ 319 - 48
src/WallpaperEngine/Render/Objects/CImage.cpp

@@ -1,20 +1,40 @@
 #include "CImage.h"
 
 #include "WallpaperEngine/Render/Shaders/Compiler.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariable.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableFloat.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableInteger.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector2.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector3.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector4.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableFloatPointer.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector2Pointer.h"
+
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantFloat.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantInteger.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantVector3.h"
 
 using namespace WallpaperEngine;
+
+using namespace WallpaperEngine::Core::Objects::Effects::Constants;
+
 using namespace WallpaperEngine::Render::Objects;
+using namespace WallpaperEngine::Render::Shaders::Variables;
+
+extern irr::f32 g_Time;
 
 CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
     Render::CObject (scene, Type, image),
-    m_image (image)
+    m_image (image),
+    m_passes (0)
 {
     // TODO: INITIALIZE NEEDED EFFECTS AND PROPERLY CALCULATE THESE?
-    irr::f32 xright     = this->m_image->getOrigin ()->X;
-    irr::f32 xleft      = -this->m_image->getOrigin ()->X;
-    irr::f32 ztop       = this->m_image->getOrigin ()->Y;
-    irr::f32 zbottom    = -this->m_image->getOrigin ()->Y;
-    irr::f32 z          = this->getScene ()->getCamera ()->getEye ()->Z;
+    irr::f32 xright     = this->m_image->getOrigin ().X;
+    irr::f32 xleft      = -this->m_image->getOrigin ().X;
+    irr::f32 ztop       = this->m_image->getOrigin ().Y;
+    irr::f32 zbottom    = -this->m_image->getOrigin ().Y;
+    irr::f32 z          = this->m_image->getOrigin ().Z;
 
     // top left
     this->m_vertex [0].Pos = irr::core::vector3df (xleft,  ztop,    z);
@@ -25,10 +45,10 @@ CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
     // bottom left
     this->m_vertex [3].Pos = irr::core::vector3df (xleft,  zbottom, z);
 
-    this->m_vertex [0].TCoords = irr::core::vector2df (1.0f, 0.0f);
-    this->m_vertex [1].TCoords = irr::core::vector2df (0.0f, 0.0f);
-    this->m_vertex [2].TCoords = irr::core::vector2df (0.0f, 1.0f);
-    this->m_vertex [3].TCoords = irr::core::vector2df (1.0f, 1.0f);
+    this->m_vertex [1].TCoords = irr::core::vector2df (1.0f, 0.0f);
+    this->m_vertex [0].TCoords = irr::core::vector2df (0.0f, 0.0f);
+    this->m_vertex [3].TCoords = irr::core::vector2df (0.0f, 1.0f);
+    this->m_vertex [2].TCoords = irr::core::vector2df (1.0f, 1.0f);
 
     this->m_vertex [0].Color = irr::video::SColor (255, 255, 255, 255);
     this->m_vertex [1].Color = irr::video::SColor (255, 255, 255, 255);
@@ -44,75 +64,326 @@ void CImage::render()
 {
     uint16_t indices [] =
     {
-            0, 1, 2, 3
+            3, 2, 1, 0
     };
 
     irr::video::IVideoDriver* driver = SceneManager->getVideoDriver ();
 
-    driver->setMaterial (this->m_material);
-    driver->drawVertexPrimitiveList (
-        this->m_vertex, 4, indices, 1,
-        irr::video::EVT_STANDARD, irr::scene::EPT_QUADS, irr::video::EIT_16BIT
-    );
+    auto cur = this->m_materials.begin ();
+    auto end = this->m_materials.end ();
+
+    auto textureCur = this->m_renderTextures.begin ();
+    auto textureEnd = this->m_renderTextures.end ();
+
+    for (; cur != end; cur ++)
+    {
+        if (textureCur == textureEnd)
+        {
+            driver->setRenderTarget (irr::video::ERT_FRAME_BUFFER, false, false);
+        }
+        else
+        {
+            driver->setRenderTarget (*textureCur, true, true, irr::video::SColor (0, 0, 0, 0));
+            textureCur ++;
+        }
+
+        driver->setMaterial (*cur);
+        driver->drawVertexPrimitiveList (
+            this->m_vertex, 4, indices, 1,
+            irr::video::EVT_STANDARD, irr::scene::EPT_QUADS, irr::video::EIT_16BIT
+        );
+    }
 }
 
 void CImage::generateMaterial ()
 {
-    if (this->m_image->getMaterial ()->getPasses ()->empty () == true)
-        return;
+    auto cur = this->m_image->getMaterial ()->getPasses ().begin ();
+    auto end = this->m_image->getMaterial ()->getPasses ().end ();
 
-    // TODO: SUPPORT OBJECT EFFECTS AND MULTIPLE MATERIAL PASSES
-    Core::Objects::Images::Materials::CPassess* pass = *this->m_image->getMaterial ()->getPasses ()->begin ();
-    std::string shader = pass->getShader ();
-    std::vector<std::string>* textures = pass->getTextures ();
+    for (; cur != end; cur++)
+    {
+        this->generatePass (*cur);
+    }
 
-    std::vector<std::string>::const_iterator cur = textures->begin ();
-    std::vector<std::string>::const_iterator end = textures->end ();
+    auto effectCur = this->m_image->getEffects ().begin ();
+    auto effectEnd = this->m_image->getEffects ().end ();
 
-    for (int textureNumber = 0; cur != end; cur ++, textureNumber ++)
+    for (; effectCur != effectEnd; effectCur++)
     {
-        // TODO: LOOK THIS UP PROPERLY
-        irr::io::path texturepath = std::string ("materials/" + (*cur) + ".tex").c_str ();
+        auto materialCur = (*effectCur)->getMaterials ().begin ();
+        auto materialEnd = (*effectCur)->getMaterials ().end ();
 
-        irr::video::ITexture* texture = this->getScene ()->getContext ()->getDevice ()->getVideoDriver ()->getTexture (texturepath);
+        for (; materialCur != materialEnd; materialCur++)
+        {
+            cur = (*materialCur)->getPasses ().begin ();
+            end = (*materialCur)->getPasses ().end ();
 
-        this->m_material.setTexture (textureNumber, texture);
+            for (; cur != end; cur++)
+            {
+                this->generatePass (*cur);
+            }
+        }
     }
+}
 
-    // TODO: MOVE SHADER INITIALIZATION ELSEWHERE
-    irr::io::path vertpath = std::string ("shaders/" + shader + ".vert").c_str ();
-    irr::io::path fragpath = std::string ("shaders/" + shader + ".frag").c_str ();
-    Render::Shaders::Compiler* vertshader = new Render::Shaders::Compiler (vertpath, Render::Shaders::Compiler::Type::Type_Vertex, pass->getCombos (), false);
-    Render::Shaders::Compiler* fragshader = new Render::Shaders::Compiler (fragpath, Render::Shaders::Compiler::Type::Type_Pixel, pass->getCombos (), false);
-
-    this->m_material.MaterialType = (irr::video::E_MATERIAL_TYPE)
-            this->getScene ()->getContext ()->getDevice ()->getVideoDriver ()->getGPUProgrammingServices ()->addHighLevelShaderMaterial (
-                vertshader->precompile ().c_str (), "main", irr::video::EVST_VS_2_0,
-                fragshader->precompile ().c_str (), "main", irr::video::EPST_PS_2_0,
-                this, irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL, 0, irr::video::EGSL_DEFAULT
+void CImage::generatePass (Core::Objects::Images::Materials::CPass* pass)
+{
+    std::vector<std::string> textures = pass->getTextures ();
+    irr::video::SMaterial material;
+
+    auto texturesCur = textures.begin ();
+    auto texturesEnd = textures.end ();
+
+    for (int textureNumber = 0; texturesCur != texturesEnd; texturesCur ++, textureNumber ++)
+    {
+        irr::io::path texturepath = this->getScene ()->getContext ()->resolveMaterials (*texturesCur);
+        irr::video::ITexture* texture = nullptr;
+
+        if (textureNumber == 0 && this->m_passes > 0)
+        {
+            irr::video::ITexture* originalTexture = this->getScene ()->getContext ()->getDevice ()->getVideoDriver ()->getTexture (texturepath);
+
+            texture = this->getScene ()->getContext ()->getDevice ()->getVideoDriver ()->addRenderTargetTexture (
+                irr::core::dimension2d<irr::u32> (
+                    originalTexture->getSize ().Width,
+                    originalTexture->getSize ().Height
+                ), ("_RT_" + this->m_image->getName () + std::to_string (textureNumber) + "_" + std::to_string (this->m_passes)).c_str ()
             );
 
-    this->m_material.MaterialType = irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL;
-    this->m_material.setFlag (irr::video::EMF_LIGHTING, false);
-    this->m_material.setFlag (irr::video::EMF_BLEND_OPERATION, true);
-}
+            this->m_renderTextures.push_back (texture);
+        }
+        else
+        {
+            texture = this->getScene ()->getContext ()->getDevice ()->getVideoDriver ()->getTexture (texturepath);
+        }
+
+        material.setTexture (textureNumber, texture);
+    }
+
+    // TODO: MOVE SHADER INITIALIZATION ELSEWHERE
+    irr::io::path vertpath = this->getScene ()->getContext ()->resolveVertexShader (pass->getShader ());
+    irr::io::path fragpath = this->getScene ()->getContext ()->resolveFragmentShader (pass->getShader ());
+
+    auto vertexShader = new Render::Shaders::Compiler (this->getScene ()->getContext (), vertpath, Render::Shaders::Compiler::Type::Type_Vertex, pass->getCombos (), false);
+    auto pixelShader = new Render::Shaders::Compiler (this->getScene ()->getContext (), fragpath, Render::Shaders::Compiler::Type::Type_Pixel, pass->getCombos (), false);
+
+    material.MaterialType = (irr::video::E_MATERIAL_TYPE)
+        this->getScene ()->getContext ()->getDevice ()->getVideoDriver ()->getGPUProgrammingServices ()->addHighLevelShaderMaterial (
+            vertexShader->precompile ().c_str (), "main", irr::video::EVST_VS_2_0,
+            pixelShader->precompile ().c_str (), "main", irr::video::EPST_PS_2_0,
+            this, irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL, this->m_passes, irr::video::EGSL_DEFAULT
+        );
+
+    // find variables in the shaders and set the value with the constants if possible
+    auto cur = pass->getConstants ().begin ();
+    auto end = pass->getConstants ().end ();
+
+    for (; cur != end; cur ++)
+    {
+        CShaderVariable* vertexVar = vertexShader->findParameter ((*cur).first);
+        CShaderVariable* pixelVar = pixelShader->findParameter ((*cur).first);
+
+        if (pixelVar)
+        {
+            if (pixelVar->is <CShaderVariableFloat> () && (*cur).second->is <CShaderConstantFloat> ())
+            {
+                pixelVar->as <CShaderVariableFloat> ()->setValue (*(*cur).second->as <CShaderConstantFloat> ()->getValue ());
+            }
+            else if (pixelVar->is <CShaderVariableInteger> () && (*cur).second->is <CShaderConstantInteger> ())
+            {
+                pixelVar->as <CShaderVariableInteger> ()->setValue (*(*cur).second->as <CShaderConstantInteger> ()->getValue ());
+            }
+            else if (pixelVar->is <CShaderVariableVector3> () && (*cur).second->is <CShaderConstantVector3> ())
+            {
+                pixelVar->as <CShaderVariableVector3> ()->setValue (*(*cur).second->as <CShaderConstantVector3> ()->getValue ());
+            }
+        }
+
+        if (vertexVar)
+        {
+            if (vertexVar->is <CShaderVariableFloat> () && (*cur).second->is <CShaderConstantFloat> ())
+            {
+                vertexVar->as <CShaderVariableFloat> ()->setValue (*(*cur).second->as <CShaderConstantFloat> ()->getValue ());
+            }
+            else if (vertexVar->is <CShaderVariableInteger> () && (*cur).second->is <CShaderConstantInteger> ())
+            {
+                vertexVar->as <CShaderVariableInteger> ()->setValue (*(*cur).second->as <CShaderConstantInteger> ()->getValue ());
+            }
+            else if (vertexVar->is <CShaderVariableVector3> () && (*cur).second->is <CShaderConstantVector3> ())
+            {
+                vertexVar->as <CShaderVariableVector3> ()->setValue (*(*cur).second->as <CShaderConstantVector3> ()->getValue ());
+            }
+        }
+    }
 
+    // TODO: TAKE INTO ACCOUNT BLENDING AND CULLING METHODS FROM THE JSON
+    material.setFlag (irr::video::EMF_LIGHTING, false);
+    material.setFlag (irr::video::EMF_BLEND_OPERATION, true);
+    material.Wireframe = false;
+    material.Lighting = false;
+
+    this->m_vertexShaders.push_back (vertexShader);
+    this->m_pixelShaders.push_back (pixelShader);
+    this->m_materials.push_back (material);
+    this->m_passes ++;
+}
 
 const irr::core::aabbox3d<irr::f32>& CImage::getBoundingBox() const
 {
     return this->m_boundingBox;
 }
 
-void CImage::OnRegisterSceneNode ()
+const Core::Objects::CImage* CImage::getImage () const
 {
-    SceneManager->registerNodeForRendering (this);
+    return this->m_image;
+}
 
-    ISceneNode::OnRegisterSceneNode ();
+const std::vector<CEffect*>& CImage::getEffects () const
+{
+    return this->m_effects;
 }
 
 void CImage::OnSetConstants (irr::video::IMaterialRendererServices *services, int32_t userData)
 {
-    // TODO: SUPPORT SHADER PARAMETERS HERE
+    irr::f32 g_Texture0 = 0;
+    irr::f32 g_Texture1 = 1;
+    irr::f32 g_Texture2 = 2;
+    irr::f32 g_Texture3 = 3;
+    irr::f32 g_Texture4 = 4;
+    irr::f32 g_Texture5 = 5;
+    irr::f32 g_Texture6 = 6;
+    irr::f32 g_Texture7 = 7;
+
+    irr::f32 g_Texture0Rotation [4] = { this->m_image->getAngles ().X, this->m_image->getAngles ().Y, this->m_image->getAngles ().Z, this->m_image->getAngles ().Z };
+    irr::f32 g_Texture1Rotation [4] = { this->m_image->getAngles ().X, this->m_image->getAngles ().Y, this->m_image->getAngles ().Z, this->m_image->getAngles ().Z };
+    irr::f32 g_Texture2Rotation [4] = { this->m_image->getAngles ().X, this->m_image->getAngles ().Y, this->m_image->getAngles ().Z, this->m_image->getAngles ().Z };
+    irr::f32 g_Texture3Rotation [4] = { this->m_image->getAngles ().X, this->m_image->getAngles ().Y, this->m_image->getAngles ().Z, this->m_image->getAngles ().Z };
+    irr::f32 g_Texture4Rotation [4] = { this->m_image->getAngles ().X, this->m_image->getAngles ().Y, this->m_image->getAngles ().Z, this->m_image->getAngles ().Z };
+    irr::f32 g_Texture5Rotation [4] = { this->m_image->getAngles ().X, this->m_image->getAngles ().Y, this->m_image->getAngles ().Z, this->m_image->getAngles ().Z };
+    irr::f32 g_Texture6Rotation [4] = { this->m_image->getAngles ().X, this->m_image->getAngles ().Y, this->m_image->getAngles ().Z, this->m_image->getAngles ().Z };
+    irr::f32 g_Texture7Rotation [4] = { this->m_image->getAngles ().X, this->m_image->getAngles ().Y, this->m_image->getAngles ().Z, this->m_image->getAngles ().Z };
+
+    irr::f32 g_Texture0Resolution [4] = { this->m_image->getSize ().X, this->m_image->getSize ().Y, this->m_image->getSize ().X, this->m_image->getSize ().Y };
+    irr::f32 g_Texture1Resolution [4] = { this->m_image->getSize ().X, this->m_image->getSize ().Y, this->m_image->getSize ().X, this->m_image->getSize ().Y };
+    irr::f32 g_Texture2Resolution [4] = { this->m_image->getSize ().X, this->m_image->getSize ().Y, this->m_image->getSize ().X, this->m_image->getSize ().Y };
+    irr::f32 g_Texture3Resolution [4] = { this->m_image->getSize ().X, this->m_image->getSize ().Y, this->m_image->getSize ().X, this->m_image->getSize ().Y };
+    irr::f32 g_Texture4Resolution [4] = { this->m_image->getSize ().X, this->m_image->getSize ().Y, this->m_image->getSize ().X, this->m_image->getSize ().Y };
+    irr::f32 g_Texture5Resolution [4] = { this->m_image->getSize ().X, this->m_image->getSize ().Y, this->m_image->getSize ().X, this->m_image->getSize ().Y };
+    irr::f32 g_Texture6Resolution [4] = { this->m_image->getSize ().X, this->m_image->getSize ().Y, this->m_image->getSize ().X, this->m_image->getSize ().Y };
+    irr::f32 g_Texture7Resolution [4] = { this->m_image->getSize ().X, this->m_image->getSize ().Y, this->m_image->getSize ().X, this->m_image->getSize ().Y };
+
+    irr::video::IVideoDriver* driver = services->getVideoDriver ();
+
+    irr::core::matrix4 worldViewProj;
+    worldViewProj = driver->getTransform (irr::video::ETS_PROJECTION);
+    worldViewProj *= driver->getTransform (irr::video::ETS_VIEW);
+    worldViewProj *= driver->getTransform (irr::video::ETS_WORLD);
+
+    Render::Shaders::Compiler* vertexShader = this->m_vertexShaders.at (userData);
+    Render::Shaders::Compiler* pixelShader = this->m_pixelShaders.at (userData);
+
+    auto cur = vertexShader->getParameters ().begin ();
+    auto end = vertexShader->getParameters ().end ();
+
+    for (; cur != end; cur ++)
+    {
+        if ((*cur)->is <CShaderVariableInteger> () == true)
+        {
+            services->setVertexShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::s32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+        }
+        else if (
+            (*cur)->is <CShaderVariableFloat> () == true ||
+            (*cur)->is <CShaderVariableVector2> () == true ||
+            (*cur)->is <CShaderVariableVector3> () == true ||
+            (*cur)->is <CShaderVariableVector4> () == true)
+        {
+            services->setVertexShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::f32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+        }
+    }
+
+    cur = pixelShader->getParameters ().begin ();
+    end = pixelShader->getParameters ().end ();
+
+    for (; cur != end; cur ++)
+    {
+        if ((*cur)->is <CShaderVariableInteger> () == true)
+        {
+            services->setPixelShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::s32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+        }
+        else if (
+            (*cur)->is <CShaderVariableFloat> () == true ||
+            (*cur)->is <CShaderVariableVector2> () == true ||
+            (*cur)->is <CShaderVariableVector3> () == true ||
+            (*cur)->is <CShaderVariableVector4> () == true)
+        {
+            services->setPixelShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::f32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+        }
+    }
+
+    cur = this->getScene ()->getContext ()->getShaderVariables ().begin ();
+    end = this->getScene ()->getContext ()->getShaderVariables ().end ();
+
+    for (; cur != end; cur ++)
+    {
+        if ((*cur)->is <CShaderVariableFloatPointer> () == true)
+        {
+            services->setPixelShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::f32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+            services->setVertexShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::f32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+        }
+    }
+
+    services->setVertexShaderConstant ("g_ModelViewProjectionMatrix", worldViewProj.pointer(), 16);
+
+    services->setVertexShaderConstant ("g_Texture0Resolution", g_Texture0Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture1Resolution", g_Texture1Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture2Resolution", g_Texture2Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture3Resolution", g_Texture3Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture4Resolution", g_Texture4Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture5Resolution", g_Texture5Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture6Resolution", g_Texture6Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture7Resolution", g_Texture7Resolution, 4);
+
+    services->setVertexShaderConstant ("g_Texture0Rotation", g_Texture0Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture1Rotation", g_Texture1Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture2Rotation", g_Texture2Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture3Rotation", g_Texture3Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture4Rotation", g_Texture4Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture5Rotation", g_Texture5Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture6Rotation", g_Texture6Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture7Rotation", g_Texture7Rotation, 4);
+
+    services->setPixelShaderConstant ("g_Texture0", &g_Texture0, 1);
+    services->setPixelShaderConstant ("g_Texture1", &g_Texture1, 1);
+    services->setPixelShaderConstant ("g_Texture2", &g_Texture2, 1);
+    services->setPixelShaderConstant ("g_Texture3", &g_Texture3, 1);
+    services->setPixelShaderConstant ("g_Texture4", &g_Texture4, 1);
+    services->setPixelShaderConstant ("g_Texture5", &g_Texture5, 1);
+    services->setPixelShaderConstant ("g_Texture6", &g_Texture6, 1);
+    services->setPixelShaderConstant ("g_Texture7", &g_Texture7, 1);
 }
 
 const std::string CImage::Type = "image";

+ 19 - 4
src/WallpaperEngine/Render/Objects/CImage.h

@@ -2,35 +2,50 @@
 
 #include "WallpaperEngine/Core/Objects/CImage.h"
 
+#include "WallpaperEngine/Render/Objects/CEffect.h"
 #include "WallpaperEngine/Render/CObject.h"
 #include "WallpaperEngine/Render/CScene.h"
 
+#include "WallpaperEngine/Render/Shaders/Compiler.h"
+
 using namespace WallpaperEngine;
 
 namespace WallpaperEngine::Render::Objects
 {
-    // TODO: MOVE IShaderConstantSetCallBack TO IT'S OWN CLASS OR ORGANIZE THIS BETTER
+    class CEffect;
+
     class CImage : public CObject, public irr::video::IShaderConstantSetCallBack
     {
     public:
         CImage (CScene* scene, Core::Objects::CImage* image);
 
-        virtual void OnSetConstants (irr::video::IMaterialRendererServices* services, int32_t userData);
+        void OnSetConstants (irr::video::IMaterialRendererServices* services, int32_t userData) override;
 
         void render () override;
         const irr::core::aabbox3d<irr::f32>& getBoundingBox() const override;
-        void OnRegisterSceneNode () override;
+
+        const Core::Objects::CImage* getImage () const;
+        const std::vector<CEffect*>& getEffects () const;
 
     protected:
         static const std::string Type;
 
     private:
+        void generateFBOs ();
         void generateMaterial ();
+        void generatePass (Core::Objects::Images::Materials::CPass* pass);
 
         irr::video::S3DVertex m_vertex [4];
-        irr::video::SMaterial m_material;
+        irr::u32 m_passes;
+        std::vector<irr::video::SMaterial> m_materials;
+        std::vector<irr::video::ITexture*> m_renderTextures;
 
         Core::Objects::CImage* m_image;
         irr::core::aabbox3d<irr::f32> m_boundingBox;
+
+        std::vector<CEffect*> m_effects;
+
+        std::vector<Render::Shaders::Compiler*> m_vertexShaders;
+        std::vector<Render::Shaders::Compiler*> m_pixelShaders;
     };
 }

+ 47 - 27
src/WallpaperEngine/Render/Objects/CSound.cpp

@@ -1,67 +1,87 @@
+#include <SDL.h>
+#include <SDL_rwops.h>
+#include <SDL_mixer.h>
+
 #include "CSound.h"
 
-using namespace WallpaperEngine;
 using namespace WallpaperEngine::Render::Objects;
 
 CSound::CSound (CScene* scene, Core::Objects::CSound* sound) :
-    Render::CObject (scene, Type, sound),
+    CObject (scene, Type, sound),
     m_sound (sound)
 {
+    this->setAutomaticCulling (irr::scene::EAC_OFF);
     this->m_boundingBox = irr::core::aabbox3d<irr::f32>(0, 0, 0, 0, 0, 0);
 
+    this->load ();
     this->play ();
 }
 
-void CSound::play ()
+void CSound::load ()
 {
-    std::vector<std::string>* sounds = this->m_sound->getSounds ();
-    std::vector<std::string>::const_iterator cur = sounds->begin ();
-    std::vector<std::string>::const_iterator end = sounds->end ();
+    if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
+    {
+        return;
+    }
+
+    auto cur = this->m_sound->getSounds ().begin ();
+    auto end = this->m_sound->getSounds ().end ();
 
     for (; cur != end; cur ++)
     {
-        SDL_RWops* rwops = nullptr;
+        SDL_RWops* sdlRwops = nullptr;
         Mix_Music* music = nullptr;
-
-        // open the sound file and read it fully
         irr::io::IReadFile* readfile = this->getScene ()->getContext ()->getDevice ()->getFileSystem ()->createAndOpenFile ((*cur).c_str ());
-        long filesize = readfile->getSize ();
-        char* buffer = new char [filesize];
-
-        // TODO: IMPLEMENT A MAXIMUM FILESIZE TO PREVENT CRAZY ALLOCATIONS
+        int filesize = readfile->getSize ();
+        char* filebuffer = new char [filesize];
 
-        readfile->read (buffer, filesize);
+        readfile->read (filebuffer, filesize);
 
-        rwops = SDL_RWFromConstMem (buffer, filesize);
-        music = Mix_LoadMUS_RW (rwops);
-
-        // free the file reader
+        sdlRwops = SDL_RWFromConstMem (filebuffer, filesize);
+        music = Mix_LoadMUS_RW (sdlRwops);
         readfile->drop ();
 
         if (music == nullptr)
         {
-            this->getScene ()->getContext ()->getDevice ()->getLogger ()->log ("Cannot load audio", Mix_GetError (), irr::ELL_ERROR);
+            this->getScene ()->getContext ()->getDevice ()->getLogger ()->log (
+                "cannot load audio", Mix_GetError (), irr::ELL_ERROR
+            );
+
+            continue;
         }
 
-        this->m_bufferReader.push_back (rwops);
-        this->m_mixSdl.push_back (music);
-        this->m_soundBuffer.push_back (buffer);
+        this->m_bufferReader.push_back (sdlRwops);
+        this->m_soundBuffer.push_back (filebuffer);
+        this->m_sdl.push_back (music);
+    }
+}
+void CSound::play ()
+{
+    if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
+    {
+        return;
     }
 
-    // after all the sounds are loaded, play them all
-    std::vector<Mix_Music*>::const_iterator mixcur = this->m_mixSdl.begin ();
-    std::vector<Mix_Music*>::const_iterator mixend = this->m_mixSdl.end ();
+    auto mixcur = this->m_sdl.begin ();
+    auto mixend = this->m_sdl.end ();
 
     for (; mixcur != mixend; mixcur ++)
     {
         if (Mix_PlayMusic ((*mixcur), -1) == -1)
         {
-            this->getScene ()->getContext ()->getDevice ()->getLogger ()->log ("Cannot play audio", Mix_GetError (), irr::ELL_ERROR);
+            this->getScene ()->getContext ()->getDevice ()->getLogger ()->log (
+                "cannot play audio", Mix_GetError (), irr::ELL_ERROR
+            );
         }
     }
 }
 
-const irr::core::aabbox3d<irr::f32>& CSound::getBoundingBox () const
+void CSound::render ()
+{
+
+}
+
+const irr::core::aabbox3d<irr::f32>& CSound::getBoundingBox() const
 {
     return this->m_boundingBox;
 }

+ 9 - 7
src/WallpaperEngine/Render/Objects/CSound.h

@@ -1,11 +1,11 @@
 #pragma once
 
+#include <SDL_rwops.h>
 #include <SDL_mixer.h>
 
 #include "WallpaperEngine/Core/Objects/CSound.h"
 
 #include "WallpaperEngine/Render/CObject.h"
-#include "WallpaperEngine/Render/CScene.h"
 
 using namespace WallpaperEngine;
 
@@ -16,20 +16,22 @@ namespace WallpaperEngine::Render::Objects
     public:
         CSound (CScene* scene, Core::Objects::CSound* sound);
 
-        void render () override {};
-        const irr::core::aabbox3d<irr::f32>& getBoundingBox () const override;
+        void render () override;
+        const irr::core::aabbox3d<irr::f32>& getBoundingBox() const override;
 
     protected:
         static const std::string Type;
 
+        void load ();
         void play ();
 
     private:
-        Core::Objects::CSound* m_sound;
-        irr::core::aabbox3d<irr::f32> m_boundingBox;
-
-        std::vector <Mix_Music*> m_mixSdl;
+        std::vector<std::string> m_filenames;
+        std::vector <Mix_Music*> m_sdl;
         std::vector <SDL_RWops*> m_bufferReader;
         std::vector <void*> m_soundBuffer;
+
+        Core::Objects::CSound* m_sound;
+        irr::core::aabbox3d<irr::f32> m_boundingBox;
     };
 }

+ 34 - 0
src/WallpaperEngine/Render/Objects/Effects/CFBO.cpp

@@ -0,0 +1,34 @@
+#include "CFBO.h"
+
+using namespace WallpaperEngine::Render::Objects::Effects;
+
+CFBO::CFBO (Core::Objects::Effects::CFBO* fbo, const Core::Objects::CImage* image, Irrlicht::CContext* context) :
+    m_fbo (fbo)
+{
+    irr::core::dimension2du size = irr::core::dimension2du (
+        image->getSize ().X * this->getScale (),
+        image->getSize ().Y * this->getScale ()
+    );
+
+    context->getDevice ()->getVideoDriver ()->addRenderTargetTexture (size, this->getName ().c_str ());
+}
+
+const irr::video::ITexture* CFBO::getTexture () const
+{
+    return this->m_texture;
+}
+
+const std::string& CFBO::getName () const
+{
+    return this->m_fbo->getName ();
+}
+
+const irr::f32& CFBO::getScale () const
+{
+    return this->m_fbo->getScale ();
+}
+
+const std::string& CFBO::getFormat () const
+{
+    return this->m_fbo->getFormat ();
+}

+ 25 - 0
src/WallpaperEngine/Render/Objects/Effects/CFBO.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include <irrlicht/irrlicht.h>
+
+#include "WallpaperEngine/Core/Objects/Effects/CFBO.h"
+#include "WallpaperEngine/Core/Objects/CImage.h"
+
+#include "WallpaperEngine/Irrlicht/CContext.h"
+
+namespace WallpaperEngine::Render::Objects::Effects
+{
+    class CFBO
+    {
+    public:
+        CFBO (Core::Objects::Effects::CFBO* fbo, const Core::Objects::CImage* image, Irrlicht::CContext* context);
+
+        const irr::video::ITexture* getTexture () const;
+        const std::string& getName () const;
+        const irr::f32& getScale () const;
+        const std::string& getFormat () const;
+    private:
+        irr::video::ITexture* m_texture;
+        const Core::Objects::Effects::CFBO* m_fbo;
+    };
+};

+ 60 - 0
src/WallpaperEngine/Render/Objects/Effects/CMaterial.cpp

@@ -0,0 +1,60 @@
+#include "CMaterial.h"
+
+using namespace WallpaperEngine::Render::Objects;
+
+using namespace WallpaperEngine::Render::Objects::Effects;
+
+CMaterial::CMaterial (Irrlicht::CContext* context, Render::Objects::CEffect* effect, Core::Objects::Images::CMaterial* material, const irr::video::ITexture* texture) :
+    m_context (context),
+    m_effect (effect),
+    m_material (material),
+    m_inputTexture (texture)
+{
+    this->m_outputTexture = this->m_context->getDevice ()->getVideoDriver ()->addRenderTargetTexture (
+        this->m_inputTexture->getSize (),
+        (
+            "_rt_WALLENGINELINUX_OUTPUT_" +
+            std::to_string (this->m_effect->getImage ()->getImage ()->getId ()) + "_" +
+            std::to_string (this->m_effect->getImage ()->getEffects ().size ()) +
+            "_material_output"
+        ).c_str ()
+    );
+
+    this->generatePasses ();
+}
+
+const std::vector<CPass*>& CMaterial::getPasses () const
+{
+    return this->m_passes;
+}
+
+const CImage* CMaterial::getImage () const
+{
+    return this->m_effect->getImage ();
+}
+
+const irr::video::ITexture* CMaterial::getOutputTexture () const
+{
+    return this->m_outputTexture;
+}
+
+const irr::video::ITexture* CMaterial::getInputTexture () const
+{
+    return this->m_inputTexture;
+}
+
+void CMaterial::generatePasses ()
+{
+    auto cur = this->m_material->getPasses ().begin ();
+    auto end = this->m_material->getPasses ().end ();
+    const irr::video::ITexture* inputTexture = this->getInputTexture ();
+
+    for (; cur != end; cur ++)
+    {
+        CPass* pass = new CPass (this->m_context, this, *cur, inputTexture);
+
+        inputTexture = pass->getOutputTexture ();
+
+        this->m_passes.push_back (pass);
+    }
+}

+ 52 - 0
src/WallpaperEngine/Render/Objects/Effects/CMaterial.h

@@ -0,0 +1,52 @@
+#pragma once
+
+#include <irrlicht/irrlicht.h>
+
+#include "WallpaperEngine/Core/Objects/Images/CMaterial.h"
+#include "WallpaperEngine/Core/Objects/CEffect.h"
+
+#include "WallpaperEngine/Irrlicht/CContext.h"
+
+#include "WallpaperEngine/Render/Objects/Effects/CPass.h"
+#include "WallpaperEngine/Render/Objects/CEffect.h"
+
+#include "CPass.h"
+
+using namespace WallpaperEngine;
+
+namespace WallpaperEngine::Render::Objects
+{
+    class CEffect;
+    class CImage;
+}
+
+namespace WallpaperEngine::Render::Objects::Effects
+{
+    class CPass;
+
+    class CMaterial
+    {
+        friend class CPass;
+    public:
+        CMaterial (Irrlicht::CContext* context, Render::Objects::CEffect* effect, Core::Objects::Images::CMaterial* material, const irr::video::ITexture* texture);
+
+        const irr::video::ITexture* getOutputTexture () const;
+        const irr::video::ITexture* getInputTexture () const;
+
+        const std::vector<CPass*>& getPasses () const;
+        const CImage* getImage () const;
+
+    private:
+        void generatePasses ();
+
+        Irrlicht::CContext* m_context;
+
+        const irr::video::ITexture* m_inputTexture;
+        irr::video::ITexture* m_outputTexture;
+
+        Render::Objects::CEffect* m_effect;
+        Core::Objects::Images::CMaterial* m_material;
+
+        std::vector<CPass*> m_passes;
+    };
+};

+ 264 - 0
src/WallpaperEngine/Render/Objects/Effects/CPass.cpp

@@ -0,0 +1,264 @@
+#include "CPass.h"
+
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariable.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableFloat.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableInteger.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector2.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector3.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector4.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableFloatPointer.h"
+#include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableVector2Pointer.h"
+
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstant.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantFloat.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantInteger.h"
+#include "WallpaperEngine/Core/Objects/Effects/Constants/CShaderConstantVector3.h"
+
+using namespace WallpaperEngine::Core::Objects::Effects::Constants;
+using namespace WallpaperEngine::Render::Shaders::Variables;
+
+using namespace WallpaperEngine::Render::Objects::Effects;
+
+CPass::CPass (Irrlicht::CContext* context, CMaterial* material, Core::Objects::Images::Materials::CPass* pass, const irr::video::ITexture* texture) :
+    m_material (material),
+    m_pass (pass),
+    m_context (context),
+    m_inputTexture (texture),
+    m_outputTexture (nullptr)
+{
+    this->m_outputTexture = this->m_context->getDevice ()->getVideoDriver ()->addRenderTargetTexture (
+        this->m_inputTexture->getSize (),
+        (
+            "_rt_WALLENGINELINUX_OUTPUT_" +
+            std::to_string (this->m_material->getImage ()->getImage ()->getId ()) + "_" +
+            std::to_string (this->m_material->getImage ()->getEffects ().size ()) +
+            "_pass_output"
+        ).c_str ()
+    );
+
+    irr::io::path vertPath = this->m_context->resolveVertexShader (pass->getShader ());
+    irr::io::path fragPath = this->m_context->resolveFragmentShader (pass->getShader ());
+    // register fragment shader
+    this->m_fragShader = new Render::Shaders::Compiler (
+        this->m_context, vertPath, Render::Shaders::Compiler::Type::Type_Pixel, pass->getCombos (), false
+    );
+    // register vertex shader
+    this->m_vertShader = new Render::Shaders::Compiler (
+        this->m_context, fragPath, Render::Shaders::Compiler::Type::Type_Vertex, pass->getCombos (), false
+    );
+    // initialize material data and compile shader used for this pass
+    this->m_irrlichtMaterial.Wireframe = false;
+    this->m_irrlichtMaterial.Lighting = false;
+    this->m_irrlichtMaterial.setFlag (irr::video::EMF_LIGHTING, false);
+    this->m_irrlichtMaterial.setFlag (irr::video::EMF_BLEND_OPERATION, true);
+    this->m_irrlichtMaterial.MaterialType = (irr::video::E_MATERIAL_TYPE)
+        this->m_context->getDevice ()->getVideoDriver ()->getGPUProgrammingServices ()->addHighLevelShaderMaterial (
+            this->m_vertShader->precompile ().c_str (), "main", irr::video::EVST_VS_2_0,
+            this->m_fragShader->precompile ().c_str (), "main", irr::video::EPST_PS_2_0,
+            this, irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL, 0, irr::video::EGSL_DEFAULT
+        );
+
+    this->setupShaderVariables ();
+}
+
+const irr::video::ITexture* CPass::getOutputTexture () const
+{
+    return this->m_outputTexture;
+}
+
+const irr::video::ITexture* CPass::getInputTexture () const
+{
+    return this->m_inputTexture;
+}
+
+const irr::video::SMaterial& CPass::getMaterial () const
+{
+    return this->m_irrlichtMaterial;
+}
+
+void CPass::OnSetConstants (irr::video::IMaterialRendererServices *services, int32_t userData)
+{
+    irr::f32 g_Texture0 = 0;
+    irr::f32 g_Texture1 = 1;
+    irr::f32 g_Texture2 = 2;
+    irr::f32 g_Texture3 = 3;
+    irr::f32 g_Texture4 = 4;
+    irr::f32 g_Texture5 = 5;
+    irr::f32 g_Texture6 = 6;
+    irr::f32 g_Texture7 = 7;
+
+    const Core::Objects::CImage* image = this->m_material->getImage ()->getImage ();
+
+    irr::f32 g_Texture0Rotation [4] = { image->getAngles ().X, image->getAngles ().Y, image->getAngles ().Z, image->getAngles ().Z };
+    irr::f32 g_Texture1Rotation [4] = { image->getAngles ().X, image->getAngles ().Y, image->getAngles ().Z, image->getAngles ().Z };
+    irr::f32 g_Texture2Rotation [4] = { image->getAngles ().X, image->getAngles ().Y, image->getAngles ().Z, image->getAngles ().Z };
+    irr::f32 g_Texture3Rotation [4] = { image->getAngles ().X, image->getAngles ().Y, image->getAngles ().Z, image->getAngles ().Z };
+    irr::f32 g_Texture4Rotation [4] = { image->getAngles ().X, image->getAngles ().Y, image->getAngles ().Z, image->getAngles ().Z };
+    irr::f32 g_Texture5Rotation [4] = { image->getAngles ().X, image->getAngles ().Y, image->getAngles ().Z, image->getAngles ().Z };
+    irr::f32 g_Texture6Rotation [4] = { image->getAngles ().X, image->getAngles ().Y, image->getAngles ().Z, image->getAngles ().Z };
+    irr::f32 g_Texture7Rotation [4] = { image->getAngles ().X, image->getAngles ().Y, image->getAngles ().Z, image->getAngles ().Z };
+
+    irr::f32 g_Texture0Resolution [4] = { image->getSize ().X, image->getSize ().Y, image->getSize ().X, image->getSize ().Y };
+    irr::f32 g_Texture1Resolution [4] = { image->getSize ().X, image->getSize ().Y, image->getSize ().X, image->getSize ().Y };
+    irr::f32 g_Texture2Resolution [4] = { image->getSize ().X, image->getSize ().Y, image->getSize ().X, image->getSize ().Y };
+    irr::f32 g_Texture3Resolution [4] = { image->getSize ().X, image->getSize ().Y, image->getSize ().X, image->getSize ().Y };
+    irr::f32 g_Texture4Resolution [4] = { image->getSize ().X, image->getSize ().Y, image->getSize ().X, image->getSize ().Y };
+    irr::f32 g_Texture5Resolution [4] = { image->getSize ().X, image->getSize ().Y, image->getSize ().X, image->getSize ().Y };
+    irr::f32 g_Texture6Resolution [4] = { image->getSize ().X, image->getSize ().Y, image->getSize ().X, image->getSize ().Y };
+    irr::f32 g_Texture7Resolution [4] = { image->getSize ().X, image->getSize ().Y, image->getSize ().X, image->getSize ().Y };
+
+    irr::video::IVideoDriver* driver = services->getVideoDriver ();
+
+    irr::core::matrix4 worldViewProj;
+    worldViewProj = driver->getTransform (irr::video::ETS_PROJECTION);
+    worldViewProj *= driver->getTransform (irr::video::ETS_VIEW);
+    worldViewProj *= driver->getTransform (irr::video::ETS_WORLD);
+
+    auto cur = this->m_vertShader->getParameters ().begin ();
+    auto end = this->m_vertShader->getParameters ().end ();
+
+    for (; cur != end; cur ++)
+    {
+        if ((*cur)->is <CShaderVariableInteger> () == true)
+        {
+            services->setVertexShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::s32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+        }
+        else if (
+            (*cur)->is <CShaderVariableFloat> () == true ||
+            (*cur)->is <CShaderVariableVector2> () == true ||
+            (*cur)->is <CShaderVariableVector3> () == true ||
+            (*cur)->is <CShaderVariableVector4> () == true)
+        {
+            services->setVertexShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::f32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+        }
+    }
+
+    cur = this->m_fragShader->getParameters ().begin ();
+    end = this->m_fragShader->getParameters ().end ();
+
+    for (; cur != end; cur ++)
+    {
+        if ((*cur)->is <CShaderVariableInteger> () == true)
+        {
+            services->setPixelShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::s32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+        }
+        else if (
+            (*cur)->is <CShaderVariableFloat> () == true ||
+            (*cur)->is <CShaderVariableVector2> () == true ||
+            (*cur)->is <CShaderVariableVector3> () == true ||
+            (*cur)->is <CShaderVariableVector4> () == true)
+        {
+            services->setPixelShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::f32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+        }
+    }
+
+    cur = this->m_context->getShaderVariables ().begin ();
+    end = this->m_context->getShaderVariables ().end ();
+
+    for (; cur != end; cur ++)
+    {
+        if ((*cur)->is <CShaderVariableFloatPointer> () == true)
+        {
+            services->setPixelShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::f32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+            services->setVertexShaderConstant (
+                (*cur)->getName ().c_str (),
+                (irr::f32*) (*cur)->getValue (),
+                (*cur)->getSize ()
+            );
+        }
+    }
+
+    services->setVertexShaderConstant ("g_ModelViewProjectionMatrix", worldViewProj.pointer(), 16);
+
+    services->setVertexShaderConstant ("g_Texture0Resolution", g_Texture0Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture1Resolution", g_Texture1Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture2Resolution", g_Texture2Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture3Resolution", g_Texture3Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture4Resolution", g_Texture4Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture5Resolution", g_Texture5Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture6Resolution", g_Texture6Resolution, 4);
+    services->setVertexShaderConstant ("g_Texture7Resolution", g_Texture7Resolution, 4);
+
+    services->setVertexShaderConstant ("g_Texture0Rotation", g_Texture0Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture1Rotation", g_Texture1Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture2Rotation", g_Texture2Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture3Rotation", g_Texture3Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture4Rotation", g_Texture4Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture5Rotation", g_Texture5Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture6Rotation", g_Texture6Rotation, 4);
+    services->setVertexShaderConstant ("g_Texture7Rotation", g_Texture7Rotation, 4);
+
+    services->setPixelShaderConstant ("g_Texture0", &g_Texture0, 1);
+    services->setPixelShaderConstant ("g_Texture1", &g_Texture1, 1);
+    services->setPixelShaderConstant ("g_Texture2", &g_Texture2, 1);
+    services->setPixelShaderConstant ("g_Texture3", &g_Texture3, 1);
+    services->setPixelShaderConstant ("g_Texture4", &g_Texture4, 1);
+    services->setPixelShaderConstant ("g_Texture5", &g_Texture5, 1);
+    services->setPixelShaderConstant ("g_Texture6", &g_Texture6, 1);
+    services->setPixelShaderConstant ("g_Texture7", &g_Texture7, 1);
+}
+
+void CPass::setupShaderVariables ()
+{
+    // find variables in the shaders and set the value with the constants if possible
+    auto cur = this->m_pass->getConstants ().begin ();
+    auto end = this->m_pass->getConstants ().end ();
+
+    for (; cur != end; cur ++)
+    {
+        CShaderVariable* vertexVar = this->m_vertShader->findParameter ((*cur).first);
+        CShaderVariable* pixelVar = this->m_fragShader->findParameter ((*cur).first);
+
+        if (pixelVar)
+        {
+            if (pixelVar->is <CShaderVariableFloat> () && (*cur).second->is <CShaderConstantFloat> ())
+            {
+                pixelVar->as <CShaderVariableFloat> ()->setValue (*(*cur).second->as <CShaderConstantFloat> ()->getValue ());
+            }
+            else if (pixelVar->is <CShaderVariableInteger> () && (*cur).second->is <CShaderConstantInteger> ())
+            {
+                pixelVar->as <CShaderVariableInteger> ()->setValue (*(*cur).second->as <CShaderConstantInteger> ()->getValue ());
+            }
+            else if (pixelVar->is <CShaderVariableVector3> () && (*cur).second->is <CShaderConstantVector3> ())
+            {
+                pixelVar->as <CShaderVariableVector3> ()->setValue (*(*cur).second->as <CShaderConstantVector3> ()->getValue ());
+            }
+        }
+
+        if (vertexVar)
+        {
+            if (vertexVar->is <CShaderVariableFloat> () && (*cur).second->is <CShaderConstantFloat> ())
+            {
+                vertexVar->as <CShaderVariableFloat> ()->setValue (*(*cur).second->as <CShaderConstantFloat> ()->getValue ());
+            }
+            else if (vertexVar->is <CShaderVariableInteger> () && (*cur).second->is <CShaderConstantInteger> ())
+            {
+                vertexVar->as <CShaderVariableInteger> ()->setValue (*(*cur).second->as <CShaderConstantInteger> ()->getValue ());
+            }
+            else if (vertexVar->is <CShaderVariableVector3> () && (*cur).second->is <CShaderConstantVector3> ())
+            {
+                vertexVar->as <CShaderVariableVector3> ()->setValue (*(*cur).second->as <CShaderConstantVector3> ()->getValue ());
+            }
+        }
+    }
+}

+ 41 - 0
src/WallpaperEngine/Render/Objects/Effects/CPass.h

@@ -0,0 +1,41 @@
+#pragma once
+
+#include <irrlicht/irrlicht.h>
+
+#include "WallpaperEngine/Irrlicht/CContext.h"
+
+#include "WallpaperEngine/Render/Objects/Effects/CMaterial.h"
+#include "WallpaperEngine/Render/Shaders/Compiler.h"
+
+namespace WallpaperEngine::Render::Objects::Effects
+{
+    class CMaterial;
+
+    class CPass : public irr::video::IShaderConstantSetCallBack
+    {
+    public:
+        CPass (Irrlicht::CContext* context, CMaterial* material, Core::Objects::Images::Materials::CPass* pass, const irr::video::ITexture* texture);
+
+        void OnSetConstants (irr::video::IMaterialRendererServices* services, int32_t userData) override;
+
+        const irr::video::ITexture* getOutputTexture () const;
+        const irr::video::ITexture* getInputTexture () const;
+
+        const irr::video::SMaterial& getMaterial () const;
+
+    private:
+        void setupShaderVariables ();
+
+        CMaterial* m_material;
+        Core::Objects::Images::Materials::CPass* m_pass;
+        Irrlicht::CContext* m_context;
+
+        const irr::video::ITexture* m_inputTexture;
+        irr::video::ITexture* m_outputTexture;
+
+        irr::video::SMaterial m_irrlichtMaterial;
+
+        Render::Shaders::Compiler* m_fragShader;
+        Render::Shaders::Compiler* m_vertShader;
+    };
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно