Effector: C++/CMake image effects app
Port of the Python prototype to C++20 with a CMake build: - effector_core: GUI-free static library (effects, image IO via gdk-pixbuf, declarative param specs, registry, portable seeded RNG, thread helper) - scanlines effect: plans strips from the seeded RNG, then copies pixels in parallel with memcpy and doubling horizontal tiling - gtkmm 4 interface: native file dialogs, widgets generated from the param specs, coalesced background renders, preview as a GDK memory texture - CLI: flags generated from the effect registry, headless rendering with no display required - ctest suite covering the RNG, registry, effect geometry and image round trip The Python prototype is kept under python-reference/.
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
#include "core/params.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace effector {
|
||||
|
||||
std::string ParamSpec::flag() const {
|
||||
std::string flag = "--" + key;
|
||||
std::replace(flag.begin(), flag.end(), '_', '-');
|
||||
return flag;
|
||||
}
|
||||
|
||||
ParamSpec ParamSpec::makeInt(std::string key, std::string label, long defaultValue, long minimum,
|
||||
long maximum, std::string help, long step) {
|
||||
ParamSpec spec;
|
||||
spec.type = Type::Int;
|
||||
spec.key = std::move(key);
|
||||
spec.label = std::move(label);
|
||||
spec.help = std::move(help);
|
||||
spec.defaultValue = static_cast<double>(defaultValue);
|
||||
spec.minimum = static_cast<double>(minimum);
|
||||
spec.maximum = static_cast<double>(maximum);
|
||||
spec.step = static_cast<double>(step);
|
||||
return spec;
|
||||
}
|
||||
|
||||
ParamSpec ParamSpec::makeDouble(std::string key, std::string label, double defaultValue,
|
||||
double minimum, double maximum, std::string help, double step,
|
||||
int digits) {
|
||||
ParamSpec spec;
|
||||
spec.type = Type::Double;
|
||||
spec.key = std::move(key);
|
||||
spec.label = std::move(label);
|
||||
spec.help = std::move(help);
|
||||
spec.defaultValue = defaultValue;
|
||||
spec.minimum = minimum;
|
||||
spec.maximum = maximum;
|
||||
spec.step = step;
|
||||
spec.digits = digits;
|
||||
return spec;
|
||||
}
|
||||
|
||||
ParamSpec ParamSpec::makeBool(std::string key, std::string label, bool defaultValue,
|
||||
std::string help) {
|
||||
ParamSpec spec;
|
||||
spec.type = Type::Bool;
|
||||
spec.key = std::move(key);
|
||||
spec.label = std::move(label);
|
||||
spec.help = std::move(help);
|
||||
spec.defaultValue = defaultValue ? 1.0 : 0.0;
|
||||
return spec;
|
||||
}
|
||||
|
||||
ParamSpec ParamSpec::makeChoice(std::string key, std::string label, std::string defaultChoice,
|
||||
std::vector<std::string> choices, std::string help) {
|
||||
ParamSpec spec;
|
||||
spec.type = Type::Choice;
|
||||
spec.key = std::move(key);
|
||||
spec.label = std::move(label);
|
||||
spec.help = std::move(help);
|
||||
spec.defaultChoice = std::move(defaultChoice);
|
||||
spec.choices = std::move(choices);
|
||||
return spec;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const ParamValue* find(const ParamValues& values, const std::string& key) {
|
||||
const auto it = values.find(key);
|
||||
return it == values.end() ? nullptr : &it->second;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
long paramInt(const ParamValues& values, const std::string& key, long fallback) {
|
||||
if (const auto* value = find(values, key)) {
|
||||
if (const auto* v = std::get_if<long>(value)) return *v;
|
||||
if (const auto* v = std::get_if<double>(value)) return static_cast<long>(*v);
|
||||
if (const auto* v = std::get_if<bool>(value)) return *v ? 1 : 0;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
double paramDouble(const ParamValues& values, const std::string& key, double fallback) {
|
||||
if (const auto* value = find(values, key)) {
|
||||
if (const auto* v = std::get_if<double>(value)) return *v;
|
||||
if (const auto* v = std::get_if<long>(value)) return static_cast<double>(*v);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
bool paramBool(const ParamValues& values, const std::string& key, bool fallback) {
|
||||
if (const auto* value = find(values, key)) {
|
||||
if (const auto* v = std::get_if<bool>(value)) return *v;
|
||||
if (const auto* v = std::get_if<long>(value)) return *v != 0;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
std::string paramChoice(const ParamValues& values, const std::string& key,
|
||||
const std::string& fallback) {
|
||||
if (const auto* value = find(values, key)) {
|
||||
if (const auto* v = std::get_if<std::string>(value)) return *v;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
} // namespace effector
|
||||
Reference in New Issue
Block a user