diff -r 1a4342d80de7 -r 654661eab7f3 src/basics.h --- a/src/basics.h Wed Jun 08 20:41:21 2022 +0300 +++ b/src/basics.h Wed Jun 08 22:29:44 2022 +0300 @@ -18,13 +18,13 @@ #pragma once #include -#include -#include -#include #include +#include +#include #include #include -#include +#include +#include #include #include #include @@ -32,64 +32,24 @@ #include #include #include -#include #include - -using GLRotationMatrix = QMatrix4x4; - -enum Axis -{ - X = 0, - Y = 1, - Z = 2 -}; +#include "geometry.h" +#include "functional.h" -enum Result -{ - Success = 0, - PartialSuccess, - Failure -}; - -constexpr bool failed(Result r) -{ - return r == Failure; -} +template +using opt = std::optional; -enum Winding -{ - NoWinding, - Anticlockwise, - Clockwise, -}; +Q_DECLARE_METATYPE(glm::vec3) +Q_DECLARE_METATYPE(glm::mat4) -/* - * Special operator definition that implements the XOR operator for windings. - * However, if either winding is NoWinding, then this function returns NoWinding. - */ -inline Winding operator^(Winding one, Winding other) -{ - if (one == NoWinding or other == NoWinding) - return NoWinding; - else - return static_cast(static_cast(one) ^ static_cast(other)); -} - -inline Winding& operator^=(Winding& one, Winding other) -{ - one = one ^ other; - return one; -} - +//! \brief count the amount of elements in a basic array template -constexpr int countof(T const (&)[N]) +constexpr int countof(T(&)[N]) { return N; } -/** - * @brief casts @c x to a suitable unsigned integer - */ +//! \brief casts @c x to a suitable unsigned integer template constexpr auto unsigned_cast(T x) -> std::enable_if_t, std::make_unsigned_t> @@ -97,9 +57,7 @@ return static_cast>(x); } -/** - * @brief casts @c x to a suitable signed integer - */ +//! \brief casts @c x to a suitable signed integer template constexpr auto signed_cast(T x) -> std::enable_if_t, std::make_signed_t> @@ -107,86 +65,42 @@ return static_cast>(x); } - -/** -* @brief casts floating point values to float, converting non-floating point values causes an error -* @param[in] x floating point value to cast -* @returns float -*/ +//! \brief casts floating point values to float template -auto toFloat(T x) -> std::enable_if_t, float> +constexpr auto float_cast(T x) + -> std::enable_if_t, float> { return static_cast(x); } -/** -* @brief casts floating point values to double, converting non-floating point values causes an error -* @param[in] x floating point value to cast -* @returns double -*/ +//! \brief casts floating point values to double template -auto toDouble(T x) -> std::enable_if_t, double> +constexpr auto double_cast(T x) + -> std::enable_if_t, double> { return static_cast(x); } -/** -* @brief casts floating point values to qreal, converting non-floating point values causes an error -* @param[in] x floating point value to cast -* @returns qreal -*/ +//! \brief casts floating point values to qreal template -auto toQreal(T x) -> std::enable_if_t, qreal> +constexpr auto qreal_cast(T x) + -> std::enable_if_t, qreal> { return static_cast(x); } template -inline QPoint toQPoint(const glm::vec& vec) +constexpr QPointF toQPointF(const glm::vec& vec) { - return {static_cast(vec.x), static_cast(vec.y)}; + return {double_cast(vec.x), double_cast(vec.y)}; } -template -inline QPointF toQPointF(const glm::vec& vec) -{ - return {toDouble(vec.x), toDouble(vec.y)}; -} - -inline glm::vec2 toVec2(const QPoint& point) -{ - return {point.x(), point.y()}; -} - -inline glm::vec2 toVec2(const QPointF& point) +constexpr glm::vec2 toVec2(const QPointF& point) { return {point.x(), point.y()}; } -/* - * coalesce(arg1, arg2, ..., argn) - * Returns the first of the given arguments that evaluates to true. - */ -template -T coalesce(T&& arg) -{ - // recursion base: 1 argument - return arg; -} -template -std::common_type_t coalesce(T&& arg, Rest&&... rest) -{ - // general case: n arguments - return arg ? arg : coalesce(rest...); -} - -/** - * @brief Finds an element in a map and possibly returns a reference to it if find - * @param map - * @param key - * @returns the value or nullptr if not found - */ template const R* findInMap(const std::map& map, K&& key) { @@ -201,12 +115,6 @@ } } -/** - * @brief Finds an element in a map and possibly returns a reference to it if find - * @param map - * @param key - * @returns the value or no value if not found - */ template R* findInMap(std::map& map, K&& key) { @@ -221,10 +129,178 @@ } } +template +void removeFromMap(std::map& map, T&& key) +{ + const auto it = map.find(key); + if (it != map.end()) { + map.erase(it); + } +} + template constexpr std::enable_if_t, T> pi = static_cast(M_PIl); -constexpr double infinity = std::numeric_limits::infinity(); + +inline QSizeF sizeToSizeF(const QSize& size) +{ + return {static_cast(size.width()), static_cast(size.height())}; +} + +//! \brief Hints to the specified vector that a certain amount of new elements +//! are going to be added. +template +void reserveMore(std::vector& vector, std::size_t amount) +{ + vector.reserve(vector.size() + amount); +} + +inline QString vectorToString(const glm::vec2& vec) +{ + return QStringLiteral("(%1, %2)") + .arg(double_cast(vec.x)) + .arg(double_cast(vec.y)); +} + +inline QString vectorToString(const glm::vec3& vec) +{ + return QStringLiteral("(%1, %2, %3)") + .arg(double_cast(vec.x)) + .arg(double_cast(vec.y)) + .arg(double_cast(vec.z)); +} + +inline QString vectorToString(const glm::vec4& vec) +{ + return QStringLiteral("%1, %2, %3, %4)") + .arg(double_cast(vec.x)) + .arg(double_cast(vec.y)) + .arg(double_cast(vec.z)) + .arg(double_cast(vec.w)); +} +template +struct TypeValue +{ + T value; + auto operator<=>(TypeValue other) const = default; +}; + +template +int qHash(TypeValue value) +{ + return qHash(value.value); +} + +/** + * Iterates a @c glm::mat + */ +template +void iter_matrix(const glm::mat& matrix, Fn&& fn) +{ + for (int i = 0; i < X; ++i) + { + for (int j = 0; j < Y; ++j) + { + fn(i, j, matrix[i][j]); + } + } +} + +inline QDataStream& operator<<(QDataStream& stream, const glm::vec3& vec) +{ + return stream << vec.x << vec.y << vec.z; +} + +inline QDataStream& operator>>(QDataStream& stream, glm::vec3& vec) +{ + return stream >> vec.x >> vec.y >> vec.z; +} -Q_DECLARE_METATYPE(glm::vec3) -Q_DECLARE_METATYPE(glm::mat4) +template +QDataStream& operator<<(QDataStream& stream, const glm::mat& mat) +{ + iter_matrix(mat, [&stream](int, int, float x) + { + stream << x; + }); + return stream; +} + +template +QDataStream& operator>>(QDataStream& stream, glm::mat& mat) +{ + iter_matrix(mat, [&stream](int, int, float x) + { + stream >> x; + }); + return stream; +} + +//! \brief Converts a pointer value to an \c std::optional value. If p has a +//! value, it will be copied into the result value. +template +std::optional pointerToOptional(const T* p) +{ + std::optional result; + if (p != nullptr) { + result = *p; + } + return result; +} + +// some magic code from https://en.cppreference.com/w/cpp/utility/variant/visit +// for use with std::visit +template struct overloaded : Ts... { using Ts::operator()...; }; +template overloaded(Ts...) -> overloaded; + +// http://stackoverflow.com/a/18204188/3629665 +template +constexpr T rotl10(T x) +{ + return (x << 10) | ((x >> 22) & 0x000000ff); +} + +template +constexpr T rotl20(T x) +{ + return (x << 20) | ((x >> 12) & 0x000000ff); +} + +inline QString quoted(QString string) +{ + if (string.contains("'")) + { + string.replace("\"", "\\\""); + string = "\"" + string + "\""; + } + else + { + string = "'" + string + "'"; + } + return string; +} + +inline QString vertexToString(const glm::vec3& vertex) +{ + return QStringLiteral("%1 %2 %3").arg(vertex.x).arg(vertex.y).arg(vertex.z); +} + +inline QString vertexToStringParens(const glm::vec3& vertex) +{ + return QStringLiteral("(%1 %2 %3)").arg(vertex.x).arg(vertex.y).arg(vertex.z); +} + +inline QString transformToString(const glm::mat4& matrix) +{ + return QStringLiteral("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12") + .arg(matrix[3][0], matrix[3][1], matrix[3][2]) + .arg(matrix[0][0], matrix[1][0], matrix[2][0]) + .arg(matrix[0][1], matrix[1][1], matrix[2][1]) + .arg(matrix[0][2], matrix[1][2], matrix[2][2]); +} + +template +constexpr unsigned int qHash(const glm::vec<3, T, Q>& key) +{ + return qHash(key.x) ^ rotl10(qHash(key.y)) ^ rotl20(qHash(key.z)); +}