mirror of
https://git.lynn.is/Gwen/pretty-automata.git
synced 2024-05-18 15:21:07 +02:00
301 lines
9.7 KiB
C++
301 lines
9.7 KiB
C++
#ifndef SHADER_AUTOMATON_CLI_PARSE_H
|
|
#define SHADER_AUTOMATON_CLI_PARSE_H
|
|
|
|
#include "color.h"
|
|
#include "colormaps/colormaps.h"
|
|
#include <PerlinNoise.hpp>
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <format>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <random>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
enum class ColorMapScale {
|
|
INHERENT,
|
|
MAX_AGE,
|
|
GLOBAL_MAX_AGE,
|
|
};
|
|
|
|
struct ColorMapOption {
|
|
ColorMapOption(const ColorMapOption &) = default;
|
|
explicit ColorMapOption(std::variant<std::string, ColorMapData> source) : ColorMapOption(source, false, ColorMapScale::INHERENT) {}
|
|
ColorMapOption(std::variant<std::string, ColorMapData> source, std::variant<ColorMapScale, uint16_t> scale) : ColorMapOption(source, false, scale) {}
|
|
ColorMapOption(std::variant<std::string, ColorMapData> source, bool invert) : ColorMapOption(source, invert, ColorMapScale::INHERENT) {}
|
|
ColorMapOption(std::variant<std::string, ColorMapData> source, std::variant<ColorMapScale, uint16_t> scale, bool invert) : ColorMapOption(source, invert, scale) {}
|
|
ColorMapOption(std::variant<std::string, ColorMapData> source, bool invert, std::variant<ColorMapScale, uint16_t> scale) : invert(invert), scale(scale), source(source) {}
|
|
std::variant<std::string, ColorMapData> source;
|
|
std::variant<ColorMapScale, uint16_t> scale;
|
|
bool invert;
|
|
};
|
|
|
|
struct GridInitialiser {
|
|
virtual void setup(unsigned int width, unsigned int height) {
|
|
this->grid_width = width;
|
|
this->grid_height = height;
|
|
}
|
|
|
|
virtual bool getCell(unsigned int x, unsigned int y) = 0;
|
|
|
|
unsigned int grid_width{};
|
|
unsigned int grid_height{};
|
|
};
|
|
|
|
struct RectGridInitialiser : GridInitialiser {
|
|
RectGridInitialiser(unsigned int width, unsigned int height) {
|
|
this->width = width;
|
|
this->height = height;
|
|
}
|
|
unsigned int width, height;
|
|
|
|
bool getCell(unsigned int x, unsigned int y) override {
|
|
auto margin_x = (grid_width - this->width) / 2;
|
|
auto margin_y = (grid_height - this->height) / 2;
|
|
return x >= margin_x && x < grid_width - margin_x && y >= margin_y && y < grid_height - margin_y;
|
|
}
|
|
};
|
|
|
|
struct EllipseGridInitialiser : GridInitialiser {
|
|
EllipseGridInitialiser(double rx, double ry) {
|
|
this->radius_x = rx;
|
|
this->radius_y = ry;
|
|
}
|
|
double radius_x;
|
|
double radius_y;
|
|
|
|
bool getCell(unsigned int x, unsigned int y) override {
|
|
auto width = static_cast<double>(grid_width);
|
|
auto height = static_cast<double>(grid_height);
|
|
auto X = static_cast<double>(x) - (width / 2);
|
|
auto Y = static_cast<double>(y) - (height / 2);
|
|
auto z = X * X / (radius_x * radius_x) + Y * Y / (radius_y * radius_y);
|
|
return z <= 1;
|
|
}
|
|
};
|
|
|
|
struct PerlinGridInitialiser : GridInitialiser {
|
|
PerlinGridInitialiser(double scale, double density) : scale(scale), density(density) {
|
|
std::random_device r;
|
|
std::default_random_engine e1(r());
|
|
const siv::PerlinNoise::seed_type seed = e1();
|
|
noise = siv::PerlinNoise{seed};
|
|
}
|
|
bool getCell(unsigned int x, unsigned int y) override {
|
|
auto val = noise.noise2D_01(x * scale, y * scale);
|
|
return val >= (1. - density);
|
|
}
|
|
double scale, density;
|
|
siv::PerlinNoise noise{};
|
|
};
|
|
|
|
struct MaxAgeProvider {
|
|
public:
|
|
virtual void setup(unsigned int width, unsigned int height) {
|
|
this->grid_width = width;
|
|
this->grid_height = height;
|
|
}
|
|
virtual uint16_t getAt(uint16_t x, uint16_t y, uint64_t generation) = 0;
|
|
virtual uint16_t global_max() const = 0;
|
|
virtual uint16_t global_min() const = 0;
|
|
virtual bool is_dynamic() const {
|
|
return false;
|
|
}
|
|
virtual uint16_t dynamic_step() const {
|
|
return 0;
|
|
}
|
|
|
|
protected:
|
|
unsigned int grid_width{};
|
|
unsigned int grid_height{};
|
|
};
|
|
|
|
struct UniformMaxAgeProvider : MaxAgeProvider {
|
|
private:
|
|
uint16_t value_;
|
|
|
|
public:
|
|
explicit UniformMaxAgeProvider(uint16_t value) : value_(value) {}
|
|
uint16_t getAt(uint16_t x, uint16_t y, uint64_t generation) override {
|
|
return value_;
|
|
}
|
|
[[nodiscard]] uint16_t global_max() const override {
|
|
return value_;
|
|
}
|
|
[[nodiscard]] uint16_t global_min() const override {
|
|
return value_;
|
|
}
|
|
[[nodiscard]] uint16_t value() const { return value_; }
|
|
};
|
|
struct RadialMaxAgeProvider : MaxAgeProvider {
|
|
private:
|
|
uint16_t center_;
|
|
uint16_t corners_;
|
|
|
|
public:
|
|
RadialMaxAgeProvider(uint16_t center, uint16_t corners) : center_(center), corners_(corners) {}
|
|
uint16_t getAt(uint16_t x, uint16_t y, uint64_t generation) override {
|
|
auto cx = static_cast<double>(grid_width) / 2.;
|
|
auto cy = static_cast<double>(grid_height) / 2.;
|
|
auto corner_center_distance = sqrt(pow(cx, 2.) + pow(cy, 2.));
|
|
auto px = static_cast<double>(x);
|
|
auto py = static_cast<double>(y);
|
|
auto point_center_distance = sqrt(pow(px - cx, 2.) + pow(py - cy, 2.));
|
|
auto center_val = static_cast<double>(center_);
|
|
auto corner_val = static_cast<double>(corners_);
|
|
auto val = center_val + point_center_distance / corner_center_distance * (corner_val - center_val);
|
|
return static_cast<uint16_t>(round(val));
|
|
}
|
|
[[nodiscard]] uint16_t global_max() const override {
|
|
return center_ > corners_ ? center_ : corners_;
|
|
}
|
|
[[nodiscard]] uint16_t global_min() const override {
|
|
return center_ < corners_ ? center_ : corners_;
|
|
}
|
|
[[nodiscard]] uint16_t center() const { return center_; }
|
|
[[nodiscard]] uint16_t corners() const { return corners_; }
|
|
};
|
|
struct RadialFitMaxAgeProvider : MaxAgeProvider {
|
|
private:
|
|
uint16_t center_;
|
|
uint16_t corners_;
|
|
|
|
public:
|
|
RadialFitMaxAgeProvider(uint16_t center, uint16_t corners) : center_(center), corners_(corners) {}
|
|
uint16_t getAt(uint16_t x, uint16_t y, uint64_t generation) override {
|
|
auto cx = static_cast<double>(grid_width) / 2.;
|
|
auto cy = static_cast<double>(grid_height) / 2.;
|
|
auto px = static_cast<double>(x);
|
|
auto py = static_cast<double>(y);
|
|
auto point_center_distance = sqrt(pow((px - cx) / cx, 2.) + pow((py - cy) / cy, 2.));
|
|
auto center_val = static_cast<double>(center_);
|
|
auto corner_val = static_cast<double>(corners_);
|
|
auto val = center_val + point_center_distance * (corner_val - center_val);
|
|
return static_cast<uint16_t>(round(val));
|
|
}
|
|
[[nodiscard]] uint16_t global_max() const override {
|
|
return center_ > corners_ ? center_ : corners_;
|
|
}
|
|
[[nodiscard]] uint16_t global_min() const override {
|
|
return center_ < corners_ ? center_ : corners_;
|
|
}
|
|
[[nodiscard]] uint16_t center() const { return center_; }
|
|
[[nodiscard]] uint16_t corners() const { return corners_; }
|
|
};
|
|
struct PerlinStaticMaxAgeProvider : MaxAgeProvider {
|
|
private:
|
|
double scale_;
|
|
uint16_t min_;
|
|
uint16_t max_;
|
|
|
|
siv::PerlinNoise noise{};
|
|
|
|
public:
|
|
PerlinStaticMaxAgeProvider(double scale, uint16_t min, uint16_t max) : scale_(scale), min_(min), max_(max) {
|
|
std::random_device r;
|
|
std::default_random_engine e1(r());
|
|
const siv::PerlinNoise::seed_type seed = e1();
|
|
noise = siv::PerlinNoise{seed};
|
|
}
|
|
uint16_t getAt(uint16_t x, uint16_t y, uint64_t generation) override {
|
|
auto x_ = static_cast<double>(x) * scale_;
|
|
auto y_ = static_cast<double>(y) * scale_;
|
|
auto v = noise.noise2D_01(x_, y_);
|
|
return static_cast<uint16_t>(round(min_ + (max_ - min_) * v));
|
|
}
|
|
[[nodiscard]] uint16_t global_max() const override {
|
|
return max_;
|
|
}
|
|
[[nodiscard]] uint16_t global_min() const override {
|
|
return min_;
|
|
}
|
|
[[nodiscard]] double scale() const { return scale_; }
|
|
[[nodiscard]] uint16_t min() const { return min_; }
|
|
[[nodiscard]] uint16_t max() const { return max_; }
|
|
};
|
|
struct PerlinDynamicMaxAgeProvider : MaxAgeProvider {
|
|
private:
|
|
double scale_;
|
|
uint16_t min_;
|
|
uint16_t max_;
|
|
double time_scale_;
|
|
uint16_t time_step_;
|
|
|
|
siv::PerlinNoise noise{};
|
|
|
|
public:
|
|
PerlinDynamicMaxAgeProvider(double scale, uint16_t min, uint16_t max, double time_scale, uint16_t time_step)
|
|
: scale_(scale), min_(min), max_(max), time_scale_(time_scale), time_step_(time_step) {
|
|
std::random_device r;
|
|
std::default_random_engine e1(r());
|
|
const siv::PerlinNoise::seed_type seed = e1();
|
|
noise = siv::PerlinNoise{seed};
|
|
}
|
|
uint16_t getAt(uint16_t x, uint16_t y, uint64_t generation) override {
|
|
auto x_ = static_cast<double>(x) * scale_;
|
|
auto y_ = static_cast<double>(y) * scale_;
|
|
auto t_ = static_cast<double>(generation) / static_cast<double>(time_step_) * time_scale_;
|
|
auto v = noise.noise3D_01(x_, y_, t_);
|
|
return static_cast<uint16_t>(round(min_ + (max_ - min_) * v));
|
|
}
|
|
[[nodiscard]] uint16_t global_max() const override {
|
|
return max_;
|
|
}
|
|
[[nodiscard]] uint16_t global_min() const override {
|
|
return min_;
|
|
}
|
|
[[nodiscard]] bool is_dynamic() const override {
|
|
return true;
|
|
}
|
|
[[nodiscard]] uint16_t dynamic_step() const override {
|
|
return time_step_;
|
|
}
|
|
[[nodiscard]] double scale() const { return scale_; }
|
|
[[nodiscard]] uint16_t min() const { return min_; }
|
|
[[nodiscard]] uint16_t max() const { return max_; }
|
|
[[nodiscard]] double time_scale() const { return time_scale_; }
|
|
[[nodiscard]] uint16_t time_step() const { return time_step_; }
|
|
};
|
|
|
|
struct DisplayOptions {
|
|
uint16_t width;
|
|
uint16_t height;
|
|
bool fullscreen;
|
|
size_t fullscreen_screen_number;
|
|
Color dead_color;
|
|
std::variant<Color, ColorMapOption> alive_color;
|
|
uint64_t generation_duration_ms;
|
|
bool blend;
|
|
};
|
|
|
|
struct AutomatonRule {
|
|
std::vector<uint8_t> birth;
|
|
std::vector<uint8_t> survive;
|
|
std::shared_ptr<MaxAgeProvider> max_age;
|
|
uint8_t starve_delay;
|
|
bool starve_recover;
|
|
};
|
|
|
|
struct AutomatonOptions {
|
|
uint16_t width;
|
|
uint16_t height;
|
|
// bool wrap_edges;
|
|
AutomatonRule rule;
|
|
std::shared_ptr<GridInitialiser> initialiser;
|
|
};
|
|
|
|
struct Options {
|
|
AutomatonOptions automaton_options;
|
|
DisplayOptions display_options;
|
|
};
|
|
|
|
Options parse_arguments(int argc, const char *const *argv);
|
|
|
|
#endif // SHADER_AUTOMATON_CLI_PARSE_H
|