diff --git a/CMakePresets.json b/CMakePresets.json index 47ba71e34..508719628 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -15,6 +15,22 @@ "VOXELENGINE_BUILD_TESTS": "ON" } }, + { + "name": "default-ninja-mingw-windows", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + }, + "generator": "Ninja Multi-Config", + "binaryDir": "${sourceDir}/build-mingw", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "VCPKG_HOST_TRIPLET": "x64-mingw-static", + "VCPKG_TARGET_TRIPLET": "x64-mingw-static", + "VOXELENGINE_BUILD_TESTS": "ON" + } + }, { "name": "default-ninja-gnu-linux", "condition": { @@ -60,6 +76,11 @@ "configurePreset": "default-vs-msvc-windows", "configuration": "Debug" }, + { + "name": "default-ninja-mingw-windows", + "configurePreset": "default-ninja-mingw-windows", + "configuration": "Debug" + }, { "name": "default-ninja-gnu-linux", "configurePreset": "default-ninja-gnu-linux", diff --git a/README.md b/README.md index 1d6a462c9..e672ef541 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,26 @@ cmake --build --preset default-vs-msvc-windows > [!NOTE] > Make sure your `CMakeUserPresets.json` (if used) contains the correct `VCPKG_ROOT` path. +--- +### Building with CLion (MinGW / Ninja) + +> [!NOTE] +> Requirements: **vcpkg**, **Git**, and **CLion** (bundled with CMake, Ninja and MinGW toolchain). + +> [!WARNING] +> Avoid installing tools in paths with spaces (e.g. `Program Files`). +> This may break MinGW builds (especially `windres`). + +Install **vcpkg** manually as described in the Visual Studio section. + + +#### Configure CLion +Open the project in CLion and configure CMake profile: +```text +Settings → Build, Execution, Deployment → CMake +``` +Reload CMake project and build the engine. + --- ## Build using Docker diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d6f4c5b74..12ece0f7f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -37,6 +37,14 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") "$ENV{VCPKG_ROOT}/packages/luajit_${VCPKG_TARGET_TRIPLET}/include/" ) else() + set(LUAJIT_PACKAGE_DIR "$ENV{VCPKG_ROOT}/packages/luajit_${VCPKG_TARGET_TRIPLET}") + + if(EXISTS "$ENV{VCPKG_ROOT}/packages/luajit_${VCPKG_TARGET_TRIPLET}/include/luajit-2.1") + set(LUAJIT_INCLUDE_DIR "$ENV{VCPKG_ROOT}/packages/luajit_${VCPKG_TARGET_TRIPLET}/include/luajit-2.1") + else() + set(LUAJIT_INCLUDE_DIR "$ENV{VCPKG_ROOT}/packages/luajit_${VCPKG_TARGET_TRIPLET}/include/luajit") + endif() + add_library(luajit SHARED IMPORTED) set_target_properties( luajit @@ -45,8 +53,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") "$ENV{VCPKG_ROOT}/packages/luajit_${VCPKG_TARGET_TRIPLET}/bin/lua51.dll" IMPORTED_IMPLIB "$ENV{VCPKG_ROOT}/packages/luajit_${VCPKG_TARGET_TRIPLET}/lib/lua51.lib" - INTERFACE_INCLUDE_DIRECTORIES - "$ENV{VCPKG_ROOT}/packages/luajit_${VCPKG_TARGET_TRIPLET}/include/luajit" + INTERFACE_INCLUDE_DIRECTORIES "${LUAJIT_INCLUDE_DIR}" ) endif() diff --git a/src/coders/BasicParser.inl b/src/coders/BasicParser.inl index 796205b2a..5b249bfcf 100644 --- a/src/coders/BasicParser.inl +++ b/src/coders/BasicParser.inl @@ -22,9 +22,26 @@ namespace { } inline double power(double base, int64_t power) { + if (power == 0) { + return 1.0; + } + + uint64_t exp; + if (power < 0) { + base = 1.0 / base; + exp = static_cast(-(power + 1)) + 1; + } else { + exp = static_cast(power); + } + double result = 1.0; - for (int64_t i = 0; i < power; i++) { - result *= base; + + while (exp > 0) { + if (exp & 1) + result *= base; + + base *= base; + exp >>= 1; } return result; } diff --git a/src/util/SmallHeap.hpp b/src/util/SmallHeap.hpp index 8a6ff9290..6ff8cf238 100644 --- a/src/util/SmallHeap.hpp +++ b/src/util/SmallHeap.hpp @@ -11,8 +11,10 @@ namespace util { template - inline T read_int_le(const uint8_t* src, size_t offset=0) { - return dataio::le2h(*(reinterpret_cast(src) + offset)); + inline T read_int_le(const uint8_t* src) { + T tmp; + std::memcpy(&tmp, src, sizeof(T)); + return dataio::le2h(tmp); } /// @brief Simple heap implementation for memory-optimal sparse array of @@ -87,8 +89,7 @@ namespace util { std::memset(found, 0, entrySize); return found; } - this->free(found); - return allocate(index, size); + free(found); } for (size_t i = 0; i < entriesCount; i++) { auto data = buffer.data() + offset; @@ -110,9 +111,12 @@ namespace util { entriesCount++; auto data = buffer.data() + offset; - *reinterpret_cast(data) = dataio::h2le(index); + + Tindex indexTmp = dataio::h2le(index); + Tsize sizeTmp = dataio::h2le(size); + std::memcpy(data, &indexTmp, sizeof(Tindex)); data += sizeof(Tindex); - *reinterpret_cast(data) = dataio::h2le(size); + std::memcpy(data, &sizeTmp, sizeof(Tsize)); return data + sizeof(Tsize); } @@ -122,7 +126,7 @@ namespace util { if (ptr == nullptr) { return 0; } - return read_int_le(ptr, -1); + return read_int_le(ptr - sizeof(Tsize)); } /// @return number of entries @@ -147,7 +151,8 @@ namespace util { ubyte* dst = out.data(); const ubyte* src = buffer.data(); - *reinterpret_cast(dst) = dataio::h2le(entriesCount); + Tindex countTmp = dataio::h2le(entriesCount); + std::memcpy(dst, &countTmp, sizeof(Tindex)); dst += sizeof(Tindex); std::memcpy(dst, src, buffer.size()); @@ -172,7 +177,7 @@ namespace util { ) : buffer(buffer), index(index), offset(offset) {} Tsize size() const { - return read_int_le(buffer.data() + offset, -1); + return read_int_le(buffer.data() + offset - sizeof(Tsize)); } bool operator!=(const const_iterator& o) const { diff --git a/src/window/detail/GLFWWindow.cpp b/src/window/detail/GLFWWindow.cpp index db3d67241..394472783 100644 --- a/src/window/detail/GLFWWindow.cpp +++ b/src/window/detail/GLFWWindow.cpp @@ -33,6 +33,7 @@ static void init_gl_extensions_list() { } } +[[maybe_unused]] static bool is_gl_extension_supported(const char *extension) { if (!extension || !*extension) { return false; @@ -40,6 +41,7 @@ static bool is_gl_extension_supported(const char *extension) { return supported_gl_extensions.find(extension) != supported_gl_extensions.end(); } +#ifndef __APPLE__ static const char* gl_error_name(int error) { switch (error) { case GL_DEBUG_TYPE_ERROR: return "ERROR"; @@ -80,6 +82,7 @@ static void GLAPIENTRY gl_message_callback( logger.warning() << "GL:" << gl_error_name(type) << ":" << gl_severity_name(severity) << ": " << message; } +#endif static bool initialize_gl(int width, int height) { glewExperimental = GL_TRUE; diff --git a/test/coders/json.cpp b/test/coders/json.cpp index be9f0534d..bf3d53a91 100644 --- a/test/coders/json.cpp +++ b/test/coders/json.cpp @@ -8,6 +8,8 @@ TEST(JSON, EncodeDecode) { const int bytesSize = 20; const int year = 2019; const float score = 3.141592; + const double distance = 1.23e45; + const double epsilon = 1e-6; const bool visible = true; dv::objects::Bytes srcBytes(bytesSize); for (int i = 0; i < bytesSize; i ++) { @@ -20,6 +22,8 @@ TEST(JSON, EncodeDecode) { object["name"] = name; object["year"] = year; object["score"] = score; + object["distance"] = distance; + object["epsilon"] = epsilon; object["visible"] = visible; object["data"] = srcBytes; @@ -30,6 +34,8 @@ TEST(JSON, EncodeDecode) { EXPECT_EQ(object["name"].asString(), name); EXPECT_EQ(object["year"].asInteger(), year); EXPECT_FLOAT_EQ(object["score"].asNumber(), score); + EXPECT_DOUBLE_EQ(object["distance"].asNumber(), distance); + EXPECT_DOUBLE_EQ(object["epsilon"].asNumber(), epsilon); EXPECT_EQ(object["visible"].asBoolean(), visible); auto b64string = object["data"].asString(); diff --git a/test/util/SmallHeap.cpp b/test/util/SmallHeap.cpp index c5b3adf28..a4ecab842 100644 --- a/test/util/SmallHeap.cpp +++ b/test/util/SmallHeap.cpp @@ -8,9 +8,13 @@ TEST(SmallHeap, Allocation) { auto index = 0; auto size = 4; + std::cout << "step 1" << std::endl; SmallHeap map; + std::cout << "step 2" << std::endl; auto ptr = map.allocate(index, size); + std::cout << "ptr: " << (void*)ptr << " le2h(1): " << dataio::le2h(1) << " h2le(1): " << dataio::h2le(1) << std::endl; EXPECT_EQ(map.sizeOf(ptr), size); + std::cout << "step 4" << std::endl; EXPECT_EQ(ptr, map.find(index)); }