#pragma once #include #include namespace std { template<> struct hash { 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{}(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{}(v.x); // seed = seed * 31 + std::hash{}(v.y); // seed = seed * 31 + std::hash{}(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{}(h); // std::memcpy(&h, reinterpret_cast(&v) + 4, sizeof(float)); // h ^= std::hash{}(h) * 0x85ebca6b; // std::memcpy(&h, reinterpret_cast(&v) + 8, sizeof(float)); // return std::hash{}(h); return seed; } }; } // namespace std namespace Artifact { template class Engine { public: std::vector> subsystems; template T * addSubsystem(Args &&... args) { auto system = std::make_unique(std::forward(args)...); auto ptr = system.get(); subsystems.push_back(std::move(system)); return ptr; } template T * subsystem() const { for (const auto & system : subsystems) { if (T * ptr = dynamic_cast(system.get())) { return ptr; } } return nullptr; } }; class BaseSubsystem { public: Engine * engine = nullptr; virtual void init() {} virtual void reload() {} virtual void deinit() {} virtual void render() {} virtual void tick() {} }; }