147 lines
4.4 KiB
C++
147 lines
4.4 KiB
C++
#pragma once
|
|
|
|
#include <vector>
|
|
|
|
#include <glm/glm.hpp>
|
|
|
|
namespace std {
|
|
|
|
template<>
|
|
struct hash<glm::ivec3> {
|
|
std::size_t operator()(const glm::ivec3& v) const noexcept {
|
|
// Very common and reasonably good quality combination for floats
|
|
// (tries to mix bits while being fast)
|
|
|
|
std::size_t seed = 0;
|
|
|
|
// You can use any of these styles — pick one:
|
|
|
|
// ────────────────────────────────────────────────────────────────
|
|
// Style 1: Boost hash_combine pattern (very popular)
|
|
auto hash_float = [](float f) -> std::size_t {
|
|
return std::hash<float>{}(f);
|
|
};
|
|
|
|
seed ^= hash_float(v.x) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
seed ^= hash_float(v.y) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
seed ^= hash_float(v.z) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
|
|
// ────────────────────────────────────────────────────────────────
|
|
// Style 2: Simpler — fold with multiplication (often enough)
|
|
// seed = std::hash<float>{}(v.x);
|
|
// seed = seed * 31 + std::hash<float>{}(v.y);
|
|
// seed = seed * 31 + std::hash<float>{}(v.z);
|
|
|
|
// ────────────────────────────────────────────────────────────────
|
|
// Style 3: Treat as 12-byte blob → good quality, but slower on some platforms
|
|
// std::size_t h = 0;
|
|
// std::memcpy(&h, &v, sizeof(float)); // x
|
|
// h ^= std::hash<std::uint32_t>{}(h);
|
|
// std::memcpy(&h, reinterpret_cast<const char*>(&v) + 4, sizeof(float));
|
|
// h ^= std::hash<std::uint32_t>{}(h) * 0x85ebca6b;
|
|
// std::memcpy(&h, reinterpret_cast<const char*>(&v) + 8, sizeof(float));
|
|
// return std::hash<std::uint32_t>{}(h);
|
|
|
|
return seed;
|
|
}
|
|
};
|
|
|
|
} // namespace std
|
|
|
|
namespace Artifact {
|
|
|
|
template<typename Subsystem>
|
|
class Engine {
|
|
public:
|
|
std::vector<std::unique_ptr<Subsystem>> subsystems;
|
|
|
|
template <typename T, typename... Args>
|
|
T * addSubsystem(Args &&... args) {
|
|
auto system = std::make_unique<T>(std::forward<Args>(args)...);
|
|
auto ptr = system.get();
|
|
subsystems.push_back(std::move(system));
|
|
return ptr;
|
|
}
|
|
template <typename T>
|
|
T * subsystem() const {
|
|
for (const auto & system : subsystems) {
|
|
if (T * ptr = dynamic_cast<T *>(system.get())) {
|
|
return ptr;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
class BaseSubsystem {
|
|
public:
|
|
virtual void init() {}
|
|
virtual void reload() {}
|
|
virtual void deinit() {}
|
|
};
|
|
|
|
template<typename T> requires std::integral<T> || std::floating_point<T>
|
|
class Composed {
|
|
enum ModifierType {
|
|
Add, Multiply
|
|
};
|
|
using Modifier = std::pair<ModifierType, T>;
|
|
|
|
uint64_t nextID = 0;
|
|
|
|
std::vector<Modifier> modifiers;
|
|
T _value;
|
|
public:
|
|
Composed() : Composed(T{0}) {}
|
|
Composed(T base) {
|
|
add(Add, base);
|
|
}
|
|
|
|
T value() {
|
|
return _value;
|
|
}
|
|
|
|
void recompute() {
|
|
T sum;
|
|
T fac;
|
|
for (auto [type, value] : modifiers) {
|
|
if (type == Add) {
|
|
sum += value;
|
|
} else if (type == Multiply) {
|
|
fac *= value;
|
|
}
|
|
}
|
|
|
|
_value = sum * fac;
|
|
}
|
|
|
|
uint64_t add(ModifierType type, T value) {
|
|
modifiers.emplace_back(type, value);
|
|
recompute();
|
|
return nextID++;
|
|
}
|
|
|
|
bool remove(uint64_t id) {
|
|
auto it = std::find_if(modifiers.begin(), modifiers.end(),
|
|
[id](const Modifier & m) { return m.id == id; });
|
|
if (it == modifiers.end()) return false;
|
|
|
|
modifiers.erase(it);
|
|
recompute();
|
|
return true;
|
|
}
|
|
|
|
bool update(uint64_t id, T newValue) {
|
|
auto it = std::find_if(modifiers.begin(), modifiers.end(),
|
|
[id](const Modifier& m) { return m.id == id; });
|
|
if (it == modifiers.end()) return false;
|
|
|
|
it->value = newValue;
|
|
recompute();
|
|
return true;
|
|
}
|
|
};
|
|
|
|
void log(std::string msg);
|
|
|
|
}
|