ArtifactEngine/Shared/Shared.h
2026-04-06 20:37:58 -04:00

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);
}