summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/CMakeLists.txt10
-rw-r--r--core/angles.hh4
-rw-r--r--core/buffer.cc2
-rw-r--r--core/concepts.hh15
-rw-r--r--core/config.cc2
-rw-r--r--core/config.hh24
-rw-r--r--core/constexpr.hh117
-rw-r--r--core/feature.hh.in5
-rw-r--r--core/floathacks.hh11
-rw-r--r--core/image.cc3
-rw-r--r--core/pch.hh3
-rw-r--r--core/vectors.hh50
-rw-r--r--core/version.cc.in12
-rw-r--r--core/version.hh12
-rw-r--r--core/version.hh.in12
15 files changed, 145 insertions, 137 deletions
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index a8a5468..7bac586 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -7,6 +7,7 @@ add_library(core STATIC
"${CMAKE_CURRENT_LIST_DIR}/buffer.cc"
"${CMAKE_CURRENT_LIST_DIR}/cmdline.hh"
"${CMAKE_CURRENT_LIST_DIR}/cmdline.cc"
+ "${CMAKE_CURRENT_LIST_DIR}/concepts.hh"
"${CMAKE_CURRENT_LIST_DIR}/config.cc"
"${CMAKE_CURRENT_LIST_DIR}/config.hh"
"${CMAKE_CURRENT_LIST_DIR}/constexpr.hh"
@@ -14,7 +15,6 @@ add_library(core STATIC
"${CMAKE_CURRENT_LIST_DIR}/crc64.hh"
"${CMAKE_CURRENT_LIST_DIR}/epoch.cc"
"${CMAKE_CURRENT_LIST_DIR}/epoch.hh"
- "${CMAKE_CURRENT_LIST_DIR}/feature.hh"
"${CMAKE_CURRENT_LIST_DIR}/floathacks.hh"
"${CMAKE_CURRENT_LIST_DIR}/image.cc"
"${CMAKE_CURRENT_LIST_DIR}/image.hh"
@@ -22,12 +22,13 @@ add_library(core STATIC
"${CMAKE_CURRENT_LIST_DIR}/resource.hh"
"${CMAKE_CURRENT_LIST_DIR}/strtools.cc"
"${CMAKE_CURRENT_LIST_DIR}/strtools.hh"
+ "${CMAKE_CURRENT_LIST_DIR}/version.cc"
"${CMAKE_CURRENT_LIST_DIR}/version.hh")
-target_compile_features(core PUBLIC cxx_std_17)
+target_compile_features(core PUBLIC cxx_std_20)
target_include_directories(core PUBLIC "${DEPS_INCLUDE_DIR}")
target_include_directories(core PUBLIC "${PROJECT_SOURCE_DIR}")
target_precompile_headers(core PRIVATE "${CMAKE_CURRENT_LIST_DIR}/pch.hh")
-target_link_libraries(core PUBLIC enet physfs spdlog stb)
+target_link_libraries(core PUBLIC enet emhash glm physfs spdlog stb)
if(WIN32)
target_compile_definitions(core PUBLIC _CRT_SECURE_NO_WARNINGS)
@@ -39,5 +40,4 @@ if(MSVC)
target_compile_options(core PUBLIC /utf-8)
endif()
-configure_file("${CMAKE_CURRENT_LIST_DIR}/feature.hh.in" "${CMAKE_CURRENT_LIST_DIR}/feature.hh")
-configure_file("${CMAKE_CURRENT_LIST_DIR}/version.hh.in" "${CMAKE_CURRENT_LIST_DIR}/version.hh")
+configure_file("${CMAKE_CURRENT_LIST_DIR}/version.cc.in" "${CMAKE_CURRENT_LIST_DIR}/version.cc")
diff --git a/core/angles.hh b/core/angles.hh
index 98dc086..a2a3d55 100644
--- a/core/angles.hh
+++ b/core/angles.hh
@@ -4,8 +4,8 @@
#include "core/constexpr.hh"
-constexpr float A180 = cxpr::radians(180.0f);
-constexpr float A360 = cxpr::radians(360.0f);
+constexpr float A180 = vx::radians(180.0f);
+constexpr float A360 = vx::radians(360.0f);
namespace cxangles
{
diff --git a/core/buffer.cc b/core/buffer.cc
index c6b67f9..0e18f4f 100644
--- a/core/buffer.cc
+++ b/core/buffer.cc
@@ -183,7 +183,7 @@ void WriteBuffer::write_UI64(std::uint64_t value)
void WriteBuffer::write_string(const std::string& value)
{
- const std::size_t size = cxpr::min<std::size_t>(UINT16_MAX, value.size());
+ const std::size_t size = vx::min<std::size_t>(UINT16_MAX, value.size());
write_UI16(static_cast<std::uint16_t>(size));
diff --git a/core/concepts.hh b/core/concepts.hh
new file mode 100644
index 0000000..47b01d2
--- /dev/null
+++ b/core/concepts.hh
@@ -0,0 +1,15 @@
+#ifndef CORE_CONCEPTS_HH
+#define CORE_CONCEPTS_HH 1
+#pragma once
+
+namespace vx
+{
+template<typename T>
+concept Arithmetic = std::is_arithmetic_v<T>;
+template<typename T>
+concept Integer = std::is_integral_v<T>;
+template<typename T>
+concept FloatingPoint = std::is_floating_point_v<T>;
+} // namespace vx
+
+#endif /* CORE_CONCEPTS_HH */
diff --git a/core/config.cc b/core/config.cc
index 52cd102..3202fb6 100644
--- a/core/config.cc
+++ b/core/config.cc
@@ -133,7 +133,7 @@ bool Config::save_file(const char* path) const
auto curtime = std::time(nullptr);
- stream << "# Voxelius " << PROJECT_VERSION_STRING << " configuration file" << std::endl;
+ stream << "# Voxelius " << project_version_string << " configuration file" << std::endl;
stream << "# Generated at: " << std::put_time(std::gmtime(&curtime), "%Y-%m-%d %H:%M:%S %z") << std::endl << std::endl;
for(const auto& it : m_values) {
diff --git a/core/config.hh b/core/config.hh
index 3df0870..efb2ef0 100644
--- a/core/config.hh
+++ b/core/config.hh
@@ -2,6 +2,8 @@
#define CORE_CONFIG_HH 1
#pragma once
+#include "core/concepts.hh"
+
class IConfigValue {
public:
virtual ~IConfigValue(void) = default;
@@ -29,10 +31,8 @@ public:
static bool from_string(const char* value);
};
-template<typename T>
+template<vx::Arithmetic T>
class ConfigNumber : public IConfigValue {
- static_assert(std::is_arithmetic_v<T>);
-
public:
explicit ConfigNumber(T default_value = T(0));
explicit ConfigNumber(T default_value, T min_value, T max_value);
@@ -112,7 +112,7 @@ private:
std::unordered_map<std::string, IConfigValue*> m_values;
};
-template<typename T>
+template<vx::Arithmetic T>
inline ConfigNumber<T>::ConfigNumber(T default_value)
{
m_value = default_value;
@@ -121,7 +121,7 @@ inline ConfigNumber<T>::ConfigNumber(T default_value)
m_string = std::to_string(default_value);
}
-template<typename T>
+template<vx::Arithmetic T>
inline ConfigNumber<T>::ConfigNumber(T default_value, T min_value, T max_value)
{
m_value = default_value;
@@ -130,7 +130,7 @@ inline ConfigNumber<T>::ConfigNumber(T default_value, T min_value, T max_value)
m_string = std::to_string(default_value);
}
-template<typename T>
+template<vx::Arithmetic T>
inline void ConfigNumber<T>::set(const char* value)
{
std::istringstream(value) >> m_value;
@@ -138,38 +138,38 @@ inline void ConfigNumber<T>::set(const char* value)
m_string = std::to_string(m_value);
}
-template<typename T>
+template<vx::Arithmetic T>
inline const char* ConfigNumber<T>::get(void) const
{
return m_string.c_str();
}
-template<typename T>
+template<vx::Arithmetic T>
inline T ConfigNumber<T>::get_value(void) const
{
return m_value;
}
-template<typename T>
+template<vx::Arithmetic T>
inline void ConfigNumber<T>::set_value(T value)
{
m_value = std::clamp(value, m_min_value, m_max_value);
m_string = std::to_string(m_value);
}
-template<typename T>
+template<vx::Arithmetic T>
inline T ConfigNumber<T>::get_min_value(void) const
{
return m_min_value;
}
-template<typename T>
+template<vx::Arithmetic T>
inline T ConfigNumber<T>::get_max_value(void) const
{
return m_max_value;
}
-template<typename T>
+template<vx::Arithmetic T>
inline void ConfigNumber<T>::set_limits(T min_value, T max_value)
{
m_min_value = min_value;
diff --git a/core/constexpr.hh b/core/constexpr.hh
index ce64060..ac82169 100644
--- a/core/constexpr.hh
+++ b/core/constexpr.hh
@@ -2,44 +2,47 @@
#define CORE_CONSTEXPR_HH 1
#pragma once
-namespace cxpr
+#include "core/concepts.hh"
+
+namespace vx
{
-template<typename T>
+template<vx::Arithmetic T>
constexpr static inline const T abs(const T x);
template<typename T, std::size_t L>
constexpr static inline const std::size_t array_size(const T (&)[L]);
-template<typename T, typename F>
+template<vx::Integer T, vx::FloatingPoint F>
constexpr static inline const T ceil(const F x);
-template<typename T>
+template<vx::Arithmetic T>
constexpr static inline const T degrees(const T x);
-template<typename T, typename F>
+template<vx::Integer T, vx::FloatingPoint F>
constexpr static inline const T floor(const F x);
-template<typename T>
+template<vx::Arithmetic T>
constexpr static inline const T clamp(const T x, const T min, const T max);
-template<typename T, typename F>
+template<vx::Arithmetic T, vx::FloatingPoint F>
constexpr static inline const T lerp(const T x, const T y, const F a);
-template<typename T>
+template<vx::Arithmetic T>
constexpr static inline const T log2(const T x);
-template<typename T>
+template<vx::Arithmetic T>
constexpr static inline const T max(const T x, const T y);
-template<typename T>
+template<vx::Arithmetic T>
constexpr static inline const T min(const T x, const T y);
-template<typename T>
+template<vx::Integer T>
+requires std::is_signed_v<T>
constexpr static inline const T mod_signed(const T x, const T m);
-template<typename T>
+template<vx::Arithmetic T>
constexpr static inline const T pow2(const T x);
-template<typename T>
+template<vx::Arithmetic T>
constexpr static inline const T radians(const T x);
-template<typename T>
+template<vx::Arithmetic T>
constexpr static inline const bool range(const T x, const T min, const T max);
-template<typename T, typename F>
+template<vx::Arithmetic T, vx::FloatingPoint F>
constexpr static inline const T sign(const F x);
-template<typename T, typename F>
+template<vx::Arithmetic T, vx::FloatingPoint F>
constexpr static inline const T smoothstep(const T x, const T y, const F a);
-} // namespace cxpr
+} // namespace vx
-template<typename T>
-constexpr static inline const T cxpr::abs(const T x)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::abs(const T x)
{
if(x < static_cast<T>(0)) {
return -x;
@@ -49,17 +52,14 @@ constexpr static inline const T cxpr::abs(const T x)
}
template<typename T, std::size_t L>
-constexpr static inline const std::size_t cxpr::array_size(const T (&)[L])
+constexpr static inline const std::size_t vx::array_size(const T (&)[L])
{
return L;
}
-template<typename T, typename F>
-constexpr static inline const T cxpr::ceil(const F x)
+template<vx::Integer T, vx::FloatingPoint F>
+constexpr static inline const T vx::ceil(const F x)
{
- static_assert(std::is_integral_v<T>);
- static_assert(std::is_floating_point_v<F>);
-
const T ival = static_cast<T>(x);
if(ival < x) {
@@ -69,18 +69,15 @@ constexpr static inline const T cxpr::ceil(const F x)
}
}
-template<typename T>
-constexpr static inline const T cxpr::degrees(const T x)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::degrees(const T x)
{
return x * static_cast<T>(180.0) / static_cast<T>(M_PI);
}
-template<typename T, typename F>
-constexpr static inline const T cxpr::floor(const F x)
+template<vx::Integer T, vx::FloatingPoint F>
+constexpr static inline const T vx::floor(const F x)
{
- static_assert(std::is_integral_v<T>);
- static_assert(std::is_floating_point_v<F>);
-
const T ival = static_cast<T>(x);
if(ival > x) {
@@ -90,8 +87,8 @@ constexpr static inline const T cxpr::floor(const F x)
}
}
-template<typename T>
-constexpr static inline const T cxpr::clamp(const T x, const T min, const T max)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::clamp(const T x, const T min, const T max)
{
if(x < min) {
return min;
@@ -102,26 +99,24 @@ constexpr static inline const T cxpr::clamp(const T x, const T min, const T max)
}
}
-template<typename T, typename F>
-constexpr static inline const T cxpr::lerp(const T x, const T y, const F a)
+template<vx::Arithmetic T, vx::FloatingPoint F>
+constexpr static inline const T vx::lerp(const T x, const T y, const F a)
{
- static_assert(std::is_arithmetic_v<T>);
- static_assert(std::is_floating_point_v<F>);
return static_cast<T>(static_cast<F>(x) * (static_cast<F>(1.0f) - a) + static_cast<F>(y) * a);
}
-template<typename T>
-constexpr static inline const T cxpr::log2(const T x)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::log2(const T x)
{
if(x < 2) {
return 0;
} else {
- return cxpr::log2<T>((x + 1) >> 1) + 1;
+ return vx::log2<T>((x + 1) >> 1) + 1;
}
}
-template<typename T>
-constexpr static inline const T cxpr::max(const T x, const T y)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::max(const T x, const T y)
{
if(x < y) {
return y;
@@ -130,8 +125,8 @@ constexpr static inline const T cxpr::max(const T x, const T y)
}
}
-template<typename T>
-constexpr static inline const T cxpr::min(const T x, const T y)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::min(const T x, const T y)
{
if(x > y) {
return y;
@@ -140,11 +135,10 @@ constexpr static inline const T cxpr::min(const T x, const T y)
}
}
-template<typename T>
-constexpr static inline const T cxpr::mod_signed(const T x, const T m)
+template<vx::Integer T>
+requires std::is_signed_v<T>
+constexpr static inline const T vx::mod_signed(const T x, const T m)
{
- static_assert(std::is_signed_v<T>);
- static_assert(std::is_integral_v<T>);
auto result = static_cast<T>(x % m);
if(result < T(0)) {
@@ -154,8 +148,8 @@ constexpr static inline const T cxpr::mod_signed(const T x, const T m)
}
}
-template<typename T>
-constexpr static inline const T cxpr::pow2(const T x)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::pow2(const T x)
{
T value = static_cast<T>(1);
while(value < x)
@@ -163,20 +157,20 @@ constexpr static inline const T cxpr::pow2(const T x)
return value;
}
-template<typename T>
-constexpr static inline const T cxpr::radians(const T x)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::radians(const T x)
{
return x * static_cast<T>(M_PI) / static_cast<T>(180.0);
}
-template<typename T>
-constexpr static inline const bool cxpr::range(const T x, const T min, const T max)
+template<vx::Arithmetic T>
+constexpr static inline const bool vx::range(const T x, const T min, const T max)
{
return ((x >= min) && (x <= max));
}
-template<typename T, typename F>
-constexpr static inline const T cxpr::sign(const F x)
+template<vx::Arithmetic T, vx::FloatingPoint F>
+constexpr static inline const T vx::sign(const F x)
{
if(x < F(0)) {
return T(-1);
@@ -187,13 +181,10 @@ constexpr static inline const T cxpr::sign(const F x)
}
}
-template<typename T, typename F>
-constexpr static inline const T cxpr::smoothstep(const T x, const T y, const F a)
+template<vx::Arithmetic T, vx::FloatingPoint F>
+constexpr static inline const T vx::smoothstep(const T x, const T y, const F a)
{
- static_assert(std::is_arithmetic_v<T>);
- static_assert(std::is_floating_point_v<F>);
-
- const F t = cxpr::clamp<F>((a - x) / (y - x), F(0), F(1));
+ const F t = vx::clamp<F>((a - x) / (y - x), F(0), F(1));
return static_cast<T>(t * t * (F(3) - F(2) * t));
}
diff --git a/core/feature.hh.in b/core/feature.hh.in
deleted file mode 100644
index 3578416..0000000
--- a/core/feature.hh.in
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef CORE_FEATURE_HH
-#define CORE_FEATURE_HH 1
-#pragma once
-
-#endif /* CORE_FEATURE_HH */
diff --git a/core/floathacks.hh b/core/floathacks.hh
index 0796b10..31915c8 100644
--- a/core/floathacks.hh
+++ b/core/floathacks.hh
@@ -10,10 +10,11 @@ static inline std::int32_t float_to_int32(const float value);
static inline std::uint32_t float_to_uint32(const float value);
} // namespace floathacks
+static_assert(std::numeric_limits<float>::is_iec559, "Floathacks only works with IEEE 754 compliant floats");
+static_assert(sizeof(std::int32_t) == sizeof(float), "Floathacks requires 32-bit integers to match float size");
+
static inline float floathacks::int32_to_float(const std::int32_t value)
{
- static_assert(std::numeric_limits<float>::is_iec559);
- static_assert(sizeof(std::int32_t) == sizeof(float));
union {
std::int32_t src;
float dst;
@@ -24,8 +25,6 @@ static inline float floathacks::int32_to_float(const std::int32_t value)
static inline float floathacks::uint32_to_float(const std::uint32_t value)
{
- static_assert(std::numeric_limits<float>::is_iec559);
- static_assert(sizeof(std::uint32_t) == sizeof(float));
union {
std::uint32_t src;
float dst;
@@ -36,8 +35,6 @@ static inline float floathacks::uint32_to_float(const std::uint32_t value)
static inline std::int32_t floathacks::float_to_int32(const float value)
{
- static_assert(std::numeric_limits<float>::is_iec559);
- static_assert(sizeof(std::int32_t) == sizeof(float));
union {
float src;
std::int32_t dst;
@@ -48,8 +45,6 @@ static inline std::int32_t floathacks::float_to_int32(const float value)
static inline std::uint32_t floathacks::float_to_uint32(const float value)
{
- static_assert(std::numeric_limits<float>::is_iec559);
- static_assert(sizeof(std::uint32_t) == sizeof(float));
union {
float src;
std::uint32_t dst;
diff --git a/core/image.cc b/core/image.cc
index 47a05b5..08be3d4 100644
--- a/core/image.cc
+++ b/core/image.cc
@@ -55,7 +55,8 @@ resource_ptr<Image> resource::load<Image>(const char* name, unsigned int flags)
if(flags & IMAGE_LOAD_GRAY) {
new_resource->pixels = stbi_load_from_callbacks(&callbacks, file, &new_resource->size.x, &new_resource->size.y, nullptr, STBI_grey);
} else {
- new_resource->pixels = stbi_load_from_callbacks(&callbacks, file, &new_resource->size.x, &new_resource->size.y, nullptr, STBI_rgb_alpha);
+ new_resource->pixels = stbi_load_from_callbacks(
+ &callbacks, file, &new_resource->size.x, &new_resource->size.y, nullptr, STBI_rgb_alpha);
}
PHYSFS_close(file);
diff --git a/core/pch.hh b/core/pch.hh
index 75ed0f6..795a287 100644
--- a/core/pch.hh
+++ b/core/pch.hh
@@ -10,7 +10,9 @@
#include <algorithm>
#include <chrono>
+#include <concepts>
#include <filesystem>
+#include <format>
#include <iostream>
#include <limits>
#include <mutex>
@@ -40,7 +42,6 @@
#include <physfs.h>
-#include <spdlog/fmt/fmt.h>
#include <spdlog/spdlog.h>
#include <stb_image.h>
diff --git a/core/vectors.hh b/core/vectors.hh
index 86263b7..a6e9c75 100644
--- a/core/vectors.hh
+++ b/core/vectors.hh
@@ -2,48 +2,46 @@
#define CORE_VECTORS_HH 1
#pragma once
-// cxvectors.hh - because NO ONE would POSSIBLY
+#include "core/concepts.hh"
+
+// core/vectors.hh - because NO ONE would POSSIBLY
// need integer-based distance calculations in a
// game about voxels. That would be INSANE! :D
-namespace cxvectors
+namespace vx
{
-template<typename value_type>
-constexpr static inline const value_type length2(const glm::vec<2, value_type>& vector);
-template<typename value_type>
-constexpr static inline const value_type length2(const glm::vec<3, value_type>& vector);
-template<typename value_type>
-constexpr static inline const value_type distance2(const glm::vec<2, value_type>& vector_a, const glm::vec<2, value_type>& vector_b);
-template<typename value_type>
-constexpr static inline const value_type distance2(const glm::vec<3, value_type>& vector_a, const glm::vec<3, value_type>& vector_b);
-} // namespace cxvectors
-
-template<typename value_type>
-constexpr static inline const value_type cxvectors::length2(const glm::vec<2, value_type>& vector)
+template<vx::Arithmetic T>
+constexpr static inline const T length2(const glm::vec<2, T>& vector);
+template<vx::Arithmetic T>
+constexpr static inline const T length2(const glm::vec<3, T>& vector);
+template<vx::Arithmetic T>
+constexpr static inline const T distance2(const glm::vec<2, T>& vector_a, const glm::vec<2, T>& vector_b);
+template<vx::Arithmetic T>
+constexpr static inline const T distance2(const glm::vec<3, T>& vector_a, const glm::vec<3, T>& vector_b);
+} // namespace vx
+
+template<vx::Arithmetic T>
+constexpr static inline const T vx::length2(const glm::vec<2, T>& vector)
{
- static_assert(std::is_arithmetic_v<value_type>);
return (vector.x * vector.x) + (vector.y * vector.y);
}
-template<typename value_type>
-constexpr static inline const value_type cxvectors::length2(const glm::vec<3, value_type>& vector)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::length2(const glm::vec<3, T>& vector)
{
- static_assert(std::is_arithmetic_v<value_type>);
return (vector.x * vector.x) + (vector.y * vector.y) + (vector.z * vector.z);
}
-template<typename value_type>
-constexpr static inline const value_type cxvectors::distance2(const glm::vec<2, value_type>& vector_a, const glm::vec<2, value_type>& vector_b)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::distance2(const glm::vec<2, T>& vector_a, const glm::vec<2, T>& vector_b)
{
- static_assert(std::is_arithmetic_v<value_type>);
- return cxvectors::length2(vector_a - vector_b);
+ return vx::length2(vector_a - vector_b);
}
-template<typename value_type>
-constexpr static inline const value_type cxvectors::distance2(const glm::vec<3, value_type>& vector_a, const glm::vec<3, value_type>& vector_b)
+template<vx::Arithmetic T>
+constexpr static inline const T vx::distance2(const glm::vec<3, T>& vector_a, const glm::vec<3, T>& vector_b)
{
- static_assert(std::is_arithmetic_v<value_type>);
- return cxvectors::length2(vector_a - vector_b);
+ return vx::length2(vector_a - vector_b);
}
#endif /* CORE_VECTORS_HH */
diff --git a/core/version.cc.in b/core/version.cc.in
new file mode 100644
index 0000000..0183ec0
--- /dev/null
+++ b/core/version.cc.in
@@ -0,0 +1,12 @@
+#include "core/pch.hh"
+
+#include "core/version.hh"
+
+// clang-format off
+const unsigned long project_version_major = ${PROJECT_VERSION_MAJOR};
+const unsigned long project_version_minor = ${PROJECT_VERSION_MINOR};
+const unsigned long project_version_patch = ${PROJECT_VERSION_PATCH};
+const unsigned long project_version_tweak = ${PROJECT_VERSION_TWEAK};
+// clang-format on
+
+const std::string project_version_string = "${PROJECT_VERSION}";
diff --git a/core/version.hh b/core/version.hh
new file mode 100644
index 0000000..2061c31
--- /dev/null
+++ b/core/version.hh
@@ -0,0 +1,12 @@
+#ifndef CORE_VERSION_HH
+#define CORE_VERSION_HH 1
+#pragma once
+
+extern const unsigned long project_version_major;
+extern const unsigned long project_version_minor;
+extern const unsigned long project_version_patch;
+extern const unsigned long project_version_tweak;
+
+extern const std::string project_version_string;
+
+#endif /* CORE_VERSION_HH */
diff --git a/core/version.hh.in b/core/version.hh.in
deleted file mode 100644
index bddd283..0000000
--- a/core/version.hh.in
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef CORE_VERSION_HH
-#define CORE_VERSION_HH 1
-#pragma once
-
-#define PROJECT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}
-#define PROJECT_VERSION_MINOR ${PROJECT_VERSION_MINOR}
-#define PROJECT_VERSION_PATCH ${PROJECT_VERSION_PATCH}
-#define PROJECT_VERSION_TWEAK ${PROJECT_VERSION_TWEAK}
-
-#define PROJECT_VERSION_STRING "${PROJECT_VERSION}"
-
-#endif /* CORE_VERSION_HH */