Compare commits

..

4 Commits

Author SHA1 Message Date
Almamu
73f716da84 refactor: new project parser 2025-08-12 03:36:44 +02:00
Almamu
be0fc25e72 chore: better error reporting for parameters, highlighting --help usage. fixess #303 and should improve #275
Some checks failed
CMake / build-x11 (ubuntu-22.04) (push) Has been cancelled
CMake / build-x11 (ubuntu-24.04) (push) Has been cancelled
CMake / build-x11-wayland (ubuntu-22.04) (push) Has been cancelled
CMake / build-x11-wayland (ubuntu-24.04) (push) Has been cancelled
CMake / build-wayland (ubuntu-22.04) (push) Has been cancelled
CMake / build-wayland (ubuntu-24.04) (push) Has been cancelled
2025-05-17 03:23:05 +02:00
Almamu
3c334aac29 chore: better error reporting after fix for #300
Some checks failed
CMake / build-x11 (ubuntu-22.04) (push) Has been cancelled
CMake / build-x11 (ubuntu-24.04) (push) Has been cancelled
CMake / build-x11-wayland (ubuntu-22.04) (push) Has been cancelled
CMake / build-x11-wayland (ubuntu-24.04) (push) Has been cancelled
CMake / build-wayland (ubuntu-22.04) (push) Has been cancelled
CMake / build-wayland (ubuntu-24.04) (push) Has been cancelled
2025-05-15 22:28:23 +02:00
Almamu
555b488951 fix: make background id optional so usages of -b, --bg do not require a fallback background (as expected) fixes #300 2025-05-15 22:20:20 +02:00
19 changed files with 501 additions and 164 deletions

View File

@ -1,31 +0,0 @@
---
name: Background doesn't load properly
about: Use this to report backgrounds that are not loading (cannot find files, black
image, effects not working, etc)
title: "[BGFIX]"
labels: bug
assignees: Almamu
---
**Wallpaper Engine Background(s)**
Link(s) to the background(s) in the steam workshop or their background ID(s).
**Console output**
When a background cannot be loaded, it's usually due to some unexpected error that is logged into the terminal. Please attach the program's output so we can properly debug it if needed.
**Screenshots**
If you have any screenshot of it working on Windows that'll help so we can compare both outputs
**Desktop (please complete the following information):**
- OS: [e.g. Arch Linux]
- Desktop Environment: [e.g. GNOME, CINNAMON, KDE...]
- Window Manager: [if in doubt, just leave it empty]
**Additional context**
Any additional information about your setup

58
.github/ISSUE_TEMPLATE/bug-report.yml vendored Normal file
View File

@ -0,0 +1,58 @@
name: "Bug Report"
description: "Report a bug or unexpected behavior."
labels: [bug]
body:
- type: markdown
attributes:
value: |
Please fill out this form to report a bug.
- type: input
id: summary
attributes:
label: Bug Summary
description: Briefly describe the bug.
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to Reproduce
description: Step-by-step instructions to reproduce the bug.
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
validations:
required: false
- type: textarea
id: actual
attributes:
label: Actual Behavior / Logs
validations:
required: false
- type: input
id: os
attributes:
label: Operating System and Version
validations:
required: true
- type: input
id: de
attributes:
label: Desktop Environment (GNOME, KDE, etc.)
validations:
required: true
- type: input
id: x11_wayland
attributes:
label: Display Server (X11/Wayland)
validations:
required: true
- type: textarea
id: extra
attributes:
label: Additional Context or Screenshots
validations:
required: false

View File

@ -0,0 +1,46 @@
name: "Wallpaper Compatibility Issue"
description: "Report a problem with a specific Wallpaper Engine wallpaper."
labels: [compatibility, wallpaper]
body:
- type: input
id: wallpaper
attributes:
label: Wallpaper Name, URL or ID
validations:
required: true
- type: textarea
id: issue
attributes:
label: Describe the Issue
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
validations:
required: false
- type: textarea
id: logs
attributes:
label: Logs or Crash Output
validations:
required: false
- type: input
id: os
attributes:
label: Operating System and Version
validations:
required: true
- type: input
id: de
attributes:
label: Desktop Environment (GNOME, KDE, etc.)
validations:
required: true
- type: input
id: x11_wayland
attributes:
label: Display Server (X11/Wayland)
validations:
required: true

View File

@ -0,0 +1,32 @@
name: "Feature Request"
description: "Propose a new feature or enhancement."
labels: [enhancement]
body:
- type: markdown
attributes:
value: |
Use this form to suggest new features or improvements.
- type: textarea
id: feature
attributes:
label: Describe the Feature
validations:
required: true
- type: textarea
id: problem
attributes:
label: Problem this Feature Addresses (if any)
validations:
required: false
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
validations:
required: false
- type: textarea
id: context
attributes:
label: Additional Context or Mockups
validations:
required: false

View File

@ -0,0 +1,38 @@
name: "Installation/Usage Help"
description: "Request help with installing or using linux-wallpaperengine."
labels: [question, support]
body:
- type: markdown
attributes:
value: |
Need help? Fill this out so we can assist you better.
- type: textarea
id: issue
attributes:
label: What are you trying to do, and what's the problem?
validations:
required: true
- type: textarea
id: attempted
attributes:
label: What have you tried so far?
validations:
required: false
- type: textarea
id: error_logs
attributes:
label: Errors or Log Output
validations:
required: false
- type: input
id: system
attributes:
label: OS, Desktop Environment, X11/Wayland
validations:
required: true
- type: input
id: install_method
attributes:
label: Installation Method (e.g., AUR, Flatpak, build from source)
validations:
required: true

View File

@ -1,10 +0,0 @@
---
name: Other issues
about: Use this to report general issues with the software
title: ''
labels: ''
assignees: Almamu
---

22
.github/ISSUE_TEMPLATE/refactor.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: "Code Cleanup / Refactor"
description: "Suggest internal improvements like refactoring or technical debt cleanup."
labels: [refactor, maintenance]
body:
- type: textarea
id: what
attributes:
label: What needs improvement?
validations:
required: true
- type: textarea
id: why
attributes:
label: Why is this necessary or beneficial?
validations:
required: false
- type: textarea
id: impact
attributes:
label: Potential Impact on Users
validations:
required: false

View File

@ -26,8 +26,11 @@ CApplicationContext::CApplicationContext (int argc, char* argv []) :
backgroundGroup.add_argument ("background id") backgroundGroup.add_argument ("background id")
.help ("The background to use as default for screens with no background specified") .help ("The background to use as default for screens with no background specified")
.default_value ("")
.action([this](const std::string& value) -> void { .action([this](const std::string& value) -> void {
this->settings.general.defaultBackground = translateBackground (value); if (!value.empty()) {
this->settings.general.defaultBackground = translateBackground (value);
}
}); });
backgroundMode.add_argument ("-w", "--window") backgroundMode.add_argument ("-w", "--window")
@ -252,40 +255,48 @@ CApplicationContext::CApplicationContext (int argc, char* argv []) :
" Runs the background 2317494988 on two screens, one on HDMI-1 and the other on HDMI-2\n\n" " Runs the background 2317494988 on two screens, one on HDMI-1 and the other on HDMI-2\n\n"
); );
program.parse_known_args (argc, argv); try {
program.parse_known_args (argc, argv);
this->settings.audio.volume = std::max(0, std::min (this->settings.audio.volume, 128)); if (this->settings.general.defaultBackground.empty ()) {
this->settings.screenshot.delay = std::max (0, std::min (this->settings.screenshot.delay, 5)); throw std::runtime_error ("At least one background ID must be specified");
}
// use std::cout on this in case logging is disabled, this way it's easy to look at what is running this->settings.audio.volume = std::max(0, std::min (this->settings.audio.volume, 128));
std::stringbuf buffer; this->settings.screenshot.delay = std::max (0, std::min (this->settings.screenshot.delay, 5));
std::ostream bufferStream (&buffer);
bufferStream << "Running with: "; // use std::cout on this in case logging is disabled, this way it's easy to look at what is running
std::stringbuf buffer;
std::ostream bufferStream (&buffer);
for (int i = 0; i < argc; i ++) { bufferStream << "Running with: ";
bufferStream << argv [i];
bufferStream << " ";
}
std::cout << buffer.str() << std::endl; for (int i = 0; i < argc; i ++) {
// perform some extra validation on the inputs bufferStream << argv [i];
this->validateAssets (); bufferStream << " ";
this->validateScreenshot (); }
// setup application state std::cout << buffer.str() << std::endl;
this->state.general.keepRunning = true; // perform some extra validation on the inputs
this->state.audio.enabled = this->settings.audio.enabled; this->validateAssets ();
this->state.audio.volume = this->settings.audio.volume; this->validateScreenshot ();
this->state.mouse.enabled = this->settings.mouse.enabled;
// setup application state
this->state.general.keepRunning = true;
this->state.audio.enabled = this->settings.audio.enabled;
this->state.audio.volume = this->settings.audio.volume;
this->state.mouse.enabled = this->settings.mouse.enabled;
#if DEMOMODE #if DEMOMODE
sLog.error ("WARNING: RUNNING IN DEMO MODE WILL STOP WALLPAPERS AFTER 5 SECONDS SO VIDEO CAN BE RECORDED"); sLog.error ("WARNING: RUNNING IN DEMO MODE WILL STOP WALLPAPERS AFTER 5 SECONDS SO VIDEO CAN BE RECORDED");
// special settings for demomode // special settings for demomode
this->settings.render.maximumFPS = 30; this->settings.render.maximumFPS = 30;
this->settings.screenshot.take = false; this->settings.screenshot.take = false;
this->settings.render.pauseOnFullscreen = false; this->settings.render.pauseOnFullscreen = false;
#endif /* DEMOMODE */ #endif /* DEMOMODE */
} catch (const std::runtime_error& e) {
throw std::runtime_error (std::string (e.what()) + ". Use " + std::string (argv[0]) + " --help for more information");
}
} }
int CApplicationContext::getArgc () const { int CApplicationContext::getArgc () const {

View File

@ -40,18 +40,18 @@ CWallpaperApplication::CWallpaperApplication (CApplicationContext& context) :
void CWallpaperApplication::setupContainer (const std::shared_ptr<CCombinedContainer>& container, const std::string& bg) const { void CWallpaperApplication::setupContainer (const std::shared_ptr<CCombinedContainer>& container, const std::string& bg) const {
const std::filesystem::path basepath = bg; const std::filesystem::path basepath = bg;
container->add (std::make_shared<CDirectory> (basepath)); container->add (std::make_unique<CDirectory> (basepath));
container->addPkg (basepath / "scene.pkg"); container->addPkg (basepath / "scene.pkg");
container->addPkg (basepath / "gifscene.pkg"); container->addPkg (basepath / "gifscene.pkg");
try { try {
container->add (std::make_shared <CDirectory> (this->m_context.settings.general.assets)); container->add (std::make_unique <CDirectory> (this->m_context.settings.general.assets));
} catch (CAssetLoadException&) { } catch (CAssetLoadException&) {
sLog.exception ("Cannot find a valid assets folder, resolved to ", this->m_context.settings.general.assets); sLog.exception ("Cannot find a valid assets folder, resolved to ", this->m_context.settings.general.assets);
} }
// TODO: move this somewhere else? // TODO: move this somewhere else?
auto virtualContainer = std::make_shared <CVirtualContainer> (); auto virtualContainer = std::make_unique <CVirtualContainer> ();
// //
// Had to get a little creative with the effects to achieve the same bloom effect without any custom code // Had to get a little creative with the effects to achieve the same bloom effect without any custom code
@ -184,7 +184,7 @@ void CWallpaperApplication::setupContainer (const std::shared_ptr<CCombinedConta
"}" "}"
); );
container->add (virtualContainer); container->add (std::move(virtualContainer));
} }
void CWallpaperApplication::loadBackgrounds () { void CWallpaperApplication::loadBackgrounds () {

View File

@ -8,14 +8,14 @@ using namespace WallpaperEngine::Assets;
CCombinedContainer::CCombinedContainer () : CContainer () {} CCombinedContainer::CCombinedContainer () : CContainer () {}
void CCombinedContainer::add (const std::shared_ptr<CContainer>& container) { void CCombinedContainer::add (std::unique_ptr<CContainer> container) {
this->m_containers.emplace_back (container); this->m_containers.emplace_back (std::move(container));
} }
void CCombinedContainer::addPkg (const std::filesystem::path& path) { void CCombinedContainer::addPkg (const std::filesystem::path& path) {
try { try {
// add the package to the list // add the package to the list
this->add (std::make_shared<CPackage> (path)); this->add (std::make_unique<CPackage> (path));
sLog.out ("Detected ", path.filename (), " file at ", path, ". Adding to list of searchable paths"); sLog.out ("Detected ", path.filename (), " file at ", path, ". Adding to list of searchable paths");
} catch (CPackageLoadException&) { } catch (CPackageLoadException&) {
// ignore this error, the package file was not found // ignore this error, the package file was not found

View File

@ -19,7 +19,7 @@ class CCombinedContainer final : public CContainer {
* *
* @param container * @param container
*/ */
void add (const std::shared_ptr<CContainer>& container); void add (std::unique_ptr<CContainer> container);
/** /**
* Adds the given package to the list * Adds the given package to the list
* *
@ -32,6 +32,6 @@ class CCombinedContainer final : public CContainer {
private: private:
/** The list of containers to search files off from */ /** The list of containers to search files off from */
std::vector<std::shared_ptr<CContainer>> m_containers {}; std::vector<std::unique_ptr<CContainer>> m_containers {};
}; };
}; // namespace WallpaperEngine::Assets }; // namespace WallpaperEngine::Assets

View File

@ -31,35 +31,75 @@ void StringPrinter::printWallpaper (const Wallpaper& wallpaper) {
this->m_out << "Scene wallpaper: "; this->m_out << "Scene wallpaper: ";
this->increaseIndentation (); this->increaseIndentation ();
this->lineEnd ();
// TODO: IMPLEMENT FBO PRINTING, AS THIS WASN'T REALLY REFLECTION HOW IT ACTUALLY WORKS // TODO: IMPLEMENT FBO PRINTING, AS THIS WASN'T REALLY REFLECTION HOW IT ACTUALLY WORKS
this->m_out << "Objects count: " << scene->objects.size (); this->m_out << "Objects count: " << scene->objects.size ();
this->increaseIndentation (); this->increaseIndentation ();
for (const auto& object : scene->objects) { for (const auto& object : scene->objects) {
if (object.second->is <Image> ()) { this->lineEnd ();
this->printImage (*object.second->as <Image> ()); this->printObject (*object.second);
} this->lineEnd ();
} }
this->decreaseIndentation ();
} }
} }
void StringPrinter::printImage (const Image& image) { void StringPrinter::printObject (const Object& object) {
this->m_out << "Image " << image.id << " " << image.name << ":"; this->m_out << "Object " << object.id << " " << object.name << ":";
this->increaseIndentation (); this->increaseIndentation ();
this->lineEnd ();
this->m_out << "Dependencies (" << object.dependencies.size () << "): ";
for (const auto& dependency : object.dependencies) {
this->m_out << dependency << ", ";
}
if (object.is <Image> ()) {
this->lineEnd ();
this->printImage (*object.as <Image> ());
} else if (object.is <Sound> ()) {
this->lineEnd ();
this->printSound (*object.as <Sound> ());
}
this->decreaseIndentation ();
}
void StringPrinter::printImage (const Image& image) {
this->printModel (*image.model); this->printModel (*image.model);
this->lineEnd ();
this->m_out << "Image effects count: " << image.effects.size ();
this->increaseIndentation ();
for (const auto& effect : image.effects) { for (const auto& effect : image.effects) {
this->lineEnd ();
this->printImageEffect (*effect); this->printImageEffect (*effect);
} }
this->decreaseIndentation (); this->decreaseIndentation ();
} }
void StringPrinter::printSound (const Sound& sound) {
this->m_out << "Sounds: " << sound.sounds.size ();
this->increaseIndentation ();
for (const auto& filename : sound.sounds) {
this->lineEnd ();
this->m_out << "Filename " << filename;
}
this->decreaseIndentation ();
}
void StringPrinter::printModel (const ModelStruct& model) { void StringPrinter::printModel (const ModelStruct& model) {
this->m_out << "Model " << model.filename << ":"; this->m_out << "Model " << model.filename << ":";
this->increaseIndentation (); this->increaseIndentation ();
this->lineEnd ();
this->m_out << "Autosize: " << model.autosize; this->m_out << "Autosize: " << model.autosize;
this->lineEnd (); this->lineEnd ();
@ -71,10 +111,12 @@ void StringPrinter::printModel (const ModelStruct& model) {
this->lineEnd (); this->lineEnd ();
this->m_out << "Solid layer: " << model.solidlayer; this->m_out << "Solid layer: " << model.solidlayer;
this->lineEnd (); this->lineEnd ();
if (model.width.has_value ()) { if (model.width.has_value ()) {
this->m_out << "Width: " << model.width.value (); this->m_out << "Width: " << model.width.value ();
this->lineEnd (); this->lineEnd ();
} }
if (model.height.has_value ()) { if (model.height.has_value ()) {
this->m_out << "Height: " << model.height.value (); this->m_out << "Height: " << model.height.value ();
this->lineEnd (); this->lineEnd ();
@ -90,82 +132,130 @@ void StringPrinter::printImageEffect (const ImageEffect& effect) {
this->increaseIndentation (); this->increaseIndentation ();
this->m_out << "Default visibility status: " << effect.visible->value->getBool ();
this->lineEnd (); this->lineEnd ();
this->m_out << "Default visibility status: " << effect.visible->value->getBool ();
this->printEffect (*effect.effect); this->printEffect (*effect.effect);
this->lineEnd ();
this->m_out << "Effect overrides count: " << effect.passOverrides.size ();
this->increaseIndentation ();
for (const auto& override : effect.passOverrides) {
this->printImageEffectPassOverride (*override);
}
this->decreaseIndentation ();
this->decreaseIndentation (); this->decreaseIndentation ();
} }
void StringPrinter::printImageEffectPass (const ImageEffectPass& imageEffectPass) { void StringPrinter::printImageEffectPassOverride (const ImageEffectPassOverride& imageEffectPass) {
this->m_out << "Pass " << imageEffectPass.id << ":"; this->lineEnd ();
this->m_out << "Pass override " << imageEffectPass.id << ":";
this->increaseIndentation (); this->increaseIndentation ();
this->lineEnd ();
this->m_out << "Textures count: " << imageEffectPass.textures.size ();
if (!imageEffectPass.textures.empty ()) { if (!imageEffectPass.textures.empty ()) {
this->m_out << "Textures count: " << imageEffectPass.textures.size ();
this->increaseIndentation (); this->increaseIndentation ();
for (const auto& texture : imageEffectPass.textures) { for (const auto& texture : imageEffectPass.textures) {
this->m_out << "Texture " << texture.first << ": " << texture.second;
this->lineEnd (); this->lineEnd ();
this->m_out << "Texture " << texture.first << ": " << texture.second;
} }
this->decreaseIndentation (); this->decreaseIndentation ();
} }
this->lineEnd ();
this->m_out << "Combos count: " << imageEffectPass.combos.size ();
if (!imageEffectPass.combos.empty ()) {
this->increaseIndentation ();
for (const auto& combo : imageEffectPass.combos) {
this->lineEnd ();
this->m_out << "Combo " << combo.first << "=" << combo.second;
}
this->decreaseIndentation ();
}
this->lineEnd ();
this->m_out << "Constants count: " << imageEffectPass.constants.size ();
if (!imageEffectPass.constants.empty ()) {
this->increaseIndentation ();
for (const auto& constant : imageEffectPass.constants) {
this->lineEnd ();
this->m_out << "Constant " << constant.first << "=" << constant.second->toString();
}
this->decreaseIndentation ();
}
this->decreaseIndentation ();
} }
void StringPrinter::printEffect (const Effect& effect) { void StringPrinter::printEffect (const Effect& effect) {
this->lineEnd ();
this->m_out << "Effect " << effect.name << ":"; this->m_out << "Effect " << effect.name << ":";
this->increaseIndentation (); this->increaseIndentation ();
if (!effect.description.empty ()) { if (!effect.description.empty ()) {
this->m_out << "Description: " << effect.description;
this->lineEnd (); this->lineEnd ();
this->m_out << "Description: " << effect.description;
} }
if (!effect.dependencies.empty ()) { if (!effect.dependencies.empty ()) {
this->lineEnd ();
this->m_out << "Dependencies count: " << effect.dependencies.size (); this->m_out << "Dependencies count: " << effect.dependencies.size ();
this->increaseIndentation (); this->increaseIndentation ();
for (const auto& dependency : effect.dependencies) { for (const auto& dependency : effect.dependencies) {
this->m_out << "Dependency: " << dependency;
this->lineEnd (); this->lineEnd ();
this->m_out << "Dependency: " << dependency;
} }
this->decreaseIndentation (); this->decreaseIndentation ();
} }
if (!effect.group.empty ()) { if (!effect.group.empty ()) {
this->m_out << "Group: " << effect.group;
this->lineEnd (); this->lineEnd ();
this->m_out << "Group: " << effect.group;
} }
if (!effect.preview.empty ()) { if (!effect.preview.empty ()) {
this->m_out << "Preview: " << effect.preview;
this->lineEnd (); this->lineEnd ();
this->m_out << "Preview: " << effect.preview;
} }
this->lineEnd ();
this->m_out << "Passes count: " << effect.passes.size (); this->m_out << "Passes count: " << effect.passes.size ();
this->increaseIndentation (); this->increaseIndentation ();
int passId = 0; int passId = 0;
for (const auto& pass : effect.passes) { for (const auto& pass : effect.passes) {
this->m_out << "Pass " << passId << ":"; this->lineEnd ();
this->m_out << "Pass " << ++passId << ":";
this->increaseIndentation (); this->increaseIndentation ();
this->lineEnd ();
this->printEffectPass (*pass); this->printEffectPass (*pass);
this->decreaseIndentation (); this->decreaseIndentation ();
passId ++;
} }
this->decreaseIndentation (); this->decreaseIndentation ();
this->lineEnd ();
this->m_out << "FBOs count: " << effect.fbos.size (); this->m_out << "FBOs count: " << effect.fbos.size ();
this->increaseIndentation (); this->increaseIndentation ();
for (const auto& fbo : effect.fbos) { for (const auto& fbo : effect.fbos) {
this->lineEnd ();
this->printFBO (*fbo); this->printFBO (*fbo);
} }
@ -182,25 +272,31 @@ void StringPrinter::printEffectPass (const EffectPass& effectPass) {
this->m_out << "Source: " << command.source; this->m_out << "Source: " << command.source;
this->lineEnd (); this->lineEnd ();
this->m_out << "Target: " << command.target; this->m_out << "Target: " << command.target;
this->lineEnd ();
} else { } else {
if (effectPass.target.has_value ()) { if (effectPass.target.has_value ()) {
this->m_out << "Target: " << effectPass.target.value (); this->m_out << "Target: " << effectPass.target.value ();
this->lineEnd ();
} }
if (!effectPass.binds.empty ()) { if (!effectPass.binds.empty ()) {
if (effectPass.target.has_value ()) {
this->lineEnd ();
}
this->m_out << "Binds count: " << effectPass.binds.size (); this->m_out << "Binds count: " << effectPass.binds.size ();
this->increaseIndentation (); this->increaseIndentation ();
for (const auto& bind : effectPass.binds) { for (const auto& bind : effectPass.binds) {
this->m_out << "Bind " << bind.first << ": " << bind.second;
this->lineEnd (); this->lineEnd ();
this->m_out << "Bind " << bind.first << ": " << bind.second;
} }
this->decreaseIndentation (); this->decreaseIndentation ();
} }
if (effectPass.target.has_value () || !effectPass.binds.empty ()) {
this->lineEnd ();
}
this->printMaterial (*effectPass.material); this->printMaterial (*effectPass.material);
} }
} }
@ -209,9 +305,10 @@ void StringPrinter::printFBO (const FBO& fbo) {
this->m_out << "FBO " << fbo.name << ":"; this->m_out << "FBO " << fbo.name << ":";
this->increaseIndentation (); this->increaseIndentation ();
this->m_out << "Format: " << fbo.format;
this->lineEnd (); this->lineEnd ();
this->m_out << "Format: " << fbo.format;
this->lineEnd ();
this->m_out << "Scale: " << fbo.scale; this->m_out << "Scale: " << fbo.scale;
this->decreaseIndentation (); this->decreaseIndentation ();
} }
@ -219,10 +316,12 @@ void StringPrinter::printFBO (const FBO& fbo) {
void StringPrinter::printMaterial (const Material& material) { void StringPrinter::printMaterial (const Material& material) {
this->m_out << "Material " << material.filename << ":"; this->m_out << "Material " << material.filename << ":";
this->increaseIndentation (); this->increaseIndentation ();
this->lineEnd ();
this->m_out << "Passes count: " << material.passes.size (); this->m_out << "Passes count: " << material.passes.size ();
this->increaseIndentation (); this->increaseIndentation ();
for (const auto& pass : material.passes) { for (const auto& pass : material.passes) {
this->lineEnd ();
this->printMaterialPass (*pass); this->printMaterialPass (*pass);
} }
@ -234,6 +333,7 @@ void StringPrinter::printMaterialPass (const MaterialPass& materialPass) {
this->m_out << "Pass " << materialPass.shader << ":"; this->m_out << "Pass " << materialPass.shader << ":";
this->increaseIndentation (); this->increaseIndentation ();
this->lineEnd ();
this->m_out << "Depth test: " << materialPass.depthtest; this->m_out << "Depth test: " << materialPass.depthtest;
this->lineEnd (); this->lineEnd ();
this->m_out << "Depth write: " << materialPass.depthwrite; this->m_out << "Depth write: " << materialPass.depthwrite;
@ -241,27 +341,28 @@ void StringPrinter::printMaterialPass (const MaterialPass& materialPass) {
this->m_out << "Blend mode: " << materialPass.blending; this->m_out << "Blend mode: " << materialPass.blending;
this->lineEnd (); this->lineEnd ();
this->m_out << "Culling mode: " << materialPass.cullmode; this->m_out << "Culling mode: " << materialPass.cullmode;
this->lineEnd ();
if (!materialPass.textures.empty ()) { if (!materialPass.textures.empty ()) {
this->lineEnd ();
this->m_out << "Textures count: " << materialPass.textures.size (); this->m_out << "Textures count: " << materialPass.textures.size ();
this->increaseIndentation (); this->increaseIndentation ();
for (const auto& texture : materialPass.textures) { for (const auto& texture : materialPass.textures) {
this->m_out << "Texture " << texture.first << ": " << texture.second;
this->lineEnd (); this->lineEnd ();
this->m_out << "Texture " << texture.first << ": " << texture.second;
} }
this->decreaseIndentation (); this->decreaseIndentation ();
} }
if (!materialPass.combos.empty ()) { if (!materialPass.combos.empty ()) {
this->lineEnd ();
this->m_out << "Combos count: " << materialPass.combos.size (); this->m_out << "Combos count: " << materialPass.combos.size ();
this->increaseIndentation (); this->increaseIndentation ();
for (const auto& combo : materialPass.combos) { for (const auto& combo : materialPass.combos) {
this->m_out << "Combo " << combo.first << ": " << combo.second;
this->lineEnd (); this->lineEnd ();
this->m_out << "Combo " << combo.first << ": " << combo.second;
} }
this->decreaseIndentation (); this->decreaseIndentation ();
@ -282,12 +383,10 @@ void StringPrinter::lineEnd () {
void StringPrinter::increaseIndentation () { void StringPrinter::increaseIndentation () {
this->m_level ++; this->m_level ++;
this->lineEnd ();
} }
void StringPrinter::decreaseIndentation () { void StringPrinter::decreaseIndentation () {
this->m_level --; this->m_level --;
this->lineEnd ();
} }
std::string StringPrinter::str () { std::string StringPrinter::str () {

View File

@ -25,6 +25,13 @@ class StringPrinter {
*/ */
void printWallpaper (const Wallpaper& wallpaper); void printWallpaper (const Wallpaper& wallpaper);
/**
* Prints the information of the given object
*
* @param object
*/
void printObject (const Object& object);
/** /**
* Prints the information of the given image * Prints the information of the given image
* *
@ -32,6 +39,13 @@ class StringPrinter {
*/ */
void printImage (const Image& image); void printImage (const Image& image);
/**
* Prints the information of the given sound
*
* @param sound
*/
void printSound (const Sound& sound);
/** /**
* Prints the information of the given model * Prints the information of the given model
* *
@ -51,7 +65,7 @@ class StringPrinter {
* *
* @param imageEffectPass * @param imageEffectPass
*/ */
void printImageEffectPass (const ImageEffectPass& imageEffectPass); void printImageEffectPassOverride (const ImageEffectPassOverride& imageEffectPass);
/** /**
* Prints the information of the given FBO * Prints the information of the given FBO

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <utility>
#include <vector> #include <vector>
#include <string> #include <string>
@ -43,9 +44,9 @@ class Object : public TypeCaster, public ObjectData {
* @see ImageEffect * @see ImageEffect
* @see EffectPass * @see EffectPass
*/ */
struct ImageEffectPass { struct ImageEffectPassOverride {
int id; int id;
std::map <std::string, int> combos; ComboMap combos;
ShaderConstantMap constants; ShaderConstantMap constants;
std::map <int, std::string> textures; std::map <int, std::string> textures;
}; };
@ -66,7 +67,7 @@ struct ImageEffect {
/** If this effect is visible or not */ /** If this effect is visible or not */
UserSettingSharedPtr visible; UserSettingSharedPtr visible;
/** Pass overrides to apply to the effect's passes */ /** Pass overrides to apply to the effect's passes */
std::vector <ImageEffectPassUniquePtr> passes; std::vector <ImageEffectPassOverrideUniquePtr> passOverrides;
/** The effect definition */ /** The effect definition */
EffectUniquePtr effect; EffectUniquePtr effect;
}; };
@ -103,7 +104,7 @@ struct ImageData {
class Image : public Object, public ImageData { class Image : public Object, public ImageData {
public: public:
explicit Image (ObjectData data, ImageData imageData) noexcept : Object (data), ImageData (std::move (imageData)) {}; explicit Image (ObjectData data, ImageData imageData) noexcept : Object (std::move(data)), ImageData (std::move (imageData)) {};
~Image () override = default; ~Image () override = default;
}; };
@ -115,7 +116,7 @@ struct SoundData {
class Sound : public Object, public SoundData { class Sound : public Object, public SoundData {
public: public:
explicit Sound (ObjectData data, SoundData soundData) noexcept : Object (data), SoundData (std::move (soundData)) {}; explicit Sound (ObjectData data, SoundData soundData) noexcept : Object (std::move(data)), SoundData (std::move (soundData)) {};
~Sound () override = default; ~Sound () override = default;
}; };
} // namespace WallpaperEngine::Data::Model } // namespace WallpaperEngine::Data::Model

View File

@ -24,7 +24,7 @@ class Object;
class Sound; class Sound;
class Image; class Image;
struct ImageEffect; struct ImageEffect;
struct ImageEffectPass; struct ImageEffectPassOverride;
class Particle; class Particle;
struct Material; struct Material;
struct MaterialPass; struct MaterialPass;
@ -75,10 +75,12 @@ using MaterialUniquePtr = std::unique_ptr <Material>;
using MaterialPassUniquePtr = std::unique_ptr <MaterialPass>; using MaterialPassUniquePtr = std::unique_ptr <MaterialPass>;
using EffectUniquePtr = std::unique_ptr <Effect>; using EffectUniquePtr = std::unique_ptr <Effect>;
using ImageEffectUniquePtr = std::unique_ptr <ImageEffect>; using ImageEffectUniquePtr = std::unique_ptr <ImageEffect>;
using ImageEffectPassUniquePtr = std::unique_ptr <ImageEffectPass>; using ImageEffectPassOverrideUniquePtr = std::unique_ptr <ImageEffectPassOverride>;
using EffectPassUniquePtr = std::unique_ptr <EffectPass>; using EffectPassUniquePtr = std::unique_ptr <EffectPass>;
using FBOUniquePtr = std::unique_ptr <FBO>; using FBOUniquePtr = std::unique_ptr <FBO>;
using ModelUniquePtr = std::unique_ptr <ModelStruct>; using ModelUniquePtr = std::unique_ptr <ModelStruct>;
using ObjectMap = std::map<int, ObjectUniquePtr>; using ObjectMap = std::map<int, ObjectUniquePtr>;
using ComboMap = std::map<std::string, int>;
using TextureMap = std::map<int, std::string>;
} }

View File

@ -2,9 +2,10 @@
#include "ModelParser.h" #include "ModelParser.h"
#include "EffectParser.h" #include "EffectParser.h"
#include "WallpaperEngine/Logging/CLog.h" #include "ShaderConstantParser.h"
#include "WallpaperEngine/Data/Model/Project.h"
#include "WallpaperEngine/Data/Model/Object.h" #include "WallpaperEngine/Data/Model/Object.h"
#include "WallpaperEngine/Data/Model/Project.h"
#include "WallpaperEngine/Logging/CLog.h"
using namespace WallpaperEngine::Data::Parsers; using namespace WallpaperEngine::Data::Parsers;
using namespace WallpaperEngine::Data::Model; using namespace WallpaperEngine::Data::Model;
@ -15,23 +16,22 @@ ObjectUniquePtr ObjectParser::parse (const JSON& it, const ProjectWeakPtr& proje
const auto particleIt = it.find ("particle"); const auto particleIt = it.find ("particle");
const auto textIt = it.find ("text"); const auto textIt = it.find ("text");
const auto lightIt = it.find ("light"); const auto lightIt = it.find ("light");
const auto dependenciesIt = it.find ("dependencies");
const auto basedata = ObjectData { const auto basedata = ObjectData {
.id = it.require <int> ("id", "Object must have an id"), .id = it.require <int> ("id", "Object must have an id"),
.name = it.require <std::string> ("name", "Object must have a name"), .name = it.require <std::string> ("name", "Object must have a name"),
.dependencies = parseDependencies (it), .dependencies = parseDependencies (it),
}; };
if (imageIt != it.end ()) { if (imageIt != it.end () && imageIt->is_string ()) {
return parseImage (it, project, basedata, *imageIt); return parseImage (it, project, basedata, *imageIt);
} else if (soundIt != it.end ()) { } else if (soundIt != it.end () && soundIt->is_array ()) {
return parseSound (it, project, basedata); return parseSound (it, project, basedata);
} else if (particleIt != it.end ()) { } else if (particleIt != it.end ()) {
sLog.error ("Particle objects are not supported yet");
} else if (textIt != it.end ()) { } else if (textIt != it.end ()) {
sLog.error ("Text objects are not supported yet");
} else if (lightIt != it.end ()) { } else if (lightIt != it.end ()) {
sLog.error ("Light objects are not supported yet");
} else { } else {
// dump the object for now, might want to change later // dump the object for now, might want to change later
sLog.exception ("Unknown object type found: ", it.dump ()); sLog.exception ("Unknown object type found: ", it.dump ());
@ -113,23 +113,22 @@ std::vector <ImageEffectUniquePtr> ObjectParser::parseEffects (const JSON& it, c
} }
ImageEffectUniquePtr ObjectParser::parseEffect (const JSON& it, const ProjectWeakPtr& project) { ImageEffectUniquePtr ObjectParser::parseEffect (const JSON& it, const ProjectWeakPtr& project) {
const auto& passes = it.optional ("passes"); const auto& passsOverrides = it.optional ("passes");
return std::make_unique <ImageEffect> (ImageEffect { return std::make_unique <ImageEffect> (ImageEffect {
.id = it.require <int> ("id", "Image effect must have an id"), .id = it.require <int> ("id", "Image effect must have an id"),
.name = it.require <std::string> ("name", "Image effect must have a name"), .name = it.require <std::string> ("name", "Image effect must have a name"),
.visible = it.user ("visible", project.lock ()->properties, true), .visible = it.user ("visible", project.lock ()->properties, true),
//TODO: ADD EFFECTS HERE .passOverrides = passsOverrides.has_value () ? parseEffectPassOverrides (passsOverrides.value (), project) : std::vector <ImageEffectPassOverrideUniquePtr> {},
.passes = passes.has_value () ? parseEffectPasses (passes.value (), project) : std::vector <ImageEffectPassUniquePtr> {},
.effect = EffectParser::load (project, it.require ("file", "Image effect must have an effect")) .effect = EffectParser::load (project, it.require ("file", "Image effect must have an effect"))
}); });
} }
std::vector <ImageEffectPassUniquePtr> ObjectParser::parseEffectPasses (const JSON& it, const ProjectWeakPtr& project) { std::vector <ImageEffectPassOverrideUniquePtr> ObjectParser::parseEffectPassOverrides (const JSON& it, const ProjectWeakPtr& project) {
if (!it.is_array ()) { if (!it.is_array ()) {
return {}; return {};
} }
std::vector <ImageEffectPassUniquePtr> result = {}; std::vector <ImageEffectPassOverrideUniquePtr> result = {};
for (const auto& cur : it) { for (const auto& cur : it) {
result.push_back (parseEffectPass (cur, project)); result.push_back (parseEffectPass (cur, project));
@ -138,8 +137,51 @@ std::vector <ImageEffectPassUniquePtr> ObjectParser::parseEffectPasses (const JS
return result; return result;
} }
ImageEffectPassUniquePtr ObjectParser::parseEffectPass (const JSON& it, const ProjectWeakPtr& project) { ImageEffectPassOverrideUniquePtr ObjectParser::parseEffectPass (const JSON& it, const ProjectWeakPtr& project) {
return std::make_unique <ImageEffectPass> (ImageEffectPass { const auto& combos = it.optional ("combos");
const auto& textures = it.optional ("textures");
const auto& constants = it.optional ("constantshadervalues");
// TODO: PARSE CONSTANT SHADER VALUES AND FIND REFS?
return std::make_unique <ImageEffectPassOverride> (ImageEffectPassOverride {
.id = it.require <int> ("id", "Image effect pass must have an id"), .id = it.require <int> ("id", "Image effect pass must have an id"),
.combos = combos.has_value () ? parseComboMap (combos.value ()) : ComboMap {},
.constants = constants.has_value () ? ShaderConstantParser::parse (constants.value (), project) : ShaderConstantMap {},
.textures = textures.has_value () ? parseTextureMap (textures.value ()) : TextureMap {},
}); });
}
TextureMap ObjectParser::parseTextureMap (const JSON& it) {
if (!it.is_array ()) {
return {};
}
TextureMap result = {};
int textureIndex = -1;
for (const auto& cur : it) {
textureIndex ++;
if (cur.is_null ()) {
continue;
}
result.emplace (textureIndex, cur);
}
return result;
}
ComboMap ObjectParser::parseComboMap (const JSON& it) {
if (!it.is_object ()) {
return {};
}
ComboMap result = {};
for (const auto& cur : it.items ()) {
result.emplace (cur.key (), cur.value ());
}
return result;
} }

View File

@ -24,7 +24,9 @@ class ObjectParser {
const JSON& it, const ProjectWeakPtr& project, ObjectData base, const std::string& image); const JSON& it, const ProjectWeakPtr& project, ObjectData base, const std::string& image);
static std::vector <ImageEffectUniquePtr> parseEffects (const JSON& it, const ProjectWeakPtr& project); static std::vector <ImageEffectUniquePtr> parseEffects (const JSON& it, const ProjectWeakPtr& project);
static ImageEffectUniquePtr parseEffect (const JSON& it, const ProjectWeakPtr& project); static ImageEffectUniquePtr parseEffect (const JSON& it, const ProjectWeakPtr& project);
static std::vector <ImageEffectPassUniquePtr> parseEffectPasses (const JSON& it, const ProjectWeakPtr& project); static std::vector <ImageEffectPassOverrideUniquePtr> parseEffectPassOverrides (const JSON& it, const ProjectWeakPtr& project);
static ImageEffectPassUniquePtr parseEffectPass (const JSON& it, const ProjectWeakPtr& project); static ImageEffectPassOverrideUniquePtr parseEffectPass (const JSON& it, const ProjectWeakPtr& project);
static TextureMap parseTextureMap (const JSON& it);
static ComboMap parseComboMap (const JSON& it);
}; };
} // namespace WallpaperEngine::Data::Parsers } // namespace WallpaperEngine::Data::Parsers

View File

@ -1,3 +1,5 @@
#include <algorithm>
#include "ProjectParser.h" #include "ProjectParser.h"
#include "WallpaperEngine/Logging/CLog.h" #include "WallpaperEngine/Logging/CLog.h"
@ -9,10 +11,14 @@ static int backgroundId = 0;
ProjectSharedPtr ProjectParser::parse (const JSON& data, const ContainerWeakPtr& container) { ProjectSharedPtr ProjectParser::parse (const JSON& data, const ContainerWeakPtr& container) {
const auto general = data.optional ("general"); const auto general = data.optional ("general");
auto type = data.require <std::string> ("type", "Project type missing");
// lowercase for consistency
std::transform (type.begin (), type.end (), type.begin (), tolower);
auto result = std::make_shared <Project> (Project { auto result = std::make_shared <Project> (Project {
.title = data.require <std::string> ("title", "Project title missing"), .title = data.require <std::string> ("title", "Project title missing"),
.type = parseType (data.require <std::string> ("type", "Project type missing")), .type = parseType (type),
.workshopId = data.optional ("workshopid", std::to_string (--backgroundId)), .workshopId = data.optional ("workshopid", std::to_string (--backgroundId)),
.supportsAudioProcessing = general.has_value () && general.value ().optional ("supportsAudioProcessing", false), .supportsAudioProcessing = general.has_value () && general.value ().optional ("supportsAudioProcessing", false),
.properties = parseProperties (general), .properties = parseProperties (general),

View File

@ -20,47 +20,52 @@ void initLogging () {
} }
int main (int argc, char* argv[]) { int main (int argc, char* argv[]) {
// if type parameter is specified, this is a subprocess, so no logging should be enabled from our side try {
bool enableLogging = true; // if type parameter is specified, this is a subprocess, so no logging should be enabled from our side
std::string typeZygote = "--type=zygote"; bool enableLogging = true;
std::string typeUtility = "--type=utility"; std::string typeZygote = "--type=zygote";
std::string typeUtility = "--type=utility";
for (int i = 1; i < argc; i ++) { for (int i = 1; i < argc; i ++) {
if (strncmp (typeZygote.c_str(), argv[i], typeZygote.size()) == 0) { if (strncmp (typeZygote.c_str(), argv[i], typeZygote.size()) == 0) {
enableLogging = false; enableLogging = false;
break; break;
} else if (strncmp (typeUtility.c_str(), argv[i], typeUtility.size()) == 0) { } else if (strncmp (typeUtility.c_str(), argv[i], typeUtility.size()) == 0) {
enableLogging = false; enableLogging = false;
break; break;
}
} }
}
if (enableLogging) { if (enableLogging) {
initLogging (); initLogging ();
} }
WallpaperEngine::Application::CApplicationContext appContext (argc, argv); WallpaperEngine::Application::CApplicationContext appContext (argc, argv);
// halt if the list-properties option was specified
if (appContext.settings.general.onlyListProperties)
return 0;
app = new WallpaperEngine::Application::CWallpaperApplication (appContext);
// attach signals to gracefully stop
std::signal (SIGINT, signalhandler);
std::signal (SIGTERM, signalhandler);
std::signal (SIGKILL, signalhandler);
// show the wallpaper application
app->show ();
// remove signal handlers before destroying app
std::signal (SIGINT, SIG_DFL);
std::signal (SIGTERM, SIG_DFL);
std::signal (SIGKILL, SIG_DFL);
delete app;
// halt if the list-properties option was specified
if (appContext.settings.general.onlyListProperties)
return 0; return 0;
} catch (const std::exception& e) {
app = new WallpaperEngine::Application::CWallpaperApplication (appContext); std::cerr << e.what () << std::endl;
return 1;
// attach signals to gracefully stop }
std::signal (SIGINT, signalhandler);
std::signal (SIGTERM, signalhandler);
std::signal (SIGKILL, signalhandler);
// show the wallpaper application
app->show ();
// remove signal handlers before destroying app
std::signal (SIGINT, SIG_DFL);
std::signal (SIGTERM, SIG_DFL);
std::signal (SIGKILL, SIG_DFL);
delete app;
return 0;
} }