Major SDK improvements + Cap'n Proto assets format
This commit is contained in:
parent
55258615c5
commit
7ec8c82569
@ -17,16 +17,15 @@ endif()
|
|||||||
|
|
||||||
project (EtrediaEmpires LANGUAGES CXX)
|
project (EtrediaEmpires LANGUAGES CXX)
|
||||||
|
|
||||||
add_subdirectory(sdk/map)
|
add_subdirectory(sdk)
|
||||||
add_subdirectory(sdk/assets)
|
|
||||||
|
|
||||||
add_subdirectory(p7lib)
|
add_subdirectory(p7lib)
|
||||||
add_subdirectory(utils)
|
add_subdirectory(utils)
|
||||||
|
|
||||||
add_subdirectory(server/lib)
|
#add_subdirectory(server/lib)
|
||||||
add_subdirectory(engine-api)
|
add_subdirectory(engine-api)
|
||||||
|
|
||||||
add_subdirectory(renderers/magnum-renderer)
|
# add_subdirectory(renderers/magnum-renderer)
|
||||||
add_subdirectory(renderers/vulkan)
|
add_subdirectory(renderers/vulkan)
|
||||||
|
|
||||||
add_subdirectory(engine)
|
add_subdirectory(engine)
|
||||||
|
Before Width: | Height: | Size: 33 MiB After Width: | Height: | Size: 33 MiB |
|
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 364 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
11
assets-src/regions.json
Normal file
11
assets-src/regions.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"pepene": "#AA00FF",
|
||||||
|
"scarna": "#FF007F",
|
||||||
|
|
||||||
|
"dineria": "#FFFF00",
|
||||||
|
"perdania": "#7FFF00",
|
||||||
|
"arstinia": "#FF0000",
|
||||||
|
"alende": "#0000FF",
|
||||||
|
"zerandia": "#FF5400",
|
||||||
|
"mgahvatia": "#5400FF"
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
贔PD゙<EFBFBD>タイ
|
|
||||||
Binary file not shown.
@ -1,7 +1,7 @@
|
|||||||
project(engine-api)
|
|
||||||
|
|
||||||
include(${CMAKE_SOURCE_DIR}/cmake/library.cmake)
|
include(${CMAKE_SOURCE_DIR}/cmake/library.cmake)
|
||||||
|
|
||||||
|
set(LIB engine-api)
|
||||||
|
|
||||||
# Find dependencies
|
# Find dependencies
|
||||||
|
|
||||||
find_package(glfw3 CONFIG REQUIRED)
|
find_package(glfw3 CONFIG REQUIRED)
|
||||||
@ -9,10 +9,9 @@ find_package(glm CONFIG REQUIRED)
|
|||||||
|
|
||||||
# Link library
|
# Link library
|
||||||
|
|
||||||
add_library_target(${PROJECT_NAME})
|
add_library_target(${LIB})
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE p7)
|
target_link_libraries(${LIB} PRIVATE p7)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC server)
|
target_link_libraries(${LIB} PUBLIC utils)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC utils)
|
target_link_libraries(${LIB} PRIVATE glfw)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE glfw)
|
target_link_libraries(${LIB} PRIVATE glm::glm)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE glm::glm)
|
|
||||||
@ -1,12 +1,12 @@
|
|||||||
export module AssetData;
|
export module AssetData;
|
||||||
import GameData;
|
export import GameData;
|
||||||
import views;
|
export import views;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
export namespace ee_assets {
|
export namespace ee_assets {
|
||||||
struct AssetData {};
|
struct AssetTag {};
|
||||||
|
|
||||||
template <typename T> concept Asset = std::is_base_of_v<AssetData, T>;
|
template <typename T> concept Asset = requires { typename T::asset_tag; };
|
||||||
|
|
||||||
enum AssetType {
|
enum AssetType {
|
||||||
BINARY,
|
BINARY,
|
||||||
@ -19,33 +19,33 @@ export namespace ee_assets {
|
|||||||
IMAGE
|
IMAGE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AssetBinary : public AssetData {
|
struct AssetBinary {
|
||||||
|
using asset_tag = AssetTag;
|
||||||
|
|
||||||
std::uint8_t *content = nullptr;
|
std::uint8_t *content = nullptr;
|
||||||
std::size_t size = 0;
|
std::size_t size = 0;
|
||||||
|
|
||||||
AssetBinary(std::uint8_t * & source, const std::size_t sourceSize);
|
AssetBinary(std::uint8_t * & source, std::size_t sourceSize);
|
||||||
~AssetBinary();
|
~AssetBinary();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AssetMapMesh : public AssetData {
|
struct AssetMapMesh {
|
||||||
ee_engine::MapMesh content;
|
using asset_tag = AssetTag;
|
||||||
|
|
||||||
std::uint8_t* Serialize(std::size_t& size);
|
ee_engine::MapMesh content;
|
||||||
AssetMapMesh() {};
|
|
||||||
AssetMapMesh(std::uint8_t * & source, const std::size_t sourceSize);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AssetSave : public AssetData {
|
struct AssetSave {
|
||||||
ee_data::GameState content;
|
using asset_tag = AssetTag;
|
||||||
|
|
||||||
std::uint8_t* Serialize(std::size_t& size);
|
ee_data::GameState content;
|
||||||
AssetSave() {};
|
|
||||||
AssetSave(std::uint8_t * & source, const std::size_t sourceSize);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using AssetShader = AssetBinary;
|
using AssetShader = AssetBinary;
|
||||||
|
|
||||||
struct AssetMaterial : public AssetData {
|
struct AssetMaterial {
|
||||||
|
using asset_tag = AssetTag;
|
||||||
|
|
||||||
std::uint32_t vertexShaderAssetID;
|
std::uint32_t vertexShaderAssetID;
|
||||||
std::uint32_t fragmentShaderAssetID;
|
std::uint32_t fragmentShaderAssetID;
|
||||||
};
|
};
|
||||||
|
|||||||
17
engine-api/modules/Packets.cppm
Normal file
17
engine-api/modules/Packets.cppm
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export module Packets;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
export namespace ee_data {
|
||||||
|
enum class Route {
|
||||||
|
LOAD_SAVE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Request {
|
||||||
|
Route route;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Response {
|
||||||
|
Route route;
|
||||||
|
std::span<std::byte> payload;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -26,7 +26,7 @@ export namespace ee_engine {
|
|||||||
float rotation;
|
float rotation;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RendererCommand : public ee_utils::WorkerCommand {
|
struct RendererCommand : ee_utils::WorkerCommand {
|
||||||
enum Type : std::uint8_t {
|
enum Type : std::uint8_t {
|
||||||
NONE,
|
NONE,
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ export namespace ee_engine {
|
|||||||
std::vector<std::uint16_t> indices;
|
std::vector<std::uint16_t> indices;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<std::uint32_t, std::vector<Province>> regions;
|
std::unordered_map<std::uint32_t /* colorId */, std::vector<Province>> regions;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProvinceSSBO {
|
struct ProvinceSSBO {
|
||||||
|
|||||||
@ -10,8 +10,6 @@ YOU CAN PREVENT SOURCE BUFFER FROM CLOSING.
|
|||||||
IT CAN BE USED FOR STORING ASSET DATA WITHOUT COPY.
|
IT CAN BE USED FOR STORING ASSET DATA WITHOUT COPY.
|
||||||
IN THIS CASE, YOU MUST SET SOURCE TO NULLPTR AND FREE BUFFER YOURSELF.
|
IN THIS CASE, YOU MUST SET SOURCE TO NULLPTR AND FREE BUFFER YOURSELF.
|
||||||
|
|
||||||
TODO: make universal binary format, think about flatbuffers or msgpacks
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ee_assets::AssetBinary::AssetBinary(std::uint8_t * & source, const std::size_t sourceSize) {
|
ee_assets::AssetBinary::AssetBinary(std::uint8_t * & source, const std::size_t sourceSize) {
|
||||||
@ -24,128 +22,3 @@ ee_assets::AssetBinary::~AssetBinary() {
|
|||||||
if (content != nullptr)
|
if (content != nullptr)
|
||||||
DeallocateArray(content);
|
DeallocateArray(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ee_assets::AssetMapMesh::AssetMapMesh(std::uint8_t * & source, const std::size_t sourceSize) {
|
|
||||||
std::uint8_t *buffer = source;
|
|
||||||
std::uint8_t *pointer = source;
|
|
||||||
std::size_t leftoverSize = sourceSize;
|
|
||||||
source = nullptr;
|
|
||||||
|
|
||||||
std::uint32_t regionsCount = 0;
|
|
||||||
ee_utils::readNext(®ionsCount, pointer, leftoverSize, sizeof(std::uint32_t));
|
|
||||||
|
|
||||||
for (std::uint32_t region = 0; region < regionsCount; region++) {
|
|
||||||
std::uint32_t id = 0;
|
|
||||||
glm::u8vec3 color{};
|
|
||||||
if (!ee_utils::readNext(&color, pointer, leftoverSize, sizeof(glm::u8vec3)))
|
|
||||||
break;
|
|
||||||
id = static_cast<std::uint32_t>(color.r) << 16 |
|
|
||||||
static_cast<std::uint32_t>(color.g) << 8 |
|
|
||||||
static_cast<std::uint32_t>(color.b);
|
|
||||||
|
|
||||||
std::uint32_t provincesCount = 0;
|
|
||||||
ee_utils::readNext(&provincesCount, pointer, leftoverSize, sizeof(std::uint32_t));
|
|
||||||
|
|
||||||
for (std::uint32_t pi = 0; pi < provincesCount; pi++) {
|
|
||||||
ee_engine::MapMesh::Province prov;
|
|
||||||
|
|
||||||
std::uint32_t verticesCount = 0;
|
|
||||||
if (!ee_utils::readNext(&verticesCount, pointer, leftoverSize, sizeof(std::uint32_t)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
prov.vertices.reserve(verticesCount);
|
|
||||||
for (std::uint32_t vi = 0; vi < verticesCount; vi++) {
|
|
||||||
glm::vec2 vertex;
|
|
||||||
if (!ee_utils::readNext(&vertex, pointer, leftoverSize, sizeof(glm::vec2)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
prov.vertices.push_back(vertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint32_t indicesCount = 0;
|
|
||||||
if (!ee_utils::readNext(&indicesCount, pointer, leftoverSize, sizeof(std::uint32_t)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
prov.indices.reserve(indicesCount);
|
|
||||||
for (std::uint32_t ii = 0; ii < indicesCount; ii++) {
|
|
||||||
std::uint16_t index = 0;
|
|
||||||
if (!ee_utils::readNext(&index, pointer, leftoverSize, sizeof(std::uint16_t)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
prov.indices.push_back(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
content.regions[id].push_back(prov);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DeallocateArray(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ee_assets::AssetSave::AssetSave(std::uint8_t * & source, const std::size_t sourceSize) {
|
|
||||||
std::uint8_t *buffer = source;
|
|
||||||
std::uint8_t *pointer = source;
|
|
||||||
std::size_t leftoverSize = sourceSize;
|
|
||||||
source = nullptr;
|
|
||||||
|
|
||||||
std::uint16_t subjectsCount = static_cast<std::uint16_t>(content.subjects.size());
|
|
||||||
ee_utils::readNext(&subjectsCount, pointer, leftoverSize, sizeof(std::uint16_t));
|
|
||||||
|
|
||||||
for (std::uint16_t i = 0; i < subjectsCount; i++) {
|
|
||||||
ee_data::Subject subject;
|
|
||||||
|
|
||||||
ee_utils::readNext(&subject.tag, pointer, leftoverSize, sizeof(subject.tag));
|
|
||||||
ee_utils::readNext(&subject.color, pointer, leftoverSize, sizeof(subject.color));
|
|
||||||
|
|
||||||
std::uint16_t regionsCount = 0;
|
|
||||||
ee_utils::readNext(®ionsCount, pointer, leftoverSize, sizeof(std::uint16_t));
|
|
||||||
subject.regions.resize(regionsCount);
|
|
||||||
ee_utils::readNext(
|
|
||||||
subject.regions.data(),
|
|
||||||
pointer,
|
|
||||||
leftoverSize,
|
|
||||||
subject.regions.size() * sizeof(std::uint32_t)
|
|
||||||
);
|
|
||||||
|
|
||||||
content.subjects.push_back(subject);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeallocateArray(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// SERIALIZERS
|
|
||||||
|
|
||||||
std::uint8_t* ee_assets::AssetSave::Serialize(std::size_t& size) {
|
|
||||||
size = sizeof(std::uint16_t);
|
|
||||||
for (ee_data::Subject& subject : content.subjects) {
|
|
||||||
size += sizeof(subject.tag);
|
|
||||||
size += sizeof(subject.color);
|
|
||||||
size += sizeof(std::uint16_t) + subject.regions.size() * sizeof(std::uint32_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t leftover = size;
|
|
||||||
std::uint8_t *result = AllocateArray<std::uint8_t>(size);
|
|
||||||
std::uint8_t *pointer = result;
|
|
||||||
|
|
||||||
std::uint16_t subjectsCount = static_cast<std::uint16_t>(content.subjects.size());
|
|
||||||
ee_utils::writeNext(pointer, &subjectsCount, leftover, sizeof(std::uint16_t));
|
|
||||||
|
|
||||||
for (ee_data::Subject& subject : content.subjects) {
|
|
||||||
ee_utils::writeNext(pointer, &subject.tag, leftover, sizeof(subject.tag));
|
|
||||||
ee_utils::writeNext(pointer, &subject.color, leftover, sizeof(subject.color));
|
|
||||||
|
|
||||||
std::uint16_t regionsCount = static_cast<std::uint16_t>(subject.regions.size());
|
|
||||||
ee_utils::writeNext(pointer, ®ionsCount, leftover, sizeof(std::uint16_t));
|
|
||||||
ee_utils::writeNext(
|
|
||||||
pointer,
|
|
||||||
subject.regions.data(),
|
|
||||||
leftover,
|
|
||||||
subject.regions.size() * sizeof(std::uint32_t)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ find_package(Boost REQUIRED COMPONENTS lockfree)
|
|||||||
find_package(xxHash CONFIG REQUIRED)
|
find_package(xxHash CONFIG REQUIRED)
|
||||||
find_package(glfw3 CONFIG REQUIRED)
|
find_package(glfw3 CONFIG REQUIRED)
|
||||||
find_package(glm CONFIG REQUIRED)
|
find_package(glm CONFIG REQUIRED)
|
||||||
|
find_package(reflectcpp CONFIG REQUIRED)
|
||||||
|
|
||||||
# Link library
|
# Link library
|
||||||
|
|
||||||
@ -15,7 +16,8 @@ add_executable_target(${EXE})
|
|||||||
|
|
||||||
target_link_libraries(${EXE} PUBLIC utils)
|
target_link_libraries(${EXE} PUBLIC utils)
|
||||||
target_link_libraries(${EXE} PUBLIC engine-api)
|
target_link_libraries(${EXE} PUBLIC engine-api)
|
||||||
target_link_libraries(${EXE} PUBLIC magnum-renderer)
|
# target_link_libraries(${EXE} PUBLIC server)
|
||||||
|
# target_link_libraries(${EXE} PUBLIC magnum-renderer)
|
||||||
target_link_libraries(${EXE} PUBLIC vulkan-renderer)
|
target_link_libraries(${EXE} PUBLIC vulkan-renderer)
|
||||||
|
|
||||||
target_link_libraries(${EXE} PRIVATE Boost::lockfree)
|
target_link_libraries(${EXE} PRIVATE Boost::lockfree)
|
||||||
@ -23,6 +25,7 @@ target_link_libraries(${EXE} PRIVATE xxHash::xxhash)
|
|||||||
target_link_libraries(${EXE} PRIVATE p7)
|
target_link_libraries(${EXE} PRIVATE p7)
|
||||||
target_link_libraries(${EXE} PRIVATE glfw)
|
target_link_libraries(${EXE} PRIVATE glfw)
|
||||||
target_link_libraries(${EXE} PRIVATE glm::glm)
|
target_link_libraries(${EXE} PRIVATE glm::glm)
|
||||||
|
target_link_libraries(${EXE} PRIVATE reflectcpp::reflectcpp)
|
||||||
|
|
||||||
# Compile options
|
# Compile options
|
||||||
if (APP_VERSION)
|
if (APP_VERSION)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ module;
|
|||||||
|
|
||||||
#include "compile_config.hpp"
|
#include "compile_config.hpp"
|
||||||
#include <xxhash.h>
|
#include <xxhash.h>
|
||||||
|
#include <rfl/capnproto.hpp>
|
||||||
|
|
||||||
export module AssetManager;
|
export module AssetManager;
|
||||||
export import AssetData;
|
export import AssetData;
|
||||||
@ -29,7 +30,7 @@ export
|
|||||||
std::atomic<bool> isReady;
|
std::atomic<bool> isReady;
|
||||||
AssetAddress *resourceAddress;
|
AssetAddress *resourceAddress;
|
||||||
|
|
||||||
AssetInfo(void *resource) {
|
explicit AssetInfo(void *resource) {
|
||||||
this->resourceAddress = Allocate<AssetAddress>();
|
this->resourceAddress = Allocate<AssetAddress>();
|
||||||
this->resourceAddress->resource.store(resource);
|
this->resourceAddress->resource.store(resource);
|
||||||
}
|
}
|
||||||
@ -122,7 +123,7 @@ export
|
|||||||
|
|
||||||
Request(command);
|
Request(command);
|
||||||
while (command.out->load() == nullptr) {}
|
while (command.out->load() == nullptr) {}
|
||||||
return *reinterpret_cast<AssetHandle*>(command.out->load());
|
return *static_cast<AssetHandle*>(command.out->load());
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetHandle& Find(const std::uint32_t id) {
|
AssetHandle& Find(const std::uint32_t id) {
|
||||||
@ -133,8 +134,8 @@ export
|
|||||||
command.out = &result;
|
command.out = &result;
|
||||||
|
|
||||||
Request(command);
|
Request(command);
|
||||||
while (command.out->load() == nullptr);
|
while (command.out->load() == nullptr) {}
|
||||||
return *reinterpret_cast<AssetHandle*>(command.out->load());
|
return *static_cast<AssetHandle*>(command.out->load());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returned resource reference should not be stored
|
// Returned resource reference should not be stored
|
||||||
@ -149,7 +150,7 @@ export
|
|||||||
return Get<T>(Find(id));
|
return Get<T>(Find(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Redirect(const AssetHandle& handle, void *resource) {
|
void Redirect(const AssetHandle& handle, void *resource) const {
|
||||||
const AssetInfo& asset = activeAssets[handle.slot];
|
const AssetInfo& asset = activeAssets[handle.slot];
|
||||||
if (asset.resourceAddress == nullptr) {
|
if (asset.resourceAddress == nullptr) {
|
||||||
LOG(WARNING, "Attempt to redirect empty handle");
|
LOG(WARNING, "Attempt to redirect empty handle");
|
||||||
@ -176,11 +177,11 @@ export
|
|||||||
command.out = &result;
|
command.out = &result;
|
||||||
|
|
||||||
Request(command);
|
Request(command);
|
||||||
while (command.out->load() == nullptr);
|
while (command.out->load() == nullptr) {}
|
||||||
return *reinterpret_cast<T*>(command.out->load());
|
return *static_cast<T*>(command.out->load());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Free(AssetHandle& handle) {
|
void Free(const AssetHandle& handle) {
|
||||||
AssetInfo& asset = activeAssets[handle.slot];
|
AssetInfo& asset = activeAssets[handle.slot];
|
||||||
Redirect(handle, nullptr);
|
Redirect(handle, nullptr);
|
||||||
Deallocate(asset.resourceAddress);
|
Deallocate(asset.resourceAddress);
|
||||||
@ -193,23 +194,22 @@ export
|
|||||||
void Update() override {
|
void Update() override {
|
||||||
// TODO: FinishLoadTasks()
|
// TODO: FinishLoadTasks()
|
||||||
for (AssetLoadingEntry& entry : loadingEntries) {
|
for (AssetLoadingEntry& entry : loadingEntries) {
|
||||||
bool isReady = entry.fileOwner->PollReady(*entry.file);
|
if (entry.fileOwner->PollReady(*entry.file)) {
|
||||||
if (isReady) {
|
|
||||||
AssetInfo& asset = activeAssets[entry.handle.slot];
|
AssetInfo& asset = activeAssets[entry.handle.slot];
|
||||||
|
|
||||||
switch (asset.type) {
|
switch (asset.type) {
|
||||||
case ee_assets::MAP_MESH:
|
case ee_assets::MAP_MESH:
|
||||||
FinishLoadConstruct(entry, mapMeshesStorage);
|
FinishLoadCapnprotoDeserialize(entry, mapMeshesStorage);
|
||||||
break;
|
break;
|
||||||
case ee_assets::SAVE:
|
case ee_assets::SAVE:
|
||||||
FinishLoadConstruct(entry, savesStorage);
|
FinishLoadCapnprotoDeserialize(entry, savesStorage);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ee_assets::SHADER:
|
case ee_assets::SHADER:
|
||||||
FinishLoadConstruct(entry, shadersStorage);
|
FinishLoadConstruct(entry, shadersStorage);
|
||||||
break;
|
break;
|
||||||
case ee_assets::MATERIAL:
|
case ee_assets::MATERIAL:
|
||||||
FinishLoadPlain(entry, materialsStorage);
|
FinishLoadCapnprotoDeserialize(entry, materialsStorage);
|
||||||
break;
|
break;
|
||||||
case ee_assets::IMAGE:
|
case ee_assets::IMAGE:
|
||||||
break;
|
break;
|
||||||
@ -298,13 +298,13 @@ export
|
|||||||
assetPos = activeAssets.size() - 1;
|
assetPos = activeAssets.size() - 1;
|
||||||
}
|
}
|
||||||
handle->slot = assetPos;
|
handle->slot = assetPos;
|
||||||
auto assetPath = command.targetPath.generic_u8string();
|
const std::basic_string<char8_t> assetPath = command.targetPath.generic_u8string();
|
||||||
std::uint32_t assetId = assetsIdMapping[command.targetPath] =
|
const std::uint32_t assetId = assetsIdMapping[command.targetPath] =
|
||||||
XXH32(assetPath.data(), assetPath.size(), ASSETS_HASH_SPACE);
|
XXH32(assetPath.data(), assetPath.size(), ASSETS_HASH_SPACE);
|
||||||
handle->id = assetId;
|
handle->id = assetId;
|
||||||
assetsMapping[assetId] = handle;
|
assetsMapping[assetId] = handle;
|
||||||
|
|
||||||
AssetLoadingEntry loadingEntry{
|
const AssetLoadingEntry loadingEntry{
|
||||||
.handle = *handle,
|
.handle = *handle,
|
||||||
.file = &file,
|
.file = &file,
|
||||||
.fileOwner = diskSystem
|
.fileOwner = diskSystem
|
||||||
@ -324,7 +324,7 @@ export
|
|||||||
id = idMapping->second;
|
id = idMapping->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<std::uint32_t, AssetHandle*>::iterator assetMapping = assetsMapping.find(id);
|
const std::unordered_map<std::uint32_t, AssetHandle*>::iterator assetMapping = assetsMapping.find(id);
|
||||||
|
|
||||||
if (assetMapping == assetsMapping.end())
|
if (assetMapping == assetsMapping.end())
|
||||||
return;
|
return;
|
||||||
@ -335,7 +335,7 @@ export
|
|||||||
command.type = AssetStreamCommand::COMPLETED;
|
command.type = AssetStreamCommand::COMPLETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetCmd(AssetStreamCommand& command) {
|
void GetCmd(AssetStreamCommand& command) const {
|
||||||
if (activeAssets.size() <= command.target.slot)
|
if (activeAssets.size() <= command.target.slot)
|
||||||
return;
|
return;
|
||||||
if (!activeAssets[command.target.slot].isReady)
|
if (!activeAssets[command.target.slot].isReady)
|
||||||
@ -355,14 +355,37 @@ export
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <ee_assets::Asset T>
|
template <ee_assets::Asset T>
|
||||||
void FinishLoadPlain(AssetLoadingEntry& loaded, std::vector<T*>& storage) {
|
void FinishLoadCapnprotoDeserialize(AssetLoadingEntry& loaded, std::vector<T*>& storage) {
|
||||||
T *resource = Allocate<T>();
|
try {
|
||||||
if (loaded.file->size < sizeof(T))
|
if (rfl::Result<T> result = rfl::capnproto::read<T>(
|
||||||
LOG(CRITICAL, "File size is less than needed for asset of type: %d", typeid(T).name());
|
reinterpret_cast<const char*>(loaded.file->data),
|
||||||
std::memcpy(resource, loaded.file->data, sizeof(T));
|
loaded.file->size
|
||||||
storage.push_back(resource);
|
)) {
|
||||||
|
storage.push_back(Allocate<T>(std::move(*result)));
|
||||||
Redirect(loaded.handle, storage.back());
|
Redirect(loaded.handle, storage.back());
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
LOG(
|
||||||
|
ERROR,
|
||||||
|
"Failed to read asset: [%s]. [%hs]",
|
||||||
|
loaded.file->debugPath.c_str(),
|
||||||
|
result.error().what().c_str()
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
LOG(ERROR, "Failed to read asset: ID[%d]. [%hs]", loaded.file->id, result.error().what().c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} catch (std::exception e) {
|
||||||
|
storage.push_back(Allocate<T>());
|
||||||
|
Redirect(loaded.handle, storage.back());
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
LOG(ERROR, "Failed to read asset: [%s]. [%hs]", loaded.file->debugPath.c_str(), e.what());
|
||||||
|
#else
|
||||||
|
LOG(ERROR, "Failed to read asset: ID[%d]. [%hs]", loaded.file->id, e.what());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <ee_assets::Asset T>
|
template <ee_assets::Asset T>
|
||||||
void ClearStorage(std::vector<T*>& storage) {
|
void ClearStorage(std::vector<T*>& storage) {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import std;
|
|||||||
|
|
||||||
export
|
export
|
||||||
{
|
{
|
||||||
struct ClientCommand : public ee_utils::WorkerCommand {
|
struct ClientCommand : ee_utils::WorkerCommand {
|
||||||
enum Type : std::uint8_t {
|
enum Type : std::uint8_t {
|
||||||
NONE,
|
NONE,
|
||||||
|
|
||||||
@ -21,14 +21,14 @@ export
|
|||||||
public:
|
public:
|
||||||
Client();
|
Client();
|
||||||
~Client() override;
|
~Client() override;
|
||||||
void Init();
|
void Init() const;
|
||||||
|
|
||||||
//void Send(); -> Request(SEND)
|
//void Send(); -> Request(SEND)
|
||||||
|
|
||||||
const IDataChannel* GetConnection();
|
const IDataChannel* GetConnection() const;
|
||||||
void ConnectServer();
|
void ConnectServer();
|
||||||
|
|
||||||
void LoadSave(const AssetHandle save);
|
void LoadSave(AssetHandle save);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Update() override;
|
void Update() override;
|
||||||
@ -40,6 +40,6 @@ export
|
|||||||
|
|
||||||
void SendCmd(ClientCommand& command);
|
void SendCmd(ClientCommand& command);
|
||||||
|
|
||||||
void ViewModelSubject(ee_data::Subject subject);
|
static void ViewModelSubject(const ee_data::Subject &subject);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,26 @@
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
export module DataChannel;
|
export module DataChannel;
|
||||||
|
import std;
|
||||||
|
|
||||||
export
|
export
|
||||||
{
|
{
|
||||||
class IDataChannel {
|
class IDataChannel {
|
||||||
public:
|
public:
|
||||||
// virtual void Request() = 0;
|
virtual ~IDataChannel() = default;
|
||||||
|
|
||||||
|
virtual void Request() = 0;
|
||||||
// virtual void Listen() = 0;
|
// virtual void Listen() = 0;
|
||||||
// virtual void Mute() = 0;
|
// virtual void Mute() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetworkChannel final : public IDataChannel {};
|
class NetworkChannel final : public IDataChannel {
|
||||||
|
public:
|
||||||
|
void Request() override;
|
||||||
|
};
|
||||||
|
|
||||||
class ThreadChannel final : public IDataChannel {};
|
class ThreadChannel final : public IDataChannel {
|
||||||
|
public:
|
||||||
|
void Request() override;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,16 +30,16 @@ export
|
|||||||
|
|
||||||
class IFileSystem {
|
class IFileSystem {
|
||||||
public:
|
public:
|
||||||
inline static constexpr std::uint32_t FILE_OPEN_NONE = 0;
|
static constexpr std::uint32_t FILE_OPEN_NONE = 0;
|
||||||
inline static constexpr std::uint32_t FILE_OPEN_READ = (1 << 0);
|
static constexpr std::uint32_t FILE_OPEN_READ = (1 << 0);
|
||||||
inline static constexpr std::uint32_t FILE_OPEN_WRITE = (1 << 1);
|
static constexpr std::uint32_t FILE_OPEN_WRITE = (1 << 1);
|
||||||
inline static constexpr std::uint32_t FILE_OPEN_MMAP = (1 << 2);
|
static constexpr std::uint32_t FILE_OPEN_MMAP = (1 << 2);
|
||||||
inline static constexpr std::uint32_t FILE_READ_SEQUENTIAL = 0;
|
static constexpr std::uint32_t FILE_READ_SEQUENTIAL = 0;
|
||||||
inline static constexpr std::uint32_t FILE_READ_RANDOM_ACCESS = (1 << 0);
|
static constexpr std::uint32_t FILE_READ_RANDOM_ACCESS = (1 << 0);
|
||||||
|
|
||||||
virtual FileHandle& Open(const std::filesystem::path& path, const std::uint32_t flags) = 0;
|
virtual FileHandle& Open(const std::filesystem::path& path, std::uint32_t flags) = 0;
|
||||||
|
|
||||||
virtual void ReadAsync(FileHandle& file, const std::uint32_t bufferSize, const std::uint32_t flags) = 0;
|
virtual void ReadAsync(FileHandle& file, std::uint32_t bufferSize, std::uint32_t flags) = 0;
|
||||||
|
|
||||||
virtual bool PollReady(FileHandle& file) = 0;
|
virtual bool PollReady(FileHandle& file) = 0;
|
||||||
|
|
||||||
@ -55,14 +55,12 @@ export
|
|||||||
|
|
||||||
class NativeFileSystem final : public IFileSystem {
|
class NativeFileSystem final : public IFileSystem {
|
||||||
public:
|
public:
|
||||||
FileHandle& Open(const std::filesystem::path& path, const std::uint32_t flags) override;
|
FileHandle& Open(const std::filesystem::path& path, std::uint32_t flags) override;
|
||||||
|
|
||||||
void ReadAsync(FileHandle& file, const std::uint32_t bufferSize, std::uint32_t flags) override;
|
void ReadAsync(FileHandle& file, std::uint32_t bufferSize, std::uint32_t flags) override;
|
||||||
|
|
||||||
bool PollReady(FileHandle& file) override;
|
bool PollReady(FileHandle& file) override;
|
||||||
|
|
||||||
void Close(FileHandle& file) override;
|
void Close(FileHandle& file) override;
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ Client::Client() : ThreadedWorker(L"Client", 0) {
|
|||||||
commandsMapping[ClientCommand::SEND] = std::bind_front(&Client::SendCmd, this);
|
commandsMapping[ClientCommand::SEND] = std::bind_front(&Client::SendCmd, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Init() {
|
void Client::Init() const {
|
||||||
if (Engine::renderer == nullptr || !Engine::renderer->isReady()) {
|
if (Engine::renderer == nullptr || !Engine::renderer->isReady()) {
|
||||||
LOG(CRITICAL, "Renderer is not ready. Client cannot be created");
|
LOG(CRITICAL, "Renderer is not ready. Client cannot be created");
|
||||||
throw std::logic_error("Renderer is not ready");
|
throw std::logic_error("Renderer is not ready");
|
||||||
@ -19,7 +19,7 @@ void Client::Init() {
|
|||||||
ViewModelSubject(asset.content.subjects[1]);
|
ViewModelSubject(asset.content.subjects[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IDataChannel* Client::GetConnection() {
|
const IDataChannel* Client::GetConnection() const {
|
||||||
return networkConnection;
|
return networkConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,14 +39,15 @@ void Client::Update() {}
|
|||||||
void Client::Release() {}
|
void Client::Release() {}
|
||||||
|
|
||||||
|
|
||||||
|
// ReSharper disable once CppMemberFunctionMayBeStatic
|
||||||
void Client::SendCmd(ClientCommand& command) {
|
void Client::SendCmd(ClientCommand& command) {
|
||||||
command.type = ClientCommand::COMPLETED;
|
command.type = ClientCommand::COMPLETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Client::ViewModelSubject(ee_data::Subject subject) {
|
void Client::ViewModelSubject(const ee_data::Subject &subject) {
|
||||||
for (const std::uint32_t region : subject.regions) {
|
for (const std::uint32_t region : subject.regions) {
|
||||||
ee_engine::ProvinceSSBO vm{
|
const ee_engine::ProvinceSSBO vm {
|
||||||
.regionId = region,
|
.regionId = region,
|
||||||
.color = subject.color
|
.color = subject.color
|
||||||
};
|
};
|
||||||
|
|||||||
7
engine/src/DataChannel.cpp
Normal file
7
engine/src/DataChannel.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module DataChannel;
|
||||||
|
|
||||||
|
void NetworkChannel::Request() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadChannel::Request() {}
|
||||||
@ -31,7 +31,7 @@ int main(int argc, char **argv) {
|
|||||||
glfwMakeContextCurrent(window);
|
glfwMakeContextCurrent(window);
|
||||||
Engine::window = window;
|
Engine::window = window;
|
||||||
|
|
||||||
// Setup Asset Manager TODO: builder
|
// Setup Asset Manager
|
||||||
Engine::assetManager = Allocate<AssetManager>();
|
Engine::assetManager = Allocate<AssetManager>();
|
||||||
Engine::assetManager->Start();
|
Engine::assetManager->Start();
|
||||||
Engine::assetManager->LoadDir(ee_assets::SHADER, "assets/shaders");
|
Engine::assetManager->LoadDir(ee_assets::SHADER, "assets/shaders");
|
||||||
@ -41,18 +41,17 @@ int main(int argc, char **argv) {
|
|||||||
Engine::assetManager->LoadAsync(ee_assets::MAP_MESH, "assets/map/regions.map");
|
Engine::assetManager->LoadAsync(ee_assets::MAP_MESH, "assets/map/regions.map");
|
||||||
Engine::assetManager->LoadAsync(ee_assets::SAVE, "assets/scenarios/empires.save");
|
Engine::assetManager->LoadAsync(ee_assets::SAVE, "assets/scenarios/empires.save");
|
||||||
|
|
||||||
// Setup input manager TODO: builder
|
// Setup input manager
|
||||||
Engine::input = Allocate<GLFWInput>(Actions::mappings);
|
Engine::input = Allocate<GLFWInput>(Actions::mappings);
|
||||||
|
|
||||||
// Setup renderer TODO: builder
|
// Setup renderer
|
||||||
//Engine::renderer = reinterpret_cast<ee_engine::IRenderer*>(Allocate<ee_magnum::MagnumRenderer>(window));
|
|
||||||
Engine::renderer = reinterpret_cast<ee_engine::IRenderer*>(Allocate<ee_vulkan::VulkanRenderer>(window));
|
Engine::renderer = reinterpret_cast<ee_engine::IRenderer*>(Allocate<ee_vulkan::VulkanRenderer>(window));
|
||||||
|
|
||||||
ee_assets::AssetMapMesh& regions = Engine::assetManager->FindOnce<ee_assets::AssetMapMesh>("assets/map/regions.map");
|
ee_assets::AssetMapMesh& regions = Engine::assetManager->FindOnce<ee_assets::AssetMapMesh>("assets/map/regions.map");
|
||||||
Engine::renderer->RegisterMapMesh(®ions.content);
|
Engine::renderer->RegisterMapMesh(®ions.content);
|
||||||
|
|
||||||
//TODO: ShaderRefs builder from set of AssetMaterial
|
//TODO: ShaderRefs builder from set of AssetMaterial
|
||||||
ee_assets::AssetMaterial& provincesMaterial =
|
const ee_assets::AssetMaterial& provincesMaterial =
|
||||||
Engine::assetManager->FindOnce<ee_assets::AssetMaterial>("assets/materials/provinces.mat");
|
Engine::assetManager->FindOnce<ee_assets::AssetMaterial>("assets/materials/provinces.mat");
|
||||||
ee_assets::AssetShader& vertProv = Engine::assetManager->FindOnce<ee_assets::AssetShader>(
|
ee_assets::AssetShader& vertProv = Engine::assetManager->FindOnce<ee_assets::AssetShader>(
|
||||||
provincesMaterial.vertexShaderAssetID);
|
provincesMaterial.vertexShaderAssetID);
|
||||||
@ -74,7 +73,7 @@ int main(int argc, char **argv) {
|
|||||||
Engine::renderer->ResizeWindow(width, height);
|
Engine::renderer->ResizeWindow(width, height);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup Client TODO: builder
|
// Setup Client
|
||||||
Engine::client = Allocate<Client>();
|
Engine::client = Allocate<Client>();
|
||||||
const AssetHandle save = Engine::assetManager->Find("assets/scenarios/empires.save");
|
const AssetHandle save = Engine::assetManager->Find("assets/scenarios/empires.save");
|
||||||
Engine::client->LoadSave(save);
|
Engine::client->LoadSave(save);
|
||||||
|
|||||||
@ -82,7 +82,7 @@ void ee_magnum::MagnumRenderer::LoadProvinces() {
|
|||||||
|
|
||||||
regionMesh.setPrimitive(GL::MeshPrimitive::Triangles)
|
regionMesh.setPrimitive(GL::MeshPrimitive::Triangles)
|
||||||
.setCount(static_cast<Magnum::Int>(province.indices.size()))
|
.setCount(static_cast<Magnum::Int>(province.indices.size()))
|
||||||
.addVertexBuffer(GL::Buffer{provinceVertices}, 0, GL::Attribute<0, Magnum::Vector2>{})
|
.addVertexBuffer(GL::Buffer{provinceVertices}, 0, GL::Attribute<0, Magnum::Vector3>{})
|
||||||
.setIndexBuffer(GL::Buffer{provinceIndices}, 0, GL::MeshIndexType::UnsignedShort);
|
.setIndexBuffer(GL::Buffer{provinceIndices}, 0, GL::MeshIndexType::UnsignedShort);
|
||||||
|
|
||||||
provinceMeshes.push_back(std::move(regionMesh));
|
provinceMeshes.push_back(std::move(regionMesh));
|
||||||
|
|||||||
25
sdk/CMakeLists.txt
Normal file
25
sdk/CMakeLists.txt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
include(${CMAKE_SOURCE_DIR}/cmake/executable.cmake)
|
||||||
|
|
||||||
|
set(EXE sdk)
|
||||||
|
|
||||||
|
# Find dependencies
|
||||||
|
|
||||||
|
find_package(cxxopts CONFIG REQUIRED)
|
||||||
|
find_package(reflectcpp CONFIG REQUIRED)
|
||||||
|
find_package(glm CONFIG REQUIRED)
|
||||||
|
find_package(nlohmann_json CONFIG REQUIRED)
|
||||||
|
find_package(xxHash CONFIG REQUIRED)
|
||||||
|
|
||||||
|
# Link library
|
||||||
|
|
||||||
|
add_executable_target(${EXE})
|
||||||
|
|
||||||
|
target_link_libraries(${EXE} PUBLIC utils)
|
||||||
|
target_link_libraries(${EXE} PUBLIC engine-api)
|
||||||
|
|
||||||
|
target_link_libraries(${EXE} PUBLIC p7)
|
||||||
|
target_link_libraries(${EXE} PRIVATE cxxopts::cxxopts)
|
||||||
|
target_link_libraries(${EXE} PRIVATE reflectcpp::reflectcpp)
|
||||||
|
target_link_libraries(${EXE} PRIVATE glm::glm)
|
||||||
|
target_link_libraries(${EXE} PRIVATE nlohmann_json::nlohmann_json)
|
||||||
|
target_link_libraries(${EXE} PRIVATE xxHash::xxhash)
|
||||||
@ -1,26 +0,0 @@
|
|||||||
cmake_minimum_required (VERSION 3.8)
|
|
||||||
|
|
||||||
if (POLICY CMP0141)
|
|
||||||
cmake_policy(SET CMP0141 NEW)
|
|
||||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
||||||
|
|
||||||
project (compile_assets)
|
|
||||||
|
|
||||||
find_package(nlohmann_json CONFIG REQUIRED)
|
|
||||||
find_package(xxHash CONFIG REQUIRED)
|
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} compile_assets.cpp define/regions.def)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC engine-api)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC server)
|
|
||||||
|
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE /Zc:preprocessor)
|
|
||||||
|
|
||||||
if (CMAKE_VERSION VERSION_GREATER 3.12)
|
|
||||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
|
|
||||||
endif()
|
|
||||||
@ -1,187 +0,0 @@
|
|||||||
import AssetData;
|
|
||||||
import GameData;
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <xxhash.h>
|
|
||||||
#include <string>
|
|
||||||
#include <charconv>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
#define bytes(value) reinterpret_cast<const char*>(value)
|
|
||||||
|
|
||||||
namespace ee_data
|
|
||||||
{
|
|
||||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
|
|
||||||
Subject,
|
|
||||||
tag,
|
|
||||||
color,
|
|
||||||
regions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ee_data
|
|
||||||
{
|
|
||||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
|
|
||||||
GameState,
|
|
||||||
subjects
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ee_assets
|
|
||||||
{
|
|
||||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
|
|
||||||
AssetSave,
|
|
||||||
content
|
|
||||||
)
|
|
||||||
|
|
||||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
|
|
||||||
AssetMaterial,
|
|
||||||
vertexShaderAssetID,
|
|
||||||
fragmentShaderAssetID
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MappingEntry
|
|
||||||
{
|
|
||||||
std::string_view name;
|
|
||||||
uint32_t value;
|
|
||||||
};
|
|
||||||
static constexpr MappingEntry mappings[] = {
|
|
||||||
#define MAP(name, value) {#name, ((value & 0x0000FF) << 16) | ( value & 0x00FF00) | ((value & 0xFF0000) >> 16)},
|
|
||||||
#include "define/regions.def"
|
|
||||||
#undef MAP
|
|
||||||
};
|
|
||||||
|
|
||||||
void CompileRecursive(json &obj, std::function<void(const std::basic_string<char> &key, json &value)> callback)
|
|
||||||
{
|
|
||||||
if (obj.is_array()) {for (auto &element : obj) CompileRecursive(element, callback); return;}
|
|
||||||
if (!obj.is_object()) {callback("", obj); return;}
|
|
||||||
|
|
||||||
for (auto &[key, value] : obj.items())
|
|
||||||
{
|
|
||||||
if (value.is_object())
|
|
||||||
CompileRecursive(value, callback);
|
|
||||||
else if (value.is_array())
|
|
||||||
for (auto &element : value)
|
|
||||||
CompileRecursive(element, callback);
|
|
||||||
else callback(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::filesystem::path in = argv[1];
|
|
||||||
std::filesystem::path out = argv[2];
|
|
||||||
char* assetTypeStr = argv[3];
|
|
||||||
|
|
||||||
std::ifstream fin(in);
|
|
||||||
std::ofstream fout(out);
|
|
||||||
ee_assets::AssetType assetType = static_cast<ee_assets::AssetType>(atoi(assetTypeStr));
|
|
||||||
|
|
||||||
if (!fin.is_open()) {
|
|
||||||
std::cout << "Error: Could not open input file: " << in << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (!fout.is_open()) {
|
|
||||||
std::cout << "Error: Could not open output file: " << out << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
json data = json::parse(fin);
|
|
||||||
|
|
||||||
// Compile hashes
|
|
||||||
CompileRecursive(data, [](const std::basic_string<char> &key, json &value) {
|
|
||||||
if (!value.is_string()) return;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!(key == "tag") &&
|
|
||||||
!key.ends_with("AssetID") &&
|
|
||||||
!key.ends_with("Type")
|
|
||||||
) return;
|
|
||||||
|
|
||||||
std::filesystem::path linkPath = value;
|
|
||||||
auto linkPath8 = linkPath.generic_u8string();
|
|
||||||
uint32_t assetId = XXH32(linkPath8.data(), linkPath8.size(), 0);
|
|
||||||
|
|
||||||
std::cout << "Replace string [" << value << "] with [" << assetId << "]" << std::endl;
|
|
||||||
value = assetId;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Compile mappings
|
|
||||||
CompileRecursive(data, [](const std::basic_string<char> &key, json &value) {
|
|
||||||
if (!value.is_string()) return;
|
|
||||||
const std::string& value_string = value.get_ref<const std::string&>();
|
|
||||||
|
|
||||||
for (const MappingEntry &map : mappings)
|
|
||||||
{
|
|
||||||
if (value_string == map.name)
|
|
||||||
{
|
|
||||||
std::cout << "Replace string [" << value << "] with [" << map.value << "]" << std::endl;
|
|
||||||
value = map.value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Compile colors
|
|
||||||
CompileRecursive(data, [](const std::basic_string<char> &key, json &value) {
|
|
||||||
if (!value.is_string()) return;
|
|
||||||
|
|
||||||
const char* color_str = value.get_ref<const std::string&>().c_str() + 1;
|
|
||||||
uint8_t b = 0, g = 0, r = 0;
|
|
||||||
uint32_t hex = 0;
|
|
||||||
|
|
||||||
std::from_chars(color_str, color_str + 2, r, 16); color_str += 2;
|
|
||||||
std::from_chars(color_str, color_str + 2, g, 16); color_str += 2;
|
|
||||||
std::from_chars(color_str, color_str + 2, b, 16); color_str += 2;
|
|
||||||
|
|
||||||
hex = static_cast<uint32_t>(r) << 16 |
|
|
||||||
static_cast<uint32_t>(g) << 8 |
|
|
||||||
static_cast<uint32_t>(b);
|
|
||||||
|
|
||||||
std::cout << "Replace string [" << value << "] with [" << (int)r << "," << (int)g << "," << (int)b << "]" << std::endl;
|
|
||||||
value = hex;
|
|
||||||
});
|
|
||||||
|
|
||||||
switch (assetType)
|
|
||||||
{
|
|
||||||
case ee_assets::MATERIAL:
|
|
||||||
{
|
|
||||||
ee_assets::AssetMaterial material = data.get<ee_assets::AssetMaterial>();
|
|
||||||
fout.write(bytes(&material), sizeof(material));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ee_assets::SAVE:
|
|
||||||
{
|
|
||||||
ee_assets::AssetSave save = data.get<ee_assets::AssetSave>();
|
|
||||||
size_t size = 0;
|
|
||||||
const char* data = bytes(save.Serialize(size));
|
|
||||||
fout.write(data, size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fin.close();
|
|
||||||
fout.close();
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
std::cerr << e.what() << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
#ifndef MAP
|
|
||||||
#define MAP(name, color)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MAP(pepene, 0xAA00FF)
|
|
||||||
MAP(scarna, 0xFF007F)
|
|
||||||
|
|
||||||
MAP(dineria, 0xFFFF00)
|
|
||||||
MAP(perdania, 0x7FFF00)
|
|
||||||
MAP(arstinia, 0xFF0000)
|
|
||||||
MAP(alende, 0x0000FF)
|
|
||||||
MAP(zerandia, 0xFF5400)
|
|
||||||
MAP(mgahvatia, 0x5400FF)
|
|
||||||
|
|
||||||
#undef MAP
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
@echo off
|
|
||||||
|
|
||||||
set ASSETS=../../assets
|
|
||||||
set COMPILE=%CD%/../../out/build/DEBUG/sdk/assets/compile_assets.exe
|
|
||||||
|
|
||||||
set MATERIAL=4
|
|
||||||
set SAVE=2
|
|
||||||
|
|
||||||
for %%F in (materials/*) do %COMPILE% "materials/%%~nF.json" "%ASSETS%/materials/%%~nF" %MATERIAL% && echo "Compiled: %%~nF"
|
|
||||||
for %%F in (saves/*) do %COMPILE% "saves/%%~nF.json" "%ASSETS%/scenarios/%%~nF" %SAVE% && echo "Compiled: %%~nF"
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
@echo off
|
|
||||||
|
|
||||||
glslc provinces/provinces.frag -O -o ../../../assets/shaders/provinces.frag
|
|
||||||
glslc provinces/provinces.vert -O -o ../../../assets/shaders/provinces.vert
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 fragColor;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 outColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
outColor = vec4(fragColor, 1.0);
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
|
|
||||||
layout(binding = 0) uniform Global {
|
|
||||||
mat4 view;
|
|
||||||
mat4 proj;
|
|
||||||
} global;
|
|
||||||
|
|
||||||
layout(binding = 1) uniform Transform {
|
|
||||||
mat4 model;
|
|
||||||
} transform;
|
|
||||||
|
|
||||||
layout(location = 0) in vec2 inPosition;
|
|
||||||
layout(location = 1) in vec3 inColor;
|
|
||||||
|
|
||||||
layout(location = 0) out vec3 fragColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_Position = global.proj * global.view * transform.model * vec4(inPosition, 0.0, 1.0);
|
|
||||||
fragColor = inColor;
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 fragColor;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 outColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
outColor = vec4(fragColor, 1.0);
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
|
|
||||||
layout(location = 0) in vec2 position;
|
|
||||||
|
|
||||||
layout(binding = 0) uniform Camera {
|
|
||||||
mat4 viewProjection;
|
|
||||||
} camera;
|
|
||||||
|
|
||||||
layout(push_constant) uniform Model {
|
|
||||||
mat4 model;
|
|
||||||
} model;
|
|
||||||
|
|
||||||
struct Province {
|
|
||||||
uint regionId;
|
|
||||||
uint color;
|
|
||||||
};
|
|
||||||
layout(std430, binding = 1) readonly buffer Data {
|
|
||||||
Province provinces[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) out vec3 fragColor;
|
|
||||||
|
|
||||||
vec3 unpackColor(uint c) {
|
|
||||||
return vec3(
|
|
||||||
c & 0xFFu,
|
|
||||||
(c >> 8) & 0xFFu,
|
|
||||||
(c >> 16) & 0xFFu
|
|
||||||
) / 255.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_Position = camera.viewProjection * vec4(position, 0.0, 1.0);
|
|
||||||
fragColor = unpackColor(provinces[gl_InstanceIndex].color);
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
cmake_minimum_required (VERSION 3.8)
|
|
||||||
|
|
||||||
if (POLICY CMP0141)
|
|
||||||
cmake_policy(SET CMP0141 NEW)
|
|
||||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
||||||
|
|
||||||
project (convert_map)
|
|
||||||
|
|
||||||
# find_package(glm CONFIG REQUIRED)
|
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} convert_map.cpp)
|
|
||||||
|
|
||||||
# target_link_libraries(${PROJECT_NAME} PRIVATE glm::glm)
|
|
||||||
# target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/engine/include/)
|
|
||||||
|
|
||||||
if (CMAKE_VERSION VERSION_GREATER 3.12)
|
|
||||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
file(GLOB MAP_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.bmp")
|
|
||||||
|
|
||||||
set(COMPILED_DIR "${CMAKE_SOURCE_DIR}/assets/map")
|
|
||||||
|
|
||||||
foreach(MAP ${MAP_FILES})
|
|
||||||
get_filename_component(MAP_NAME ${MAP} NAME_WE)
|
|
||||||
set(OUT_FILE "${COMPILED_DIR}/${MAP_NAME}.map")
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${OUT_FILE}
|
|
||||||
COMMAND $<TARGET_FILE:${PROJECT_NAME}> ${MAP} ${OUT_FILE}
|
|
||||||
DEPENDS ${MAP} ${PROJECT_NAME}
|
|
||||||
COMMENT "Converting map ${MAP_NAME}"
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND COMPILED_BINARIES ${OUT_FILE})
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
add_custom_target(compile_maps ALL
|
|
||||||
DEPENDS ${COMPILED_BINARIES}
|
|
||||||
)
|
|
||||||
@ -1,499 +0,0 @@
|
|||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <queue>
|
|
||||||
#include <stack>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#define bytes(value) reinterpret_cast<const char*>(value)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
struct BMPFileHeader {
|
|
||||||
uint16_t bfType;
|
|
||||||
uint32_t bfSize;
|
|
||||||
uint16_t bfReserved1;
|
|
||||||
uint16_t bfReserved2;
|
|
||||||
uint32_t bfOffBits;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BMPInfoHeader {
|
|
||||||
uint32_t biSize;
|
|
||||||
int32_t biWidth;
|
|
||||||
int32_t biHeight;
|
|
||||||
uint16_t biPlanes;
|
|
||||||
uint16_t biBitCount;
|
|
||||||
uint32_t biCompression;
|
|
||||||
uint32_t biSizeImage;
|
|
||||||
int32_t biXPelsPerMeter;
|
|
||||||
int32_t biYPelsPerMeter;
|
|
||||||
uint32_t biClrUsed;
|
|
||||||
uint32_t biClrImportant;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BGR { uint8_t b,g,r; };
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
struct vertex { float x,y; };
|
|
||||||
|
|
||||||
struct BGRHash {
|
|
||||||
size_t operator()(const BGR& c) const noexcept {
|
|
||||||
return static_cast<uint32_t>(c.r) << 16 |
|
|
||||||
static_cast<uint32_t>(c.g) << 8 |
|
|
||||||
static_cast<uint32_t>(c.b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool operator==(const BGR&a,const BGR&b){
|
|
||||||
return a.r==b.r && a.g==b.g && a.b==b.b;
|
|
||||||
}
|
|
||||||
|
|
||||||
BGR EMPTY_COLOR{255,255,255};
|
|
||||||
|
|
||||||
uint8_t* imageData;
|
|
||||||
uint8_t* tempImageData;
|
|
||||||
size_t width,height,rowSize;
|
|
||||||
|
|
||||||
struct prov
|
|
||||||
{
|
|
||||||
std::vector<size_t> vertices;
|
|
||||||
std::vector<uint16_t> indices;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<BGR,std::vector<prov>,BGRHash> pixelsPerProvincesPerState;
|
|
||||||
|
|
||||||
inline BGR getPixelSafe(size_t r,size_t c){
|
|
||||||
if(r>=height||c>=width) return EMPTY_COLOR;
|
|
||||||
return *reinterpret_cast<BGR*>(
|
|
||||||
imageData + r*rowSize + c*3
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline BGR getPixelSafeIndex(size_t i){
|
|
||||||
return getPixelSafe(i/width,i%width);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================= FLOOD FILL ================= */
|
|
||||||
|
|
||||||
void FloodFill(){
|
|
||||||
size_t size=width*height;
|
|
||||||
for(size_t i=0;i<size;i++){
|
|
||||||
if(*reinterpret_cast<BGR*>(tempImageData + (i/width)*rowSize + (i%width)*3)==EMPTY_COLOR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
BGR color=*reinterpret_cast<BGR*>(tempImageData + (i/width)*rowSize + (i%width)*3);
|
|
||||||
std::vector<size_t> prov;
|
|
||||||
std::queue<size_t> q;
|
|
||||||
q.push(i);
|
|
||||||
|
|
||||||
while(!q.empty()){
|
|
||||||
size_t n=q.front(); q.pop();
|
|
||||||
BGR& px=*reinterpret_cast<BGR*>(tempImageData + (n/width)*rowSize + (n%width)*3);
|
|
||||||
if(px!=color) continue;
|
|
||||||
px=EMPTY_COLOR;
|
|
||||||
prov.push_back(n);
|
|
||||||
|
|
||||||
if(n>=width) q.push(n-width);
|
|
||||||
if(n+width<size) q.push(n+width);
|
|
||||||
if(n%width) q.push(n-1);
|
|
||||||
if(n%width+1<width) q.push(n+1);
|
|
||||||
}
|
|
||||||
pixelsPerProvincesPerState[color].push_back({prov});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================= MOORE ================= */
|
|
||||||
|
|
||||||
struct offset{int8_t x,y;};
|
|
||||||
|
|
||||||
static const offset moore[8]={
|
|
||||||
{1,0},{1,-1},{0,-1},{-1,-1},
|
|
||||||
{-1,0},{-1,1},{0,1},{1,1}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool MooreStep(size_t cur,size_t prev,BGR id,size_t& next){
|
|
||||||
int cr=cur/width, cc=cur%width;
|
|
||||||
int pr=prev/width,pc=prev%width;
|
|
||||||
|
|
||||||
int dx=cc-pc, dy=cr-pr;
|
|
||||||
int startDir=0;
|
|
||||||
for(int i=0;i<8;i++)
|
|
||||||
if(moore[i].x==dx&&moore[i].y==dy)
|
|
||||||
startDir=(i+6)&7;
|
|
||||||
|
|
||||||
for(int k=0;k<8;k++){
|
|
||||||
int d=(startDir+k)&7;
|
|
||||||
int nr=cr+moore[d].y;
|
|
||||||
int nc=cc+moore[d].x;
|
|
||||||
if(getPixelSafe(nr,nc)==id){
|
|
||||||
next=size_t(nr)*width+size_t(nc);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================= FIND CONTOUR ================= */
|
|
||||||
|
|
||||||
size_t FindStart(const std::vector<size_t>&prov,BGR id){
|
|
||||||
for(size_t i:prov){
|
|
||||||
size_t r=i/width,c=i%width;
|
|
||||||
if(getPixelSafe(r-1,c)!=id||
|
|
||||||
getPixelSafe(r+1,c)!=id||
|
|
||||||
getPixelSafe(r,c-1)!=id||
|
|
||||||
getPixelSafe(r,c+1)!=id)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return std::numeric_limits<size_t>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FindContour(){
|
|
||||||
for(auto&[state,provs]:pixelsPerProvincesPerState){
|
|
||||||
for(auto&prov:provs){
|
|
||||||
if(prov.vertices.empty()) continue;
|
|
||||||
BGR id=getPixelSafeIndex(prov.vertices[0]);
|
|
||||||
size_t start=FindStart(prov.vertices,id);
|
|
||||||
if(start==std::numeric_limits<size_t>::max()) continue;
|
|
||||||
|
|
||||||
std::vector<size_t> contour;
|
|
||||||
contour.push_back(start);
|
|
||||||
|
|
||||||
size_t cur=start;
|
|
||||||
size_t prev = (start % width > 0) ? start - 1 : start + 1;
|
|
||||||
|
|
||||||
|
|
||||||
const size_t MAX=prov.vertices.size()*8;
|
|
||||||
for(size_t i=0;i<MAX;i++){
|
|
||||||
size_t next;
|
|
||||||
if(!MooreStep(cur,prev,id,next)) break;
|
|
||||||
if(next==start) break;
|
|
||||||
contour.push_back(next);
|
|
||||||
prev=cur;
|
|
||||||
cur=next;
|
|
||||||
}
|
|
||||||
prov.vertices.swap(contour);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static double PerpendicularDistance(size_t p, size_t a, size_t b, size_t width)
|
|
||||||
{
|
|
||||||
double px = p % width;
|
|
||||||
double py = p / width;
|
|
||||||
|
|
||||||
double ax = a % width;
|
|
||||||
double ay = a / width;
|
|
||||||
|
|
||||||
double bx = b % width;
|
|
||||||
double by = b / width;
|
|
||||||
|
|
||||||
double dx = bx - ax;
|
|
||||||
double dy = by - ay;
|
|
||||||
|
|
||||||
if(dx == 0 && dy == 0)
|
|
||||||
return std::hypot(px - ax, py - ay);
|
|
||||||
|
|
||||||
double num = std::abs(dy * px - dx * py + bx * ay - by * ax);
|
|
||||||
double den = std::sqrt(dx * dx + dy * dy);
|
|
||||||
|
|
||||||
return num / den;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Douglas-Peucker iterative
|
|
||||||
void Aproximate(size_t epsilon)
|
|
||||||
{
|
|
||||||
for(auto& [state, provs] : pixelsPerProvincesPerState)
|
|
||||||
{
|
|
||||||
for(prov& prov : provs)
|
|
||||||
{
|
|
||||||
if(prov.vertices.size() < 3)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const size_t n = prov.vertices.size();
|
|
||||||
|
|
||||||
std::vector<bool> keep_point(n, true);
|
|
||||||
std::stack<std::pair<size_t, size_t>> st;
|
|
||||||
|
|
||||||
// в стек кладем первый и последний индекс
|
|
||||||
st.push({0, n - 1});
|
|
||||||
|
|
||||||
while(!st.empty())
|
|
||||||
{
|
|
||||||
auto [startIndex, endIndex] = st.top();
|
|
||||||
st.pop();
|
|
||||||
|
|
||||||
double dMax = 0.0;
|
|
||||||
size_t index = startIndex;
|
|
||||||
|
|
||||||
for(size_t i = startIndex + 1; i < endIndex; ++i)
|
|
||||||
{
|
|
||||||
if(keep_point[i])
|
|
||||||
{
|
|
||||||
double d = PerpendicularDistance(
|
|
||||||
prov.vertices[i],
|
|
||||||
prov.vertices[startIndex],
|
|
||||||
prov.vertices[endIndex],
|
|
||||||
width
|
|
||||||
);
|
|
||||||
|
|
||||||
if(d > dMax)
|
|
||||||
{
|
|
||||||
dMax = d;
|
|
||||||
index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(dMax >= epsilon)
|
|
||||||
{
|
|
||||||
st.push({startIndex, index});
|
|
||||||
st.push({index, endIndex});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(size_t j = startIndex + 1; j < endIndex; ++j)
|
|
||||||
keep_point[j] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// формируем итоговый список
|
|
||||||
std::vector<size_t> result;
|
|
||||||
result.reserve(n);
|
|
||||||
|
|
||||||
for(size_t i = 0; i < n; ++i)
|
|
||||||
{
|
|
||||||
if(keep_point[i])
|
|
||||||
result.push_back(prov.vertices[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
prov.vertices.swap(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Pt {
|
|
||||||
int x, y;
|
|
||||||
size_t id;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline Pt make_pt(size_t i, size_t width) {
|
|
||||||
return { int(i % width), int(i / width), i };
|
|
||||||
}
|
|
||||||
|
|
||||||
inline long long cross(const Pt& a, const Pt& b, const Pt& c) {
|
|
||||||
return 1LL * (b.x - a.x) * (c.y - a.y)
|
|
||||||
- 1LL * (b.y - a.y) * (c.x - a.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
long long signed_area2(const std::vector<Pt>& p) {
|
|
||||||
long long a = 0;
|
|
||||||
for (size_t i = 0; i < p.size(); ++i) {
|
|
||||||
const auto& p0 = p[i];
|
|
||||||
const auto& p1 = p[(i + 1) % p.size()];
|
|
||||||
a += 1LL * p0.x * p1.y - 1LL * p1.x * p0.y;
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool point_in_triangle(const Pt& p,
|
|
||||||
const Pt& a,
|
|
||||||
const Pt& b,
|
|
||||||
const Pt& c)
|
|
||||||
{
|
|
||||||
long long c1 = cross(a, b, p);
|
|
||||||
long long c2 = cross(b, c, p);
|
|
||||||
long long c3 = cross(c, a, p);
|
|
||||||
return (c1 >= 0 && c2 >= 0 && c3 >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<size_t> triangulate_prov(const std::vector<size_t>& prov,
|
|
||||||
size_t width)
|
|
||||||
{
|
|
||||||
std::vector<Pt> poly;
|
|
||||||
poly.reserve(prov.size());
|
|
||||||
for (size_t i : prov)
|
|
||||||
poly.push_back(make_pt(i, width));
|
|
||||||
|
|
||||||
// CCW
|
|
||||||
if (signed_area2(poly) < 0)
|
|
||||||
std::reverse(poly.begin(), poly.end());
|
|
||||||
|
|
||||||
std::vector<size_t> out; // a,b,c,a,b,c,...
|
|
||||||
|
|
||||||
while (poly.size() > 3) {
|
|
||||||
bool ear_found = false;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < poly.size(); ++i) {
|
|
||||||
size_t i0 = (i + poly.size() - 1) % poly.size();
|
|
||||||
size_t i1 = i;
|
|
||||||
size_t i2 = (i + 1) % poly.size();
|
|
||||||
|
|
||||||
const Pt& a = poly[i0];
|
|
||||||
const Pt& b = poly[i1];
|
|
||||||
const Pt& c = poly[i2];
|
|
||||||
|
|
||||||
if (cross(a, b, c) <= 0)
|
|
||||||
continue; // не выпуклая
|
|
||||||
|
|
||||||
bool inside = false;
|
|
||||||
for (size_t j = 0; j < poly.size(); ++j) {
|
|
||||||
if (j == i0 || j == i1 || j == i2) continue;
|
|
||||||
if (point_in_triangle(poly[j], a, b, c)) {
|
|
||||||
inside = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!inside) {
|
|
||||||
out.push_back(a.id);
|
|
||||||
out.push_back(b.id);
|
|
||||||
out.push_back(c.id);
|
|
||||||
poly.erase(poly.begin() + i1);
|
|
||||||
ear_found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ear_found) {
|
|
||||||
// плохой контур (самопересечение / коллинеарность)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (poly.size() == 3) {
|
|
||||||
out.push_back(poly[0].id);
|
|
||||||
out.push_back(poly[1].id);
|
|
||||||
out.push_back(poly[2].id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Triangulate()
|
|
||||||
{
|
|
||||||
for(auto& [state, provs] : pixelsPerProvincesPerState)
|
|
||||||
{
|
|
||||||
for(prov& prov : provs)
|
|
||||||
{
|
|
||||||
if (prov.vertices.size() < 3)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
prov.vertices = triangulate_prov(prov.vertices, width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Optimize()
|
|
||||||
{
|
|
||||||
for(auto& [state, provs] : pixelsPerProvincesPerState)
|
|
||||||
{
|
|
||||||
for(prov& prov : provs)
|
|
||||||
{
|
|
||||||
std::unordered_map<size_t, uint16_t> vertexToIndex;
|
|
||||||
vertexToIndex.reserve(prov.vertices.size());
|
|
||||||
|
|
||||||
std::vector<size_t> uniqueVertices;
|
|
||||||
uniqueVertices.reserve(prov.vertices.size());
|
|
||||||
|
|
||||||
prov.indices.clear();
|
|
||||||
|
|
||||||
for (size_t v : prov.vertices)
|
|
||||||
{
|
|
||||||
auto it = vertexToIndex.find(v);
|
|
||||||
if (it != vertexToIndex.end())
|
|
||||||
{
|
|
||||||
// вершина уже есть
|
|
||||||
prov.indices.push_back(it->second);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// новая вершина
|
|
||||||
uint16_t newIndex = static_cast<uint16_t>(uniqueVertices.size());
|
|
||||||
uniqueVertices.push_back(v);
|
|
||||||
vertexToIndex[v] = newIndex;
|
|
||||||
prov.indices.push_back(newIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prov.vertices.swap(uniqueVertices);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================= OUTPUT ================= */
|
|
||||||
|
|
||||||
void GenVertices(std::ofstream&out){
|
|
||||||
uint32_t statesCount = static_cast<uint32_t>(pixelsPerProvincesPerState.size());
|
|
||||||
out.write(bytes(&statesCount),4);
|
|
||||||
|
|
||||||
for(auto&[color, provs]:pixelsPerProvincesPerState)
|
|
||||||
{
|
|
||||||
out.write(bytes(&color), sizeof(BGR));
|
|
||||||
|
|
||||||
uint32_t provsCount = static_cast<uint32_t>(provs.size());
|
|
||||||
out.write(bytes(&provsCount), sizeof(uint32_t));
|
|
||||||
|
|
||||||
for(prov& prov:provs)
|
|
||||||
{
|
|
||||||
//Skip invalid meshes
|
|
||||||
if (prov.indices.size() % 3 != 0)
|
|
||||||
{
|
|
||||||
prov.vertices.clear();
|
|
||||||
prov.indices.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t verticesCount = static_cast<uint32_t>(prov.vertices.size());
|
|
||||||
out.write(bytes(&verticesCount), sizeof(uint32_t));
|
|
||||||
|
|
||||||
for(size_t i: prov.vertices)
|
|
||||||
{
|
|
||||||
vertex v{
|
|
||||||
static_cast<float>(i%width),
|
|
||||||
static_cast<float>(i/width)
|
|
||||||
};
|
|
||||||
out.write(bytes(&v),sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t indicesCount = static_cast<uint32_t>(prov.indices.size());
|
|
||||||
out.write(bytes(&indicesCount), sizeof(uint32_t));
|
|
||||||
|
|
||||||
out.write(reinterpret_cast<char*>(prov.indices.data()), prov.indices.size() * sizeof(uint16_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================= MAIN ================= */
|
|
||||||
|
|
||||||
int main(int argc,char**argv){
|
|
||||||
std::ifstream fin(argv[1],std::ios::binary);
|
|
||||||
std::ofstream fout(argv[2],std::ios::binary);
|
|
||||||
|
|
||||||
BMPFileHeader fh;
|
|
||||||
BMPInfoHeader ih;
|
|
||||||
fin.read((char*)&fh,sizeof(fh));
|
|
||||||
fin.read((char*)&ih,sizeof(ih));
|
|
||||||
|
|
||||||
width=ih.biWidth;
|
|
||||||
height=ih.biHeight;
|
|
||||||
rowSize=(width*3+3)&~3;
|
|
||||||
|
|
||||||
std::vector<uint8_t> img(rowSize*height);
|
|
||||||
std::vector<uint8_t> tmp(rowSize*height);
|
|
||||||
|
|
||||||
fin.seekg(fh.bfOffBits);
|
|
||||||
fin.read((char*)img.data(),img.size());
|
|
||||||
fin.seekg(fh.bfOffBits);
|
|
||||||
fin.read((char*)tmp.data(),tmp.size());
|
|
||||||
|
|
||||||
imageData=img.data();
|
|
||||||
tempImageData=tmp.data();
|
|
||||||
|
|
||||||
FloodFill();
|
|
||||||
FindContour();
|
|
||||||
Aproximate(1);
|
|
||||||
Triangulate();
|
|
||||||
Optimize();
|
|
||||||
GenVertices(fout);
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
@echo off
|
|
||||||
|
|
||||||
set ASSETS=../../assets
|
|
||||||
set COMPILE=%CD%/../../out/build/DEBUG/sdk/map/convert_map.exe
|
|
||||||
|
|
||||||
for %%F in (maps/*) do %COMPILE% "maps/%%~nF.bmp" "%ASSETS%/map/%%~nF" && echo "Compiled: %%~nF"
|
|
||||||
121
sdk/modules/compile.json.cppm
Normal file
121
sdk/modules/compile.json.cppm
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
#include <xxhash.h>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
export module compile.json;
|
||||||
|
import utils;
|
||||||
|
import io;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
export namespace ee_sdk {
|
||||||
|
class JsonCompiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit JsonCompiler(const std::filesystem::path &mappingsConfig) {
|
||||||
|
for (
|
||||||
|
const json mappingsJson = ReadJson(mappingsConfig);
|
||||||
|
auto &[key, value] : mappingsJson.items()
|
||||||
|
) {
|
||||||
|
const char* color_str = value.get_ref<const std::string&>().c_str() + 1;
|
||||||
|
std::uint8_t b = 0, g = 0, r = 0;
|
||||||
|
std::uint32_t hex = 0;
|
||||||
|
|
||||||
|
std::from_chars(color_str, color_str + 2, r, 16); color_str += 2;
|
||||||
|
std::from_chars(color_str, color_str + 2, g, 16); color_str += 2;
|
||||||
|
std::from_chars(color_str, color_str + 2, b, 16);
|
||||||
|
|
||||||
|
hex = colorToHex(r, g, b);
|
||||||
|
|
||||||
|
mappings[key] = hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compile(json &asset) const {
|
||||||
|
CompileRecursive(asset, CompileHashes);
|
||||||
|
CompileRecursive(asset, std::bind_front(&JsonCompiler::CompileMappings, this));
|
||||||
|
CompileRecursive(asset, &CompileColors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, std::uint32_t> mappings;
|
||||||
|
|
||||||
|
static void CompileRecursive(
|
||||||
|
json &obj,
|
||||||
|
const std::function<void(const std::basic_string<char> &key, json &value)> &callback
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (obj.is_array()) {for (auto &element : obj) CompileRecursive(element, callback); return;}
|
||||||
|
if (!obj.is_object()) {callback("", obj); return;}
|
||||||
|
|
||||||
|
for (auto &[key, value] : obj.items())
|
||||||
|
{
|
||||||
|
if (value.is_object())
|
||||||
|
CompileRecursive(value, callback);
|
||||||
|
else if (value.is_array())
|
||||||
|
for (auto &element : value)
|
||||||
|
CompileRecursive(element, callback);
|
||||||
|
else callback(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: extern config
|
||||||
|
static bool NeedsCompile(const std::basic_string<char> &key) {
|
||||||
|
return
|
||||||
|
key == "tag" ||
|
||||||
|
key.ends_with("AssetID") ||
|
||||||
|
key.ends_with("Type");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CompileHashes(const std::basic_string<char> &key, json &value) {
|
||||||
|
if (!value.is_string()) return;
|
||||||
|
if (!NeedsCompile(key)) return;
|
||||||
|
|
||||||
|
const std::filesystem::path linkPath = value;
|
||||||
|
const auto linkPath8 = linkPath.generic_u8string();
|
||||||
|
std::uint32_t assetId = XXH32(linkPath8.data(), linkPath8.size(), 0);
|
||||||
|
|
||||||
|
LOG(INFO, "COMPILED HASH: Replace string [%s] with [%d] asset ID", linkPath.c_str(), assetId);
|
||||||
|
value = assetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompileMappings(const std::basic_string<char> &, json &value) const {
|
||||||
|
if (!value.is_string()) return;
|
||||||
|
const std::string& value_string = value.get_ref<const std::string&>();
|
||||||
|
|
||||||
|
for (const auto &[name, toValue] : mappings)
|
||||||
|
{
|
||||||
|
if (value_string == name)
|
||||||
|
{
|
||||||
|
LOG(INFO, "COMPILED MAPPING: Replace string [%hs] with [0x%X] (%d) value",
|
||||||
|
value_string.c_str(),
|
||||||
|
toValue,
|
||||||
|
toValue
|
||||||
|
);
|
||||||
|
value = toValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CompileColors(const std::basic_string<char> &, json &value) {
|
||||||
|
if (!value.is_string()) return;
|
||||||
|
|
||||||
|
const char *colorStr = value.get_ref<const std::string&>().c_str() + 1;
|
||||||
|
const char *colorStrPointer = colorStr;
|
||||||
|
std::uint8_t b = 0, g = 0, r = 0;
|
||||||
|
std::uint32_t hex = 0;
|
||||||
|
|
||||||
|
std::from_chars(colorStrPointer, colorStrPointer + 2, r, 16); colorStrPointer += 2;
|
||||||
|
std::from_chars(colorStrPointer, colorStrPointer + 2, g, 16); colorStrPointer += 2;
|
||||||
|
std::from_chars(colorStrPointer, colorStrPointer + 2, b, 16); colorStrPointer += 2;
|
||||||
|
|
||||||
|
hex = colorToHex(r, g, b);
|
||||||
|
|
||||||
|
LOG(INFO, "COMPILED COLOR: Replace string [%hs] with 0x[%X] (RGB %d, %d, %d) color", colorStr, hex, r, g, b);
|
||||||
|
value = hex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
499
sdk/modules/compile.mapmesh.cppm
Normal file
499
sdk/modules/compile.mapmesh.cppm
Normal file
@ -0,0 +1,499 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
export module compile.mapmesh;
|
||||||
|
import utils;
|
||||||
|
import io;
|
||||||
|
import AssetData;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
struct Pt;
|
||||||
|
|
||||||
|
namespace ee_sdk {
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct BMPFileHeader {
|
||||||
|
std::uint16_t bfType;
|
||||||
|
std::uint32_t bfSize;
|
||||||
|
std::uint16_t bfReserved1;
|
||||||
|
std::uint16_t bfReserved2;
|
||||||
|
std::uint32_t bfOffBits;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BMPInfoHeader {
|
||||||
|
std::uint32_t biSize;
|
||||||
|
std::int32_t biWidth;
|
||||||
|
std::int32_t biHeight;
|
||||||
|
std::uint16_t biPlanes;
|
||||||
|
std::uint16_t biBitCount;
|
||||||
|
std::uint32_t biCompression;
|
||||||
|
std::uint32_t biSizeImage;
|
||||||
|
std::int32_t biXPelsPerMeter;
|
||||||
|
std::int32_t biYPelsPerMeter;
|
||||||
|
std::uint32_t biClrUsed;
|
||||||
|
std::uint32_t biClrImportant;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
using BGR = glm::vec<3, std::uint8_t>;
|
||||||
|
struct BGRHash {
|
||||||
|
std::size_t operator()(const BGR& c) const noexcept {return colorToHex(c.r, c.g, c.b, true);}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct prov
|
||||||
|
{
|
||||||
|
std::vector<std::size_t> vertices; // pixels indices
|
||||||
|
std::vector<std::uint16_t> indices;
|
||||||
|
};
|
||||||
|
|
||||||
|
using PixelMesh = std::unordered_map<BGR,std::vector<prov>,BGRHash>;
|
||||||
|
|
||||||
|
struct Image {
|
||||||
|
std::int32_t width;
|
||||||
|
std::int32_t height;
|
||||||
|
std::size_t rowSize;
|
||||||
|
std::vector<std::byte> image;
|
||||||
|
std::vector<std::byte> tempImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Point {
|
||||||
|
public:
|
||||||
|
std::int32_t x, y;
|
||||||
|
std::size_t id;
|
||||||
|
|
||||||
|
Point() = default;
|
||||||
|
Point (const std::size_t i, const std::size_t width) {
|
||||||
|
x = i % width;
|
||||||
|
y = i / width;
|
||||||
|
id = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::int64_t Cross(const Point &a, const Point &b, const Point &c) {
|
||||||
|
return 1LL * (b.x - a.x) * (c.y - a.y) - 1LL * (b.y - a.y) * (c.x - a.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::int64_t SignedArea2(const std::span<Point> &p) {
|
||||||
|
std::int64_t a = 0;
|
||||||
|
for (std::size_t i = 0; i < p.size(); i++) {
|
||||||
|
const Point &p0 = p[i];
|
||||||
|
const Point& p1 = p[(i + 1) % p.size()];
|
||||||
|
a += 1LL * p0.x * p1.y - 1LL * p1.x * p0.y;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInTriangle(const Point &a, const Point &b, const Point &c) const {
|
||||||
|
const std::int64_t c1 = Cross(a, b, *this);
|
||||||
|
const std::int64_t c2 = Cross(b, c, *this);
|
||||||
|
const std::int64_t c3 = Cross(c, a, *this);
|
||||||
|
return (c1 >= 0 && c2 >= 0 && c3 >= 0) || (c1 <= 0 && c2 <= 0 && c3 <= 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace ee_sdk {
|
||||||
|
class MapMeshCompiler {
|
||||||
|
public:
|
||||||
|
static ee_engine::MapMesh CompileBMP(std::span<std::byte> asset) {
|
||||||
|
|
||||||
|
ee_engine::MapMesh mesh;
|
||||||
|
|
||||||
|
// Read BMP file info from header
|
||||||
|
BMPFileHeader fileHeader;
|
||||||
|
BMPInfoHeader infoHeader;
|
||||||
|
std::memcpy(&fileHeader, asset.data(), sizeof(BMPFileHeader));
|
||||||
|
std::memcpy(&infoHeader, asset.data() + sizeof(BMPFileHeader), sizeof(BMPInfoHeader));
|
||||||
|
|
||||||
|
Image imageInfo {
|
||||||
|
.width = infoHeader.biWidth,
|
||||||
|
.height = infoHeader.biHeight,
|
||||||
|
.rowSize = static_cast<std::size_t>(infoHeader.biWidth)*3+3&~3
|
||||||
|
};
|
||||||
|
|
||||||
|
// Copy file to buffers for algorithms
|
||||||
|
imageInfo.image.resize(imageInfo.rowSize * imageInfo.height);
|
||||||
|
imageInfo.tempImage.resize(imageInfo.rowSize * imageInfo.height);
|
||||||
|
|
||||||
|
std::memcpy(imageInfo.image.data(), asset.data() + fileHeader.bfOffBits, imageInfo.image.size());
|
||||||
|
std::memcpy(imageInfo.tempImage.data(), asset.data() + fileHeader.bfOffBits, imageInfo.tempImage.size());
|
||||||
|
|
||||||
|
PixelMesh pixelMesh;
|
||||||
|
|
||||||
|
// Extract mesh from image
|
||||||
|
FloodFill(imageInfo, pixelMesh);
|
||||||
|
FindContour(imageInfo, pixelMesh);
|
||||||
|
Aproximate(imageInfo, pixelMesh, 1);
|
||||||
|
Triangulate(imageInfo, pixelMesh);
|
||||||
|
Optimize(pixelMesh);
|
||||||
|
|
||||||
|
// Provide mesh in suitable format
|
||||||
|
for(auto&[color, provs]: pixelMesh)
|
||||||
|
{
|
||||||
|
std::vector<ee_engine::MapMesh::Province> outProvinces;
|
||||||
|
|
||||||
|
for(auto&[vertices, indices]: provs)
|
||||||
|
{
|
||||||
|
ee_engine::MapMesh::Province outProvince;
|
||||||
|
|
||||||
|
//Skip invalid meshes
|
||||||
|
if (indices.size() % 3 != 0)
|
||||||
|
{
|
||||||
|
vertices.clear();
|
||||||
|
indices.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::size_t i: vertices)
|
||||||
|
{
|
||||||
|
glm::vec2 v{
|
||||||
|
static_cast<float>(i % imageInfo.width),
|
||||||
|
static_cast<float>(i / imageInfo.width)
|
||||||
|
};
|
||||||
|
outProvince.vertices.push_back(v);
|
||||||
|
}
|
||||||
|
outProvince.indices = indices;
|
||||||
|
|
||||||
|
outProvinces.push_back(outProvince);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh.regions[colorToHex(color.r, color.g, color.b, true)] = outProvinces;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(INFO, "COMPILED MAPMESH: generated [%d] regions", mesh.regions.size());
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr BGR EMPTY_COLOR = {255, 255, 255};
|
||||||
|
|
||||||
|
static inline BGR getPixelSafe(const Image &image, const std::size_t r, const std::size_t c) {
|
||||||
|
if(r >= image.height || c >= image.width) return EMPTY_COLOR;
|
||||||
|
return *reinterpret_cast<const BGR*>(
|
||||||
|
image.image.data() + r * image.rowSize + c * 3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline BGR getPixelSafeIndex(const Image &image, const std::size_t i) {
|
||||||
|
return getPixelSafe(image, i / image.width, i % image.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FloodFill(Image &image, PixelMesh &mesh) {
|
||||||
|
const std::size_t size = image.width * image.height;
|
||||||
|
for(std::size_t i = 0; i < size; i++) {
|
||||||
|
BGR color= *reinterpret_cast<BGR*>(image.tempImage.data() + (i/image.width)*image.rowSize + (i%image.width)*3);
|
||||||
|
|
||||||
|
if(color == EMPTY_COLOR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::vector<std::size_t> prov;
|
||||||
|
std::queue<std::size_t> q;
|
||||||
|
q.push(i);
|
||||||
|
|
||||||
|
while (!q.empty()) {
|
||||||
|
std::size_t n = q.front(); q.pop();
|
||||||
|
BGR& px = *reinterpret_cast<BGR*>(image.tempImage.data() + (n/image.width)*image.rowSize + (n%image.width)*3);
|
||||||
|
if(px != color) continue;
|
||||||
|
px = EMPTY_COLOR;
|
||||||
|
prov.push_back(n);
|
||||||
|
|
||||||
|
if(n >= image.width) q.push(n - image.width);
|
||||||
|
if(n + image.width < size) q.push(n + image.width);
|
||||||
|
if(n % image.width) q.push(n - 1);
|
||||||
|
if(n % image.width + 1 < image.width) q.push(n + 1);
|
||||||
|
}
|
||||||
|
mesh[color].push_back({.vertices = prov});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool MooreStep(
|
||||||
|
const Image &image,
|
||||||
|
const std::size_t cur,
|
||||||
|
const std::size_t prev,
|
||||||
|
const BGR id,
|
||||||
|
std::size_t &next
|
||||||
|
) {
|
||||||
|
struct offset{int8_t x,y;};
|
||||||
|
|
||||||
|
static const offset moore[8]={
|
||||||
|
{1,0},{1,-1},{0,-1},{-1,-1},
|
||||||
|
{-1,0},{-1,1},{0,1},{1,1}
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::int32_t cr = cur / image.width, cc = cur % image.width;
|
||||||
|
const std::int32_t pr = prev / image.width, pc = prev % image.width;
|
||||||
|
|
||||||
|
const std::int32_t dx = cc - pc, dy = cr - pr;
|
||||||
|
std::int32_t startDir = 0;
|
||||||
|
for(std::int32_t i = 0; i < 8; i++) {
|
||||||
|
if(moore[i].x == dx && moore[i].y == dy)
|
||||||
|
startDir=(i+6)&7;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::int32_t k=0; k<8; k++){
|
||||||
|
const std::int32_t d = (startDir+k)&7;
|
||||||
|
const std::int32_t nr = cr + moore[d].y;
|
||||||
|
if(
|
||||||
|
const std::int32_t nc = cc + moore[d].x;
|
||||||
|
getPixelSafe(image, nr,nc) == id
|
||||||
|
){
|
||||||
|
next= static_cast<std::size_t>(nr) * image.width + static_cast<std::size_t>(nc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static std::size_t FindStart(const Image &image, const std::vector<size_t>&prov, const BGR &id) {
|
||||||
|
for(const std::size_t i : prov){
|
||||||
|
const std::size_t r = i / image.width;
|
||||||
|
const std::size_t c = i % image.width;
|
||||||
|
|
||||||
|
if(getPixelSafe(image, r - 1, c) != id||
|
||||||
|
getPixelSafe(image, r + 1, c) != id||
|
||||||
|
getPixelSafe(image, r, c- 1) != id||
|
||||||
|
getPixelSafe(image, r, c+ 1) != id)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return std::numeric_limits<std::size_t>::max();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FindContour(const Image &image, PixelMesh &mesh) {
|
||||||
|
for(auto &provs : mesh | std::views::values){
|
||||||
|
for(auto&[vertices, indices] : provs){
|
||||||
|
if(vertices.empty()) continue;
|
||||||
|
BGR id = getPixelSafeIndex(image, vertices[0]);
|
||||||
|
std::size_t start = FindStart(image, vertices,id);
|
||||||
|
if(start == std::numeric_limits<std::size_t>::max()) continue;
|
||||||
|
|
||||||
|
std::vector<std::size_t> contour;
|
||||||
|
contour.push_back(start);
|
||||||
|
|
||||||
|
std::size_t cur=start;
|
||||||
|
std::size_t prev = (start % image.width > 0) ? start - 1 : start + 1;
|
||||||
|
|
||||||
|
|
||||||
|
const std::size_t MAX = vertices.size()*8;
|
||||||
|
for(std::size_t i = 0 ;i < MAX; i++){
|
||||||
|
std::size_t next;
|
||||||
|
if(!MooreStep(image, cur, prev, id, next)) break;
|
||||||
|
if(next == start) break;
|
||||||
|
contour.push_back(next);
|
||||||
|
prev = cur;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
vertices.swap(contour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static double PerpendicularDistance(
|
||||||
|
const std::size_t p,
|
||||||
|
const std::size_t a,
|
||||||
|
const std::size_t b,
|
||||||
|
const std::size_t width
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const double px = p % width;
|
||||||
|
const double py = p / width;
|
||||||
|
|
||||||
|
const double ax = a % width;
|
||||||
|
const double ay = a / width;
|
||||||
|
|
||||||
|
const double bx = b % width;
|
||||||
|
const double by = b / width;
|
||||||
|
|
||||||
|
const double dx = bx - ax;
|
||||||
|
const double dy = by - ay;
|
||||||
|
|
||||||
|
if(dx == 0 && dy == 0)
|
||||||
|
return std::hypot(px - ax, py - ay);
|
||||||
|
|
||||||
|
const double num = std::abs(dy * px - dx * py + bx * ay - by * ax);
|
||||||
|
const double den = std::sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
return num / den;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Douglas-Peucker iterative
|
||||||
|
static void Aproximate(const Image &image, PixelMesh &mesh, const std::size_t epsilon)
|
||||||
|
{
|
||||||
|
for(auto &provs : mesh | std::views::values)
|
||||||
|
{
|
||||||
|
for(auto&[vertices, indices] : provs)
|
||||||
|
{
|
||||||
|
if(vertices.size() < 3)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const std::size_t n = vertices.size();
|
||||||
|
|
||||||
|
std::vector keep_point(n, true);
|
||||||
|
std::stack<std::pair<std::size_t, std::size_t>> st;
|
||||||
|
|
||||||
|
// в стек кладем первый и последний индекс
|
||||||
|
st.push({0, n - 1});
|
||||||
|
|
||||||
|
while(!st.empty())
|
||||||
|
{
|
||||||
|
auto [startIndex, endIndex] = st.top();
|
||||||
|
st.pop();
|
||||||
|
|
||||||
|
double dMax = 0.0;
|
||||||
|
std::size_t index = startIndex;
|
||||||
|
|
||||||
|
for(std::size_t i = startIndex + 1; i < endIndex; ++i)
|
||||||
|
{
|
||||||
|
if(keep_point[i])
|
||||||
|
{
|
||||||
|
double d = PerpendicularDistance(
|
||||||
|
vertices[i],
|
||||||
|
vertices[startIndex],
|
||||||
|
vertices[endIndex],
|
||||||
|
image.width
|
||||||
|
);
|
||||||
|
|
||||||
|
if(d > dMax)
|
||||||
|
{
|
||||||
|
dMax = d;
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dMax >= epsilon)
|
||||||
|
{
|
||||||
|
st.push({startIndex, index});
|
||||||
|
st.push({index, endIndex});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(size_t j = startIndex + 1; j < endIndex; ++j)
|
||||||
|
keep_point[j] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// формируем итоговый список
|
||||||
|
std::vector<std::size_t> result;
|
||||||
|
result.reserve(n);
|
||||||
|
|
||||||
|
for(std::size_t i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
if(keep_point[i])
|
||||||
|
result.push_back(vertices[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
vertices.swap(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::size_t> TriangulateProv(const std::vector<std::size_t> &prov, const std::size_t width) {
|
||||||
|
std::vector<Point> poly;
|
||||||
|
poly.reserve(prov.size());
|
||||||
|
for (const std::size_t i : prov)
|
||||||
|
poly.push_back(Point(i, width));
|
||||||
|
|
||||||
|
// CCW
|
||||||
|
if (Point::SignedArea2(poly) < 0)
|
||||||
|
std::ranges::reverse(poly);
|
||||||
|
|
||||||
|
std::vector<std::size_t> out; // a,b,c,a,b,c,...
|
||||||
|
|
||||||
|
while (poly.size() > 3) {
|
||||||
|
bool ear_found = false;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < poly.size(); ++i) {
|
||||||
|
const std::size_t i0 = (i + poly.size() - 1) % poly.size();
|
||||||
|
const std::size_t i1 = i;
|
||||||
|
const std::size_t i2 = (i + 1) % poly.size();
|
||||||
|
|
||||||
|
const Point& a = poly[i0];
|
||||||
|
const Point& b = poly[i1];
|
||||||
|
const Point& c = poly[i2];
|
||||||
|
|
||||||
|
if (Point::Cross(a, b, c) <= 0)
|
||||||
|
continue; // не выпуклая
|
||||||
|
|
||||||
|
bool inside = false;
|
||||||
|
for (std::size_t j = 0; j < poly.size(); ++j) {
|
||||||
|
if (j == i0 || j == i1 || j == i2) continue;
|
||||||
|
if (poly[j].IsInTriangle(a, b, c)) {
|
||||||
|
inside = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inside) {
|
||||||
|
out.push_back(a.id);
|
||||||
|
out.push_back(b.id);
|
||||||
|
out.push_back(c.id);
|
||||||
|
poly.erase(poly.begin() + i1);
|
||||||
|
ear_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ear_found) {
|
||||||
|
// плохой контур (самопересечение / коллинеарность)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poly.size() == 3) {
|
||||||
|
out.push_back(poly[0].id);
|
||||||
|
out.push_back(poly[1].id);
|
||||||
|
out.push_back(poly[2].id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Triangulate(const Image &image, PixelMesh &pixelMesh)
|
||||||
|
{
|
||||||
|
for(auto &provs : pixelMesh | std::views::values)
|
||||||
|
{
|
||||||
|
for(auto&[vertices, indices] : provs)
|
||||||
|
{
|
||||||
|
if (vertices.size() < 3)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
vertices = TriangulateProv(vertices, image.width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Optimize(PixelMesh &pixelMesh)
|
||||||
|
{
|
||||||
|
for(auto &provs : pixelMesh | std::views::values)
|
||||||
|
{
|
||||||
|
for(auto&[vertices, indices] : provs)
|
||||||
|
{
|
||||||
|
std::unordered_map<std::size_t, std::uint16_t> vertexToIndex;
|
||||||
|
vertexToIndex.reserve(vertices.size());
|
||||||
|
|
||||||
|
std::vector<std::size_t> uniqueVertices;
|
||||||
|
uniqueVertices.reserve(vertices.size());
|
||||||
|
|
||||||
|
indices.clear();
|
||||||
|
|
||||||
|
for (std::size_t v : vertices)
|
||||||
|
{
|
||||||
|
if (auto it = vertexToIndex.find(v); it != vertexToIndex.end())
|
||||||
|
{
|
||||||
|
indices.push_back(it->second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::uint16_t newIndex = static_cast<std::uint16_t>(uniqueVertices.size());
|
||||||
|
uniqueVertices.push_back(v);
|
||||||
|
vertexToIndex[v] = newIndex;
|
||||||
|
indices.push_back(newIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vertices.swap(uniqueVertices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
113
sdk/modules/io.cppm
Normal file
113
sdk/modules/io.cppm
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <rfl/capnproto.hpp>
|
||||||
|
|
||||||
|
export module io;
|
||||||
|
import utils;
|
||||||
|
import AssetData;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
export namespace ee_data
|
||||||
|
{
|
||||||
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
|
||||||
|
Subject,
|
||||||
|
tag,
|
||||||
|
color,
|
||||||
|
regions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace ee_data
|
||||||
|
{
|
||||||
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
|
||||||
|
GameState,
|
||||||
|
subjects
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace ee_assets
|
||||||
|
{
|
||||||
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
|
||||||
|
AssetSave,
|
||||||
|
content
|
||||||
|
)
|
||||||
|
|
||||||
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
|
||||||
|
AssetMaterial,
|
||||||
|
vertexShaderAssetID,
|
||||||
|
fragmentShaderAssetID
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace ee_sdk {
|
||||||
|
|
||||||
|
std::optional<json> ReadJson(const std::filesystem::path &assetPath) {
|
||||||
|
std::ifstream fin(assetPath);
|
||||||
|
if (!fin.is_open()) {
|
||||||
|
LOG(ERROR, "Could not open output file: [%s]", assetPath.c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
json data = json::parse(fin);
|
||||||
|
|
||||||
|
fin.close();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::vector<std::byte>> ReadBinary(const std::filesystem::path &assetPath) {
|
||||||
|
std::ifstream fin(assetPath, std::ios::binary);
|
||||||
|
if (!fin.is_open()) {
|
||||||
|
LOG(ERROR, "Could not open output file: [%s]", assetPath.c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::byte> data;
|
||||||
|
|
||||||
|
// Read size
|
||||||
|
fin.seekg(0, std::ios::end);
|
||||||
|
const std::streamsize size = fin.tellg();
|
||||||
|
fin.seekg(0, std::ios::beg);
|
||||||
|
data.reserve(size);
|
||||||
|
|
||||||
|
// Read content
|
||||||
|
fin.read(reinterpret_cast<char *>(data.data()), size);
|
||||||
|
fin.close();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ee_assets::Asset TAsset>
|
||||||
|
void WriteAsset(const std::filesystem::path &assetPath, const TAsset &asset) {
|
||||||
|
std::ofstream fout(assetPath, std::ios::binary);
|
||||||
|
if (!fout.is_open()) {
|
||||||
|
LOG(ERROR, "Could not open input file: [%s]", assetPath.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<char> data = rfl::capnproto::write(asset);
|
||||||
|
|
||||||
|
fout.write(data.data(), data.size());
|
||||||
|
fout.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::uint32_t colorToHex(
|
||||||
|
const std::uint8_t r,
|
||||||
|
const std::uint8_t g,
|
||||||
|
const std::uint8_t b,
|
||||||
|
const bool isBGR = false
|
||||||
|
) {
|
||||||
|
if (isBGR) {
|
||||||
|
return
|
||||||
|
static_cast<std::uint32_t>(b) << 16 |
|
||||||
|
static_cast<std::uint32_t>(g) << 8 |
|
||||||
|
static_cast<std::uint32_t>(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
static_cast<std::uint32_t>(r) << 16 |
|
||||||
|
static_cast<std::uint32_t>(g) << 8 |
|
||||||
|
static_cast<std::uint32_t>(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
95
sdk/src/main.cpp
Normal file
95
sdk/src/main.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include <cxxopts.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
// IT'S NEEDED FOR MSVC COMPILER TO NOT CRASH WITH C1001
|
||||||
|
#include <rfl/capnproto.hpp>
|
||||||
|
|
||||||
|
import utils;
|
||||||
|
import AssetData;
|
||||||
|
import io;
|
||||||
|
import compile.json;
|
||||||
|
import compile.mapmesh;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
using path = std::filesystem::path;
|
||||||
|
|
||||||
|
template <ee_assets::Asset TAsset>
|
||||||
|
void CompileJson(const ee_sdk::JsonCompiler &compiler, const path &relative, const path &src, const path &out) {
|
||||||
|
LOG(INFO, "Start compiling %s...", relative.c_str());
|
||||||
|
|
||||||
|
std::filesystem::create_directories(out/relative);
|
||||||
|
for (const std::filesystem::directory_entry &asset : std::filesystem::directory_iterator(src/relative)) {
|
||||||
|
if (!asset.is_regular_file()) continue;
|
||||||
|
|
||||||
|
std::optional<json> data = ee_sdk::ReadJson(asset.path());
|
||||||
|
if (!data.has_value()) continue;
|
||||||
|
|
||||||
|
compiler.Compile(*data);
|
||||||
|
ee_sdk::WriteAsset(out/relative/asset.path().stem().filename(), data->get<TAsset>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompileMaps(const ee_sdk::MapMeshCompiler &compiler, const path &relative, const path &src, const path &out) {
|
||||||
|
LOG(INFO, "Start compiling %s...", relative.c_str());
|
||||||
|
|
||||||
|
std::filesystem::create_directories(out/relative);
|
||||||
|
for (const std::filesystem::directory_entry &asset : std::filesystem::directory_iterator(src/relative)) {
|
||||||
|
if (!asset.is_regular_file()) continue;
|
||||||
|
|
||||||
|
std::optional<std::vector<std::byte>> data = ee_sdk::ReadBinary(asset.path());
|
||||||
|
if (!data.has_value()) continue;
|
||||||
|
|
||||||
|
ee_sdk::WriteAsset(
|
||||||
|
out/relative/asset.path().stem().filename(),
|
||||||
|
ee_assets::AssetMapMesh{ .content = compiler.CompileBMP(*data) }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(const int argc, char **argv) {
|
||||||
|
std::uint32_t status = 0;
|
||||||
|
|
||||||
|
Logger::Init(L"/P7.Sink=Console");
|
||||||
|
Logger::RegisterThread(L"Main");
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
cxxopts::Options options(
|
||||||
|
"Etredia Empires SDK",
|
||||||
|
"This modding kit prepares your content assets for integration into game."
|
||||||
|
);
|
||||||
|
options.add_options()
|
||||||
|
("src", "Path to your mod source assets", cxxopts::value<path>())
|
||||||
|
("o,out", "Path to compiled assets", cxxopts::value<path>()->default_value("out"))
|
||||||
|
("h,help", "Print usage");
|
||||||
|
|
||||||
|
if (
|
||||||
|
const cxxopts::ParseResult cmd = options.parse(argc, argv);
|
||||||
|
cmd.contains("help")
|
||||||
|
) {
|
||||||
|
LOG(INFO, "\n%hs", options.help().c_str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const path &src = cmd["src"].as<path>();
|
||||||
|
const path &out = cmd["out"].as<path>();
|
||||||
|
|
||||||
|
const ee_sdk::JsonCompiler jsonCompiler(src/"regions.json");
|
||||||
|
CompileJson<ee_assets::AssetMaterial>(jsonCompiler, "materials", src, out);
|
||||||
|
CompileJson<ee_assets::AssetSave>(jsonCompiler, "scenarios", src, out);
|
||||||
|
|
||||||
|
constexpr ee_sdk::MapMeshCompiler mapMeshCompiler;
|
||||||
|
CompileMaps(mapMeshCompiler, "map", src, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
LOG(CRITICAL, "%hs", e.what());
|
||||||
|
status = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::UnregisterThread();
|
||||||
|
Logger::Release();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
@ -5,6 +5,8 @@ set(LIB utils)
|
|||||||
# Find dependencies
|
# Find dependencies
|
||||||
|
|
||||||
find_package(Boost REQUIRED COMPONENTS lockfree)
|
find_package(Boost REQUIRED COMPONENTS lockfree)
|
||||||
|
find_package(reflectcpp CONFIG REQUIRED)
|
||||||
|
find_package(glm CONFIG REQUIRED)
|
||||||
|
|
||||||
# Link library
|
# Link library
|
||||||
|
|
||||||
@ -12,3 +14,5 @@ add_library_target(${LIB})
|
|||||||
|
|
||||||
target_link_libraries(${LIB} PUBLIC p7)
|
target_link_libraries(${LIB} PUBLIC p7)
|
||||||
target_link_libraries(${LIB} PRIVATE Boost::lockfree)
|
target_link_libraries(${LIB} PRIVATE Boost::lockfree)
|
||||||
|
target_link_libraries(${LIB} PRIVATE reflectcpp::reflectcpp)
|
||||||
|
target_link_libraries(${LIB} PRIVATE glm::glm)
|
||||||
@ -83,6 +83,7 @@ namespace logger {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
P7_Set_Crash_Handler();
|
||||||
client = P7_Create_Client(options);
|
client = P7_Create_Client(options);
|
||||||
P7_Set_Crash_Handler();
|
P7_Set_Crash_Handler();
|
||||||
trace = P7_Create_Trace(client, L"TC 1");
|
trace = P7_Create_Trace(client, L"TC 1");
|
||||||
@ -159,10 +160,14 @@ namespace logger {
|
|||||||
nullptr,
|
nullptr,
|
||||||
location.line(),
|
location.line(),
|
||||||
location.file_name(),
|
location.file_name(),
|
||||||
location.function_name(),
|
"", //TODO: location.function_name(),
|
||||||
format,
|
format,
|
||||||
std::forward<Args>(args)...
|
std::forward<Args>(args)...
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (level == ERROR || level == CRITICAL) {
|
||||||
|
Logger::client->Flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -202,10 +207,14 @@ namespace logger {
|
|||||||
nullptr,
|
nullptr,
|
||||||
location.line(),
|
location.line(),
|
||||||
location.file_name(),
|
location.file_name(),
|
||||||
location.function_name(),
|
"", //TODO: location.function_name(),
|
||||||
TM(format),
|
TM(format),
|
||||||
std::forward<Args>(args)...
|
std::forward<Args>(args)...
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (level == ERROR || level == CRITICAL) {
|
||||||
|
Logger::client->Flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
35
utils/modules/serialization.cppm
Normal file
35
utils/modules/serialization.cppm
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
module;
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <rfl/capnproto.hpp>
|
||||||
|
|
||||||
|
export module utils:serialization;
|
||||||
|
|
||||||
|
namespace rfl {
|
||||||
|
template <glm::length_t length, typename T>
|
||||||
|
struct GlmVecImpl {
|
||||||
|
float x; float y;
|
||||||
|
|
||||||
|
static GlmVecImpl from_class(const glm::vec<length, T>& vector) noexcept {
|
||||||
|
return {vector.x,vector.y};
|
||||||
|
}
|
||||||
|
glm::vec<length, T> to_class() const { return {x, y}; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace rfl {
|
||||||
|
template <class ReaderType, class WriterType, class ProcessorsType>
|
||||||
|
struct parsing::Parser<ReaderType, WriterType, glm::vec2, ProcessorsType>
|
||||||
|
: CustomParser<ReaderType, WriterType, ProcessorsType, glm::vec2, GlmVecImpl<2, float>> {};
|
||||||
|
|
||||||
|
template <class ReaderType, class WriterType, class ProcessorsType>
|
||||||
|
struct parsing::Parser<ReaderType, WriterType, glm::vec3, ProcessorsType>
|
||||||
|
: CustomParser<ReaderType, WriterType, ProcessorsType, glm::vec3, GlmVecImpl<3, float>> {};
|
||||||
|
|
||||||
|
template <class ReaderType, class WriterType, class ProcessorsType>
|
||||||
|
struct parsing::Parser<ReaderType, WriterType, glm::vec4, ProcessorsType>
|
||||||
|
: CustomParser<ReaderType, WriterType, ProcessorsType, glm::vec4, GlmVecImpl<4, float>> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace ee_utils {
|
||||||
|
|
||||||
|
}
|
||||||
@ -4,5 +4,6 @@ export import :worker;
|
|||||||
export import :buffers;
|
export import :buffers;
|
||||||
export import :lockfree;
|
export import :lockfree;
|
||||||
export import :logger;
|
export import :logger;
|
||||||
|
export import :serialization;
|
||||||
|
|
||||||
export namespace ee_utils {}
|
export namespace ee_utils {}
|
||||||
15
vcpkg.json
15
vcpkg.json
@ -1,15 +1,24 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
"cxxopts",
|
||||||
"boost-lockfree",
|
"boost-lockfree",
|
||||||
"xxhash",
|
"xxhash",
|
||||||
"nlohmann-json",
|
"nlohmann-json",
|
||||||
|
{
|
||||||
|
"name": "reflectcpp",
|
||||||
|
"features": [
|
||||||
|
"capnproto"
|
||||||
|
]
|
||||||
|
},
|
||||||
"entt",
|
"entt",
|
||||||
"vulkan",
|
"vulkan",
|
||||||
"glfw3",
|
"glfw3",
|
||||||
"glm",
|
"glm",
|
||||||
{
|
{
|
||||||
"name": "magnum",
|
"name": "magnum",
|
||||||
"features": ["glfwapplication"],
|
"features": [
|
||||||
|
"glfwapplication"
|
||||||
|
],
|
||||||
"version>=": "0"
|
"version>=": "0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -18,5 +27,7 @@
|
|||||||
},
|
},
|
||||||
"rmlui",
|
"rmlui",
|
||||||
"gtest"
|
"gtest"
|
||||||
]
|
],
|
||||||
|
"version": "0.0.1",
|
||||||
|
"name": "etredia-empires"
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user