Rendering states in Magnum

This commit is contained in:
legatt 2026-01-24 15:51:21 +03:00
parent 91bee9f300
commit 6bcea3087a
35 changed files with 593 additions and 133 deletions

View File

@ -1,5 +0,0 @@
{
"cmake.debugConfig": {
"args": ["D:/PROJECTS/EtrediaEmpires/sdk/map/provinces.bmp", "D:/PROJECTS/EtrediaEmpires/sdk/map/provinces.map"]
}
}

Binary file not shown.

View File

@ -0,0 +1 @@
Vpクx /}

View File

@ -0,0 +1 @@
贔PD゙<EFBFBD>タイ

View File

@ -0,0 +1,7 @@
layout(location = 0) in vec3 fragColor;
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(fragColor, 1.0);
}

View File

@ -0,0 +1,28 @@
struct Province {
uint stateId;
uint color;
};
layout(std430, binding=0) buffer Data {
Province provinces[];
};
layout(location = 0) in vec2 position;
layout(location = 1) uniform mat4 camera;
layout(location = 2) uniform mat4 transform;
layout(location = 3) uniform uint provinceIndex;
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 * vec4(position, 0.0, 1.0);
fragColor = unpackColor(provinces[provinceIndex].color);
}

View File

@ -25,7 +25,12 @@ find_package(glfw3 CONFIG REQUIRED)
add_library(${PROJECT_NAME} ${SOURCES}) add_library(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} PRIVATE p7)
target_link_libraries(${PROJECT_NAME} PUBLIC utils) target_link_libraries(${PROJECT_NAME} PUBLIC utils)
target_link_libraries(${PROJECT_NAME} PRIVATE glfw) target_link_libraries(${PROJECT_NAME} PRIVATE glfw)
target_include_directories(${PROJECT_NAME} PUBLIC include/) target_include_directories(${PROJECT_NAME} PUBLIC include/)
if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
endif()

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "Map.hpp"
#include <concepts> #include <concepts>
#include <cstdint> #include <cstdint>
@ -14,25 +15,17 @@ struct AssetBinary : AssetData
~AssetBinary(); ~AssetBinary();
}; };
struct AssetVulkanShader : AssetData struct AssetMapMesh : AssetData
{ {
uint32_t* content = nullptr; MapMesh content;
size_t size = 0;
AssetVulkanShader(uint8_t* &source, const size_t &sourceSize); AssetMapMesh(uint8_t* &source, const size_t &sourceSize);
~AssetVulkanShader();
}; };
struct AssetVulkanMaterial : AssetData #define AssetShader AssetBinary
struct AssetMaterial : AssetData
{ {
uint32_t vertexShaderAssetID; uint32_t vertexShaderAssetID;
uint32_t fragmentShaderAssetID; uint32_t fragmentShaderAssetID;
uint32_t renderType;
uint32_t renderStage;
// Vertex shader params
// <param id:value>
// Fragment shader params
// <param id:value>
}; };

View File

@ -0,0 +1,21 @@
#pragma once
#include <vector>
#include <unordered_map>
#include <glm/glm.hpp>
struct MapMesh
{
struct Province
{
std::vector<glm::vec2> vertices;
std::vector<uint16_t> indices;
};
std::unordered_map<uint32_t, std::vector<Province>> states;
};
struct ProvinceSSBO
{
uint32_t stateId;
uint32_t color;
};

View File

@ -1,22 +1,61 @@
#pragma once #pragma once
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include "Map.hpp"
#include "AssetData.hpp"
struct ShaderRefs
{
AssetShader *vertProvinces;
AssetShader *fragProvinces;
};
struct CameraTransform
{
glm::vec2 position {0.0f, 0.0f};
float zoom = 1.0f;
};
struct MeshTransform
{
glm::vec2 position {0.0f, 0.0f};
glm::vec2 scale {1.0f, 1.0f};
float rotation;
};
class IRenderer class IRenderer
{ {
public: public:
virtual ~IRenderer(); virtual ~IRenderer();
void RegisterMaterials(const ShaderRefs &shaders);
void RegisterMapMesh(MapMesh *mapMesh);
virtual void Init() = 0;
virtual void Shutdown() = 0;
void Draw(); void Draw();
virtual void ResizeWindow(int width, int height); virtual void ResizeWindow(int width, int height);
void SetCamera(const CameraTransform &camera);
void SetMapTransform(const MeshTransform &mapTransform);
protected: protected:
int screenWidth, screenHeight; int screenWidth, screenHeight;
float screenAspect;
CameraTransform camera;
MeshTransform mapTransform;
glm::mat4 mapModel;
glm::mat4 viewProjection;
GLFWwindow *window; GLFWwindow *window;
MapMesh *mapMesh;
ShaderRefs shaders;
explicit IRenderer(GLFWwindow *window); explicit IRenderer(GLFWwindow *window);
virtual void Clear() = 0; virtual void Clear() = 0;
virtual void DrawMap() = 0; virtual void DrawMap() = 0;
virtual void DrawUI() = 0; virtual void DrawUI() = 0;
virtual void ApplyCamera() = 0;
virtual void ApplyMapTransform() = 0;
}; };

View File

@ -0,0 +1,89 @@
#include <ee_engine_api/AssetData.hpp>
#include <ee_utils/allocator.hpp>
#include <ee_utils/buffers.hpp>
#include <glm/glm.hpp>
/*
YOU CAN PREVENT SOURCE BUFFER FROM CLOSING.
IT CAN BE USED FOR STORING ASSET DATA WITHOUT COPY.
IN THIS CASE, YOU MUST SET SOURCE TO NULLPTR AND FREE BUFFER YOURSELF.
*/
AssetBinary::AssetBinary(uint8_t* &source, const size_t &sourceSize)
{
content = source;
size = sourceSize;
source = nullptr;
}
AssetBinary::~AssetBinary()
{
if (content != nullptr)
DeallocateArray(content);
}
AssetMapMesh::AssetMapMesh(uint8_t* &source, const size_t &sourceSize)
{
uint8_t* buffer = source;
uint8_t* pointer = source;
size_t leftoverSize = sourceSize;
source = nullptr;
uint32_t statesCount = 0;
readNext(&statesCount, pointer, leftoverSize, sizeof(uint32_t));
for (uint32_t state = 0; state < statesCount; state++)
{
uint32_t id = 0;
glm::u8vec3 color {};
if (!readNext(&color, pointer, leftoverSize, sizeof(glm::u8vec3)))
break;
id = static_cast<uint32_t>(color.r) << 16 |
static_cast<uint32_t>(color.g) << 8 |
static_cast<uint32_t>(color.b);
uint32_t provincesCount = 0;
readNext(&provincesCount, pointer, leftoverSize, sizeof(uint32_t));
for (uint32_t pi = 0; pi < provincesCount; pi++)
{
MapMesh::Province prov;
uint32_t verticesCount = 0;
if (!readNext(&verticesCount, pointer, leftoverSize, sizeof(uint32_t)))
break;
prov.vertices.reserve(verticesCount);
for (uint32_t vi = 0; vi < verticesCount; vi++)
{
glm::vec2 vertex;
if (!readNext(&vertex, pointer, leftoverSize, sizeof(glm::vec2)))
break;
prov.vertices.push_back(vertex);
}
uint32_t indicesCount = 0;
if (!readNext(&indicesCount, pointer, leftoverSize, sizeof(uint32_t)))
break;
prov.indices.reserve(indicesCount);
for(uint32_t ii = 0; ii < indicesCount; ii++)
{
uint16_t index = 0;
if (!readNext(&index, pointer, leftoverSize, sizeof(uint16_t)))
break;
prov.indices.push_back(index);
}
content.states[id].push_back(prov);
}
}
DeallocateArray(buffer);
}

View File

@ -1,10 +1,13 @@
#include <ee_engine_api/RenderInterface.hpp> #include <ee_engine_api/RenderInterface.hpp>
#include <ee_utils/allocator.hpp> #include <ee_utils/allocator.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "Logger.h"
IRenderer::IRenderer(GLFWwindow *window) IRenderer::IRenderer(GLFWwindow *window)
{ {
this->window = window; this->window = window;
glfwGetFramebufferSize(window, &screenWidth, &screenHeight); glfwGetFramebufferSize(window, &screenWidth, &screenHeight);
screenAspect = static_cast<float>(screenWidth) / static_cast<float>(screenHeight);
} }
IRenderer::~IRenderer() IRenderer::~IRenderer()
@ -12,6 +15,16 @@ IRenderer::~IRenderer()
} }
void IRenderer::RegisterMaterials(const ShaderRefs &shaders)
{
this->shaders = shaders;
}
void IRenderer::RegisterMapMesh(MapMesh* mapMesh)
{
this->mapMesh = mapMesh;
}
void IRenderer::Draw() void IRenderer::Draw()
{ {
Clear(); Clear();
@ -23,4 +36,45 @@ void IRenderer::ResizeWindow(int width, int height)
{ {
screenWidth = width; screenWidth = width;
screenHeight = height; screenHeight = height;
screenAspect = static_cast<float>(screenWidth) / static_cast<float>(screenHeight);
}
void IRenderer::SetCamera(const CameraTransform &camera)
{
if (camera.zoom <= 0)
{
LOG(WARNING, "Camera zoom cannot be zero or less!");
return;
}
this->camera = camera;
float halfHeight = camera.zoom;
float halfWidth = camera.zoom * screenAspect;
glm::mat4 P = glm::ortho(
-halfWidth, +halfWidth,
-halfHeight, +halfHeight
);
glm::mat4 V = glm::translate(
glm::mat4(1.0f),
glm::vec3(-camera.position, 0.0f)
);
viewProjection = P * V;
ApplyCamera();
}
void IRenderer::SetMapTransform(const MeshTransform &mapTransform)
{
this->mapTransform = mapTransform;
glm::mat4 M(1.0f);
M = glm::translate(M, glm::vec3(mapTransform.position, 0.0f));
M = glm::rotate(M, mapTransform.rotation, glm::vec3(0.0f, 0.0f, 1.0f));
M = glm::scale(M, glm::vec3(mapTransform.scale, 1.0f));
ApplyMapTransform();
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "FileSystem.hpp" #include "FileSystem.hpp"
#include "AssetData.hpp" #include <ee_engine_api/AssetData.hpp>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
@ -30,8 +30,10 @@ public:
{ {
BINARY, BINARY,
VULKAN_SHADER, MAP_MESH,
VULKAN_MATERIAL,
SHADER,
MATERIAL,
IMAGE IMAGE
} type = BINARY; } type = BINARY;
@ -85,11 +87,13 @@ public:
void Start(); void Start();
void Shutdown(); void Shutdown();
void LoadShaders(); void LoadDir(AssetInfo::Type type, const std::filesystem::path &path);
void LoadAsync(AssetInfo::Type type, const std::filesystem::path &path); void LoadAsync(AssetInfo::Type type, const std::filesystem::path &path);
AssetHandle& Find(const std::filesystem::path &path); AssetHandle& Find(const std::filesystem::path &path);
AssetHandle& Find(const uint32_t &id); AssetHandle& Find(const uint32_t &id);
template <Asset T> T& FindOnce(const std::filesystem::path &path);
template <Asset T> T& FindOnce(const uint32_t &id);
void Redirect(AssetHandle &handle, void *resource); void Redirect(AssetHandle &handle, void *resource);
template <Asset T> T& Get(const AssetHandle &handle); template <Asset T> T& Get(const AssetHandle &handle);
void Free(AssetHandle &handle); void Free(AssetHandle &handle);
@ -108,8 +112,9 @@ private:
std::vector<AssetLoadingEntry> loadingEntries; std::vector<AssetLoadingEntry> loadingEntries;
std::vector<AssetBinary*> binaryStorage; std::vector<AssetBinary*> binaryStorage;
std::vector<AssetVulkanShader*> shadersStorage; std::vector<AssetMapMesh*> mapMeshesStorage;
std::vector<AssetVulkanMaterial*> materialsStorage; std::vector<AssetShader*> shadersStorage;
std::vector<AssetMaterial*> materialsStorage;
void Threading(); void Threading();
void Request(const AssetStreamCommand &command); void Request(const AssetStreamCommand &command);
@ -117,6 +122,8 @@ private:
void Loop(); void Loop();
void ProcessCommand(AssetStreamCommand &command); void ProcessCommand(AssetStreamCommand &command);
void Release(); void Release();
template<Asset T> void ClearStorage(std::vector<T*> &storage);
}; };
template <Asset T> T& AssetManager::Get(const AssetHandle &handle) template <Asset T> T& AssetManager::Get(const AssetHandle &handle)
@ -130,4 +137,24 @@ template <Asset T> T& AssetManager::Get(const AssetHandle &handle)
Request(command); Request(command);
while (command.out->load() == nullptr); while (command.out->load() == nullptr);
return *reinterpret_cast<T*>(command.out->load()); return *reinterpret_cast<T*>(command.out->load());
}
template <Asset T> T& AssetManager::FindOnce(const std::filesystem::path &path)
{
return Get<T>(Find(path));
}
template <Asset T> T& AssetManager::FindOnce(const uint32_t &id)
{
return Get<T>(Find(id));
}
template<Asset T> void AssetManager::ClearStorage(std::vector<T*> &storage)
{
for (T* &resource : storage)
{
if (resource != nullptr)
Deallocate(resource);
}
storage.clear();
} }

View File

@ -10,6 +10,8 @@ public:
static AssetManager *assetManager; static AssetManager *assetManager;
static IRenderer *renderer; static IRenderer *renderer;
static void Shutdown();
private: private:
Engine(); Engine();
}; };

View File

@ -1,28 +0,0 @@
#include "AssetData.hpp"
#include <ee_utils/allocator.hpp>
AssetBinary::AssetBinary(uint8_t* &source, const size_t &sourceSize)
{
content = source;
size = sourceSize;
source = nullptr;
}
AssetBinary::~AssetBinary()
{
if (content != nullptr)
DeallocateArray(content);
}
AssetVulkanShader::AssetVulkanShader(uint8_t* &source, const size_t &sourceSize)
{
content = reinterpret_cast<uint32_t*>(source);
size = sourceSize;
source = nullptr;
}
AssetVulkanShader::~AssetVulkanShader()
{
if (content != nullptr)
DeallocateArray(content);
}

View File

@ -50,7 +50,8 @@ void AssetManager::Redirect(AssetHandle &handle, void* resource)
{ {
void* oldResource = asset.resourceAddress->resource.exchange(nullptr, std::memory_order_acq_rel); void* oldResource = asset.resourceAddress->resource.exchange(nullptr, std::memory_order_acq_rel);
if (oldResource) if (oldResource)
Deallocate(asset.resourceAddress->resource.load()); //Deallocate(asset.resourceAddress->resource.load());
Deallocate(oldResource);
} }
asset.resourceAddress->resource.store(resource); asset.resourceAddress->resource.store(resource);
@ -174,20 +175,29 @@ void AssetManager::Loop()
switch (asset.type) switch (asset.type)
{ {
case AssetInfo::VULKAN_SHADER: case AssetInfo::MAP_MESH:
{ {
AssetVulkanShader* shader = Allocate<AssetVulkanShader>(entry.file->data, entry.file->size); AssetMapMesh* mesh = Allocate<AssetMapMesh>(entry.file->data, entry.file->size);
mapMeshesStorage.push_back(mesh);
Redirect(entry.handle, mapMeshesStorage.back());
break;
}
case AssetInfo::SHADER:
{
AssetShader* shader = Allocate<AssetShader>(entry.file->data, entry.file->size);
shadersStorage.push_back(shader); shadersStorage.push_back(shader);
Redirect(entry.handle, shadersStorage.back()); Redirect(entry.handle, shadersStorage.back());
break; break;
} }
case AssetInfo::VULKAN_MATERIAL: case AssetInfo::MATERIAL:
{ {
AssetVulkanMaterial* material = Allocate<AssetVulkanMaterial>(); AssetMaterial* material = Allocate<AssetMaterial>();
if (entry.file->size < sizeof(AssetVulkanMaterial)) if (entry.file->size < sizeof(AssetMaterial))
LOG(CRITICAL, "File size is less than needed for material"); LOG(CRITICAL, "File size is less than needed for material");
std::memcpy(material, entry.file->data, sizeof(AssetVulkanMaterial)); std::memcpy(material, entry.file->data, sizeof(AssetMaterial));
materialsStorage.push_back(material); materialsStorage.push_back(material);
Redirect(entry.handle, materialsStorage.back()); Redirect(entry.handle, materialsStorage.back());
break; break;
@ -246,6 +256,7 @@ void AssetManager::ProcessCommand(AssetStreamCommand &command)
if (freeAssetSlots.size() > 0) if (freeAssetSlots.size() > 0)
{ {
assetPos = freeAssetSlots.back(); assetPos = freeAssetSlots.back();
Deallocate(activeAssets[assetPos].resourceAddress);
activeAssets[assetPos] = std::move(asset); activeAssets[assetPos] = std::move(asset);
freeAssetSlots.pop_back(); freeAssetSlots.pop_back();
} }
@ -321,9 +332,9 @@ void AssetManager::Release()
{ {
if (asset.resourceAddress->resource.load() != nullptr) if (asset.resourceAddress->resource.load() != nullptr)
{ {
void* oldResource = asset.resourceAddress->resource.exchange(nullptr, std::memory_order_acq_rel); void* resource = asset.resourceAddress->resource.exchange(nullptr, std::memory_order_acq_rel);
if (oldResource) if (resource)
Deallocate(asset.resourceAddress->resource.load()); Deallocate(resource);
} }
Deallocate(asset.resourceAddress); Deallocate(asset.resourceAddress);
} }
@ -333,30 +344,20 @@ void AssetManager::Release()
Deallocate(mapping.second); Deallocate(mapping.second);
assetsMapping.clear(); assetsMapping.clear();
//TODO: ClrearStorage(&storage);
for (AssetBinary* &resource : binaryStorage)
{
if (resource != nullptr)
Deallocate(resource);
}
binaryStorage.clear(); binaryStorage.clear();
for (AssetVulkanShader* &resource : shadersStorage) mapMeshesStorage.clear();
{
if (resource != nullptr)
Deallocate(resource);
}
shadersStorage.clear(); shadersStorage.clear();
materialsStorage.clear();
LOG(INFO, "Asset Streaming is released"); LOG(INFO, "Asset Streaming is released");
isRunning.store(false); isRunning.store(false);
} }
void AssetManager::LoadShaders() void AssetManager::LoadDir(AssetInfo::Type type, const std::filesystem::path &path)
{ {
std::filesystem::path shadersRoot = "assets/shaders"; for (const std::filesystem::directory_entry &entry : std::filesystem::directory_iterator(path))
for (const std::filesystem::directory_entry &entry : std::filesystem::directory_iterator(shadersRoot))
{ {
if (entry.is_directory()) continue; if (entry.is_directory()) continue;
LoadAsync(AssetInfo::VULKAN_SHADER, entry.path()); LoadAsync(type, entry.path());
} }
} }

View File

@ -1,4 +1,25 @@
#include "Engine.hpp" #include "Engine.hpp"
#include <ee_utils/allocator.hpp>
AssetManager* Engine::assetManager; AssetManager* Engine::assetManager;
IRenderer* Engine::renderer; IRenderer* Engine::renderer;
void Engine::Shutdown()
{
if (renderer != nullptr)
{
renderer->Shutdown();
Deallocate(renderer);
}
renderer = nullptr;
if (Engine::assetManager != nullptr)
{ // Wait for asset manager to clean and shutdown
Engine::assetManager->Shutdown();
while(Engine::assetManager->isRunning.load());
}
if (assetManager != nullptr)
Deallocate(assetManager);
assetManager = nullptr;
}

View File

@ -122,6 +122,9 @@ bool NativeFileSystem::PollReady(FileHandle &file)
void NativeFileSystem::Close(FileHandle &file) void NativeFileSystem::Close(FileHandle &file)
{ {
if (file.overlapped.hEvent)
CloseHandle(file.overlapped.hEvent);
if (file.buffer != nullptr) if (file.buffer != nullptr)
{ {
DeallocateArray(file.buffer); DeallocateArray(file.buffer);

View File

@ -34,20 +34,33 @@ int main(int argc, char **argv)
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
// Setup assets // Setup Asset Manager
AssetManager assetManager; Engine::assetManager = Allocate<AssetManager>();
assetManager.Start(); Engine::assetManager->Start();
//assetManager.LoadShaders(); Engine::assetManager->LoadDir(AssetInfo::SHADER, "assets/shaders");
Engine::assetManager->LoadDir(AssetInfo::MATERIAL, "assets/materials");
// Setup Renderer // Load assets
// assetManager.LoadAsync(AssetInfo::MATERIAL, "assets/materials/helloworld.mat"); Engine::assetManager->LoadAsync(AssetInfo::MAP_MESH, "assets/map/states.map");
// AssetHandle baseMaterialHandle = assetManager.Find("assets/materials/helloworld.mat");
// AssetMaterial baseMaterial = assetManager.Get<AssetMaterial>(baseMaterialHandle);
//Setup Engine // Setup renderer TODO: builder
Engine::assetManager = &assetManager;
Engine::renderer = reinterpret_cast<IRenderer*>(Allocate<MagnumRenderer>(window)); Engine::renderer = reinterpret_cast<IRenderer*>(Allocate<MagnumRenderer>(window));
AssetMapMesh &states = Engine::assetManager->FindOnce<AssetMapMesh>("assets/map/states.map");
Engine::renderer->RegisterMapMesh(&states.content);
//TODO: ShaderRefs builder from set of AssetMaterial
AssetMaterial &provincesMaterial = Engine::assetManager->FindOnce<AssetMaterial>("assets/materials/provinces.mat");
AssetShader &vertProv = Engine::assetManager->FindOnce<AssetShader>(provincesMaterial.vertexShaderAssetID);
AssetShader &fragProv = Engine::assetManager->FindOnce<AssetShader>(provincesMaterial.fragmentShaderAssetID);
Engine::renderer->RegisterMaterials({
.vertProvinces = &vertProv,
.fragProvinces = &fragProv
});
Engine::renderer->Init();
Engine::renderer->SetCamera({.zoom = 100.0f});
glfwSetFramebufferSizeCallback(window, [](GLFWwindow *window, int width, int height) { glfwSetFramebufferSizeCallback(window, [](GLFWwindow *window, int width, int height) {
Engine::renderer->ResizeWindow(width, height); Engine::renderer->ResizeWindow(width, height);
}); });
@ -63,11 +76,7 @@ int main(int argc, char **argv)
// Free memory // Free memory
LOG(INFO, "Exit..."); LOG(INFO, "Exit...");
if (Engine::assetManager != nullptr) Engine::Shutdown();
{ // Wait for asset manager to clean and shutdown
Engine::assetManager->Shutdown();
while(Engine::assetManager->isRunning.load());
}
glfwDestroyWindow(window); glfwDestroyWindow(window);
glfwTerminate(); glfwTerminate();
//TODO: check Unregister in other threads and make threaded module base class //TODO: check Unregister in other threads and make threaded module base class

View File

@ -0,0 +1,35 @@
#pragma once
#undef min
#undef max
#include <Magnum/GL/AbstractShaderProgram.h>
#include <Magnum/GL/Shader.h>
#include <Magnum/GL/Version.h>
#include <Magnum/Math/Matrix4.h>
#include <glm/glm.hpp>
#define PROVINCES_SSBO_BINDING 0
#define CAMERA_UNIFORM 1
//TODO: push constant
#define TRANSFORM_UNIFORM 2
#define PROVINCES_ID_UNIFORM 3
using namespace Magnum;
class BaseMaterial : public GL::AbstractShaderProgram
{
public:
void setModelViewProjection(const Matrix4 &m, const Matrix4 &vp);
protected:
explicit BaseMaterial(const std::string &vertSrc, const std::string &fragSrc);
};
class ProvinceMaterial : public BaseMaterial
{
public:
explicit ProvinceMaterial(const std::string &vertSrc, const std::string &fragSrc);
void setId(const uint32_t &id);
};

View File

@ -4,8 +4,11 @@
#undef max #undef max
#include <Magnum/Platform/GLContext.h> #include <Magnum/Platform/GLContext.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/GL/Buffer.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include "Materials.hpp"
#include <ee_engine_api/RenderInterface.hpp> #include <ee_engine_api/RenderInterface.hpp>
using namespace Magnum; using namespace Magnum;
@ -15,12 +18,28 @@ class MagnumRenderer : public IRenderer
public: public:
MagnumRenderer(GLFWwindow *window); MagnumRenderer(GLFWwindow *window);
~MagnumRenderer(); ~MagnumRenderer();
void Init() override;
void Shutdown() override;
protected: protected:
void Clear() override; void Clear() override;
void DrawMap() override; void DrawMap() override;
void DrawUI() override; void DrawUI() override;
void ApplyCamera() override;
void ApplyMapTransform() override;
private: private:
Platform::GLContext context; Platform::GLContext context;
std::vector<GL::Mesh> provinceMeshes;
GL::Buffer provinceSSBO;
ProvinceMaterial *provinceMaterial;
void ValidateSupport();
void LoadShaders();
void LoadProvinces();
void ApplyMapMVP();
}; };

View File

@ -0,0 +1,37 @@
#include <ee_magnum/Materials.hpp>
#include "Logger.h"
BaseMaterial::BaseMaterial(const std::string &vertSrc, const std::string &fragSrc)
{
GL::Shader vert {GL::Version::GL430, GL::Shader::Type::Vertex};
GL::Shader frag {GL::Version::GL430, GL::Shader::Type::Fragment};
vert.addSource(vertSrc);
frag.addSource(fragSrc);
if (!vert.compile())
LOG(CRITICAL, "Failed to compile vertex shader");
if (!frag.compile())
LOG(CRITICAL, "Failed to compile fragment shader");
attachShader(vert);
attachShader(frag);
link();
}
void BaseMaterial::setModelViewProjection(const Matrix4 &m, const Matrix4 &vp)
{
setUniform(TRANSFORM_UNIFORM, m);
setUniform(CAMERA_UNIFORM, vp);
}
ProvinceMaterial::ProvinceMaterial(const std::string &vertSrc, const std::string &fragSrc): BaseMaterial(vertSrc, fragSrc)
{
}
void ProvinceMaterial::setId(const uint32_t &id)
{
setUniform(PROVINCES_ID_UNIFORM, id);
}

View File

@ -1,4 +1,5 @@
#include "Logger.h" #include "Logger.h"
#include "ee_utils/allocator.hpp"
#include <ee_magnum/Renderer.hpp> #include <ee_magnum/Renderer.hpp>
#include <Magnum/GL/Buffer.h> #include <Magnum/GL/Buffer.h>
@ -6,19 +7,28 @@
#include <Magnum/GL/Mesh.h> #include <Magnum/GL/Mesh.h>
#include <Magnum/Math/Color.h> #include <Magnum/Math/Color.h>
#include <Magnum/Shaders/VertexColor.h> #include <Magnum/Shaders/VertexColor.h>
#include <Corrade/Utility/Debug.h> #include <Corrade/Utility/Debug.h>
#include <glm/gtc/type_ptr.hpp>
#include <string>
using namespace Math::Literals; using namespace Math::Literals;
MagnumRenderer::MagnumRenderer(GLFWwindow *window) : IRenderer(window) MagnumRenderer::MagnumRenderer(GLFWwindow *window) : IRenderer(window)
{ {
ValidateSupport();
LOG(INFO, "Renderer created");
} }
MagnumRenderer::~MagnumRenderer() void MagnumRenderer::Init()
{ {
LOG(INFO, "GLSL version: %d", GL::Context::current().version());
LoadShaders();
LoadProvinces();
LOG(INFO, "Renderer initialized");
} }
void MagnumRenderer::Clear() void MagnumRenderer::Clear()
@ -28,29 +38,102 @@ void MagnumRenderer::Clear()
void MagnumRenderer::DrawMap() void MagnumRenderer::DrawMap()
{ {
//TEST TRIANGLE ApplyCamera();
struct TriangleVertex { for (uint32_t i = 0; i < provinceMeshes.size(); i++)
Vector2 position; {
Color3 color; provinceMaterial->setId(i);
}; provinceMaterial->draw(provinceMeshes[i]);
const TriangleVertex vertices[]{ }
{{-0.5f, -0.5f}, 0xff0000_rgbf}, /* Left vertex, red color */
{{ 0.5f, -0.5f}, 0x00ff00_rgbf}, /* Right vertex, green color */
{{ 0.0f, 0.5f}, 0x0000ff_rgbf} /* Top vertex, blue color */
};
GL::Mesh mesh;
mesh.setCount((int)Containers::arraySize(vertices))
.addVertexBuffer(GL::Buffer{vertices}, 0,
Shaders::VertexColor2D::Position{},
Shaders::VertexColor2D::Color3{});
Shaders::VertexColor2D shader;
shader.draw(mesh);
} }
void MagnumRenderer::DrawUI() void MagnumRenderer::DrawUI()
{ {
}
void MagnumRenderer::ValidateSupport()
{
}
void MagnumRenderer::ApplyCamera()
{
ApplyMapMVP();
}
void MagnumRenderer::ApplyMapTransform()
{
ApplyMapMVP();
}
void MagnumRenderer::ApplyMapMVP()
{
Matrix4 viewProjection {Magnum::NoInit};
std::memcpy(viewProjection.data(), glm::value_ptr(this->viewProjection), sizeof(float) * 16);
Matrix4 mapModel {Magnum::NoInit};
std::memcpy(mapModel.data(), glm::value_ptr(this->mapModel), sizeof(float) * 16);
provinceMaterial->setModelViewProjection(mapModel, viewProjection);
}
void MagnumRenderer::LoadShaders()
{
provinceMaterial = Allocate<ProvinceMaterial>(std::string(
reinterpret_cast<const char*>(shaders.vertProvinces->content),
shaders.vertProvinces->size
) + '\0', std::string(
reinterpret_cast<const char*>(shaders.fragProvinces->content),
shaders.fragProvinces->size
)) + '\0';
LOG(INFO, "Shaders loaded");
}
void MagnumRenderer::LoadProvinces()
{
std::vector<ProvinceSSBO> provincesData;
for (auto& [state, provs]: mapMesh->states)
{
for (MapMesh::Province &province: provs)
{
GL::Mesh stateMesh;
stateMesh.setPrimitive(GL::MeshPrimitive::Triangles)
.setCount(static_cast<Magnum::Int>(province.indices.size()))
.addVertexBuffer(GL::Buffer{province.vertices}, 0, GL::Attribute<0, Magnum::Vector2>{})
.setIndexBuffer(GL::Buffer{province.indices}, 0, GL::MeshIndexType::UnsignedShort);
provinceMeshes.push_back(std::move(stateMesh));
ProvinceSSBO data {
.stateId = state,
.color = state
};
provincesData.push_back(data);
}
}
LOG(INFO, "Registered %d province meshes in renderer", provinceMeshes.size());
provinceSSBO.setTargetHint(GL::Buffer::TargetHint::ShaderStorage);
provinceSSBO.setData(provincesData, GL::BufferUsage::DynamicDraw);
provinceSSBO.bind(GL::Buffer::Target::ShaderStorage, PROVINCES_SSBO_BINDING);
}
void MagnumRenderer::Shutdown()
{
provinceMeshes.clear();
provinceSSBO = GL::Buffer{NoCreate};
if (provinceMaterial != nullptr)
Deallocate(provinceMaterial);
provinceMaterial = nullptr;
}
MagnumRenderer::~MagnumRenderer()
{
} }

View File

@ -31,8 +31,8 @@ foreach(MAP ${MAP_FILES})
add_custom_command( add_custom_command(
OUTPUT ${OUT_FILE} OUTPUT ${OUT_FILE}
COMMAND ${PROJECT_NAME} ${MAP} ${OUT_FILE} COMMAND $<TARGET_FILE:${PROJECT_NAME}> ${MAP} ${OUT_FILE}
DEPENDS ${MAP} DEPENDS ${MAP} ${PROJECT_NAME}
COMMENT "Converting map ${MAP_NAME}" COMMENT "Converting map ${MAP_NAME}"
VERBATIM VERBATIM
) )

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 MiB

2
sdk/map/run.cmd Normal file
View File

@ -0,0 +1,2 @@
@echo off
"%CD%/../../out/build/DEBUG/sdk/map/convert_map.exe" states.bmp ../../assets/map/states.map

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -16,7 +16,7 @@ find_package(xxHash CONFIG REQUIRED)
add_executable(${PROJECT_NAME} compile_materials.cpp) add_executable(${PROJECT_NAME} compile_materials.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json) target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json)
target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash) target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/engine/include/) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/engine-api/include/)
if (CMAKE_VERSION VERSION_GREATER 3.12) if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)

View File

@ -4,16 +4,14 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <xxhash.h> #include <xxhash.h>
#include <string> #include <string>
#include "AssetData.hpp" #include <ee_engine_api/AssetData.hpp>
using json = nlohmann::json; using json = nlohmann::json;
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
AssetVulkanMaterial, AssetMaterial,
vertexShaderAssetID, vertexShaderAssetID,
fragmentShaderAssetID, fragmentShaderAssetID
renderType,
renderStage
) )
int main(int argc, char **argv) int main(int argc, char **argv)
@ -51,7 +49,7 @@ int main(int argc, char **argv)
data[key] = assetId; data[key] = assetId;
} }
AssetVulkanMaterial material = data.get<AssetVulkanMaterial>(); AssetMaterial material = data.get<AssetMaterial>();
fout.write(reinterpret_cast<const char*>(&material), sizeof(material)); fout.write(reinterpret_cast<const char*>(&material), sizeof(material));
fin.close(); fin.close();

View File

@ -1,6 +0,0 @@
{
"vertexShaderAssetID": "assets/shaders/helloworld.vert.spv",
"fragmentShaderAssetID": "assets/shaders/helloworld.frag.spv",
"renderType": "base",
"renderStage": 0
}

View File

@ -0,0 +1,4 @@
{
"vertexShaderAssetID": "assets/shaders/provinces.vert",
"fragmentShaderAssetID": "assets/shaders/provinces.frag"
}

View File

@ -0,0 +1,4 @@
#pragma once
#include <cstdint>
bool readNext(void* dist, uint8_t* &srcPointer, size_t &srcLeftoverSize, const size_t &readSize);

16
utils/src/buffers.cpp Normal file
View File

@ -0,0 +1,16 @@
#include <ee_utils/buffers.hpp>
#include <cstring>
bool readNext(void* dist, uint8_t* &srcPointer, size_t &srcLeftoverSize, const size_t &readSize)
{
if (srcLeftoverSize >= readSize)
{
srcLeftoverSize -= readSize;
std::memcpy(dist, srcPointer, readSize);
srcPointer += readSize;
return true;
}
return false;
}