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>
This commit is contained in:
Alexis Maiquez 2023-03-21 07:07:36 +01:00
parent e2d80a074c
commit b69ce8ba57
49 changed files with 787 additions and 377 deletions

View File

@ -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

View File

@ -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");

View File

@ -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);

View File

@ -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);
}
CProject* CWallpaperApplication::loadProject (const std::string& bg)
{
CCombinedContainer* container = new CCombinedContainer ();
this->setupContainer (*container, bg);
// TODO: Change this to pointer instead of reference
return CProject::fromFile ("project.json", container);
}
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 ()
{
// 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 ());
for (const auto& it : this->m_projects)
this->setupPropertiesForProject (it.second);
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 ());
}
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;
}

View File

@ -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;
};
}

View File

@ -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)

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

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

View File

@ -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 ();

View File

@ -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; }

View File

@ -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;
}

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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

View File

@ -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))
{

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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));

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

@ -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];

View File

@ -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);
}

View File

@ -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;

View File

@ -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 ();
}

View File

@ -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:

View File

@ -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)
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))
{
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)
void CRenderContext::render ()
{
#if !NDEBUG
sLog.debugerror ("Detected X error");
#endif /* DEBUG */
bool firstFrame = true;
bool renderFrame = true;
// 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 ()
{
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 ()
{
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);
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);
}
void CRenderContext::renderWindow ()
{
// render the background to the window directly
this->m_wallpaper->render ({0, 0, this->m_driver.getFramebufferSize ()}, true);
}
void CRenderContext::render ()
{
if (this->m_wallpaper == nullptr)
return;
if (this->m_viewports.empty ())
this->renderWindow ();
else
this->renderScreens ();
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::setWallpaper (CWallpaper* wallpaper)
void CRenderContext::setDefaultWallpaper (CWallpaper* wallpaper)
{
this->m_wallpaper = wallpaper;
this->m_defaultWallpaper = 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 ());
}
void CRenderContext::setWallpaper (const std::string& display, CWallpaper* wallpaper)
{
this->m_wallpapers.insert_or_assign (display, wallpaper);
}
CInputContext& CRenderContext::getInputContext () const
@ -267,21 +82,16 @@ CInputContext& CRenderContext::getInputContext () const
return this->m_input;
}
CWallpaper* CRenderContext::getWallpaper () const
{
return this->m_wallpaper;
}
const CContainer& CRenderContext::getContainer () const
{
return this->m_container;
}
const CWallpaperApplication& CRenderContext::getApp () const
{
return this->m_app;
}
const COutput* CRenderContext::getOutput () const
{
return this->m_output;
}
const ITexture* CRenderContext::resolveTexture (const std::string& name)
{
return this->m_textureCache->resolve (name);

View File

@ -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;
};
}

View File

@ -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);
this->store (filename, texture);
return 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);
return texture;
}
throw CAssetLoadException (filename, "Cannot find file");
}
void CTextureCache::store (std::string name, const ITexture* texture)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
};
}

View File

@ -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"};
}

View File

@ -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;
};
}

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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);

View File

@ -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");

View File

@ -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)
*/