| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- #include "CWallpaperApplication.h"
- #include "Steam/FileSystem/FileSystem.h"
- #include "WallpaperEngine/Application/CApplicationState.h"
- #include "WallpaperEngine/Assets/CAssetLoadException.h"
- #include "WallpaperEngine/Assets/CDirectory.h"
- #include "WallpaperEngine/Assets/CVirtualContainer.h"
- #include "WallpaperEngine/Audio/Drivers/Detectors/CPulseAudioPlayingDetector.h"
- #include "WallpaperEngine/Core/Wallpapers/CVideo.h"
- #include "WallpaperEngine/Input/Drivers/CGLFWMouseInput.h"
- #include "WallpaperEngine/Logging/CLog.h"
- #include "WallpaperEngine/Render/CRenderContext.h"
- #include "WallpaperEngine/Input/Drivers/CWaylandMouseInput.h"
- #include "WallpaperEngine/Render/Drivers/CWaylandOpenGLDriver.h"
- #include "WallpaperEngine/Render/Drivers/Detectors/CX11FullScreenDetector.h"
- #include <unistd.h>
- #define FULLSCREEN_CHECK_WAIT_TIME 250
- float g_Time;
- float g_TimeLast;
- float g_Daytime;
- namespace WallpaperEngine::Application {
- CWallpaperApplication::CWallpaperApplication (CApplicationContext& context,
- WallpaperEngine::WebBrowser::CWebBrowserContext& browserContext) :
- m_context (context),
- m_browserContext (browserContext) {
- this->loadBackgrounds ();
- this->setupProperties ();
- }
- CWallpaperApplication::~CWallpaperApplication () {
- delete m_renderContext;
- delete m_videoDriver;
- delete m_audioContext;
- delete m_audioDriver;
- delete m_inputContext;
- }
- void CWallpaperApplication::setupContainer (CCombinedContainer& container, const std::string& bg) const {
- const std::filesystem::path basepath = bg;
- container.add (new CDirectory (basepath));
- container.addPkg (basepath / "scene.pkg");
- container.addPkg (basepath / "gifscene.pkg");
- try {
- container.add (new CDirectory (this->m_context.settings.general.assets));
- } catch (CAssetLoadException&) {
- sLog.exception("Cannot find a valid assets folder, resolved to ", this->m_context.settings.general.assets);
- }
- // add two possible patches directories to the container
- // hopefully one sticks
- bool relative = true;
- bool absolute = true;
- try {
- container.add (new CDirectory ("../share/"));
- } catch (CAssetLoadException&) {
- relative = false;
- }
- try {
- container.add (new CDirectory (DATADIR));
- } catch (CAssetLoadException&) {
- absolute = false;
- }
- if (!relative && !absolute)
- sLog.error ("WARNING: Shader patches directory cannot be found, this might make some backgrounds not work "
- "properly");
- // TODO: move this somewhere else?
- auto* virtualContainer = new CVirtualContainer ();
- //
- // Had to get a little creative with the effects to achieve the same bloom effect without any custom code
- // these virtual files are loaded by an image in the scene that takes current _rt_FullFrameBuffer and
- // applies the bloom effect to render it out to the screen
- //
- // add the effect file for screen bloom
- // add some model for the image element even if it's going to waste rendering cycles
- virtualContainer->add ("effects/wpenginelinux/bloomeffect.json",
- "{"
- "\t\"name\":\"camerabloom_wpengine_linux\","
- "\t\"group\":\"wpengine_linux_camera\","
- "\t\"dependencies\":[],"
- "\t\"passes\":"
- "\t["
- "\t\t{"
- "\t\t\t\"material\": \"materials/util/downsample_quarter_bloom.json\","
- "\t\t\t\"target\": \"_rt_4FrameBuffer\","
- "\t\t\t\"bind\":"
- "\t\t\t["
- "\t\t\t\t{"
- "\t\t\t\t\t\"name\": \"_rt_FullFrameBuffer\","
- "\t\t\t\t\t\"index\": 0"
- "\t\t\t\t}"
- "\t\t\t]"
- "\t\t},"
- "\t\t{"
- "\t\t\t\"material\": \"materials/util/downsample_eighth_blur_v.json\","
- "\t\t\t\"target\": \"_rt_8FrameBuffer\","
- "\t\t\t\"bind\":"
- "\t\t\t["
- "\t\t\t\t{"
- "\t\t\t\t\t\"name\": \"_rt_4FrameBuffer\","
- "\t\t\t\t\t\"index\": 0"
- "\t\t\t\t}"
- "\t\t\t]"
- "\t\t},"
- "\t\t{"
- "\t\t\t\"material\": \"materials/util/blur_h_bloom.json\","
- "\t\t\t\"target\": \"_rt_Bloom\","
- "\t\t\t\"bind\":"
- "\t\t\t["
- "\t\t\t\t{"
- "\t\t\t\t\t\"name\": \"_rt_8FrameBuffer\","
- "\t\t\t\t\t\"index\": 0"
- "\t\t\t\t}"
- "\t\t\t]"
- "\t\t},"
- "\t\t{"
- "\t\t\t\"material\": \"materials/util/combine.json\","
- "\t\t\t\"target\": \"_rt_FullFrameBuffer\","
- "\t\t\t\"bind\":"
- "\t\t\t["
- "\t\t\t\t{"
- "\t\t\t\t\t\"name\": \"_rt_imageLayerComposite_-1_a\","
- "\t\t\t\t\t\"index\": 0"
- "\t\t\t\t},"
- "\t\t\t\t{"
- "\t\t\t\t\t\"name\": \"_rt_Bloom\","
- "\t\t\t\t\t\"index\": 1"
- "\t\t\t\t}"
- "\t\t\t]"
- "\t\t}"
- "\t]"
- "}");
- virtualContainer->add ("models/wpenginelinux.json", "{"
- "\t\"material\":\"materials/wpenginelinux.json\""
- "}");
- // models require materials, so add that too
- virtualContainer->add ("materials/wpenginelinux.json", "{"
- "\t\"passes\":"
- "\t\t["
- "\t\t\t{"
- "\t\t\t\t\"blending\": \"normal\","
- "\t\t\t\t\"cullmode\": \"nocull\","
- "\t\t\t\t\"depthtest\": \"disabled\","
- "\t\t\t\t\"depthwrite\": \"disabled\","
- "\t\t\t\t\"shader\": \"genericimage2\","
- "\t\t\t\t\"textures\": [\"_rt_FullFrameBuffer\"]"
- "\t\t\t}"
- "\t\t]"
- "}");
- container.add (virtualContainer);
- }
- void CWallpaperApplication::loadBackgrounds () {
- if (this->m_context.settings.render.mode == CApplicationContext::NORMAL_WINDOW || this->m_context.settings.render.mode == CApplicationContext::EXPLICIT_WINDOW) {
- this->m_backgrounds ["default"] = this->loadBackground(this->m_context.settings.general.defaultBackground);
- return;
- }
- for (const auto& [screen, path] : this->m_context.settings.general.screenBackgrounds) {
- // screens with no screen should use the default
- if (path.empty ()) {
- this->m_backgrounds [screen] = this->loadBackground (this->m_context.settings.general.defaultBackground);
- } else {
- this->m_backgrounds [screen] = this->loadBackground (path);
- }
- }
- }
- Core::CProject* CWallpaperApplication::loadBackground (const std::string& bg) {
- auto* container = new CCombinedContainer ();
- this->setupContainer (*container, bg);
- return Core::CProject::fromFile ("project.json", container);
- }
- void CWallpaperApplication::setupPropertiesForProject (const Core::CProject* project) {
- // show properties if required
- for (const auto cur : project->getProperties ()) {
- // update the value of the property
- auto override = this->m_context.settings.general.properties.find (cur->getName ());
- if (override != this->m_context.settings.general.properties.end ()) {
- sLog.out ("Applying override value for ", cur->getName ());
- cur->update (override->second);
- }
- if (this->m_context.settings.general.onlyListProperties)
- sLog.out (cur->dump ());
- }
- }
- void CWallpaperApplication::setupProperties () {
- for (const auto& [backgrounc, info] : this->m_backgrounds)
- this->setupPropertiesForProject (info);
- }
- void CWallpaperApplication::takeScreenshot (const std::filesystem::path& filename, FREE_IMAGE_FORMAT format) {
- // this should be getting called at the end of the frame, so the right thing should be bound already
- const int width = this->m_renderContext->getOutput ().getFullWidth ();
- const int height = this->m_renderContext->getOutput ().getFullHeight ();
- // build the output file with FreeImage
- static FIBITMAP* bitmap = FreeImage_Allocate (width, height, 24);
- RGBQUAD color;
- int xoffset = 0;
- for (const auto& [screen, viewport] : this->m_renderContext->getOutput ().getViewports ()) {
- // activate opengl context so we can read from the framebuffer
- viewport->makeCurrent ();
- // make room for storing the pixel of this viewport
- auto* buffer = new uint8_t [viewport->viewport.z * viewport->viewport.w * sizeof (uint8_t) * 3];
- const uint8_t* pixel = buffer;
- // read the viewport data into the pixel buffer
- glReadPixels (viewport->viewport.x, viewport->viewport.y, viewport->viewport.z, viewport->viewport.w, GL_RGB,
- GL_UNSIGNED_BYTE, buffer);
- // now get access to the pixels
- for (int y = viewport->viewport.w; y > 0; y--) {
- for (int x = 0; x < viewport->viewport.z; x++) {
- color.rgbRed = *pixel++;
- color.rgbGreen = *pixel++;
- color.rgbBlue = *pixel++;
- // set the pixel in the destination
- FreeImage_SetPixelColor (bitmap, x + xoffset,
- this->m_renderContext->getOutput ().renderVFlip () ? (viewport->viewport.w - y) : y, &color);
- }
- }
- if (viewport->single)
- xoffset += viewport->viewport.z;
- // free the buffer allocated for the viewport
- delete [] buffer;
- }
- // finally save the file
- FreeImage_Save (format, bitmap, filename.c_str (), 0);
- FreeImage_Unload (bitmap);
- }
- void CWallpaperApplication::show () {
- const char* XDG_SESSION_TYPE = getenv ("XDG_SESSION_TYPE");
- if (!XDG_SESSION_TYPE) {
- sLog.exception (
- "Cannot read environment variable XDG_SESSION_TYPE, window server detection failed. Please ensure proper values are set");
- }
- sLog.debug("Checking for window servers: ");
- #ifdef ENABLE_WAYLAND
- sLog.debug("\twayland");
- #endif // ENABLE_WAYLAND
- #ifdef ENABLE_X11
- sLog.debug("\tx11");
- #endif // ENABLE_X11
- #ifdef ENABLE_WAYLAND
- bool isWayland = strncmp ("wayland", XDG_SESSION_TYPE, strlen ("wayland")) == 0;
- #endif // ENABLE_WAYLAND
- #ifdef ENABLE_X11
- bool isX11 = strncmp ("x11", XDG_SESSION_TYPE, strlen ("x11")) == 0;
- #endif // ENABLE_X11
- if (this->m_context.settings.render.mode == CApplicationContext::DESKTOP_BACKGROUND) {
- #ifdef ENABLE_WAYLAND
- if (isWayland) {
- m_videoDriver = new WallpaperEngine::Render::Drivers::CWaylandOpenGLDriver (this->m_context, *this);
- m_inputContext =
- new WallpaperEngine::Input::CInputContext (new WallpaperEngine::Input::Drivers::CWaylandMouseInput (
- reinterpret_cast<WallpaperEngine::Render::Drivers::CWaylandOpenGLDriver*> (m_videoDriver)));
- this->m_fullScreenDetector =
- new WallpaperEngine::Render::Drivers::Detectors::CWaylandFullScreenDetector (this->m_context);
- }
- #endif // ENABLE_WAYLAND
- #ifdef ENABLE_X11
- #ifdef ENABLE_WAYLAND
- else
- #endif // ENABLE_WAYLAND
- if (isX11) {
- m_videoDriver =
- new WallpaperEngine::Render::Drivers::CGLFWOpenGLDriver ("wallpaperengine", this->m_context, *this);
- m_inputContext =
- new WallpaperEngine::Input::CInputContext (new WallpaperEngine::Input::Drivers::CGLFWMouseInput (
- reinterpret_cast<Render::Drivers::CGLFWOpenGLDriver*> (m_videoDriver)));
- this->m_fullScreenDetector = new WallpaperEngine::Render::Drivers::Detectors::CX11FullScreenDetector (
- this->m_context, *reinterpret_cast<Render::Drivers::CGLFWOpenGLDriver*> (m_videoDriver));
- }
- #endif // ENABLE_X11
- #ifdef ENABLE_X11
- else
- #endif // ENABLE_X11
- {
- sLog.exception (
- "Cannot run in background mode, window server could not be detected. XDG_SESSION_TYPE must be wayland or x11");
- }
- } else {
- m_videoDriver =
- new WallpaperEngine::Render::Drivers::CGLFWOpenGLDriver ("wallpaperengine", this->m_context, *this);
- #ifdef ENABLE_WAYLAND
- if (isWayland) {
- this->m_fullScreenDetector =
- new WallpaperEngine::Render::Drivers::Detectors::CWaylandFullScreenDetector (this->m_context);
- }
- #endif // ENABLE_WAYLAND
- #ifdef ENABLE_X11
- #ifdef ENABLE_WAYLAND
- else
- #endif // ENABLE_WAYLAND
- if (isX11) {
- this->m_fullScreenDetector = new WallpaperEngine::Render::Drivers::Detectors::CX11FullScreenDetector (
- this->m_context, *reinterpret_cast<Render::Drivers::CGLFWOpenGLDriver*> (m_videoDriver));
- }
- #endif // ENABLE_X11
- else {
- this->m_fullScreenDetector =
- new WallpaperEngine::Render::Drivers::Detectors::CFullScreenDetector (this->m_context);
- }
- m_inputContext = new WallpaperEngine::Input::CInputContext (new WallpaperEngine::Input::Drivers::CGLFWMouseInput (
- reinterpret_cast<Render::Drivers::CGLFWOpenGLDriver*> (m_videoDriver)));
- }
- if (this->m_context.settings.audio.audioprocessing) {
- this->m_audioRecorder = new WallpaperEngine::Audio::Drivers::Recorders::CPulseAudioPlaybackRecorder ();
- } else {
- this->m_audioRecorder = new WallpaperEngine::Audio::Drivers::Recorders::CPlaybackRecorder ();
- }
- // audio playing detector
- WallpaperEngine::Audio::Drivers::Detectors::CPulseAudioPlayingDetector audioDetector (this->m_context,
- *this->m_fullScreenDetector);
- // initialize sdl audio driver
- m_audioDriver =
- new WallpaperEngine::Audio::Drivers::CSDLAudioDriver (this->m_context, audioDetector, *this->m_audioRecorder);
- // initialize audio context
- m_audioContext = new WallpaperEngine::Audio::CAudioContext (*m_audioDriver);
- // initialize render context
- m_renderContext = new WallpaperEngine::Render::CRenderContext (*m_videoDriver, *m_inputContext, *this);
- // create a new background for each screen
- // set all the specific wallpapers required
- for (const auto& [background, info] : this->m_backgrounds) {
- m_renderContext->setWallpaper (background, WallpaperEngine::Render::CWallpaper::fromWallpaper (
- info->getWallpaper (), *m_renderContext, *m_audioContext, m_browserContext,
- this->m_context.settings.general.screenScalings [background]));
- }
- // wallpapers are setup, free browsesr context if possible
- if (!this->m_browserContext.isUsed ()) {
- this->m_browserContext.stop ();
- }
- static time_t seconds;
- static struct tm* timeinfo;
- while (this->m_context.state.general.keepRunning && !m_videoDriver->closeRequested ()) {
- // update g_Daytime
- time (&seconds);
- timeinfo = localtime (&seconds);
- g_Daytime = ((timeinfo->tm_hour * 60) + timeinfo->tm_min) / (24.0 * 60.0);
- // keep track of the previous frame's time
- g_TimeLast = g_Time;
- // calculate the current time value
- g_Time = m_videoDriver->getRenderTime ();
- // update audio recorder
- m_audioDriver->update ();
- // update input information
- m_inputContext->update ();
- // process driver events
- m_videoDriver->dispatchEventQueue ();
- if (!this->m_context.settings.screenshot.take || m_videoDriver->getFrameCounter () < 5)
- continue;
- this->takeScreenshot (this->m_context.settings.screenshot.path,
- this->m_context.settings.screenshot.format);
- this->m_context.settings.screenshot.take = false;
- }
- // ensure this is updated as sometimes it might not come from a signal
- this->m_context.state.general.keepRunning = false;
- sLog.out ("Stop requested");
- SDL_Quit ();
- }
- void CWallpaperApplication::update (Render::Drivers::Output::COutputViewport* viewport) {
- // check for fullscreen windows and wait until there's none fullscreen
- while (this->m_fullScreenDetector->anythingFullscreen () && this->m_context.state.general.keepRunning)
- usleep (FULLSCREEN_CHECK_WAIT_TIME);
- // render the scene
- m_renderContext->render (viewport);
- }
- void CWallpaperApplication::signal (int signal) {
- this->m_context.state.general.keepRunning = false;
- }
- const std::map<std::string, Core::CProject*>& CWallpaperApplication::getBackgrounds () const {
- return this->m_backgrounds;
- }
- CApplicationContext& CWallpaperApplication::getContext () const {
- return this->m_context;
- }
- const WallpaperEngine::Render::Drivers::Output::COutput& CWallpaperApplication::getOutput () const {
- return this->m_renderContext->getOutput ();
- }
- } // namespace WallpaperEngine::Application
|