Преглед изворни кода

Added support for running multiple X11 backgrounds off the same instance
Window mode now has extra settings for setting the position and size
Fixed audio not muting when --silent was used

Signed-off-by: Alexis Maiquez <almamu@almamu.com>

Alexis Maiquez пре 3 година
родитељ
комит
b69ce8ba57
49 измењених фајлова са 785 додато и 375 уклоњено
  1. 6 0
      CMakeLists.txt
  2. 54 9
      src/WallpaperEngine/Application/CApplicationContext.cpp
  3. 13 2
      src/WallpaperEngine/Application/CApplicationContext.h
  4. 118 48
      src/WallpaperEngine/Application/CWallpaperApplication.cpp
  5. 12 6
      src/WallpaperEngine/Application/CWallpaperApplication.h
  6. 21 0
      src/WallpaperEngine/Assets/CCombinedContainer.cpp
  7. 1 0
      src/WallpaperEngine/Assets/CCombinedContainer.h
  8. 5 0
      src/WallpaperEngine/Assets/CContainer.cpp
  9. 9 0
      src/WallpaperEngine/Assets/CContainer.h
  10. 5 0
      src/WallpaperEngine/Assets/CDirectory.cpp
  11. 1 0
      src/WallpaperEngine/Assets/CDirectory.h
  12. 0 1
      src/WallpaperEngine/Audio/CAudioContext.cpp
  13. 1 1
      src/WallpaperEngine/Core/CObject.cpp
  14. 1 1
      src/WallpaperEngine/Core/CObject.h
  15. 3 3
      src/WallpaperEngine/Core/CProject.cpp
  16. 4 4
      src/WallpaperEngine/Core/CProject.h
  17. 3 3
      src/WallpaperEngine/Core/CScene.cpp
  18. 4 4
      src/WallpaperEngine/Core/CScene.h
  19. 2 2
      src/WallpaperEngine/Core/Objects/CEffect.cpp
  20. 2 2
      src/WallpaperEngine/Core/Objects/CEffect.h
  21. 1 1
      src/WallpaperEngine/Core/Objects/CImage.cpp
  22. 1 1
      src/WallpaperEngine/Core/Objects/CImage.h
  23. 1 3
      src/WallpaperEngine/Core/Objects/CParticle.cpp
  24. 1 1
      src/WallpaperEngine/Core/Objects/CParticle.h
  25. 2 2
      src/WallpaperEngine/Core/Objects/Images/CMaterial.cpp
  26. 2 2
      src/WallpaperEngine/Core/Objects/Images/CMaterial.h
  27. 2 2
      src/WallpaperEngine/FileSystem/FileSystem.cpp
  28. 1 1
      src/WallpaperEngine/FileSystem/FileSystem.h
  29. 1 0
      src/WallpaperEngine/Render/CFBO.h
  30. 1 1
      src/WallpaperEngine/Render/CObject.cpp
  31. 1 1
      src/WallpaperEngine/Render/CObject.h
  32. 39 229
      src/WallpaperEngine/Render/CRenderContext.cpp
  33. 14 29
      src/WallpaperEngine/Render/CRenderContext.h
  34. 21 3
      src/WallpaperEngine/Render/CTextureCache.cpp
  35. 4 1
      src/WallpaperEngine/Render/CVideo.cpp
  36. 2 2
      src/WallpaperEngine/Render/CWallpaper.cpp
  37. 1 1
      src/WallpaperEngine/Render/CWallpaper.h
  38. 6 0
      src/WallpaperEngine/Render/Drivers/COpenGLDriver.cpp
  39. 10 0
      src/WallpaperEngine/Render/Drivers/COpenGLDriver.h
  40. 2 0
      src/WallpaperEngine/Render/Drivers/CVideoDriver.h
  41. 23 0
      src/WallpaperEngine/Render/Drivers/Output/COutput.cpp
  42. 47 0
      src/WallpaperEngine/Render/Drivers/Output/COutput.h
  43. 77 0
      src/WallpaperEngine/Render/Drivers/Output/CWindowOutput.cpp
  44. 25 0
      src/WallpaperEngine/Render/Drivers/Output/CWindowOutput.h
  45. 183 0
      src/WallpaperEngine/Render/Drivers/Output/CX11Output.cpp
  46. 40 0
      src/WallpaperEngine/Render/Drivers/Output/CX11Output.h
  47. 5 2
      src/WallpaperEngine/Render/Objects/CSound.cpp
  48. 5 5
      src/WallpaperEngine/Render/Shaders/Compiler.cpp
  49. 2 2
      src/WallpaperEngine/Render/Shaders/Compiler.h

+ 6 - 0
CMakeLists.txt

@@ -105,6 +105,12 @@ add_executable(
     src/WallpaperEngine/Render/Shaders/Compiler.h
     src/WallpaperEngine/Render/Shaders/Compiler.cpp
 
+    src/WallpaperEngine/Render/Drivers/Output/COutput.cpp
+    src/WallpaperEngine/Render/Drivers/Output/COutput.h
+    src/WallpaperEngine/Render/Drivers/Output/CX11Output.cpp
+    src/WallpaperEngine/Render/Drivers/Output/CX11Output.h
+    src/WallpaperEngine/Render/Drivers/Output/CWindowOutput.cpp
+    src/WallpaperEngine/Render/Drivers/Output/CWindowOutput.h
     src/WallpaperEngine/Render/Drivers/COpenGLDriver.h
     src/WallpaperEngine/Render/Drivers/COpenGLDriver.cpp
     src/WallpaperEngine/Render/Drivers/CVideoDriver.h

+ 54 - 9
src/WallpaperEngine/Application/CApplicationContext.cpp

@@ -14,6 +14,8 @@ using namespace WallpaperEngine::Application;
 
 struct option long_options [] = {
     {"screen-root",     required_argument, nullptr, 'r'},
+	{"bg",				required_argument, nullptr, 'b'},
+	{"window",			optional_argument, nullptr, 'w'},
     {"pkg",             required_argument, nullptr, 'p'},
     {"dir",             required_argument, nullptr, 'd'},
     {"silent",          no_argument,       nullptr, 's'},
@@ -52,10 +54,21 @@ CApplicationContext::CApplicationContext (int argc, char* argv[]) :
 {
     int c;
 
-    while ((c = getopt_long (argc, argv, "r:p:d:shf:a:", long_options, nullptr)) != -1)
+	std::string lastScreen;
+
+    while ((c = getopt_long (argc, argv, "b:r:p:d:shf:a:w::", long_options, nullptr)) != -1)
     {
         switch (c)
         {
+			case 'b':
+				if (lastScreen.empty ())
+					sLog.exception ("--bg has to go after a --screen-root argument");
+
+				// no need to check for previous screen being in the list, as it's the only way for this variable
+				// to have any value
+				this->screenSettings.insert_or_assign (lastScreen, this->validatePath (optarg));
+				break;
+
             case 'o':
                 {
                     std::string value = optarg;
@@ -77,13 +90,41 @@ CApplicationContext::CApplicationContext (int argc, char* argv[]) :
                 break;
 
             case 'r':
-                screens.emplace_back (optarg);
+				if (this->screenSettings.find (optarg) != this->screenSettings.end ())
+					sLog.exception ("Cannot specify the same screen more than once: ", optarg);
+				if (this->windowMode == EXPLICIT_WINDOW)
+					sLog.exception ("Cannot run in both background and window mode");
+
+				this->windowMode = X11_BACKGROUND;
+				lastScreen = optarg;
+                this->screenSettings.insert_or_assign (lastScreen, "");
                 break;
 
+			case 'w':
+				if (this->windowMode == X11_BACKGROUND)
+					sLog.exception ("Cannot run in both background and window mode");
+
+				if (optarg != nullptr)
+				{
+					this->windowMode = EXPLICIT_WINDOW;
+					// read window geometry
+					char* pos = optarg;
+
+					if (pos != nullptr)
+						this->windowGeometry.x = atoi (pos);
+					if ((pos = strchr (pos, '.')) != nullptr)
+						this->windowGeometry.y = atoi (pos + 1);
+					if ((pos = strchr (pos + 1, '.')) != nullptr)
+						this->windowGeometry.z = atoi (pos + 1);
+					if ((pos = strchr (pos + 1, '.')) != nullptr)
+						this->windowGeometry.w = atoi (pos + 1);
+				}
+				break;
+
             case 'p':
             case 'd':
                 sLog.error ("--dir/--pkg is deprecated and not used anymore");
-                this->background = stringPathFixes (optarg);
+                this->background = this->validatePath (stringPathFixes (optarg));
                 break;
 
             case 's':
@@ -110,6 +151,10 @@ CApplicationContext::CApplicationContext (int argc, char* argv[]) :
                 this->takeScreenshot = true;
                 this->screenshot = stringPathFixes (optarg);
                 break;
+
+			default:
+				sLog.out ("Default on path parsing: ", optarg);
+				break;
         }
     }
 
@@ -117,7 +162,7 @@ CApplicationContext::CApplicationContext (int argc, char* argv[]) :
     {
         if (optind < argc && strlen (argv [optind]) > 0)
         {
-            this->background = argv [optind];
+            this->background = this->validatePath (argv [optind]);
         }
         else
         {
@@ -126,17 +171,16 @@ CApplicationContext::CApplicationContext (int argc, char* argv[]) :
     }
 
     // perform some extra validation on the inputs
-    this->validatePath ();
     this->validateAssets ();
     this->validateScreenshot ();
 }
 
-void CApplicationContext::validatePath ()
+std::string CApplicationContext::validatePath (const std::string& path)
 {
-    if (this->background.find ('/') != std::string::npos)
-        return;
+	if (path.find ('/') == std::string::npos)
+		return Steam::FileSystem::workshopDirectory (WORKSHOP_APP_ID, path);
 
-    this->background = Steam::FileSystem::workshopDirectory (WORKSHOP_APP_ID, this->background);
+	return path;
 }
 
 void CApplicationContext::validateAssets ()
@@ -191,6 +235,7 @@ void CApplicationContext::printHelp (const char* route)
     sLog.out ("\t--silent\t\t\t\t\tMutes all the sound the wallpaper might produce");
     sLog.out ("\t--volume <amount>\t\t\tSets the volume for all the sounds in the background");
     sLog.out ("\t--screen-root <screen name>\tDisplay as screen's background");
+	sLog.out ("\t--window <geometry>\tRuns in window mode, geometry has to be XxYxWxH");
     sLog.out ("\t--fps <maximum-fps>\t\t\tLimits the FPS to the given number, useful to keep battery consumption low");
     sLog.out ("\t--assets-dir <path>\t\t\tFolder where the assets are stored");
     sLog.out ("\t--screenshot\t\t\t\tTakes a screenshot of the background");

+ 13 - 2
src/WallpaperEngine/Application/CApplicationContext.h

@@ -6,6 +6,8 @@
 #include <string>
 #include <vector>
 
+#include <glm/vec4.hpp>
+
 namespace WallpaperEngine::Application
 {
     class CApplicationContext
@@ -13,7 +15,15 @@ namespace WallpaperEngine::Application
     public:
         CApplicationContext (int argc, char* argv[]);
 
-        std::vector <std::string> screens;
+		enum WINDOW_MODE
+		{
+			NORMAL_WINDOW = 0,
+			X11_BACKGROUND = 1,
+			EXPLICIT_WINDOW = 2,
+		};
+
+		glm::ivec4 windowGeometry;
+        std::map <std::string, std::string> screenSettings;
         std::map <std::string, std::string> properties;
         std::string background;
         std::filesystem::path assets;
@@ -24,9 +34,10 @@ namespace WallpaperEngine::Application
         bool audioEnabled;
         bool onlyListProperties;
         FREE_IMAGE_FORMAT screenshotFormat;
+		WINDOW_MODE windowMode;
 
     private:
-        void validatePath ();
+		std::string validatePath (const std::string& path);
         void validateAssets ();
         void validateScreenshot ();
         static void printHelp (const char* route);

+ 118 - 48
src/WallpaperEngine/Application/CWallpaperApplication.cpp

@@ -5,9 +5,13 @@
 #include "WallpaperEngine/Core/CVideo.h"
 #include "WallpaperEngine/Logging/CLog.h"
 #include "WallpaperEngine/Render/CRenderContext.h"
+#include "WallpaperEngine/Render/Drivers/Output/CX11Output.h"
+#include "WallpaperEngine/Render/Drivers/Output/CWindowOutput.h"
+#include "Steam/FileSystem/FileSystem.h"
 
 #include <unistd.h>
 
+
 float g_Time;
 float g_TimeLast;
 bool g_KeepRunning = true;
@@ -18,30 +22,32 @@ using namespace WallpaperEngine::Application;
 using namespace WallpaperEngine::Core;
 
 CWallpaperApplication::CWallpaperApplication (CApplicationContext& context) :
-    m_context (context)
+    m_context (context),
+	m_defaultProject (nullptr)
 {
     // copy state to global variables for now
     g_AudioVolume = context.audioVolume;
     g_AudioEnabled = context.audioEnabled;
-    this->setupContainer ();
-    this->loadProject ();
+    this->loadProjects ();
     this->setupProperties ();
 }
 
-void CWallpaperApplication::setupContainer ()
+void CWallpaperApplication::setupContainer (CCombinedContainer& container, const std::string& bg) const
 {
-    this->m_vfs.add (new CDirectory (this->m_context.background));
-    this->m_vfs.addPkg (std::filesystem::path (this->m_context.background) / "scene.pkg");
-    this->m_vfs.addPkg (std::filesystem::path (this->m_context.background) / "gifscene.pkg");
-    this->m_vfs.add (new CDirectory (this->m_context.assets));
+	std::filesystem::path basepath = bg;
+
+    container.add (new CDirectory (basepath));
+	container.addPkg (basepath / "scene.pkg");
+	container.addPkg (basepath / "gifscene.pkg");
+	container.add (new CDirectory (this->m_context.assets));
 #if !NDEBUG
-	this->m_vfs.add (new CDirectory ("../share/"));
+	container.add (new CDirectory ("../share/"));
 #else
 	this->m_vfs.add (new CDirectory (DATADIR));
 #endif /* DEBUG */
 
     // TODO: move this somewhere else?
-    CVirtualContainer* container = new CVirtualContainer ();
+    CVirtualContainer* virtualContainer = new CVirtualContainer ();
 
     //
     // Had to get a little creative with the effects to achieve the same bloom effect without any custom code
@@ -50,7 +56,7 @@ void CWallpaperApplication::setupContainer ()
     //
 
     // add the effect file for screen bloom
-    container->add (
+	virtualContainer->add (
         "effects/wpenginelinux/bloomeffect.json",
         "{"
         "\t\"name\":\"camerabloom_wpengine_linux\","
@@ -111,7 +117,7 @@ void CWallpaperApplication::setupContainer ()
     );
 
     // add some model for the image element even if it's going to waste rendering cycles
-    container->add (
+	virtualContainer->add (
         "models/wpenginelinux.json",
         "{"
         "\t\"material\":\"materials/wpenginelinux.json\""
@@ -119,7 +125,7 @@ void CWallpaperApplication::setupContainer ()
     );
 
     // models require materials, so add that too
-    container->add (
+	virtualContainer->add (
         "materials/wpenginelinux.json",
         "{"
         "\t\"passes\":"
@@ -136,47 +142,74 @@ void CWallpaperApplication::setupContainer ()
         "}"
     );
 
-    this->m_vfs.add (container);
+	container.add (virtualContainer);
 }
 
-void CWallpaperApplication::loadProject ()
+void CWallpaperApplication::loadProjects ()
 {
-    this->m_project = CProject::fromFile ("project.json", this->m_vfs);
-    // go to the right folder so the videos will play
-    // TODO: stop doing chdir and use full path
-    if (this->m_project->getWallpaper ()->is <WallpaperEngine::Core::CVideo> ())
-        chdir (this->m_context.background.c_str ());
+	for (const auto& it : this->m_context.screenSettings)
+	{
+		// ignore the screen settings if there was no background specified
+		// the default will be used
+		if (it.second.empty())
+			continue;
+
+		this->m_projects.insert_or_assign (
+			it.first,
+			this->loadProject (it.second)
+		);
+	}
+
+	// load the default project if required
+	if (!this->m_context.background.empty ())
+		this->m_defaultProject = this->loadProject (this->m_context.background);
 }
 
-void CWallpaperApplication::setupProperties ()
+CProject* CWallpaperApplication::loadProject (const std::string& bg)
 {
-    // show properties if required
-    for (auto cur : this->m_project->getProperties ())
-    {
-        // update the value of the property
-        auto override = this->m_context.properties.find (cur->getName ());
+	CCombinedContainer* container = new CCombinedContainer ();
 
-        if (override != this->m_context.properties.end ())
-        {
-            sLog.out ("Applying override value for ", cur->getName ());
+	this->setupContainer (*container, bg);
 
-            cur->update (override->second);
-        }
+	// TODO: Change this to pointer instead of reference
+    return CProject::fromFile ("project.json", container);
+}
 
-        if (this->m_context.onlyListProperties)
-            sLog.out (cur->dump ());
-    }
+void CWallpaperApplication::setupPropertiesForProject (CProject* project)
+{
+	// show properties if required
+	for (auto cur : project->getProperties ())
+	{
+		// update the value of the property
+		auto override = this->m_context.properties.find (cur->getName ());
+
+		if (override != this->m_context.properties.end ())
+		{
+			sLog.out ("Applying override value for ", cur->getName ());
+
+			cur->update (override->second);
+		}
+
+		if (this->m_context.onlyListProperties)
+			sLog.out (cur->dump ());
+	}
+}
+
+void CWallpaperApplication::setupProperties ()
+{
+	for (const auto& it : this->m_projects)
+		this->setupPropertiesForProject (it.second);
+
+	if (this->m_defaultProject != nullptr)
+		this->setupPropertiesForProject (this->m_defaultProject);
 }
 
-void CWallpaperApplication::takeScreenshot (WallpaperEngine::Render::CWallpaper* wp, const std::filesystem::path& filename, FREE_IMAGE_FORMAT format)
+void CWallpaperApplication::takeScreenshot (const Render::CRenderContext& context, const std::filesystem::path& filename, FREE_IMAGE_FORMAT format)
 {
-    GLint width, height;
+	// this should be getting called at the end of the frame, so the right thing should be bound already
 
-    // bind texture and get the size
-    glBindFramebuffer (GL_FRAMEBUFFER, wp->getWallpaperFramebuffer ());
-    glBindTexture (GL_TEXTURE_2D, wp->getWallpaperTexture ());
-    glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
-    glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
+	int width = context.getOutput ()->getFullWidth ();
+	int height = context.getOutput ()->getFullHeight ();
 
     // make room for storing the pixel data
     uint8_t* buffer = new uint8_t [width * height * sizeof (uint8_t) * 3];
@@ -222,15 +255,42 @@ void CWallpaperApplication::show ()
     // initialize audio context
     WallpaperEngine::Audio::CAudioContext audioContext (audioDriver);
     // initialize OpenGL driver
-    WallpaperEngine::Render::Drivers::COpenGLDriver videoDriver (this->m_project->getTitle ().c_str ());
+    WallpaperEngine::Render::Drivers::COpenGLDriver videoDriver ("wallpaperengine");
     // initialize the input subsystem
     WallpaperEngine::Input::CInputContext inputContext (videoDriver);
+	// output requested
+	WallpaperEngine::Render::Drivers::Output::COutput* output;
+
+	// initialize the requested output
+	switch (this->m_context.windowMode)
+	{
+		case CApplicationContext::EXPLICIT_WINDOW:
+		case CApplicationContext::NORMAL_WINDOW:
+			output = new WallpaperEngine::Render::Drivers::Output::CWindowOutput (this->m_context, videoDriver);
+			break;
+
+		case CApplicationContext::X11_BACKGROUND:
+			output = new WallpaperEngine::Render::Drivers::Output::CX11Output (this->m_context, videoDriver);
+			break;
+	}
+
     // initialize render context
-    WallpaperEngine::Render::CRenderContext context (this->m_context.screens, videoDriver, inputContext, this->m_vfs, *this);
-    // ensure the context knows what wallpaper to render
-    context.setWallpaper (
-        WallpaperEngine::Render::CWallpaper::fromWallpaper (this->m_project->getWallpaper (), context, audioContext)
-    );
+    WallpaperEngine::Render::CRenderContext context (output, videoDriver, inputContext, *this);
+
+	// set all the specific wallpapers required
+	for (const auto& it : this->m_projects)
+	{
+		context.setWallpaper (
+			it.first,
+			WallpaperEngine::Render::CWallpaper::fromWallpaper (it.second->getWallpaper (), context, audioContext)
+		);
+	}
+
+    // set the default rendering wallpaper if available
+	if (this->m_defaultProject != nullptr)
+		context.setDefaultWallpaper (
+			WallpaperEngine::Render::CWallpaper::fromWallpaper (this->m_defaultProject->getWallpaper (), context, audioContext)
+		);
 
     float startTime, endTime, minimumTime = 1.0f / this->m_context.maximumFPS;
 
@@ -255,7 +315,7 @@ void CWallpaperApplication::show ()
 
         if (this->m_context.takeScreenshot && videoDriver.getFrameCounter () == 5)
         {
-            this->takeScreenshot (context.getWallpaper (), this->m_context.screenshot, this->m_context.screenshotFormat);
+            this->takeScreenshot (context, this->m_context.screenshot, this->m_context.screenshotFormat);
             // disable screenshot just in case the counter overflows
             this->m_context.takeScreenshot = false;
         }
@@ -272,4 +332,14 @@ void CWallpaperApplication::show ()
 void CWallpaperApplication::signal (int signal)
 {
     g_KeepRunning = false;
+}
+
+const std::map <std::string, CProject*>& CWallpaperApplication::getProjects () const
+{
+	return this->m_projects;
+}
+
+CProject* CWallpaperApplication::getDefaultProject () const
+{
+	return this->m_defaultProject;
 }

+ 12 - 6
src/WallpaperEngine/Application/CWallpaperApplication.h

@@ -5,10 +5,12 @@
 #include "WallpaperEngine/Assets/CCombinedContainer.h"
 #include "WallpaperEngine/Core/CProject.h"
 #include "WallpaperEngine/Render/CWallpaper.h"
+#include "WallpaperEngine/Render/CRenderContext.h"
 
 namespace WallpaperEngine::Render
 {
     class CWallpaper;
+	class CRenderContext;
 }
 
 namespace WallpaperEngine::Application
@@ -22,15 +24,19 @@ namespace WallpaperEngine::Application
 
         void show ();
         void signal (int signal);
+		const std::map <std::string, Core::CProject*>& getProjects () const;
+		Core::CProject* getDefaultProject () const;
 
-    private:
-        void setupContainer ();
-        void loadProject ();
+	private:
+        void setupContainer (CCombinedContainer& container, const std::string& bg) const;
+		void loadProjects ();
+        Core::CProject* loadProject (const std::string& bg);
         void setupProperties ();
-        void takeScreenshot (WallpaperEngine::Render::CWallpaper* wp, const std::filesystem::path& filename, FREE_IMAGE_FORMAT format);
+		void setupPropertiesForProject (Core::CProject* project);
+        void takeScreenshot (const Render::CRenderContext& context, const std::filesystem::path& filename, FREE_IMAGE_FORMAT format);
 
-        Core::CProject* m_project;
+        Core::CProject* m_defaultProject;
         CApplicationContext& m_context;
-        CCombinedContainer m_vfs;
+		std::map <std::string, Core::CProject*> m_projects;
     };
 }

+ 21 - 0
src/WallpaperEngine/Assets/CCombinedContainer.cpp

@@ -37,6 +37,27 @@ void CCombinedContainer::addPkg (const std::filesystem::path& path)
     }
 }
 
+
+std::filesystem::path CCombinedContainer::resolveRealFile (std::string filename) const
+{
+    for (auto cur : this->m_containers)
+    {
+        try
+        {
+            // try to read the file on the current container, if the file doesn't exists
+            // an exception will be thrown
+            return cur->resolveRealFile (filename);
+        }
+        catch (CAssetLoadException& ex)
+        {
+            // not found in this container, next try
+        }
+    }
+
+    // no container was able to load the file, abort!
+    throw CAssetLoadException (filename, "Cannot resolve file in any of the containers");
+}
+
 const void* CCombinedContainer::readFile (std::string filename, uint32_t* length) const
 {
     for (auto cur : this->m_containers)

+ 1 - 0
src/WallpaperEngine/Assets/CCombinedContainer.h

@@ -21,6 +21,7 @@ namespace WallpaperEngine::Assets
         void add (CContainer* container);
         void addPkg (const std::filesystem::path& path);
 
+		std::filesystem::path resolveRealFile (std::string filename) const override;
         const void* readFile (std::string filename, uint32_t* length = nullptr) const override;
 
     private:

+ 5 - 0
src/WallpaperEngine/Assets/CContainer.cpp

@@ -9,6 +9,11 @@
 
 using namespace WallpaperEngine::Assets;
 
+std::filesystem::path CContainer::resolveRealFile (std::string filename) const
+{
+	throw CAssetLoadException (filename, "Cannot resolve physical file in this container");
+}
+
 const ITexture* CContainer::readTexture (std::string filename) const
 {
     // get the texture's filename (usually .tex)

+ 9 - 0
src/WallpaperEngine/Assets/CContainer.h

@@ -1,5 +1,6 @@
 #pragma once
 
+#include <filesystem>
 #include <string>
 #include "WallpaperEngine/Assets/ITexture.h"
 
@@ -8,6 +9,14 @@ namespace WallpaperEngine::Assets
     class CContainer
     {
     public:
+		/**
+		 * Resolves the full path to the specified file in the filesystem
+		 *
+		 * @param filename
+		 * @return
+		 */
+		virtual std::filesystem::path resolveRealFile (std::string filename) const;
+
         /**
          * Reads the given file from the container and returns it's data
          * Additionally sets a length parameter to return back the file's length

+ 5 - 0
src/WallpaperEngine/Assets/CDirectory.cpp

@@ -24,6 +24,11 @@ CDirectory::CDirectory (std::filesystem::path  basepath) :
 CDirectory::~CDirectory ()
 = default;
 
+std::filesystem::path CDirectory::resolveRealFile (std::string filename) const
+{
+	return std::filesystem::path (this->m_basepath) / filename;
+}
+
 const void* CDirectory::readFile (std::string filename, uint32_t* length) const
 {
     std::filesystem::path final = std::filesystem::path (this->m_basepath) / filename;

+ 1 - 0
src/WallpaperEngine/Assets/CDirectory.h

@@ -16,6 +16,7 @@ namespace WallpaperEngine::Assets
         explicit CDirectory (std::filesystem::path basepath);
         ~CDirectory ();
 
+		std::filesystem::path resolveRealFile (std::string filename) const override;
         const void* readFile (std::string filename, uint32_t* length) const override;
     private:
         std::filesystem::path m_basepath;

+ 0 - 1
src/WallpaperEngine/Audio/CAudioContext.cpp

@@ -7,7 +7,6 @@ using namespace WallpaperEngine::Audio::Drivers;
 CAudioContext::CAudioContext (CAudioDriver& driver) :
     m_driver (driver)
 {
-
 }
 
 void CAudioContext::addStream (CAudioStream* stream)

+ 1 - 1
src/WallpaperEngine/Core/CObject.cpp

@@ -35,7 +35,7 @@ CObject::CObject (
 {
 }
 
-CObject* CObject::fromJSON (json data, CScene* scene, const CContainer& container)
+CObject* CObject::fromJSON (json data, CScene* scene, CContainer* container)
 {
     std::string json = data.dump ();
 

+ 1 - 1
src/WallpaperEngine/Core/CObject.h

@@ -33,7 +33,7 @@ namespace WallpaperEngine::Core
     {
         friend class CScene;
     public:
-        static CObject* fromJSON (json data, CScene* scene, const CContainer& container);
+        static CObject* fromJSON (json data, CScene* scene, CContainer* container);
 
         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; }

+ 3 - 3
src/WallpaperEngine/Core/CProject.cpp

@@ -9,14 +9,14 @@
 using namespace WallpaperEngine::Core;
 using namespace WallpaperEngine::Assets;
 
-CProject::CProject (std::string title, std::string type, CContainer& container) :
+CProject::CProject (std::string title, std::string type, CContainer* container) :
     m_title (std::move (title)),
     m_type (std::move (type)),
     m_container (container)
 {
 }
 
-CProject* CProject::fromFile (const std::string& filename, CContainer& container)
+CProject* CProject::fromFile (const std::string& filename, CContainer* container)
 {
     json content = json::parse (WallpaperEngine::FileSystem::loadFullFile (filename, container));
 
@@ -85,7 +85,7 @@ const std::vector<Projects::CProperty*>& CProject::getProperties () const
     return this->m_properties;
 }
 
-CContainer& CProject::getContainer ()
+CContainer* CProject::getContainer ()
 {
     return this->m_container;
 }

+ 4 - 4
src/WallpaperEngine/Core/CProject.h

@@ -16,7 +16,7 @@ namespace WallpaperEngine::Core
     class CProject
     {
     public:
-        static CProject* fromFile (const std::string& filename, CContainer& container);
+        static CProject* fromFile (const std::string& filename, CContainer* container);
 
         CWallpaper* getWallpaper () const;
 
@@ -24,10 +24,10 @@ namespace WallpaperEngine::Core
         const std::string& getType () const;
         const std::vector<Projects::CProperty*>& getProperties () const;
 
-        CContainer& getContainer ();
+        CContainer* getContainer ();
 
     protected:
-        CProject (std::string title, std::string type, CContainer& container);
+        CProject (std::string title, std::string type, CContainer* container);
 
 		void setWallpaper (CWallpaper* wallpaper);
         void insertProperty (Projects::CProperty* property);
@@ -37,6 +37,6 @@ namespace WallpaperEngine::Core
         std::string m_title;
         std::string m_type;
         CWallpaper* m_wallpaper;
-        CContainer& m_container;
+        CContainer* m_container;
     };
 }

+ 3 - 3
src/WallpaperEngine/Core/CScene.cpp

@@ -10,7 +10,7 @@ using namespace WallpaperEngine::Core;
 
 CScene::CScene (
 		CProject& project,
-        CContainer& container,
+        CContainer* container,
         Scenes::CCamera* camera,
         glm::vec3 ambientColor,
         CUserSettingBoolean* bloom,
@@ -52,7 +52,7 @@ CScene::CScene (
 {
 }
 
-CScene* CScene::fromFile (const std::string& filename, CProject& project, CContainer& container)
+CScene* CScene::fromFile (const std::string& filename, CProject& project, CContainer* container)
 {
     std::string stringContent = WallpaperEngine::FileSystem::loadFullFile (filename, container);
     json content = json::parse (WallpaperEngine::FileSystem::loadFullFile (filename, container));
@@ -128,7 +128,7 @@ void CScene::insertObject (CObject* object)
     }
 }
 
-CContainer& CScene::getContainer ()
+CContainer* CScene::getContainer ()
 {
     return this->m_container;
 }

+ 4 - 4
src/WallpaperEngine/Core/CScene.h

@@ -17,7 +17,7 @@ namespace WallpaperEngine::Core
     class CScene : public CWallpaper
     {
     public:
-        static CScene* fromFile (const std::string& filename, CProject& project, CContainer& container);
+        static CScene* fromFile (const std::string& filename, CProject& project, CContainer* container);
 
         const std::map<uint32_t, CObject*>& getObjects () const;
         const std::vector<CObject*>& getObjectsByRenderOrder () const;
@@ -46,7 +46,7 @@ namespace WallpaperEngine::Core
 
         CScene (
 				CProject& project,
-                CContainer& container,
+                CContainer* container,
                 Scenes::CCamera* camera,
                 glm::vec3 ambientColor,
                 CUserSettingBoolean* bloom,
@@ -71,9 +71,9 @@ namespace WallpaperEngine::Core
 
         void insertObject (CObject* object);
 
-        CContainer& getContainer ();
+        CContainer* getContainer ();
     private:
-        CContainer& m_container;
+        CContainer* m_container;
         Scenes::CCamera* m_camera;
 
         // data from general section on the json

+ 2 - 2
src/WallpaperEngine/Core/Objects/CEffect.cpp

@@ -36,7 +36,7 @@ CEffect::CEffect (
 {
 }
 
-CEffect* CEffect::fromJSON (json data, CUserSettingBoolean* visible, Core::CObject* object, const CContainer& container)
+CEffect* CEffect::fromJSON (json data, CUserSettingBoolean* visible, Core::CObject* object, CContainer* container)
 {
     auto file_it = jsonFindRequired (data, "file", "Object effect must have a file");
     auto effectpasses_it = data.find ("passes");
@@ -202,7 +202,7 @@ void CEffect::dependencyFromJSON (json::const_iterator dependencies_it, CEffect*
         effect->insertDependency (cur);
 }
 
-void CEffect::materialsFromJSON (json::const_iterator passes_it, CEffect* effect, const CContainer& container)
+void CEffect::materialsFromJSON (json::const_iterator passes_it, CEffect* effect, CContainer* container)
 {
     for (const auto& cur : (*passes_it))
     {

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

@@ -35,7 +35,7 @@ namespace WallpaperEngine::Core::Objects
             CUserSettingBoolean* visible
         );
 
-        static CEffect* fromJSON (json data, CUserSettingBoolean* visible, Core::CObject* object, const CContainer& container);
+        static CEffect* fromJSON (json data, CUserSettingBoolean* visible, Core::CObject* object, CContainer* container);
 
         const std::vector<std::string>& getDependencies () const;
         const std::vector<Images::CMaterial*>& getMaterials () const;
@@ -48,7 +48,7 @@ namespace WallpaperEngine::Core::Objects
         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, const CContainer& container);
+        static void materialsFromJSON (json::const_iterator passes_it, CEffect* effect, CContainer* container);
 
         void insertDependency (const std::string& dep);
         void insertMaterial (Images::CMaterial* material);

+ 1 - 1
src/WallpaperEngine/Core/Objects/CImage.cpp

@@ -44,7 +44,7 @@ CImage::CImage (
 WallpaperEngine::Core::CObject* CImage::fromJSON (
     CScene* scene,
     json data,
-    const CContainer& container,
+    CContainer* container,
     CUserSettingBoolean* visible,
     uint32_t id,
     std::string name,

+ 1 - 1
src/WallpaperEngine/Core/Objects/CImage.h

@@ -29,7 +29,7 @@ namespace WallpaperEngine::Core::Objects
         static CObject* fromJSON (
             CScene* scene,
             json data,
-            const CContainer& container,
+            CContainer* container,
             CUserSettingBoolean* visible,
             uint32_t id,
             std::string name,

+ 1 - 3
src/WallpaperEngine/Core/Objects/CParticle.cpp

@@ -8,7 +8,7 @@ using namespace WallpaperEngine::Core::Objects;
 CParticle* CParticle::fromFile (
     CScene* scene,
     const std::string& filename,
-    const CContainer& container,
+    CContainer* container,
     CUserSettingBoolean* visible,
     uint32_t id,
     std::string name,
@@ -34,10 +34,8 @@ CParticle* CParticle::fromFile (
     );
 
     if (controlpoint_it != data.end ())
-    {
         for (const auto& cur : (*controlpoint_it))
             particle->insertControlPoint (Particles::CControlPoint::fromJSON (cur));
-    }
 
     for (const auto& cur : (*emitter_it))
         particle->insertEmitter (Particles::CEmitter::fromJSON (cur));

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

@@ -19,7 +19,7 @@ namespace WallpaperEngine::Core::Objects
         static CParticle* fromFile (
                 CScene* scene,
                 const std::string& filename,
-                const CContainer& container,
+                CContainer* container,
                 CUserSettingBoolean* visible,
                 uint32_t id,
                 std::string name,

+ 2 - 2
src/WallpaperEngine/Core/Objects/Images/CMaterial.cpp

@@ -16,13 +16,13 @@ CMaterial::CMaterial (std::string  name) :
 {
 }
 
-CMaterial* CMaterial::fromFile (const std::string& filename, const CContainer& container)
+CMaterial* CMaterial::fromFile (const std::string& filename, CContainer* container)
 {
     return fromJSON (
         filename, json::parse (WallpaperEngine::FileSystem::loadFullFile (filename, container))
     );
 }
-CMaterial* CMaterial::fromFile (const std::string& filename, const std::string& target, const CContainer& container)
+CMaterial* CMaterial::fromFile (const std::string& filename, const std::string& target, CContainer* container)
 {
     return fromJSON (
         filename, json::parse (WallpaperEngine::FileSystem::loadFullFile (filename, container)), target

+ 2 - 2
src/WallpaperEngine/Core/Objects/Images/CMaterial.h

@@ -14,9 +14,9 @@ namespace WallpaperEngine::Core::Objects::Images
     class CMaterial
     {
     public:
-        static CMaterial* fromFile (const std::string& filename, const CContainer& container);
+        static CMaterial* fromFile (const std::string& filename, CContainer* container);
         static CMaterial* fromJSON (const std::string& name, json data);
-        static CMaterial* fromFile (const std::string& filename, const std::string& target, const CContainer& container);
+        static CMaterial* fromFile (const std::string& filename, const std::string& target, CContainer* container);
         static CMaterial* fromJSON (const std::string& name, json data, const std::string& target);
 
         void insertPass (Materials::CPass* mass);

+ 2 - 2
src/WallpaperEngine/FileSystem/FileSystem.cpp

@@ -5,10 +5,10 @@
 
 using namespace WallpaperEngine;
 
-std::string FileSystem::loadFullFile (const std::string& file, const WallpaperEngine::Assets::CContainer& containers)
+std::string FileSystem::loadFullFile (const std::string& file, WallpaperEngine::Assets::CContainer* containers)
 {
     uint32_t length = 0;
-    const void* contents = containers.readFile (file, &length);
+    const void* contents = containers->readFile (file, &length);
 
     // build a new buffer that can fit in the string
     char* filedata = new char [length + 1];

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

@@ -17,5 +17,5 @@ namespace WallpaperEngine::FileSystem
      * @param file
      * @return
      */
-    std::string loadFullFile (const std::string& file, const WallpaperEngine::Assets::CContainer& containers);
+    std::string loadFullFile (const std::string& file, WallpaperEngine::Assets::CContainer* containers);
 }

+ 1 - 0
src/WallpaperEngine/Render/CFBO.h

@@ -12,6 +12,7 @@ namespace WallpaperEngine::Render
     {
     public:
         CFBO (std::string name, ITexture::TextureFormat format, ITexture::TextureFlags flags, float scale, uint32_t realWidth, uint32_t realHeight, uint32_t textureWidth, uint32_t textureHeight);
+		// TODO: ADD DESTRUCTOR TO FREE RESOURCES
 
         const std::string& getName () const;
         const float& getScale () const;

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

@@ -20,7 +20,7 @@ CScene* CObject::getScene () const
     return this->m_scene;
 }
 
-const CContainer& CObject::getContainer () const
+CContainer* CObject::getContainer () const
 {
     return this->getScene ()->getContainer ();
 }

+ 1 - 1
src/WallpaperEngine/Render/CObject.h

@@ -21,7 +21,7 @@ namespace WallpaperEngine::Render
         virtual void render () = 0;
 
         CScene* getScene () const;
-        const CContainer& getContainer () const;
+        CContainer* getContainer () const;
         int getId () const;
 
     protected:

+ 39 - 229
src/WallpaperEngine/Render/CRenderContext.cpp

@@ -12,190 +12,39 @@
 #include "CRenderContext.h"
 #include "CVideo.h"
 
-#define DEFAULT_WINDOW_WIDTH 1280
-#define DEFAULT_WINDOW_HEIGHT 720
-
 using namespace WallpaperEngine::Render;
 
-XErrorHandler originalErrorHandler;
-
-void CustomXIOErrorExitHandler (Display* dsp, void* userdata)
-{
-    auto context = static_cast <CRenderContext*> (userdata);
-
-#if !NDEBUG
-    sLog.debugerror ("Critical XServer error detected. Attempting to recover...");
-#endif /* DEBUG */
-
-    // refetch all the resources
-    context->initialize ();
-}
-
-int CustomXErrorHandler (Display* dpy, XErrorEvent* event)
-{
-#if !NDEBUG
-    sLog.debugerror ("Detected X error");
-#endif /* DEBUG */
-
-    // call the original handler so we can keep some information reporting
-    originalErrorHandler (dpy, event);
-
-    return 0;
-}
-
-int CustomXIOErrorHandler (Display* dsp)
-{
-#if !NDEBUG
-    sLog.debugerror ("Detected X error");
-#endif /* DEBUG */
-
-    return 0;
-}
-
-CRenderContext::CRenderContext (std::vector <std::string> screens, CVideoDriver& driver, CInputContext& input, CContainer& container, CWallpaperApplication& app) :
-    m_wallpaper (nullptr),
-    m_screens (std::move (screens)),
-    m_driver (driver),
-    m_container (container),
-    m_app (app),
-    m_input (input),
-    m_textureCache (new CTextureCache (*this)),
-	m_display (nullptr),
-	m_pixmap (0),
-	m_gc (nullptr),
-	m_image (nullptr),
-	m_imageData (nullptr),
-	m_fbo (nullptr)
-{
-    this->initialize ();
-}
-
-void CRenderContext::initialize ()
-{
-    if (this->m_screens.empty ())
-        this->setupWindow ();
-    else
-        this->setupScreens ();
-}
-
-void CRenderContext::setupWindow ()
-{
-    this->m_driver.showWindow ();
-    this->m_driver.resizeWindow ({DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT});
-}
-
-void CRenderContext::setupScreens ()
-{
-    this->m_viewports.clear ();
-
-    this->m_display = XOpenDisplay (nullptr);
-
-    // set the error handling to try and recover from X disconnections
-#ifdef HAVE_XSETIOERROREXITHANDLER
-    XSetIOErrorExitHandler (this->m_display, CustomXIOErrorExitHandler, this);
-#endif /* HAVE_XSETIOERROREXITHANDLER */
-    originalErrorHandler = XSetErrorHandler (CustomXErrorHandler);
-    XSetIOErrorHandler (CustomXIOErrorHandler);
-
-    int xrandr_result, xrandr_error;
-
-    if (!XRRQueryExtension (this->m_display, &xrandr_result, &xrandr_error))
-    {
-        sLog.error ("XRandr is not present, cannot detect specified screens, running in window mode");
-        return;
-    }
-
-    Window root = DefaultRootWindow (this->m_display);
-    int fullWidth = DisplayWidth (this->m_display, DefaultScreen (this->m_display));
-    int fullHeight = DisplayHeight (this->m_display, DefaultScreen (this->m_display));
-    XRRScreenResources* screenResources = XRRGetScreenResources (this->m_display, DefaultRootWindow (this->m_display));
-
-    // there are some situations where xrandr returns null (like screen not using the extension)
-    if (screenResources == nullptr)
-        return;
-
-    // create the pixmap and gc used for this display, most situations only have one "display"
-    this->m_pixmap = XCreatePixmap (this->m_display, DefaultRootWindow (this->m_display), fullWidth, fullHeight, 24);
-    this->m_gc = XCreateGC (this->m_display, this->m_pixmap, 0, nullptr);
-    // fill the whole pixmap with black for now
-    XFillRectangle (this->m_display, this->m_pixmap, this->m_gc, 0, 0, fullWidth, fullHeight);
-
-    for (int i = 0; i < screenResources->noutput; i ++)
-    {
-        XRROutputInfo* info = XRRGetOutputInfo (this->m_display, screenResources, screenResources->outputs [i]);
-
-        // there are some situations where xrandr returns null (like screen not using the extension)
-        if (info == nullptr || info->connection != RR_Connected)
-            continue;
-
-        for (const auto& cur : this->m_screens)
-        {
-            if (strcmp (info->name, cur.c_str ()) != 0)
-                continue;
-
-            XRRCrtcInfo* crtc = XRRGetCrtcInfo (this->m_display, screenResources, info->crtc);
-
-            sLog.out ("Found requested screen: ", info->name, " -> ", crtc->x, "x", crtc->y, ":", crtc->width, "x", crtc->height);
-
-            this->m_viewports.push_back ({{crtc->x, crtc->y, crtc->width, crtc->height}, cur});
-
-            XRRFreeCrtcInfo (crtc);
-        }
-
-        XRRFreeOutputInfo (info);
-    }
-
-    XRRFreeScreenResources (screenResources);
-
-    // create the fbo that will handle the screen
-    this->m_fbo = new CFBO(
-        "_sc_FullFrameBuffer",
-        ITexture::TextureFormat::ARGB8888,
-        ITexture::TextureFlags::NoFlags,
-        1.0,
-        fullWidth, fullHeight,
-        fullWidth, fullHeight
-    );
-
-    // set the window background so the pixmap is drawn
-    XSetWindowBackgroundPixmap(this->m_display, root, this->m_pixmap);
-
-    this->m_imageData = new char [fullWidth * fullHeight * 4];
-
-    // create the image for X11 to be able to copy it over
-    this->m_image = XCreateImage (this->m_display, CopyFromParent, 24, ZPixmap, 0, this->m_imageData, fullWidth, fullHeight, 32, 0);
-}
-
-CRenderContext::~CRenderContext ()
+CRenderContext::CRenderContext (const COutput* output, CVideoDriver& driver, CInputContext& input, CWallpaperApplication& app) :
+	m_defaultWallpaper (nullptr),
+	m_output (output),
+	m_driver (driver),
+	m_app (app),
+	m_input (input),
+	m_textureCache (new CTextureCache (*this))
 {
-    if (!this->m_screens.empty ())
-    {
-        // free any used resource
-        XDestroyImage (this->m_image);
-        XFreeGC (this->m_display, this->m_gc);
-        XFreePixmap (this->m_display, this->m_pixmap);
-        XCloseDisplay (this->m_display);
-    }
 }
 
-void CRenderContext::renderScreens ()
+void CRenderContext::render ()
 {
-    bool firstFrame = true;
-    bool renderFrame = true;
-    int fullWidth = DisplayWidth (this->m_display, DefaultScreen (this->m_display));
-    int fullHeight = DisplayHeight (this->m_display, DefaultScreen (this->m_display));
-    Window root = DefaultRootWindow (this->m_display);
+	bool firstFrame = true;
+	bool renderFrame = true;
 
-    for (const auto& cur : this->m_viewports)
+    for (const auto& cur : this->m_output->getViewports ())
     {
 #if !NDEBUG
-		std::string str = "Rendering to screen " + cur.name;
+		std::string str = "Rendering to output " + cur.first;
 
 		glPushDebugGroup (GL_DEBUG_SOURCE_APPLICATION, 0, -1, str.c_str ());
 #endif /* DEBUG */
 
-        // render the background
-        this->m_wallpaper->render (cur.viewport, false, renderFrame, firstFrame);
+		// search the background in the viewport selection
+		auto ref = this->m_wallpapers.find (cur.first);
+
+		// render the background
+		if (ref != this->m_wallpapers.end ())
+			ref->second->render (cur.second.viewport, this->m_output->renderVFlip (), renderFrame, firstFrame);
+		else
+			this->m_defaultWallpaper->render (cur.second.viewport, this->m_output->renderVFlip (), renderFrame, firstFrame);
         // scenes need to render a new frame for each viewport as they produce different results
         // but videos should only be rendered once per group of viewports
         firstFrame = false;
@@ -205,61 +54,27 @@ void CRenderContext::renderScreens ()
     }
 
     // read the full texture into the image
-    glReadPixels (0, 0, fullWidth, fullHeight, GL_BGRA, GL_UNSIGNED_BYTE, (void*) this->m_imageData);
-
-    // put the image back into the screen
-    XPutImage (this->m_display, this->m_pixmap, this->m_gc, this->m_image, 0, 0, 0, 0, fullWidth, fullHeight);
-
-    // _XROOTPMAP_ID & ESETROOT_PMAP_ID allow other programs (compositors) to
-    // edit the background. Without these, other programs will clear the screen.
-    // it also forces the compositor to refresh the background (tested with picom)
-    Atom prop_root = XInternAtom(this->m_display, "_XROOTPMAP_ID", False);
-    Atom prop_esetroot = XInternAtom(this->m_display, "ESETROOT_PMAP_ID", False);
-    XChangeProperty(this->m_display, root, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &this->m_pixmap, 1);
-    XChangeProperty(this->m_display, root, prop_esetroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &this->m_pixmap, 1);
-
-    XClearWindow(this->m_display, root);
-    XFlush(this->m_display);
+	if (this->m_output->haveImageBuffer ())
+		glReadPixels (
+			0, 0, this->m_output->getFullWidth (), this->m_output->getFullHeight (),
+			GL_BGRA, GL_UNSIGNED_BYTE,
+			this->m_output->getImageBuffer ()
+		);
+
+	// update the output with the given image
+	this->m_output->updateRender ();
+	// finally swap buffers
+    this->m_driver.swapBuffers ();
 }
 
-void CRenderContext::renderWindow ()
+void CRenderContext::setDefaultWallpaper (CWallpaper* wallpaper)
 {
-    // render the background to the window directly
-    this->m_wallpaper->render ({0, 0, this->m_driver.getFramebufferSize ()}, true);
+	this->m_defaultWallpaper = wallpaper;
 }
 
-void CRenderContext::render ()
+void CRenderContext::setWallpaper (const std::string& display, CWallpaper* wallpaper)
 {
-    if (this->m_wallpaper == nullptr)
-        return;
-
-	if (this->m_viewports.empty ())
-		this->renderWindow ();
-	else
-		this->renderScreens ();
-
-    this->m_driver.swapBuffers ();
-}
-
-void CRenderContext::setWallpaper (CWallpaper* wallpaper)
-{
-    this->m_wallpaper = wallpaper;
-
-    // update the wallpaper's texcoords based on the mode we're running
-    if (!this->m_screens.empty ())
-    {
-        GLfloat texCoords [] = {
-            0.0f, 1.0f,
-            1.0f, 1.0f,
-            0.0f, 0.0f,
-            0.0f, 0.0f,
-            1.0f, 1.0f,
-            1.0f, 0.0f
-        };
-
-        this->m_wallpaper->updateTexCoord (texCoords, sizeof (texCoords));
-        this->m_wallpaper->setDestinationFramebuffer (this->m_fbo->getFramebuffer ());
-    }
+	this->m_wallpapers.insert_or_assign (display, wallpaper);
 }
 
 CInputContext& CRenderContext::getInputContext () const
@@ -267,19 +82,14 @@ CInputContext& CRenderContext::getInputContext () const
     return this->m_input;
 }
 
-CWallpaper* CRenderContext::getWallpaper () const
-{
-    return this->m_wallpaper;
-}
-
-const CContainer& CRenderContext::getContainer () const
+const CWallpaperApplication& CRenderContext::getApp () const
 {
-    return this->m_container;
+    return this->m_app;
 }
 
-const CWallpaperApplication& CRenderContext::getApp () const
+const COutput* CRenderContext::getOutput () const
 {
-    return this->m_app;
+	return this->m_output;
 }
 
 const ITexture* CRenderContext::resolveTexture (const std::string& name)

+ 14 - 29
src/WallpaperEngine/Render/CRenderContext.h

@@ -9,12 +9,19 @@
 #include "WallpaperEngine/Input/CInputContext.h"
 #include "WallpaperEngine/Input/CMouseInput.h"
 #include "WallpaperEngine/Render/Drivers/CVideoDriver.h"
+#include "WallpaperEngine/Render/Drivers/Output/COutput.h"
 #include <X11/Xlib.h>
 
 using namespace WallpaperEngine::Application;
 using namespace WallpaperEngine::Assets;
 using namespace WallpaperEngine::Input;
 using namespace WallpaperEngine::Render::Drivers;
+using namespace WallpaperEngine::Render::Drivers::Output;
+
+namespace WallpaperEngine::Render::Drivers::Output
+{
+	class COutput;
+}
 
 namespace WallpaperEngine::Render::Drivers
 {
@@ -34,45 +41,23 @@ namespace WallpaperEngine::Render
     class CRenderContext
     {
     public:
-        CRenderContext (std::vector <std::string> screens, CVideoDriver& driver, CInputContext& input, CContainer& container, CWallpaperApplication& app);
-        ~CRenderContext ();
+        CRenderContext (const COutput* output, CVideoDriver& driver, CInputContext& input, CWallpaperApplication& app);
 
-        void initialize ();
         void render ();
-        void setWallpaper (CWallpaper* wallpaper);
+		void setDefaultWallpaper (CWallpaper* wallpaper);
+		void setWallpaper (const std::string& display, CWallpaper* wallpaper);
         CInputContext& getInputContext () const;
-        void setMouse (CMouseInput* mouse);
-        CWallpaper* getWallpaper () const;
-        const CContainer& getContainer () const;
         const CWallpaperApplication& getApp () const;
+		const COutput* getOutput () const;
         const ITexture* resolveTexture (const std::string& name);
 
     private:
-        void setupScreens ();
-        void setupWindow ();
-
-        void renderScreens ();
-        void renderWindow ();
-
-        struct viewport
-        {
-            glm::ivec4 viewport;
-            std::string name;
-        };
-
-        Display* m_display;
-        Pixmap m_pixmap;
-        GC m_gc;
-        XImage* m_image;
         CVideoDriver& m_driver;
-        char* m_imageData;
-        CFBO* m_fbo;
-        std::vector <std::string> m_screens;
-        std::vector <viewport> m_viewports;
-        CWallpaper* m_wallpaper;
+		std::map <std::string, CWallpaper*> m_wallpapers;
+        CWallpaper* m_defaultWallpaper;
         CInputContext& m_input;
-        CContainer& m_container;
         CWallpaperApplication& m_app;
         CTextureCache* m_textureCache;
+		const COutput* m_output;
     };
 }

+ 21 - 3
src/WallpaperEngine/Render/CTextureCache.cpp

@@ -1,6 +1,9 @@
 #include "CTextureCache.h"
 
+#include "WallpaperEngine/Assets/CAssetLoadException.h"
+
 using namespace WallpaperEngine::Render;
+using namespace WallpaperEngine::Assets;
 
 CTextureCache::CTextureCache (CRenderContext& context) :
     m_context (context)
@@ -17,11 +20,26 @@ const ITexture* CTextureCache::resolve (const std::string& filename)
     if (found != this->m_textureCache.end ())
         return (*found).second;
 
-    const ITexture* texture = this->m_context.getContainer ().readTexture (filename);
+	// search for the texture in all the different containers just in case
+	for (auto it : this->m_context.getApp ().getProjects ())
+	{
+		const ITexture* texture = it.second->getContainer ()->readTexture (filename);
+
+		this->store (filename, texture);
+
+		return texture;
+	}
+
+	if (this->m_context.getApp ().getDefaultProject () != nullptr)
+	{
+		const ITexture* texture = this->m_context.getApp ().getDefaultProject ()->getContainer ()->readTexture (filename);
+
+		this->store (filename, texture);
 
-    this->store (filename, texture);
+		return texture;
+	}
 
-    return texture;
+	throw CAssetLoadException (filename, "Cannot find file");
 }
 
 void CTextureCache::store (std::string name, const ITexture* texture)

+ 4 - 1
src/WallpaperEngine/Render/CVideo.cpp

@@ -54,8 +54,11 @@ CVideo::CVideo (Core::CVideo* video, CRenderContext& context, CAudioContext& aud
     if (mpv_render_context_create (&this->m_mpvGl, this->m_mpv, params) < 0)
         sLog.exception ("Failed to initialize MPV's GL context");
 
+	std::filesystem::path videopath = this->getVideo ()->getProject ().getContainer ()->resolveRealFile (this->getVideo ()->getFilename ());
+
+	// build the path to the video file
     const char* command [] = {
-        "loadfile", this->getVideo ()->getFilename ().c_str (), nullptr
+        "loadfile", videopath.c_str (), nullptr
     };
 
     if (mpv_command (this->m_mpv, command) < 0)

+ 2 - 2
src/WallpaperEngine/Render/CWallpaper.cpp

@@ -61,9 +61,9 @@ CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRend
 CWallpaper::~CWallpaper ()
 = default;
 
-const CContainer& CWallpaper::getContainer () const
+CContainer* CWallpaper::getContainer () const
 {
-    return this->m_context.getContainer ();
+    return this->m_wallpaperData->getProject ().getContainer ();
 }
 
 WallpaperEngine::Core::CWallpaper* CWallpaper::getWallpaperData () const

+ 1 - 1
src/WallpaperEngine/Render/CWallpaper.h

@@ -38,7 +38,7 @@ namespace WallpaperEngine::Render
         /**
          * @return The container to resolve files for this wallpaper
          */
-        const CContainer& getContainer () const;
+        CContainer* getContainer () const;
 
         /**
          * @return The current context rendering this wallpaper

+ 6 - 0
src/WallpaperEngine/Render/Drivers/COpenGLDriver.cpp

@@ -62,6 +62,12 @@ void COpenGLDriver::resizeWindow (glm::ivec2 size)
     glfwSetWindowSize (this->m_window, size.x, size.y);
 }
 
+void COpenGLDriver::resizeWindow (glm::ivec4 sizeandpos)
+{
+	glfwSetWindowPos (this->m_window, sizeandpos.x, sizeandpos.y);
+    glfwSetWindowSize (this->m_window, sizeandpos.z, sizeandpos.w);
+}
+
 void COpenGLDriver::showWindow ()
 {
     glfwShowWindow (this->m_window);

+ 10 - 0
src/WallpaperEngine/Render/Drivers/COpenGLDriver.h

@@ -3,9 +3,17 @@
 #include <GL/glew.h>
 #include <GLFW/glfw3.h>
 #include "WallpaperEngine/Render/Drivers/CVideoDriver.h"
+#include "WallpaperEngine/Application/CApplicationContext.h"
+
+namespace WallpaperEngine::Application
+{
+	class CApplicationContext;
+}
 
 namespace WallpaperEngine::Render::Drivers
 {
+	using namespace WallpaperEngine::Application;
+
     class COpenGLDriver : public CVideoDriver
     {
     public:
@@ -15,6 +23,7 @@ namespace WallpaperEngine::Render::Drivers
         float getRenderTime () override;
         bool closeRequested () override;
         void resizeWindow (glm::ivec2 size) override;
+		void resizeWindow (glm::ivec4 sizeandpos) override;
         void showWindow () override;
         void hideWindow () override;
         glm::ivec2 getFramebufferSize () override;
@@ -22,6 +31,7 @@ namespace WallpaperEngine::Render::Drivers
         uint32_t getFrameCounter () override;
 
         GLFWwindow* getWindow ();
+
     private:
         GLFWwindow* m_window;
         uint32_t m_frameCounter;

+ 2 - 0
src/WallpaperEngine/Render/Drivers/CVideoDriver.h

@@ -1,5 +1,6 @@
 #pragma once
 
+#include <glm/vec4.hpp>
 #include <glm/vec2.hpp>
 
 namespace WallpaperEngine::Render::Drivers
@@ -10,6 +11,7 @@ namespace WallpaperEngine::Render::Drivers
         virtual float getRenderTime () = 0;
         virtual bool closeRequested () = 0;
         virtual void resizeWindow (glm::ivec2 size) = 0;
+		virtual void resizeWindow (glm::ivec4 size) = 0;
         virtual void showWindow () = 0;
         virtual void hideWindow () = 0;
         virtual glm::ivec2 getFramebufferSize () = 0;

+ 23 - 0
src/WallpaperEngine/Render/Drivers/Output/COutput.cpp

@@ -0,0 +1,23 @@
+#include "COutput.h"
+
+using namespace WallpaperEngine::Render::Drivers::Output;
+
+COutput::COutput (CApplicationContext& context) :
+	m_context (context)
+{
+}
+
+const std::map <std::string, COutput::ScreenInfo>& COutput::getViewports () const
+{
+	return this->m_viewports;
+}
+
+int COutput::getFullWidth () const
+{
+	return this->m_fullWidth;
+}
+
+int COutput::getFullHeight () const
+{
+	return this->m_fullHeight;
+}

+ 47 - 0
src/WallpaperEngine/Render/Drivers/Output/COutput.h

@@ -0,0 +1,47 @@
+#pragma once
+
+#include <map>
+#include <string>
+#include <glm/vec4.hpp>
+
+#include "WallpaperEngine/Application/CApplicationContext.h"
+
+using namespace WallpaperEngine::Application;
+
+namespace WallpaperEngine::Application
+{
+	class CApplicationContext;
+}
+
+namespace WallpaperEngine::Render::Drivers::Output
+{
+	class COutput
+	{
+	public:
+		COutput (CApplicationContext& context);
+
+		virtual void reset () = 0;
+
+		int getFullWidth () const;
+		int getFullHeight () const;
+
+		struct ScreenInfo
+		{
+			glm::ivec4 viewport;
+			std::string name;
+		};
+
+		virtual bool renderVFlip () const = 0;
+		virtual bool renderMultiple () const = 0;
+		virtual bool haveImageBuffer () const = 0;
+		const std::map <std::string, ScreenInfo>& getViewports () const;
+		virtual void* getImageBuffer () const = 0;
+		virtual void updateRender () const = 0;
+
+	protected:
+		mutable int m_fullWidth;
+		mutable int m_fullHeight;
+		mutable std::map <std::string, ScreenInfo> m_viewports;
+		CApplicationContext& m_context;
+	};
+}

+ 77 - 0
src/WallpaperEngine/Render/Drivers/Output/CWindowOutput.cpp

@@ -0,0 +1,77 @@
+#include "CWindowOutput.h"
+#include "WallpaperEngine/Logging/CLog.h"
+
+using namespace WallpaperEngine::Render::Drivers::Output;
+
+CWindowOutput::CWindowOutput (CApplicationContext& context, CVideoDriver& driver) :
+	COutput (context),
+	m_driver (driver)
+{
+	if (
+		this->m_context.windowMode != Application::CApplicationContext::NORMAL_WINDOW &&
+		this->m_context.windowMode != Application::CApplicationContext::EXPLICIT_WINDOW)
+		sLog.exception ("Inititalizing window output when not in output mode, how did you get here?!");
+
+	// window should be visible
+	driver.showWindow ();
+
+	if (this->m_context.windowMode == Application::CApplicationContext::EXPLICIT_WINDOW)
+	{
+		this->m_fullWidth = this->m_context.windowGeometry.z;
+		this->m_fullHeight = this->m_context.windowGeometry.w;
+		this->repositionWindow ();
+	}
+	else
+	{
+		// take the size from the driver (default window size)
+		this->m_fullWidth = this->m_driver.getFramebufferSize ().x;
+		this->m_fullHeight = this->m_driver.getFramebufferSize ().y;
+	}
+
+	// register the default viewport
+	this->m_viewports ["default"] = {{0, 0, this->m_fullWidth, this->m_fullHeight}, "default"};
+}
+
+void CWindowOutput::repositionWindow ()
+{
+	// reposition the window
+	this->m_driver.resizeWindow (this->m_context.windowGeometry);
+}
+
+void CWindowOutput::reset ()
+{
+	if (this->m_context.windowMode == Application::CApplicationContext::EXPLICIT_WINDOW)
+		this->repositionWindow ();
+}
+
+bool CWindowOutput::renderVFlip () const
+{
+	return true;
+}
+
+bool CWindowOutput::renderMultiple () const
+{
+	return false;
+}
+
+bool CWindowOutput::haveImageBuffer () const
+{
+	return false;
+}
+
+void* CWindowOutput::getImageBuffer () const
+{
+	return nullptr;
+}
+void CWindowOutput::updateRender () const
+{
+	if (this->m_context.windowMode != Application::CApplicationContext::NORMAL_WINDOW)
+		return;
+
+	// take the size from the driver (default window size)
+	this->m_fullWidth = this->m_driver.getFramebufferSize ().x;
+	this->m_fullHeight = this->m_driver.getFramebufferSize ().y;
+
+	// update the default viewport
+	this->m_viewports ["default"] = {{0, 0, this->m_fullWidth, this->m_fullHeight}, "default"};
+}

+ 25 - 0
src/WallpaperEngine/Render/Drivers/Output/CWindowOutput.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "WallpaperEngine/Render/Drivers/CVideoDriver.h"
+#include "COutput.h"
+
+namespace WallpaperEngine::Render::Drivers::Output
+{
+	class CWindowOutput : public COutput
+	{
+	public:
+		CWindowOutput (CApplicationContext& context, CVideoDriver& driver);
+
+		void reset () override;
+		bool renderVFlip () const override;
+		bool renderMultiple () const override;
+		bool haveImageBuffer () const override;
+		void* getImageBuffer () const override;
+		void updateRender () const override;
+
+	private:
+		void repositionWindow ();
+
+		CVideoDriver& m_driver;
+	};
+}

+ 183 - 0
src/WallpaperEngine/Render/Drivers/Output/CX11Output.cpp

@@ -0,0 +1,183 @@
+#include "common.h"
+#include "CX11Output.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
+
+using namespace WallpaperEngine::Render::Drivers::Output;
+
+XErrorHandler originalErrorHandler;
+
+void CustomXIOErrorExitHandler (Display* dsp, void* userdata)
+{
+    auto context = static_cast <CX11Output*> (userdata);
+
+#if !NDEBUG
+    sLog.debugerror ("Critical XServer error detected. Attempting to recover...");
+#endif /* DEBUG */
+
+    // refetch all the resources
+    context->reset ();
+}
+
+int CustomXErrorHandler (Display* dpy, XErrorEvent* event)
+{
+#if !NDEBUG
+    sLog.debugerror ("Detected X error");
+#endif /* DEBUG */
+
+    // call the original handler so we can keep some information reporting
+    originalErrorHandler (dpy, event);
+
+    return 0;
+}
+
+int CustomXIOErrorHandler (Display* dsp)
+{
+#if !NDEBUG
+    sLog.debugerror ("Detected X error");
+#endif /* DEBUG */
+
+    return 0;
+}
+
+CX11Output::CX11Output (CApplicationContext& context, CVideoDriver& driver) :
+	COutput (context),
+	m_driver (driver)
+{
+	this->m_display = XOpenDisplay (nullptr);
+	this->loadScreenInfo ();
+}
+CX11Output::~CX11Output ()
+{
+	this->free ();
+	XCloseDisplay (this->m_display);
+}
+
+void CX11Output::reset ()
+{
+	// first free whatever we have right now
+	this->free ();
+	// re-load screen info
+	this->loadScreenInfo ();
+}
+
+void CX11Output::free ()
+{
+	// free all the resources we've got
+	XDestroyImage (this->m_image);
+	XFreeGC (this->m_display, this->m_gc);
+	XFreePixmap (this->m_display, this->m_pixmap);
+	delete this->m_imageData;
+}
+
+void* CX11Output::getImageBuffer () const
+{
+	return this->m_imageData;
+}
+
+bool CX11Output::renderVFlip () const
+{
+	return false;
+}
+
+bool CX11Output::renderMultiple () const
+{
+	return this->m_viewports.size () > 1;
+}
+
+bool CX11Output::haveImageBuffer () const
+{
+	return true;
+}
+
+void CX11Output::loadScreenInfo ()
+{
+	// reset the viewports
+	this->m_viewports.clear ();
+
+    // set the error handling to try and recover from X disconnections
+#ifdef HAVE_XSETIOERROREXITHANDLER
+    XSetIOErrorExitHandler (this->m_display, CustomXIOErrorExitHandler, this);
+#endif /* HAVE_XSETIOERROREXITHANDLER */
+    originalErrorHandler = XSetErrorHandler (CustomXErrorHandler);
+    XSetIOErrorHandler (CustomXIOErrorHandler);
+
+	int xrandr_result, xrandr_error;
+
+	if (!XRRQueryExtension (this->m_display, &xrandr_result, &xrandr_error))
+	{
+		sLog.error ("XRandr is not present, cannot detect specified screens, running in window mode");
+		return;
+	}
+
+	this->m_root = DefaultRootWindow (this->m_display);
+	this->m_fullWidth = DisplayWidth (this->m_display, DefaultScreen (this->m_display));
+	this->m_fullHeight = DisplayHeight (this->m_display, DefaultScreen (this->m_display));
+	XRRScreenResources* screenResources = XRRGetScreenResources (this->m_display, DefaultRootWindow (this->m_display));
+
+	if (screenResources == nullptr)
+	{
+		sLog.error ("Cannot detect screen sizes using xrandr, running in window mode");
+		return;
+	}
+
+	for (int i = 0; i < screenResources->noutput; i ++)
+	{
+		XRROutputInfo* info = XRRGetOutputInfo (this->m_display, screenResources, screenResources->outputs [i]);
+
+		// screen not in use, ignore it
+		if (info == nullptr || info->connection != RR_Connected)
+			continue;
+
+		// only keep info of registered screens
+		if (this->m_context.screenSettings.find (info->name) == this->m_context.screenSettings.end ())
+			continue;
+
+		XRRCrtcInfo* crtc = XRRGetCrtcInfo (this->m_display, screenResources, info->crtc);
+
+		sLog.out ("Found requested screen: ", info->name, " -> ", crtc->x, "x", crtc->y, ":", crtc->width, "x", crtc->height);
+
+		this->m_viewports [info->name] =
+		{
+			{crtc->x, crtc->y, crtc->width, crtc->height},
+			info->name
+		};
+
+		XRRFreeCrtcInfo (crtc);
+	}
+
+	XRRFreeScreenResources (screenResources);
+
+	// create pixmap so we can draw things in there
+	this->m_pixmap = XCreatePixmap (this->m_display, this->m_root, this->m_fullWidth, this->m_fullHeight, 24);
+	this->m_gc = XCreateGC (this->m_display, this->m_pixmap, 0, nullptr);
+	// pre-fill it with black
+	XFillRectangle (this->m_display, this->m_pixmap, this->m_gc, 0, 0, this->m_fullWidth, this->m_fullHeight);
+	// set the window background as our pixmap
+	XSetWindowBackgroundPixmap (this->m_display, this->m_root, this->m_pixmap);
+	// allocate space for the image's data
+	this->m_imageData = new char [this->m_fullWidth * this->m_fullHeight * 4];
+	// create an image so we can copy it over
+	this->m_image = XCreateImage (this->m_display, CopyFromParent, 24, ZPixmap, 0, this->m_imageData, this->m_fullWidth, this->m_fullHeight, 32, 0);
+	// setup driver's render changing the window's size
+	this->m_driver.resizeWindow ({this->m_fullWidth, this->m_fullHeight});
+}
+
+void CX11Output::updateRender () const
+{
+    // put the image back into the screen
+    XPutImage (this->m_display, this->m_pixmap, this->m_gc, this->m_image, 0, 0, 0, 0, this->m_fullWidth, this->m_fullHeight);
+
+    // _XROOTPMAP_ID & ESETROOT_PMAP_ID allow other programs (compositors) to
+    // edit the background. Without these, other programs will clear the screen.
+    // it also forces the compositor to refresh the background (tested with picom)
+    Atom prop_root = XInternAtom(this->m_display, "_XROOTPMAP_ID", False);
+    Atom prop_esetroot = XInternAtom(this->m_display, "ESETROOT_PMAP_ID", False);
+    XChangeProperty(this->m_display, this->m_root, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &this->m_pixmap, 1);
+    XChangeProperty(this->m_display, this->m_root, prop_esetroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &this->m_pixmap, 1);
+
+    XClearWindow(this->m_display, this->m_root);
+    XFlush(this->m_display);
+}

+ 40 - 0
src/WallpaperEngine/Render/Drivers/Output/CX11Output.h

@@ -0,0 +1,40 @@
+#pragma once
+
+#include <map>
+#include <string>
+#include <glm/vec4.hpp>
+
+#include <X11/Xlib.h>
+
+#include "WallpaperEngine/Render/Drivers/CVideoDriver.h"
+#include "COutput.h"
+
+namespace WallpaperEngine::Render::Drivers::Output
+{
+	class CX11Output : public COutput
+	{
+	public:
+		CX11Output (CApplicationContext& context, CVideoDriver& driver);
+		~CX11Output ();
+
+		void reset () override;
+
+		bool renderVFlip () const override;
+		bool renderMultiple () const override;
+		bool haveImageBuffer () const override;
+		void* getImageBuffer () const override;
+		void updateRender () const override;
+
+	private:
+		void loadScreenInfo ();
+		void free ();
+
+		Display* m_display;
+		Pixmap m_pixmap;
+		Window m_root;
+		GC m_gc;
+		char* m_imageData;
+		XImage* m_image;
+		CVideoDriver& m_driver;
+	};
+}

+ 5 - 2
src/WallpaperEngine/Render/Objects/CSound.cpp

@@ -2,13 +2,16 @@
 
 #include "CSound.h"
 
+extern bool g_AudioEnabled;
+
 using namespace WallpaperEngine::Render::Objects;
 
 CSound::CSound (CScene* scene, Core::Objects::CSound* sound) :
     CObject (scene, Type, sound),
     m_sound (sound)
 {
-    this->load ();
+	if (g_AudioEnabled)
+	    this->load ();
 }
 
 void CSound::load ()
@@ -16,7 +19,7 @@ void CSound::load ()
     for (const auto& cur : this->m_sound->getSounds ())
     {
         uint32_t filesize = 0;
-        const void* filebuffer = this->getContainer ().readFile (cur, &filesize);
+        const void* filebuffer = this->getContainer ()->readFile (cur, &filesize);
 
         auto stream = new Audio::CAudioStream (this->getScene ()->getAudioContext (), filebuffer, filesize);
 

+ 5 - 5
src/WallpaperEngine/Render/Shaders/Compiler.cpp

@@ -29,7 +29,7 @@ using namespace WallpaperEngine::Assets;
 namespace WallpaperEngine::Render::Shaders
 {
     Compiler::Compiler (
-            const CContainer& container,
+            CContainer* container,
             std::string filename,
             Type type,
             std::map <std::string, int>* combos,
@@ -50,11 +50,11 @@ namespace WallpaperEngine::Render::Shaders
         m_baseCombos ()
     {
         if (type == Type_Vertex)
-            this->m_content = this->m_container.readVertexShader (this->m_file);
+            this->m_content = this->m_container->readVertexShader (this->m_file);
         else if (type == Type_Pixel)
-            this->m_content = this->m_container.readFragmentShader (this->m_file);
+            this->m_content = this->m_container->readFragmentShader (this->m_file);
         else if (type == Type_Include)
-            this->m_content = this->m_container.readIncludeShader (this->m_file);
+            this->m_content = this->m_container->readIncludeShader (this->m_file);
 
         // clone the combos into the baseCombos to keep track of values that must be embedded no matter what
         for (const auto& cur : *this->m_combos)
@@ -650,7 +650,7 @@ namespace WallpaperEngine::Render::Shaders
 		file += ".json";
 
 		std::string tmp = file;
-		std::string patchContents = this->m_container.readFileAsString (file);
+		std::string patchContents = this->m_container->readFileAsString (file);
 
 		json data = json::parse (patchContents);
 		auto patches = data.find ("patches");

+ 2 - 2
src/WallpaperEngine/Render/Shaders/Compiler.h

@@ -51,7 +51,7 @@ namespace WallpaperEngine::Render::Shaders
          * @param recursive Whether the compiler should add base definitions or not
          */
         Compiler (
-            const CContainer& container,
+            CContainer* container,
             std::string filename,
             Type type,
             std::map<std::string, int>* combos,
@@ -264,7 +264,7 @@ namespace WallpaperEngine::Render::Shaders
          /**
           * The container to load files from
           */
-         const CContainer& m_container;
+         CContainer* m_container;
          /**
           * List of textures that the shader expects (inferred from sampler2D and it's JSON data)
           */