Zepha/src/util/Util.h

294 lines
7.9 KiB
C++

//
// Created by aurailus on 28/04/19.
//
#pragma once
#include <sstream>
#include <iostream>
#include <functional>
#include <type_traits>
#include "util/Log.h"
#include "util/Types.h"
namespace Util {
struct EnumClassHash {
template<typename T>
usize operator()(T t) const {
return static_cast<usize>(t);
}
};
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
inline static string toFixed(T val, u8 precision = 2) {
std::ostringstream out;
out.precision(precision);
out << std::fixed << val;
return out.str();
}
template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
static string toString(T val) {
return std::to_string(val);
}
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
static string toString(T val) {
return toFixed<T>(val);
}
template <typename V, std::enable_if_t<(std::is_trivially_copyable_v<typename V::value_type>
|| std::is_same_v<typename V::value_type, string>)
&& std::is_same_v<vec<typename V::value_type>, V>, bool> = true>
static string toString(V vec) {
std::ostringstream out;
out << "[ ";
for (usize i = 0; i < vec.size(); i++) out << (i == 0 ? "" : ", ") << vec[i];
out << " ]";
return out.str();
}
template <typename A, std::enable_if_t<(std::is_trivially_copyable_v<typename A::value_type>
|| std::is_same_v<typename A::value_type, string>)
&& std::is_same_v<array<typename A::value_type, A::size_type>, A>, bool> = true>
static string toString(A arr) {
std::ostringstream out;
for (usize i = 0; i < arr.size(); i++) out << (i == 0 ? "" : ", ") << arr[i];
return out.str();
}
template <typename T, std::enable_if_t<std::is_integral_v<typename T::value_type> &&
std::is_integral_v<typename T::length_type>, bool> = true>
static string toString(T vec) {
std::ostringstream out;
for (usize i = 0; i < T::length(); i++) out << (i == 0 ? "" : ", ") << vec[i];
return out.str();
}
template <typename T, std::enable_if_t<std::is_floating_point_v<typename T::value_type> &&
std::is_integral_v<typename T::length_type>, bool> = true>
static string toString(T vec) {
std::ostringstream out;
for (usize i = 0; i < T::length(); i++) out << (i == 0 ? "" : ", ") << toString<typename T::value_type>(vec[i]);
return out.str();
}
inline static f32 packFloat(const vec3& vec) {
auto charX = static_cast<u8>((vec.x + 1.0f) * 0.5f * 255.f);
auto charY = static_cast<u8>((vec.y + 1.0f) * 0.5f * 255.f);
auto charZ = static_cast<u8>((vec.z + 1.0f) * 0.5f * 255.f);
u32 packedInt = (charX << 16) | (charY << 8) | charZ;
return static_cast<f32>(static_cast<f64>(packedInt) / static_cast<f64>(1 << 24));
}
inline static u32 intFromHexSegment(const string& t) {
u32 x;
std::stringstream ss;
ss << std::hex << t;
ss >> x;
return x;
}
static vec4 hexToColorVec(string hex) {
vec4 color {};
if (hex[0] == '#') hex.erase(0, 1);
else throw std::runtime_error("Color string '" + hex + "' is ill-formed. (missing #)");
string r, g, b, a;
if (hex.length() == 3 || hex.length() == 4) {
r = hex.substr(0, 1);
r += r;
g = hex.substr(1, 1);
g += g;
b = hex.substr(2, 1);
b += b;
a = (hex.length() == 4) ? hex.substr(3, 1) : "f";
a += a;
}
else if (hex.length() == 6 || hex.length() == 8) {
r = hex.substr(0, 2);
g = hex.substr(2, 2);
b = hex.substr(4, 2);
a = (hex.length() == 8) ? hex.substr(6, 2) : "ff";
}
else {
throw std::runtime_error("Color string '" + hex + "' is ill-formed. (invalid length)");
}
color.r = intFromHexSegment(r) / 255.f;
color.g = intFromHexSegment(g) / 255.f;
color.b = intFromHexSegment(b) / 255.f;
color.a = intFromHexSegment(a) / 255.f;
return color;
}
static string getKeyStr(u16 key) {
switch (key) {
default: return "";
case 0: return "mouse0";
case 1: return "mouse1";
case 2: return "mouse2";
case 3: return "mouse3";
case 4: return "mouse4";
case 5: return "mouse5";
case 6: return "mouse6";
case 7: return "mouse7";
case 8: return "scrollup";
case 9: return "scrolldown";
case 10: return "scrollleft";
case 11: return "scrollright";
case 32: return "space";
case 39: return "'";
case 44: return ",";
case 45: return "-";
case 46: return ".";
case 47: return "/";
case 48: return "0";
case 49: return "1";
case 50: return "2";
case 51: return "3";
case 52: return "4";
case 53: return "5";
case 54: return "6";
case 55: return "7";
case 56: return "8";
case 57: return "9";
case 59: return ";";
case 61: return "=";
case 65: return "a";
case 66: return "b";
case 67: return "c";
case 68: return "d";
case 69: return "e";
case 70: return "f";
case 71: return "g";
case 72: return "h";
case 73: return "i";
case 74: return "j";
case 75: return "k";
case 76: return "l";
case 77: return "m";
case 78: return "n";
case 79: return "o";
case 80: return "p";
case 81: return "q";
case 82: return "r";
case 83: return "s";
case 84: return "t";
case 85: return "u";
case 86: return "v";
case 87: return "w";
case 88: return "x";
case 89: return "y";
case 90: return "z";
case 91: return "[";
case 92: return "\\";
case 93: return "]";
case 96: return "`";
case 161: return "world1";
case 162: return "world2";
case 256: return "escape";
case 257: return "enter";
case 258: return "tab";
case 259: return "backspace";
case 260: return "insert";
case 261: return "delete";
case 262: return "right";
case 263: return "left";
case 264: return "down";
case 265: return "up";
case 266: return "pageup";
case 267: return "pagedown";
case 268: return "home";
case 269: return "end";
case 280: return "capslock";
case 281: return "scrolllock";
case 282: return "numlock";
case 283: return "printscreen";
case 284: return "pause";
case 290: return "f1";
case 291: return "f2";
case 292: return "f3";
case 293: return "f4";
case 294: return "f5";
case 295: return "f6";
case 296: return "f7";
case 297: return "f8";
case 298: return "f9";
case 299: return "f10";
case 300: return "f11";
case 301: return "f12";
case 302: return "f13";
case 303: return "f14";
case 304: return "f15";
case 305: return "f16";
case 306: return "f17";
case 307: return "f18";
case 308: return "f19";
case 309: return "f20";
case 310: return "f21";
case 311: return "f22";
case 312: return "f23";
case 313: return "f24";
case 314: return "f25";
case 320: return "num0";
case 321: return "num1";
case 322: return "num2";
case 323: return "num3";
case 324: return "num4";
case 325: return "num5";
case 326: return "num6";
case 327: return "num7";
case 328: return "num8";
case 329: return "num9";
case 330: return "num.";
case 331: return "num/";
case 332: return "num*";
case 333: return "num-";
case 334: return "num+";
case 335: return "numenter";
case 336: return "num=";
case 340: return "leftshift";
case 341: return "leftctrl";
case 342: return "leftalt";
case 344: return "rightshift";
case 345: return "rightctrl";
case 346: return "rightalt";
case 348: return "menu";
}
}
namespace {
constexpr static u64 mix(char m, u64 s) {
return ((s << 7) + ~(s >> 3)) + ~m;
}
}
constexpr static u64 hash(const char* m) {
return (*m) ? mix(*m, hash(m + 1)) : 0;
}
template<class C, typename Ret, typename ... Ts>
std::function<Ret(Ts...)> bind_this(C* c, Ret (C::*m)(Ts...)) {
return [=](auto&& ... args) { return (c->*m)(std::forward<decltype(args)>(args)...); };
}
template<class C, typename Ret, typename ... Ts>
std::function<Ret(Ts...)> bind_this(const C* c, Ret (C::*m)(Ts...) const) {
return [=](auto&& ... args) { return (c->*m)(std::forward<decltype(args)>(args)...); };
}
};
template <typename T, std::enable_if_t<std::is_trivial_v<T>
|| (std::is_trivial_v<typename T::value_type> && std::is_integral_v<typename T::length_type>), bool> = true>
std::ostream& operator<<(std::ostream& out, const T& t) {
return out << Util::toString(t);
}