Commit and pus current changes

This commit is contained in:
Walter Julius Hennecke 2019-09-20 23:32:37 +02:00
parent ad4d7a4b52
commit 12229678b6
25 changed files with 18122 additions and 150 deletions

View file

@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 17)
add_subdirectory(catch2)
add_subdirectory(common)
add_subdirectory(base_game)
add_subdirectory(game)

View file

@ -6,4 +6,5 @@ file(GLOB BASE_GAME_SRC "*.h" "*.c" "*.cpp")
add_library(base_game OBJECT ${BASE_GAME_SRC})
target_compile_options(base_game PUBLIC -Wno-write-strings)
target_include_directories(base_game PUBLIC ..)
set_property(TARGET base_game PROPERTY POSITION_INDEPENDENT_CODE ON)

View file

@ -594,7 +594,7 @@ void Vector4Scale( const vec4_t in, vec_t scale, vec4_t out );
void VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out );
int32_t Q_log2(int32_t val);
#define random() ((rand () & 0x7fff) / ((float)0x7fff))
inline auto random() { return ((rand () & 0x7fff) / ((float)0x7fff)); }
#define crandom() (2.0 * (random() - 0.5))
float flrandom(float min, float max);

View file

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 17)
add_library(catch2_main OBJECT runner.cpp)
add_library(catch2_symbols OBJECT UnitTest.cpp)

4
code/catch2/UnitTest.cpp Normal file
View file

@ -0,0 +1,4 @@
#ifndef UNIT_TEST
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#endif

17073
code/catch2/catch.hpp Normal file

File diff suppressed because it is too large Load diff

2
code/catch2/runner.cpp Normal file
View file

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

View file

@ -5,4 +5,10 @@ set(CMAKE_CXX_STANDARD 17)
file(GLOB COMMON_SRC "*.h" "*.c" "*.cpp")
add_library(common OBJECT ${COMMON_SRC})
target_include_directories(common PUBLIC ..)
set_property(TARGET common PROPERTY POSITION_INDEPENDENT_CODE ON)
add_executable(unittest_common ${COMMON_SRC} $<TARGET_OBJECTS:catch2_main>)
target_include_directories(unittest_common PUBLIC ..)
target_compile_definitions(unittest_common PUBLIC UNIT_TEST)
set_property(TARGET unittest_common PROPERTY POSITION_INDEPENDENT_CODE ON)

98
code/common/Color.cpp Normal file
View file

@ -0,0 +1,98 @@
#include "Color.h"
#include <catch2/catch.hpp>
static_assert(common::detail::color_check_bounds(-0.1f) == 0.0f);
static_assert(common::detail::color_check_bounds(255.1f) == 255.0f);
static_assert(common::detail::color_check_bounds(0.0f) == 0.0f);
static_assert(common::detail::color_check_bounds(255.0f) == 255.0f);
static_assert(common::detail::color_check_bounds(43.5f) == 43.5f);
static_assert(common::detail::color_check_bounds(-0.1) == 0.0f);
static_assert(common::detail::color_check_bounds(255.1) == 255.0f);
static_assert(common::detail::color_check_bounds(0.0) == 0.0f);
static_assert(common::detail::color_check_bounds(255.0) == 255.0f);
static_assert(common::detail::color_check_bounds(43.5) == 43.5f);
static_assert(common::detail::color_check_bounds(-1) == 0.0f);
static_assert(common::detail::color_check_bounds(256) == 255.0f);
static_assert(common::detail::color_check_bounds(0) == 0.0f);
static_assert(common::detail::color_check_bounds(255) == 255.0f);
static_assert(common::detail::color_check_bounds(43) == 43.0f);
static_assert(common::Color(1.0f).r_ == 1.0f);
static_assert(common::Color(1.0f).g_ == 0.0f);
static_assert(common::Color(1.0f).b_ == 0.0f);
static_assert(common::Color(1.0f).a_ == 0.0f);
static_assert(common::Color(1.0f, 2.4f).r_ == 1.0f);
static_assert(common::Color(1.0f, 2.4f).g_ == 2.4f);
static_assert(common::Color(1.0f, 2.4f).b_ == 0.0f);
static_assert(common::Color(1.0f, 2.4f).a_ == 0.0f);
static_assert(common::Color(1.0f, 2.4f, 3.5f).r_ == 1.0f);
static_assert(common::Color(1.0f, 2.4f, 3.5f).g_ == 2.4f);
static_assert(common::Color(1.0f, 2.4f, 3.5f).b_ == 3.5f);
static_assert(common::Color(1.0f, 2.4f, 3.5f).a_ == 0.0f);
static_assert(common::Color(1.0f, 2.4f, 3.5f, 54.43f).r_ == 1.0f);
static_assert(common::Color(1.0f, 2.4f, 3.5f, 54.43f).g_ == 2.4f);
static_assert(common::Color(1.0f, 2.4f, 3.5f, 54.43f).b_ == 3.5f);
static_assert(common::Color(1.0f, 2.4f, 3.5f, 54.43f).a_ == 54.43f);
TEST_CASE("default construct", "[common::Color]") {
auto color = common::Color();
REQUIRE_THAT(color.r_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.g_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.b_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.a_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.values[0], Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.values[1], Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.values[2], Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.values[3], Catch::WithinAbs(0.0f, 0.0001));
}
TEST_CASE("construct from numbers", "[common::Color]") {
auto color = common::Color(42);
REQUIRE_THAT(color.r_, Catch::WithinAbs(42.0f, 0.0001));
REQUIRE_THAT(color.g_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.b_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.a_, Catch::WithinAbs(0.0f, 0.0001));
color = common::Color(42, -42);
REQUIRE_THAT(color.r_, Catch::WithinAbs(42.0f, 0.0001));
REQUIRE_THAT(color.g_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.b_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.a_, Catch::WithinAbs(0.0f, 0.0001));
color = common::Color(42, -42, 24, -22);
REQUIRE_THAT(color.r_, Catch::WithinAbs(42.0f, 0.0001));
REQUIRE_THAT(color.g_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.b_, Catch::WithinAbs(24.0f, 0.0001));
REQUIRE_THAT(color.a_, Catch::WithinAbs(0.0f, 0.0001));
color = common::Color(42.3, -42, 24, -22);
REQUIRE_THAT(color.r_, Catch::WithinAbs(42.3f, 0.0001));
REQUIRE_THAT(color.g_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.b_, Catch::WithinAbs(24.0f, 0.0001));
REQUIRE_THAT(color.a_, Catch::WithinAbs(0.0f, 0.0001));
color = common::Color(42.3, -42.2, 24, -22);
REQUIRE_THAT(color.r_, Catch::WithinAbs(42.3f, 0.0001));
REQUIRE_THAT(color.g_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.b_, Catch::WithinAbs(24.0f, 0.0001));
REQUIRE_THAT(color.a_, Catch::WithinAbs(0.0f, 0.0001));
color = common::Color(42.3, -42.2, 24, -22.7f);
REQUIRE_THAT(color.r_, Catch::WithinAbs(42.3f, 0.0001));
REQUIRE_THAT(color.g_, Catch::WithinAbs(0.0f, 0.0001));
REQUIRE_THAT(color.b_, Catch::WithinAbs(24.0f, 0.0001));
REQUIRE_THAT(color.a_, Catch::WithinAbs(0.0f, 0.0001));
color = common::Color(42.3, 42.2, 24, 22.7f);
REQUIRE_THAT(color.r_, Catch::WithinAbs(42.3f, 0.0001));
REQUIRE_THAT(color.g_, Catch::WithinAbs(42.2f, 0.0001));
REQUIRE_THAT(color.b_, Catch::WithinAbs(24.0f, 0.0001));
REQUIRE_THAT(color.a_, Catch::WithinAbs(22.7f, 0.0001));
}

View file

@ -3,27 +3,42 @@
#include <base_game/q_shared.h>
namespace common {
class Color {
public:
constexpr Color() noexcept : r{0.f}, g{0.f}, b{0.f}, a{0.f} {}
template<typename R, typename G, typename B, typename A, typename = std::enable_if_t<
std::is_convertible_v<R, float> && std::is_convertible_v<G, float> && std::is_convertible_v<B, float> &&
std::is_convertible_v<A, float>>>
constexpr Color(R _r, G _g = 0, B _b = 0, A _a = 0) noexcept :
r{_r}, g{_g}, b{_b}, a{_a} {}
constexpr Color(vec4_t v) noexcept : r{v[0]}, g{v[1]}, b{v[2]}, a{v[3]} {}
union {
vec4_t values{};
struct {
float r;
float g;
float b;
float a;
};
};
};
namespace detail {
template <typename R,
typename = std::enable_if_t<std::is_convertible_v<R, float>>>
static constexpr float color_check_bounds(R value) {
return value < 0.0f ? 0.0f
: value > 255.f ? 255.0f : static_cast<float>(value);
}
} // namespace detail
class Color {
public:
constexpr Color() noexcept : r_{0.f}, g_{0.f}, b_{0.f}, a_{0.f} {}
template <
typename R, typename G = float, typename B = float, typename A = float,
typename = std::enable_if_t<
std::is_convertible_v<R, float> && std::is_convertible_v<G, float> &&
std::is_convertible_v<B, float> && std::is_convertible_v<A, float>>>
constexpr explicit Color(R _r, G _g = 0, B _b = 0, A _a = 0) noexcept
: r_{detail::color_check_bounds(_r)}, g_{detail::color_check_bounds(_g)},
b_{detail::color_check_bounds(_b)}, a_{detail::color_check_bounds(_a)} {
}
constexpr Color(vec4_t v) noexcept : r_{v[0]}, g_{v[1]}, b_{v[2]}, a_{v[3]} {}
union {
vec4_t values{};
struct {
float r_;
float g_;
float b_;
float a_;
};
};
};
} // namespace common

View file

@ -1,69 +1,69 @@
#pragma once
#include <array>
#include "Color.h"
#include <array>
namespace common {
constexpr std::array<Color, 51> ColorTable {
Color{ 0, 0, 0, 0 }, /* CT_NONE */
Color{ 0, 0, 0, 1 }, /* CT_BLACK */
Color{ 1, 0, 0, 1 }, /* CT_RED */
Color{ 0, 1, 0, 1 }, /* CT_GREEN */
Color{ 0, 0, 1, 1 }, /* CT_BLUE */
Color{ 1, 1, 0, 1 }, /* CT_YELLOW */
Color{ 1, 0, 1, 1 }, /* CT_MAGENTA */
Color{ 0, 1, 1, 1 }, /* CT_CYAN */
Color{ 0.071f, 0.271f, 0.29f, 1 }, /* CT_TEAL */
Color{ 0.529f, 0.373f, 0.017f, 1 },/* CT_GOLD */
Color{ 1, 1, 1, 1 }, /* CT_WHITE */
Color{ 0.75f, 0.75f, 0.75f, 1 }, /* CT_LTGREY */
Color{ 0.50f, 0.50f, 0.50f, 1 }, /* CT_MDGREY */
Color{ 0.25f, 0.25f, 0.25f, 1 }, /* CT_DKGREY */
Color{ 0.15f, 0.15f, 0.15f, 1 }, /* CT_DKGREY2 */
constexpr std::array<Color, 51> ColorTable{
Color{0, 0, 0, 0}, /* CT_NONE */
Color{0, 0, 0, 1}, /* CT_BLACK */
Color{1, 0, 0, 1}, /* CT_RED */
Color{0, 1, 0, 1}, /* CT_GREEN */
Color{0, 0, 1, 1}, /* CT_BLUE */
Color{1, 1, 0, 1}, /* CT_YELLOW */
Color{1, 0, 1, 1}, /* CT_MAGENTA */
Color{0, 1, 1, 1}, /* CT_CYAN */
Color{0.071f, 0.271f, 0.29f, 1}, /* CT_TEAL */
Color{0.529f, 0.373f, 0.017f, 1}, /* CT_GOLD */
Color{1, 1, 1, 1}, /* CT_WHITE */
Color{0.75f, 0.75f, 0.75f, 1}, /* CT_LTGREY */
Color{0.50f, 0.50f, 0.50f, 1}, /* CT_MDGREY */
Color{0.25f, 0.25f, 0.25f, 1}, /* CT_DKGREY */
Color{0.15f, 0.15f, 0.15f, 1}, /* CT_DKGREY2 */
Color{ 0.688f, 0.797f, 1, 1 }, /* CT_VLTORANGE -- needs values */
Color{ 0.688f, 0.797f, 1, 1 }, /* CT_LTORANGE */
Color{ 0.620f, 0.710f, 0.894f, 1 },/* CT_DKORANGE */
Color{ 0.463f, 0.525f, 0.671f, 1 },/* CT_VDKORANGE */
Color{0.688f, 0.797f, 1, 1}, /* CT_VLTORANGE -- needs values */
Color{0.688f, 0.797f, 1, 1}, /* CT_LTORANGE */
Color{0.620f, 0.710f, 0.894f, 1}, /* CT_DKORANGE */
Color{0.463f, 0.525f, 0.671f, 1}, /* CT_VDKORANGE */
Color{ 0.616f, 0.718f, 0.898f, 1 },/* CT_VLTBLUE1 */
Color{ 0.286f, 0.506f, 0.898f, 1 },/* CT_LTBLUE1 */
Color{ 0.082f, 0.388f, 0.898f, 1 },/* CT_DKBLUE1 */
Color{ 0.063f, 0.278f, 0.514f, 1 },/* CT_VDKBLUE1 */
Color{0.616f, 0.718f, 0.898f, 1}, /* CT_VLTBLUE1 */
Color{0.286f, 0.506f, 0.898f, 1}, /* CT_LTBLUE1 */
Color{0.082f, 0.388f, 0.898f, 1}, /* CT_DKBLUE1 */
Color{0.063f, 0.278f, 0.514f, 1}, /* CT_VDKBLUE1 */
Color{ 0.302f, 0.380f, 0.612f, 1 },/* CT_VLTBLUE2 -- needs values */
Color{ 0.196f, 0.314f, 0.612f, 1 },/* CT_LTBLUE2 */
Color{ 0.060f, 0.227f, 0.611f, 1 },/* CT_DKBLUE2 */
Color{ 0.043f, 0.161f, 0.459f, 1 },/* CT_VDKBLUE2 */
Color{0.302f, 0.380f, 0.612f, 1}, /* CT_VLTBLUE2 -- needs values */
Color{0.196f, 0.314f, 0.612f, 1}, /* CT_LTBLUE2 */
Color{0.060f, 0.227f, 0.611f, 1}, /* CT_DKBLUE2 */
Color{0.043f, 0.161f, 0.459f, 1}, /* CT_VDKBLUE2 */
Color{ 0.082f, 0.388f, 0.898f, 1 },/* CT_VLTBROWN1 -- needs values */
Color{ 0.082f, 0.388f, 0.898f, 1 },/* CT_LTBROWN1 */
Color{ 0.078f, 0.320f, 0.813f, 1 },/* CT_DKBROWN1 */
Color{ 0.060f, 0.227f, 0.611f, 1 },/* CT_VDKBROWN1 */
Color{0.082f, 0.388f, 0.898f, 1}, /* CT_VLTBROWN1 -- needs values */
Color{0.082f, 0.388f, 0.898f, 1}, /* CT_LTBROWN1 */
Color{0.078f, 0.320f, 0.813f, 1}, /* CT_DKBROWN1 */
Color{0.060f, 0.227f, 0.611f, 1}, /* CT_VDKBROWN1 */
Color{ 1, 0.784f, 0.365f, 1 }, /* CT_VLTGOLD1 -- needs values */
Color{ 1, 0.706f, 0.153f, 1 }, /* CT_LTGOLD1 */
Color{ 0.733f, 0.514f, 0.086f, 1 },/* CT_DKGOLD1 */
Color{ 0.549f, 0.384f, 0.063f, 1 },/* CT_VDKGOLD1 */
Color{1, 0.784f, 0.365f, 1}, /* CT_VLTGOLD1 -- needs values */
Color{1, 0.706f, 0.153f, 1}, /* CT_LTGOLD1 */
Color{0.733f, 0.514f, 0.086f, 1}, /* CT_DKGOLD1 */
Color{0.549f, 0.384f, 0.063f, 1}, /* CT_VDKGOLD1 */
Color{ 0.688f, 0.797f, 1, 1 }, /* CT_VLTPURPLE1 -- needs values */
Color{ 0.688f, 0.797f, 1, 1 }, /* CT_LTPURPLE1 */
Color{ 0.313f, 0.578f, 1, 1 }, /* CT_DKPURPLE1 */
Color{ 0.031f, 0.110f, 0.341f, 1 },/* CT_VDKPURPLE1 */
Color{0.688f, 0.797f, 1, 1}, /* CT_VLTPURPLE1 -- needs values */
Color{0.688f, 0.797f, 1, 1}, /* CT_LTPURPLE1 */
Color{0.313f, 0.578f, 1, 1}, /* CT_DKPURPLE1 */
Color{0.031f, 0.110f, 0.341f, 1}, /* CT_VDKPURPLE1 */
Color{ 0.688f, 0.797f, 1, 1 }, /* CT_VLTPURPLE2 -- needs values */
Color{ 0.688f, 0.797f, 1, 1 }, /* CT_LTPURPLE2 */
Color{ 0.688f, 0.797f, 1, 1 }, /* CT_DKPURPLE2 */
Color{ 0.031f, 0.110f, 0.341f, 1 },/* CT_VDKPURPLE2 */
Color{0.688f, 0.797f, 1, 1}, /* CT_VLTPURPLE2 -- needs values */
Color{0.688f, 0.797f, 1, 1}, /* CT_LTPURPLE2 */
Color{0.688f, 0.797f, 1, 1}, /* CT_DKPURPLE2 */
Color{0.031f, 0.110f, 0.341f, 1}, /* CT_VDKPURPLE2 */
Color{ 0.686f, 0.808f, 0.1f, 1 }, /* CT_VLTPURPLE3 */
Color{ 0.188f, 0.494f, 1, 1 }, /* CT_LTPURPLE3 */
Color{ 0.094f, 0.471f, 1, 1 }, /* CT_DKPURPLE3 */
Color{ 0.067f, 0.325f, 0.749f, 1 },/* CT_VDKPURPLE3 */
Color{0.686f, 0.808f, 0.1f, 1}, /* CT_VLTPURPLE3 */
Color{0.188f, 0.494f, 1, 1}, /* CT_LTPURPLE3 */
Color{0.094f, 0.471f, 1, 1}, /* CT_DKPURPLE3 */
Color{0.067f, 0.325f, 0.749f, 1}, /* CT_VDKPURPLE3 */
Color{ 1, 0.612f, 0.325f, 1 }, /* CT_VLTRED1 */
Color{ 1, 0.478f, 0.098f, 1 }, /* CT_LTRED1 */
Color{ 1, 0.438f, 0, 1 }, /* CT_DKRED1 */
Color{ 0.784f, 0.329f, 0, 1 }, /* CT_VDKRED1 */
};
Color{1, 0.612f, 0.325f, 1}, /* CT_VLTRED1 */
Color{1, 0.478f, 0.098f, 1}, /* CT_LTRED1 */
Color{1, 0.438f, 0, 1}, /* CT_DKRED1 */
Color{0.784f, 0.329f, 0, 1}, /* CT_VDKRED1 */
};
}

32
code/common/Point2d.cpp Normal file
View file

@ -0,0 +1,32 @@
#include "Point2d.h"
#include <catch2/catch.hpp>
TEST_CASE("point2di_construct", "[common::Point2dI]") {
auto p = common::Point2dI{42, 4};
REQUIRE(p.x == 42);
REQUIRE(p.y == 4);
p = common::Point2dI{32.3f, 43.2f};
REQUIRE(p.x == 32);
REQUIRE(p.y == 43);
p = common::Point2dI{32.4, 85.3};
REQUIRE(p.x == 32);
REQUIRE(p.y == 85);
p = common::Point2dI{44, 32.43f};
REQUIRE(p.x == 44);
REQUIRE(p.y == 32);
p = common::Point2dI{44, 564.324};
REQUIRE(p.x == 44);
REQUIRE(p.y == 564);
p = common::Point2dI{234.52f, 65};
REQUIRE(p.x == 234);
REQUIRE(p.y == 65);
p = common::Point2dI{743.345, 76};
REQUIRE(p.x == 743);
REQUIRE(p.y == 76);
}

View file

@ -5,19 +5,20 @@
namespace common {
template<typename T>
class Point2d {
public:
template<typename A, typename B, typename = std::enable_if_t<std::is_convertible_v<A, T> && std::is_convertible_v<B, T>>>
constexpr Point2d(A _x = 0, B _y = 0) : x{T{_x}}, y{T{_y}} {}
template <typename T> class Point2d {
public:
template <typename A, typename B,
typename = std::enable_if_t<std::is_convertible_v<A, T> &&
std::is_convertible_v<B, T>>>
constexpr explicit Point2d(A _x = 0, B _y = 0)
: x{static_cast<T>(_x)}, y{static_cast<T>(_y)} {}
T x;
T y;
};
T x;
T y;
};
using Point2dI = Point2d<int32_t>;
using Point2dF = Point2d<float>;
using Point2dD = Point2d<double>;
}
using Point2dI = Point2d<int32_t>;
using Point2dF = Point2d<float>;
using Point2dD = Point2d<double>;
} // namespace common

64
code/common/Random.cpp Normal file
View file

@ -0,0 +1,64 @@
#include "Random.h"
#include <catch2/catch.hpp>
TEST_CASE("random_int", "[common::random]") {
for (auto x = 0; x < 1000; x++) {
auto i = common::random<int>();
auto a = common::random<int>();
REQUIRE(i != a);
}
}
TEST_CASE("random_int_limit", "[common::random]") {
for (auto j = 0; j < 10; j++) {
auto min = common::random<int>();
auto max = common::random<int>();
if (min > max) {
std::swap(min, max);
}
if (min == max) {
if (min == std::numeric_limits<int>::min()) {
max++;
} else if (min == std::numeric_limits<int>::max()) {
min--;
}
}
for (auto x = 0; x < 100; x++) {
auto a = common::random(min, max);
REQUIRE(a >= min);
REQUIRE(a <= max);
}
}
}
TEST_CASE("random_real", "[common::random]") {
for (auto x = 0; x < 1000; x++) {
auto a = common::random<double>();
auto b = common::random<double>();
REQUIRE(a != b);
}
}
TEST_CASE("random_real_limit", "[common::random]") {
for (auto j = 0; j < 10; j++) {
auto min = common::random<double>();
auto max = common::random<double>();
if (min > max) {
std::swap(min, max);
}
if (min == max) {
if (min == std::numeric_limits<double>::min()) {
max++;
} else if (min == std::numeric_limits<double>::max()) {
min--;
}
}
for (auto x = 0; x < 100; x++) {
auto a = common::random(min, max);
REQUIRE(a >= min);
REQUIRE(a <= max);
}
}
}

26
code/common/Random.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include <random>
namespace common {
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
T random(T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max()) {
static auto seeder = std::random_device();
static auto engine = std::mt19937_64(seeder());
std::uniform_int_distribution<T> dist(min, max);
return dist(engine);
}
template <typename T, bool Dummy = true,
typename = std::enable_if_t<std::is_floating_point_v<T> && Dummy>>
T random(T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max()) {
static auto seeder = std::random_device();
static auto engine = std::mt19937_64(seeder());
std::uniform_real_distribution<T> dist(min, max);
return dist(engine);
}
} // namespace common

298
code/common/Rectangle.cpp Normal file
View file

@ -0,0 +1,298 @@
#include "Rectangle.h"
#include <catch2/catch.hpp>
static_assert(common::Rectangle<int>().left == 0);
static_assert(common::Rectangle<int>().top == 0);
static_assert(common::Rectangle<int>().right == 0);
static_assert(common::Rectangle<int>().left == 0);
static_assert(common::Rectangle<int>(1).left == 1);
static_assert(common::Rectangle<int>(1).top == 0);
static_assert(common::Rectangle<int>(1).right == 0);
static_assert(common::Rectangle<int>(1).bottom == 0);
static_assert(common::Rectangle<int>(1, -4).left == 1);
static_assert(common::Rectangle<int>(1, -4).top == -4);
static_assert(common::Rectangle<int>(1, -4).right == 0);
static_assert(common::Rectangle<int>(1, -4).bottom == 0);
static_assert(common::Rectangle<int>(1, -4, 564).left == 1);
static_assert(common::Rectangle<int>(1, -4, 564).top == -4);
static_assert(common::Rectangle<int>(1, -4, 564).right == 564);
static_assert(common::Rectangle<int>(1, -4, 564).bottom == 0);
static_assert(common::Rectangle<int>(1, -4, 564, 45).left == 1);
static_assert(common::Rectangle<int>(1, -4, 564, 45).top == -4);
static_assert(common::Rectangle<int>(1, -4, 564, 45).right == 564);
static_assert(common::Rectangle<int>(1, -4, 564, 45).bottom == 45);
static_assert(common::Rectangle<int>(1.0, -4.3, 23.4f, 45).left == 1);
static_assert(common::Rectangle<int>(1.0, -4.3, 23.4f, 45).top == -4);
static_assert(common::Rectangle<int>(1.0, -4.3, 23.4f, 45).right == 23);
static_assert(common::Rectangle<int>(1.0, -4.3, 23.4f, 45).bottom == 45);
static_assert(common::Rectangle<int>(0, 0, 1, 1).width() == 1);
static_assert(common::Rectangle<int>(0, 0, 1, 1).height() == 1);
static_assert(common::Rectangle<int>(0, 0, 1, 1).area() == 1);
static_assert(common::Rectangle<int>(4, 4, 10, 10).width() == 6);
static_assert(common::Rectangle<int>(4, 4, 10, 10).height() == 6);
static_assert(common::Rectangle<int>(4, 4, 10, 10).area() == 36);
static_assert(common::Rectangle<int>(1, 2, 3, 4) ==
common::Rectangle<int>(1, 2, 3, 4));
static_assert(common::Rectangle<int>(1, 2, 3, 4) !=
common::Rectangle<int>(4, 3, 2, 1));
static_assert(common::bounds(common::Rectangle<int>{3, 6, 7, 10},
common::Rectangle<int>{4, 7, 6, 9})
.left == 3);
static_assert(common::bounds(common::Rectangle<int>{3, 6, 7, 10},
common::Rectangle<int>{4, 7, 6, 9})
.top == 6);
static_assert(common::bounds(common::Rectangle<int>{3, 6, 7, 10},
common::Rectangle<int>{4, 7, 6, 9})
.right == 7);
static_assert(common::bounds(common::Rectangle<int>{3, 6, 7, 10},
common::Rectangle<int>{4, 7, 6, 9})
.bottom == 10);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{4, 3, 6, 5})
.left == 1);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{4, 3, 6, 5})
.top == 1);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{4, 3, 6, 5})
.right == 6);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{4, 3, 6, 5})
.bottom == 5);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{2, 2, 5, 4})
.left == 1);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{2, 2, 5, 4})
.top == 1);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{2, 2, 5, 4})
.right == 5);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{2, 2, 5, 4})
.bottom == 4);
static_assert(common::bounds(common::Rectangle<int>{2, 2, 5, 4},
common::Rectangle<int>{4, 3, 6, 5})
.left == 2);
static_assert(common::bounds(common::Rectangle<int>{2, 2, 5, 4},
common::Rectangle<int>{4, 3, 6, 5})
.top == 2);
static_assert(common::bounds(common::Rectangle<int>{2, 2, 5, 4},
common::Rectangle<int>{4, 3, 6, 5})
.right == 6);
static_assert(common::bounds(common::Rectangle<int>{2, 2, 5, 4},
common::Rectangle<int>{4, 3, 6, 5})
.bottom == 5);
static_assert(common::bounds(common::Rectangle<int>{3, 6, 7, 10},
common::Rectangle<int>{3, 6, 7, 10})
.left == 3);
static_assert(common::bounds(common::Rectangle<int>{3, 6, 7, 10},
common::Rectangle<int>{3, 6, 7, 10})
.top == 6);
static_assert(common::bounds(common::Rectangle<int>{3, 6, 7, 10},
common::Rectangle<int>{3, 6, 7, 10})
.right == 7);
static_assert(common::bounds(common::Rectangle<int>{3, 6, 7, 10},
common::Rectangle<int>{3, 6, 7, 10})
.bottom == 10);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{4, 3, 6, 5},
common::Rectangle<int>{2, 2, 5, 4},
common::Rectangle<int>{3, 6, 7, 10})
.left == 1);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{4, 3, 6, 5},
common::Rectangle<int>{2, 2, 5, 4},
common::Rectangle<int>{3, 6, 7, 10})
.top == 1);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{4, 3, 6, 5},
common::Rectangle<int>{2, 2, 5, 4},
common::Rectangle<int>{3, 6, 7, 10})
.right == 7);
static_assert(common::bounds(common::Rectangle<int>{1, 1, 3, 3},
common::Rectangle<int>{4, 3, 6, 5},
common::Rectangle<int>{2, 2, 5, 4},
common::Rectangle<int>{3, 6, 7, 10})
.bottom == 10);
TEST_CASE("rectangle_construct", "[common::Rectangle]") {
REQUIRE(common::Rectangle<int>().left == 0);
REQUIRE(common::Rectangle<int>().top == 0);
REQUIRE(common::Rectangle<int>().right == 0);
REQUIRE(common::Rectangle<int>().left == 0);
REQUIRE(common::Rectangle<int>(1).left == 1);
REQUIRE(common::Rectangle<int>(1).top == 0);
REQUIRE(common::Rectangle<int>(1).right == 0);
REQUIRE(common::Rectangle<int>(1).bottom == 0);
REQUIRE(common::Rectangle<int>(1, -4).left == 1);
REQUIRE(common::Rectangle<int>(1, -4).top == -4);
REQUIRE(common::Rectangle<int>(1, -4).right == 0);
REQUIRE(common::Rectangle<int>(1, -4).bottom == 0);
REQUIRE(common::Rectangle<int>(1, -4, 564).left == 1);
REQUIRE(common::Rectangle<int>(1, -4, 564).top == -4);
REQUIRE(common::Rectangle<int>(1, -4, 564).right == 564);
REQUIRE(common::Rectangle<int>(1, -4, 564).bottom == 0);
REQUIRE(common::Rectangle<int>(1, -4, 564, 45).left == 1);
REQUIRE(common::Rectangle<int>(1, -4, 564, 45).top == -4);
REQUIRE(common::Rectangle<int>(1, -4, 564, 45).right == 564);
REQUIRE(common::Rectangle<int>(1, -4, 564, 45).bottom == 45);
REQUIRE(common::Rectangle<int>(1.0, -4.3, 23.4f, 45).left == 1);
REQUIRE(common::Rectangle<int>(1.0, -4.3, 23.4f, 45).top == -4);
REQUIRE(common::Rectangle<int>(1.0, -4.3, 23.4f, 45).right == 23);
REQUIRE(common::Rectangle<int>(1.0, -4.3, 23.4f, 45).bottom == 45);
}
TEST_CASE("rectangle_width", "[common::Rectangle]") {
REQUIRE(common::Rectangle<int>(0, 0, 1, 1).width() == 1);
REQUIRE(common::Rectangle<int>(4, 4, 10, 10).width() == 6);
}
TEST_CASE("rectangle_height", "[common::Rectangle]") {
REQUIRE(common::Rectangle<int>(0, 0, 1, 1).height() == 1);
REQUIRE(common::Rectangle<int>(4, 4, 10, 10).height() == 6);
}
TEST_CASE("reactangle_area", "[common::Rectangle]") {
REQUIRE(common::Rectangle<int>(0, 0, 1, 1).area() == 1);
REQUIRE(common::Rectangle<int>(4, 4, 10, 10).area() == 36);
}
TEST_CASE("rectangle_equality", "[common::Rectangle]") {
REQUIRE(common::Rectangle<int>(1, 2, 3, 4) ==
common::Rectangle<int>(1, 2, 3, 4));
REQUIRE(common::Rectangle<int>(1, 2, 3, 4) !=
common::Rectangle<int>(4, 3, 2, 1));
}
TEST_CASE("rectangle_intersect", "[common::Rectangle]") {
auto rect_a = common::Rectangle<int>{1, 1, 3, 3};
auto rect_b = common::Rectangle<int>{4, 3, 6, 5};
auto rect_c = common::Rectangle<int>{2, 2, 5, 4};
REQUIRE(!common::intersect(rect_a, rect_b));
REQUIRE(common::intersect(rect_a, rect_a));
REQUIRE(common::intersect(rect_b, rect_b));
REQUIRE(common::intersect(rect_c, rect_c));
REQUIRE(common::intersect(rect_c, rect_a));
REQUIRE(common::intersect(rect_c, rect_b));
auto rect_d = common::Rectangle<int>{3, 6, 7, 10};
auto rect_e = common::Rectangle<int>{4, 7, 6, 9};
REQUIRE(common::intersect(rect_d, rect_e));
REQUIRE(common::intersect(rect_e, rect_d));
}
TEST_CASE("rectangle_intersection", "[common::Rectangle]") {
auto rect_d = common::Rectangle<int>{3, 6, 7, 10};
auto rect_e = common::Rectangle<int>{4, 7, 6, 9};
auto intersectopn_d_e = common::intersection(rect_d, rect_e);
REQUIRE(intersectopn_d_e);
REQUIRE(intersectopn_d_e->left == rect_e.left);
REQUIRE(intersectopn_d_e->top == rect_e.top);
REQUIRE(intersectopn_d_e->right == rect_e.right);
REQUIRE(intersectopn_d_e->bottom == rect_e.bottom);
auto intersection_e_d = common::intersection(rect_e, rect_d);
REQUIRE(intersection_e_d);
REQUIRE(intersection_e_d->left == rect_e.left);
REQUIRE(intersection_e_d->top == rect_e.top);
REQUIRE(intersection_e_d->right == rect_e.right);
REQUIRE(intersection_e_d->bottom == rect_e.bottom);
auto rect_a = common::Rectangle<int>{1, 1, 3, 3};
auto rect_b = common::Rectangle<int>{4, 3, 6, 5};
auto rect_c = common::Rectangle<int>{2, 2, 5, 4};
auto intersection_a_b = common::intersection(rect_a, rect_b);
REQUIRE(!intersection_a_b);
auto intersection_b_a = common::intersection(rect_b, rect_a);
REQUIRE(!intersection_b_a);
auto intersection_a_c = common::intersection(rect_a, rect_c);
REQUIRE(intersection_a_c);
REQUIRE(intersection_a_c->left == 2);
REQUIRE(intersection_a_c->top == 2);
REQUIRE(intersection_a_c->right == 3);
REQUIRE(intersection_a_c->bottom == 3);
auto intersection_c_a = common::intersection(rect_c, rect_a);
REQUIRE(intersection_c_a);
REQUIRE(intersection_c_a->left == 2);
REQUIRE(intersection_c_a->top == 2);
REQUIRE(intersection_c_a->right == 3);
REQUIRE(intersection_c_a->bottom == 3);
auto intersection_a_a = common::intersection(rect_a, rect_a);
REQUIRE(intersection_a_a);
REQUIRE(intersection_a_a->left == 1);
REQUIRE(intersection_a_a->top == 1);
REQUIRE(intersection_a_a->right == 3);
REQUIRE(intersection_a_a->bottom == 3);
}
TEST_CASE("rectangle_bounds", "[common::Rectangle]") {
auto rect_d = common::Rectangle<int>{3, 6, 7, 10};
auto rect_e = common::Rectangle<int>{4, 7, 6, 9};
auto bounds_d_e = common::bounds(rect_d, rect_e);
REQUIRE(bounds_d_e.top == rect_d.top);
REQUIRE(bounds_d_e.left == rect_d.left);
REQUIRE(bounds_d_e.bottom == rect_d.bottom);
REQUIRE(bounds_d_e.right == rect_d.right);
auto rect_a = common::Rectangle<int>{1, 1, 3, 3};
auto rect_b = common::Rectangle<int>{4, 3, 6, 5};
auto rect_c = common::Rectangle<int>{2, 2, 5, 4};
auto bounds_a_b = common::bounds(rect_a, rect_b);
REQUIRE(bounds_a_b.left == rect_a.left);
REQUIRE(bounds_a_b.top == rect_a.top);
REQUIRE(bounds_a_b.right == rect_b.right);
REQUIRE(bounds_a_b.bottom == rect_b.bottom);
auto bounds_a_c = common::bounds(rect_a, rect_c);
REQUIRE(bounds_a_c.left == rect_a.left);
REQUIRE(bounds_a_c.top == rect_a.top);
REQUIRE(bounds_a_c.right == rect_c.right);
REQUIRE(bounds_a_c.bottom == rect_c.bottom);
auto bounds_c_b = common::bounds(rect_c, rect_b);
REQUIRE(bounds_c_b.left == rect_c.left);
REQUIRE(bounds_c_b.top == rect_c.top);
REQUIRE(bounds_c_b.right == rect_b.right);
REQUIRE(bounds_c_b.bottom == rect_b.bottom);
auto bounds_d_d = common::bounds(rect_d, rect_d);
REQUIRE(bounds_d_d.left == rect_d.left);
REQUIRE(bounds_d_d.top == rect_d.top);
REQUIRE(bounds_d_d.right == rect_d.right);
REQUIRE(bounds_d_d.bottom == rect_d.bottom);
auto bounds_a_b_c_d = common::bounds(rect_a, rect_b, rect_c, rect_d);
REQUIRE(bounds_a_b_c_d.left == rect_a.left);
REQUIRE(bounds_a_b_c_d.top == rect_a.top);
REQUIRE(bounds_a_b_c_d.right == rect_d.right);
REQUIRE(bounds_a_b_c_d.bottom == rect_d.bottom);
}

View file

@ -1,30 +1,103 @@
#pragma once
#include <algorithm>
#include <cstdint>
#include <optional>
#include <tuple>
#include <type_traits>
namespace common {
template<typename T>
class Rectangle {
public:
template<typename A, typename B, typename C, typename D, typename = std::enable_if_t<
std::is_convertible_v<A, T> && std::is_convertible_v<B, T> && std::is_convertible_v<C, T> &&
std::is_convertible_v<D, T>>>
constexpr explicit
Rectangle(A _left = 0, B _top = 0, C _right = 0, D _bottom = 0) : left{_left}, top{_top}, right{_right},
bottom{_bottom} {}
template <typename T> class Rectangle {
public:
constexpr Rectangle() : left{0}, top{0}, right{0}, bottom{0} {}
constexpr T width() const { return right - left; }
constexpr T height() const { return bottom - top; }
template <typename A, typename B = A, typename C = A, typename D = A,
typename = std::enable_if_t<
std::is_convertible_v<A, T> && std::is_convertible_v<B, T> &&
std::is_convertible_v<C, T> && std::is_convertible_v<D, T>>>
constexpr explicit Rectangle(A _left, B _top = 0, C _right = 0, D _bottom = 0)
: left{static_cast<T>(_left)}, top{static_cast<T>(_top)},
right{static_cast<T>(_right)}, bottom{static_cast<T>(_bottom)} {}
T left;
T top;
T right;
T bottom;
};
constexpr T width() const { return right - left; }
constexpr T height() const { return bottom - top; }
constexpr T area() const { return width() * height(); }
using RectangleI = Rectangle<int32_t>;
using RectangleF = Rectangle<float>;
using RectangleD = Rectangle<double>;
constexpr bool operator==(const Rectangle &rhs) const {
return std::tie(left, top, right, bottom) ==
std::tie(rhs.left, rhs.top, rhs.right, rhs.bottom);
}
constexpr bool operator!=(const Rectangle &rhs) const {
return !(rhs == *this);
}
T left;
T top;
T right;
T bottom;
};
template <typename A, typename B>
bool intersect(const Rectangle<A> &a, const Rectangle<B> &b) {
return !(a.left > b.right || a.right < b.left || a.top > b.bottom ||
a.bottom < b.top);
}
template <typename A, typename B, typename ResultType = A>
std::optional<Rectangle<ResultType>> intersection(const Rectangle<A> &a,
const Rectangle<B> &b) {
if (!intersect(a, b)) {
return {};
}
auto left = std::max(a.left, b.left);
auto bottom = std::min(a.bottom, b.bottom);
auto right = std::min(a.right, b.right);
auto top = std::max(a.top, b.top);
return Rectangle<ResultType>(left, top, right, bottom);
}
template <typename A, typename... Args>
constexpr Rectangle<A> bounds(const Rectangle<A> &a, Args &&... args) {
if constexpr (sizeof...(args) > 0) {
auto b = bounds(std::forward<Args>(args)...);
return Rectangle<A>{std::min(a.left, b.left), std::min(a.top, b.top),
std::max(a.right, b.right),
std::max(a.bottom, b.bottom)};
}
return a;
}
#if 0
template <typename A, typename B, typename... Args, typename ResultType = A>
Rectangle<ResultType> bounds(const Rectangle<A> &a, const Rectangle<B> &b,
Args &&... args) {
auto bounds_a_b = bounds<A, B, ResultType>(a, b);
auto bounds_args = bounds(std::forward<Args>(args)...);
return bounds<ResultType, decltype(bounds_args), ResultType>(bounds_a_b,
bounds_args);
}
template <typename A, typename B, typename ResultType = A>
Rectangle<ResultType> bounds(const Rectangle<A> &a, const Rectangle<B> &b) {
auto left = std::min(a.left, b.left);
auto bottom = std::max(a.bottom, b.bottom);
auto right = std::max(a.right, b.right);
auto top = std::min(a.top, b.top);
return Rectangle<ResultType>(left, top, right, bottom);
}
template <typename A, typename ResultType = A>
Rectangle<ResultType> bounds(const Rectangle<A> &a) {
return a;
}
#endif
using RectangleI = Rectangle<int32_t>;
using RectangleF = Rectangle<float>;
using RectangleD = Rectangle<double>;
} // namespace common

99
code/common/String.cpp Normal file
View file

@ -0,0 +1,99 @@
#include "String.h"
#include <catch2/catch.hpp>
TEST_CASE("icompare_string_view", "[common::icompare]") {
auto str_1 = "TesT"sv;
auto str_2 = "test"sv;
auto str_3 = "TEST"sv;
REQUIRE(common::icompare(str_1, str_2));
REQUIRE(common::icompare(str_1, str_2));
REQUIRE(common::icompare(str_2, str_3));
REQUIRE(common::icompare(str_1, str_3));
}
TEST_CASE("icompare_string", "[common::icompare]") {
auto str_1 = "TesT"s;
auto str_2 = "test"s;
auto str_3 = "TEST"s;
REQUIRE(common::icompare(str_1, str_2));
REQUIRE(common::icompare(str_1, str_2));
REQUIRE(common::icompare(str_2, str_3));
REQUIRE(common::icompare(str_1, str_3));
}
TEST_CASE("icompare_cstring", "[common::icompare]") {
const char *str_1 = "TesT";
const char *str_2 = "test";
const char *str_3 = "TEST";
REQUIRE(common::icompare(str_1, str_2));
REQUIRE(common::icompare(str_1, str_2));
REQUIRE(common::icompare(str_2, str_3));
REQUIRE(common::icompare(str_1, str_3));
}
TEST_CASE("icompare_mixed", "[common::icompare]") {
const auto str_1 = "TesT"sv;
const auto str_2 = "test"s;
const char *str_3 = "TEST";
REQUIRE(common::icompare(str_1, str_2));
REQUIRE(common::icompare(str_1, str_2));
REQUIRE(common::icompare(str_2, str_3));
REQUIRE(common::icompare(str_1, str_3));
}
TEST_CASE("ifind_string_view", "[common::ifind]") {
auto haystack = "tipedy TAPEDY tOpEDy tap"sv;
REQUIRE(common::ifind(haystack, "blah"sv) == std::string_view::npos);
REQUIRE(common::ifind(haystack, "tapedy"sv) == 7);
REQUIRE(common::ifind(haystack, "TOPEDY"sv) == 14);
REQUIRE(common::ifind(haystack, "iPe"sv) == 1);
}
TEST_CASE("ifind_string", "[common::ifind]") {
auto haystack = "tipedy TAPEDY tOpEDy tap"s;
REQUIRE(common::ifind(haystack, "blah"s) == std::string_view::npos);
REQUIRE(common::ifind(haystack, "tapedy"s) == 7);
REQUIRE(common::ifind(haystack, "TOPEDY"s) == 14);
REQUIRE(common::ifind(haystack, "iPe"s) == 1);
}
TEST_CASE("ifind_cstring", "[common::ifind]") {
auto haystack = "tipedy TAPEDY tOpEDy tap";
REQUIRE(common::ifind(haystack, "blah") == std::string_view::npos);
REQUIRE(common::ifind(haystack, "tapedy") == 7);
REQUIRE(common::ifind(haystack, "TOPEDY") == 14);
REQUIRE(common::ifind(haystack, "iPe") == 1);
}
TEST_CASE("ifind_mixed", "[common::ifind]") {
auto haystack = "tipedy TAPEDY tOpEDy tap";
REQUIRE(common::ifind(haystack, "blah") == std::string_view::npos);
REQUIRE(common::ifind(haystack, "tapedy"s) == 7);
REQUIRE(common::ifind(haystack, "TOPEDY"sv) == 14);
REQUIRE(common::ifind(haystack, "iPe") == 1);
auto haystack2 = "tipedy TAPEDY tOpEDy tap"sv;
REQUIRE(common::ifind(haystack2, "blah") == std::string_view::npos);
REQUIRE(common::ifind(haystack2, "tapedy"s) == 7);
REQUIRE(common::ifind(haystack2, "TOPEDY"sv) == 14);
REQUIRE(common::ifind(haystack2, "iPe") == 1);
auto haystack3 = "tipedy TAPEDY tOpEDy tap"s;
REQUIRE(common::ifind(haystack3, "blah") == std::string_view::npos);
REQUIRE(common::ifind(haystack3, "tapedy"s) == 7);
REQUIRE(common::ifind(haystack3, "TOPEDY"sv) == 14);
REQUIRE(common::ifind(haystack3, "iPe") == 1);
}
// TODO ifind tests

28
code/common/String.h Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#include <algorithm>
#include <string>
#include <string_view>
using namespace std::literals;
namespace common {
inline bool icompare(std::string_view a, std::string_view b) {
return std::equal(a.begin(), a.end(), b.begin(), b.end(),
[](auto ca, auto cb) {
return ca == cb || std::toupper(ca) == std::toupper(ca);
});
}
inline auto ifind(std::string_view haystack, std::string_view needle) {
auto it =
std::search(haystack.begin(), haystack.end(), needle.begin(),
needle.end(), [](auto ch1, auto ch2) {
return ch1 == ch2 || std::toupper(ch1) == std::toupper(ch2);
});
return it == haystack.end() ? std::string_view::npos
: std::distance(haystack.begin(), it);
}
} // namespace common

112
code/common/Vector.cpp Normal file
View file

@ -0,0 +1,112 @@
#include "Vector.h"
#include "Random.h"
#include <catch2/catch.hpp>
namespace common {}
static_assert(common::Vector().x_ == 0.0f);
static_assert(common::Vector().y_ == 0.0f);
static_assert(common::Vector().z_ == 0.0f);
static_assert(common::Vector(1, 2, 3).x_ == 1.0f);
static_assert(common::Vector(1, 2, 3).y_ == 2.0f);
static_assert(common::Vector(1, 2, 3).z_ == 3.0f);
static_assert(common::Vector(1.0f, 2.5f, -3.123f).x_ == 1.0f);
static_assert(common::Vector(1.0f, 2.5f, -3.123f).y_ == 2.5f);
static_assert(common::Vector(1.0f, 2.5f, -3.123f).z_ == -3.123f);
static_assert(common::Vector(1.0, 2.5, -3.123).x_ == 1.0f);
static_assert(common::Vector(1.0, 2.5, -3.123).y_ == 2.5f);
static_assert(common::Vector(1.0, 2.5, -3.123).z_ == -3.123f);
TEST_CASE("vector_construct", "[common::Vector]") {
REQUIRE(common::Vector().x_ == Approx(0.0f));
REQUIRE(common::Vector().y_ == Approx(0.0f));
REQUIRE(common::Vector().z_ == Approx(0.0f));
REQUIRE(common::Vector(1, 2, 3).x_ == Approx(1.0f));
REQUIRE(common::Vector(1, 2, 3).y_ == Approx(2.0f));
REQUIRE(common::Vector(1, 2, 3).z_ == Approx(3.0f));
REQUIRE(common::Vector(1.0f, 2.5f, -3.123f).x_ == Approx(1.0f));
REQUIRE(common::Vector(1.0f, 2.5f, -3.123f).y_ == Approx(2.5f));
REQUIRE(common::Vector(1.0f, 2.5f, -3.123f).z_ == Approx(-3.123f));
REQUIRE(common::Vector(1.0, 2.5, -3.123).x_ == Approx(1.0f));
REQUIRE(common::Vector(1.0, 2.5, -3.123).y_ == Approx(2.5f));
REQUIRE(common::Vector(1.0, 2.5, -3.123).z_ == Approx(-3.123f));
vec3_t vec_3{1, 2, 3};
REQUIRE(common::Vector(vec_3).x_ == Approx(1.0f));
REQUIRE(common::Vector(vec_3).y_ == Approx(2.0f));
REQUIRE(common::Vector(vec_3).z_ == Approx(3.0f));
}
static_assert(common::dotProduct({1, 2, 3}, {3, 2, 1}) == 10.0f);
static_assert(common::dotProduct({1, 5, 3}, {3, 2, 1}) == 16.0f);
TEST_CASE("vector_dotproduct", "[common::Vector]") {
REQUIRE(common::dotProduct({1, 2, 3}, {3, 2, 1}) == Approx(10.0f));
REQUIRE(common::dotProduct({1, 5, 3}, {3, 2, 1}) == Approx(16.0f));
for (auto i = 0; i < 100; i++) {
auto v1 = common::Vector{common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000)};
auto v2 = common::Vector{common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000)};
REQUIRE(common::dotProduct(v1, v2) ==
Approx(v1.x_ * v2.x_ + v1.y_ * v2.y_ + v1.z_ * v2.z_));
}
}
static_assert((common::Vector{2, 5, 4} - common::Vector{1, -2, 4}).x_ == 1.0f);
static_assert((common::Vector{2, 5, 4} - common::Vector{1, -2, 4}).y_ == 7.0f);
static_assert((common::Vector{2, 5, 4} - common::Vector{1, -2, 4}).z_ == 0.0f);
TEST_CASE("vector_substract", "[common::Vector}") {
REQUIRE((common::Vector{2, 5, 4} - common::Vector{1, -2, 4}).x_ == 1.0f);
REQUIRE((common::Vector{2, 5, 4} - common::Vector{1, -2, 4}).y_ == 7.0f);
REQUIRE((common::Vector{2, 5, 4} - common::Vector{1, -2, 4}).z_ == 0.0f);
for (auto i = 0; i < 100; i++) {
auto v1 = common::Vector{common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000)};
auto v2 = common::Vector{common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000)};
auto res = v1 - v2;
REQUIRE(res.x_ == v1.x_ - v2.x_);
REQUIRE(res.y_ == v1.y_ - v2.y_);
REQUIRE(res.z_ == v1.z_ - v2.z_);
}
}
static_assert((common::Vector{2, 5, 4} + common::Vector{1, -2, 4}).x_ == 3.0f);
static_assert((common::Vector{2, 5, 4} + common::Vector{1, -2, 4}).y_ == 3.0f);
static_assert((common::Vector{2, 5, 4} + common::Vector{1, -2, 4}).z_ == 8.0f);
TEST_CASE("vector_add", "[common::Vector]") {
REQUIRE((common::Vector{2, 5, 4} + common::Vector{1, -2, 4}).x_ == 3.0f);
REQUIRE((common::Vector{2, 5, 4} + common::Vector{1, -2, 4}).y_ == 3.0f);
REQUIRE((common::Vector{2, 5, 4} + common::Vector{1, -2, 4}).z_ == 8.0f);
for (auto i = 0; i < 100; i++) {
auto v1 = common::Vector{common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000)};
auto v2 = common::Vector{common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000),
common::random<float>(-100000, 100000)};
auto res = v1 + v2;
REQUIRE(res.x_ == v1.x_ + v2.x_);
REQUIRE(res.y_ == v1.y_ + v2.y_);
REQUIRE(res.z_ == v1.z_ + v2.z_);
}
}

51
code/common/Vector.h Normal file
View file

@ -0,0 +1,51 @@
#pragma once
#include <base_game/q_shared.h>
namespace common {
class Vector {
public:
constexpr Vector() noexcept : x_{0}, y_{0}, z_{0} {}
template <typename X, typename Y = float, typename Z = float,
typename = std::enable_if_t<std::is_convertible_v<X, float> &&
std::is_convertible_v<Y, float> &&
std::is_convertible_v<Z, float>>>
constexpr Vector(X x, Y y, Z z) noexcept
: x_{static_cast<float>(x)}, y_{static_cast<float>(y)},
z_{static_cast<float>(z)} {}
constexpr Vector(vec3_t v) noexcept : x_{v[0]}, y_{v[1]}, z_{v[2]} {}
union {
vec3_t values{};
struct {
float x_;
float y_;
float z_;
};
};
};
inline constexpr float dotProduct(const Vector &a, const Vector &b) {
return a.x_ * b.x_ + a.y_ * b.y_ + a.z_ * b.z_;
}
inline constexpr Vector operator-(const Vector &a, const Vector &b) {
return {a.x_ - b.x_, a.y_ - b.y_, a.z_ - b.z_};
}
inline constexpr Vector operator+(const Vector &a, const Vector &b) {
return {a.x_ + b.x_, a.y_ + b.y_, a.z_ + b.z_};
}
inline constexpr Vector operator*(const Vector &a, float factor) {
return {a.x_ * factor, a.y_ * factor, a.z_ * factor};
}
inline constexpr Vector operator*(float factor, Vector &a) {
return {a.x_ * factor, a.y_ * factor, a.z_ * factor};
}
} // namespace common

View file

@ -1,18 +0,0 @@
#pragma once
#include <string>
#include <string_view>
#include <algorithm>
namespace common {
inline bool icompare(std::string_view a, std::string_view b) {
return std::equal(a.begin(), a.end(), b.begin(), b.end(),
[](auto ca, auto cb) { return ca == cb || std::toupper(ca) == std::toupper(ca); });
}
inline auto ifind(std::string_view haystack, std::string_view needle) {
auto it = std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end(),
[](auto ch1, auto ch2) { return ch1 == ch2 || std::toupper(ch1) == std::toupper(ch2); });
return std::distance(haystack.begin(), it);
}
}

@ -1 +1 @@
Subproject commit d456a2d7774b31a13bf3aa02d56a8ae145bd0e20
Subproject commit 771d5dadc634e102a4b98bd58f9feae57d7a7f95

View file

@ -1606,31 +1606,31 @@ namespace ui {
}
if (style & UI_DROPSHADOW) {
drawcolor.r = drawcolor.g = drawcolor.b = 0;
drawcolor.a = color.a;
drawcolor.r_ = drawcolor.g_ = drawcolor.b_ = 0;
drawcolor.a_ = color.a_;
DrawProportionalString2({pos.x + 2, pos.y + 2}, str, drawcolor, sizeScale, uis.charsetProp);
}
if (style & UI_INVERSE) {
drawcolor.r = color.r * 0.7f;
drawcolor.g = color.g * 0.7f;
drawcolor.b = color.b * 0.7f;
drawcolor.a = color.a;
drawcolor.r_ = color.r_ * 0.7f;
drawcolor.g_ = color.g_ * 0.7f;
drawcolor.b_ = color.b_ * 0.7f;
drawcolor.a_ = color.a_;
DrawProportionalString2(pos, str, drawcolor, sizeScale, uis.charsetProp);
return;
}
if (style & UI_PULSE) {
drawcolor.r = color.a * 0.7f;
drawcolor.g = color.g * 0.7f;
drawcolor.b = color.b * 0.7f;
drawcolor.a = color.a;
drawcolor.r_ = color.a_ * 0.7f;
drawcolor.g_ = color.g_ * 0.7f;
drawcolor.b_ = color.b_ * 0.7f;
drawcolor.a_ = color.a_;
DrawProportionalString2(pos, str, color, sizeScale, uis.charsetProp);
drawcolor.r = color.r;
drawcolor.g = color.g;
drawcolor.b = color.b;
drawcolor.a = static_cast<float>(0.5f + 0.5f * std::sin(uis.realtime / PULSE_DIVISOR));
drawcolor.r_ = color.r_;
drawcolor.g_ = color.g_;
drawcolor.b_ = color.b_;
drawcolor.a_ = static_cast<float>(0.5f + 0.5f * std::sin(uis.realtime / PULSE_DIVISOR));
DrawProportionalString2(pos, str, drawcolor, sizeScale, uis.charsetProp);
return;
}
@ -1682,7 +1682,7 @@ namespace ui {
if(Q_IsColorString(it)) {
if(!forceColor) {
tempcolor = g_color_table[ColorIndex(*(it + 1))];
tempcolor.a = color.a;
tempcolor.a_ = color.a_;
trap_R_SetColor(tempcolor.values);
}
it += 2;
@ -1736,10 +1736,10 @@ namespace ui {
}
if (style & UI_PULSE) {
lowlight.r = 0.8 * color.r;
lowlight.g = 0.8 * color.g;
lowlight.b = 0.8 * color.b;
lowlight.a = 0.8 * color.a;
lowlight.r_ = 0.8 * color.r_;
lowlight.g_ = 0.8 * color.g_;
lowlight.b_ = 0.8 * color.b_;
lowlight.a_ = 0.8 * color.a_;
LerpColor(color, lowlight, newcolor, 0.5 + 0.5 * sin(uis.realtime / PULSE_DIVISOR));
drawcolor = newcolor;
} else
@ -1770,8 +1770,8 @@ namespace ui {
}
if (style & UI_DROPSHADOW) {
dropcolor.r = dropcolor.g = dropcolor.b = 0;
dropcolor.a = drawcolor.a;
dropcolor.r_ = dropcolor.g_ = dropcolor.b_ = 0;
dropcolor.a_ = drawcolor.a_;
if (highRes)
DrawProportionalString({pos.x + 2, pos.y + 2}, str, style, dropcolor);

View file

@ -32,7 +32,7 @@ set(UI_LIB_NAME "ui${ARCH}")
file(GLOB_RECURSE UI_SRC "*.h" "*.c" "*.cpp")
add_library(${UI_LIB_NAME} SHARED ${UI_SRC} $<TARGET_OBJECTS:common> $<TARGET_OBJECTS:base_game>)
add_library(${UI_LIB_NAME} SHARED ${UI_SRC} $<TARGET_OBJECTS:common> $<TARGET_OBJECTS:base_game> $<TARGET_OBJECTS:catch2_symbols>)
target_include_directories(${UI_LIB_NAME} PUBLIC ../json/include ..)
target_link_libraries(${UI_LIB_NAME} ${UI_LINKER_OPTIONS})
target_compile_options(${UI_LIB_NAME} PUBLIC -Wno-narrowing -Wno-write-strings)