This commit is contained in:
Chewico 2026-03-09 18:07:35 +01:00
parent d377e99d31
commit b72fb412a7
15 changed files with 72 additions and 194 deletions

View File

@ -4,6 +4,7 @@
#ifdef DEER_RENDER #ifdef DEER_RENDER
#include "DeerRender/Mesh.h" #include "DeerRender/Mesh.h"
#include "DeerRender/Shader.h" #include "DeerRender/Shader.h"
#include "DeerRender/Resource.h"
#include "DeerRender/Tools/Memory.h" #include "DeerRender/Tools/Memory.h"
#include <functional> #include <functional>
@ -15,8 +16,8 @@ namespace Deer {
bool includeServer = false; bool includeServer = false;
bool includeClient = true; bool includeClient = true;
std::function<Scope<MeshData>(StorageType)> meshLoadingFunction = nullptr; std::function<Resource<GPUMesh>(StorageType)> meshLoadingFunction = nullptr;
std::function<Scope<ShaderData>(StorageType)> shaderLoadingFunction = nullptr; std::function<Resource<Shader>(StorageType)> shaderLoadingFunction = nullptr;
#else #else
bool includeServer = true; bool includeServer = true;
bool includeClient = false; bool includeClient = false;

View File

@ -80,7 +80,7 @@ namespace Deer {
data = ResourceBuilder<T>::buildResource(*baseData.get()); data = ResourceBuilder<T>::buildResource(*baseData.get());
Resource<T> resource = Resource<T>::unsafeFromId(resources.size()); Resource<T> resource = Resource<T>::unsafeFromId(resources.size());
resources.push_back(); resources.push_back({});
ResourceData& rd = resources.back(); ResourceData& rd = resources.back();
rd.data = std::move(data); rd.data = std::move(data);

View File

@ -25,6 +25,8 @@ namespace Deer {
} // namespace Scripting } // namespace Scripting
void Scripting::registerResourceStructs() { void Scripting::registerResourceStructs() {
AS_CHECK(scriptEngine->RegisterObjectType("StorageId", sizeof(StorageType), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_ALLINTS | asGetTypeTraits<StorageType>()));
AS_CHECK(scriptEngine->RegisterObjectType("GPUMesh", sizeof(Resource<GPUMesh>), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_ALLINTS | asGetTypeTraits<Resource<GPUMesh>>())); AS_CHECK(scriptEngine->RegisterObjectType("GPUMesh", sizeof(Resource<GPUMesh>), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_ALLINTS | asGetTypeTraits<Resource<GPUMesh>>()));
AS_CHECK(scriptEngine->RegisterObjectType("Shader", sizeof(Resource<Shader>), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_ALLINTS | asGetTypeTraits<Resource<Shader>>())); AS_CHECK(scriptEngine->RegisterObjectType("Shader", sizeof(Resource<Shader>), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_ALLINTS | asGetTypeTraits<Resource<Shader>>()));
AS_CHECK(scriptEngine->RegisterObjectType("Texture", sizeof(Resource<Texture>), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_ALLINTS | asGetTypeTraits<Resource<Texture>>())); AS_CHECK(scriptEngine->RegisterObjectType("Texture", sizeof(Resource<Texture>), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_ALLINTS | asGetTypeTraits<Resource<Texture>>()));

View File

@ -1,25 +0,0 @@
#pragma once
#include "DeerRender/Resource.h"
#include "DeerRender/Tools/Path.h"
namespace Deer {
class EditorDataSource;
class MeshData;
class ShaderData;
class TextureData;
template <>
class StorageBackend<EditorDataSource> {
public:
template <typename T>
static Scope<T> load(StorageType storageId);
template <>
static Scope<MeshData> load(StorageType storageId);
template <>
static Scope<ShaderData> load(StorageType storageId);
template <>
static Scope<TextureData> load(StorageType storageId);
};
} // namespace Deer

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include "DeerRender/Resource.h" #include "DeerStudio/StudioResources.h"
#include <string> #include <string>
@ -8,13 +8,6 @@ class CScriptDictionary;
namespace Deer { namespace Deer {
class Texture; class Texture;
enum class ResourceType : int {
NONE = 0,
MESH = 1,
SHADER = 2,
TEXTURE = 3
};
namespace StudioAPI { namespace StudioAPI {
int32_t getResourceFolder(std::string&); int32_t getResourceFolder(std::string&);

View File

@ -1,9 +1,18 @@
#pragma once #pragma once
#include "DeerRender/Resource.h"
#include "DeerRender/Tools/Path.h"
#include "cereal/cereal.hpp" #include "cereal/cereal.hpp"
#include <string> #include <string>
namespace Deer { namespace Deer {
class EditorDataSource;
class MeshData;
class ShaderData;
class TextureData;
enum class ResourceType : int { enum class ResourceType : int {
NONE = 0, NONE = 0,
MESH = 1, MESH = 1,
@ -38,4 +47,19 @@ namespace Deer {
void scanResources(); void scanResources();
} // namespace StudioResources } // namespace StudioResources
} // namespace Deer
template <>
class StorageBackend<EditorDataSource> {
public:
template <typename T>
static Scope<T> load(StorageType storageId);
template <>
Scope<MeshData> load(StorageType storageId);
template <>
Scope<ShaderData> load(StorageType storageId);
template <>
Scope<TextureData> load(StorageType storageId);
};
} // namespace Deer

View File

@ -7,7 +7,6 @@
#include "DeerRender/Universe.h" #include "DeerRender/Universe.h"
#include "DeerRender/World.h" #include "DeerRender/World.h"
#include "DeerStudio/ResourceStorageBackend.h"
#include "DeerStudio/StudioResources.h" #include "DeerStudio/StudioResources.h"
// TMP // TMP

View File

@ -1,7 +1,6 @@
#include "DeerRender/Log.h" #include "DeerRender/Log.h"
#include "DeerRender/Mesh.h" #include "DeerRender/Mesh.h"
#include "DeerStudio/ResourceStorageBackend.h"
#include "DeerStudio/StudioResources.h" #include "DeerStudio/StudioResources.h"
#include "assimp/Importer.hpp" #include "assimp/Importer.hpp"
@ -22,8 +21,8 @@ namespace Deer {
return Scope<MeshData>(); return Scope<MeshData>();
Assimp::Importer importer; Assimp::Importer importer;
const aiScene* scene = importer.ReadFileFromMemory(data.get(), size, aiProcess_Triangulate, extension_char); // aiProcess_JoinIdenticalVertices aiProcess_GenNormals | const aiScene* scene = importer.ReadFile(info->fullPath, aiProcess_Triangulate);
if (scene == nullptr) { if (scene == nullptr) {
DEER_CORE_ERROR("Error processing assimp"); DEER_CORE_ERROR("Error processing assimp");
return Scope<MeshData>(); return Scope<MeshData>();

View File

@ -1,5 +1,7 @@
#include "DeerRender/Shader.h" #include "DeerRender/Shader.h"
#include "DeerStudio/EditorDataImporter.h" #include "DeerStudio/StudioResources.h"
#include <fstream>
namespace Deer { namespace Deer {
static std::unordered_map<std::string, std::string> preProcess(const std::string& source) { static std::unordered_map<std::string, std::string> preProcess(const std::string& source) {
@ -30,8 +32,16 @@ namespace Deer {
} }
template <> template <>
Scope<ShaderData> StorageData::deserialize<EditorDataImporter, ShaderData>() { Scope<ShaderData> StorageBackend<EditorDataSource>::load(StorageType storageId) {
std::string str_data((char*)data.get(), size); ResourceInformation* info = StudioResources::getResourceInfoFromId(storageId);
if (!info)
return Scope<ShaderData>();
std::ifstream file(info->fullPath);
std::ostringstream ss;
ss << file.rdbuf();
std::string str_data = ss.str();
std::unordered_map<std::string, std::string> types = preProcess(str_data); std::unordered_map<std::string, std::string> types = preProcess(str_data);

View File

@ -1,20 +1,25 @@
#include "DeerRender/Log.h" #include "DeerRender/Log.h"
#include "DeerRender/Texture.h" #include "DeerRender/Texture.h"
#include "DeerStudio/EditorDataImporter.h"
#include "stb_image.h" #include "stb_image.h"
#include "DeerStudio/StudioResources.h"
#include <cstring> #include <cstring>
namespace Deer { namespace Deer {
template <> template <>
Scope<TextureData> StorageData::deserialize<EditorDataImporter, TextureData>() { Scope<TextureData> StorageBackend<EditorDataSource>::load(StorageType storageId) {
ResourceInformation* info = StudioResources::getResourceInfoFromId(storageId);
if (!info)
return Scope<TextureData>();
stbi_set_flip_vertically_on_load(true); stbi_set_flip_vertically_on_load(true);
int width, height, channels; int width, height, channels;
stbi_uc* data = stbi_load_from_memory(getData(), size, &width, &height, &channels, 0); stbi_uc* data = stbi_load(info->fullPath.c_str(), &width, &height, &channels, 0);
if (!data) { if (!data) {
DEER_CORE_ERROR("Error loading {}", getMetadata()["storageId"].c_str()); DEER_CORE_ERROR("Error loading {}", info->resourcePath.c_str());
return nullptr; return nullptr;
} }
@ -30,7 +35,7 @@ namespace Deer {
format = R8; format = R8;
break; break;
default: default:
DEER_CORE_ERROR("Error loading {}, invalid chanel count {}", getMetadata()["storageId"].c_str(), channels); DEER_CORE_ERROR("Error loading {}, invalid chanel count {}", info->resourcePath.c_str(), channels);
return nullptr; return nullptr;
} }

View File

@ -1,113 +0,0 @@
#include "DeerStudio/ResourceDataSource.h"
#include "DeerRender/Log.h"
#include <fstream>
#include <sstream>
#include <vector>
namespace Deer {
StorageData StorageBackend<ResourceDataSource>::loadData(const std::string& location) {
Path path = Path("Resources") / location;
std::ifstream file(path, std::ios::binary | std::ios::ate);
if (!file.is_open()) {
DEER_CORE_ERROR("Failed to open file '{}'", location.c_str());
return StorageData();
}
auto size = file.tellg();
if (size <= 0) {
DEER_CORE_ERROR("File '{}' is empty or has invalid size", location.c_str());
return StorageData();
}
StorageData data = StorageData(size);
uint8_t* data_raw = data.getData();
file.seekg(0, std::ios::beg);
if (!file.read(reinterpret_cast<char*>(data_raw), size)) {
DEER_CORE_ERROR("Failed to read full file '{}'", location.c_str());
return StorageData();
}
return data;
}
void StorageBackend<ResourceDataSource>::saveData(const std::string& location, const StorageData& data) {
Path path = Path("Resources") / location;
std::ofstream file(path, std::ios::binary);
if (!file.is_open()) {
DEER_CORE_ERROR("Failed to open file '{}' for writing", location.c_str());
return;
}
const uint8_t* data_raw = data.getData();
size_t size = data.getSize();
if (!file.write(reinterpret_cast<const char*>(data_raw), size)) {
DEER_CORE_ERROR("Failed to write full data to file '{}'", location.c_str());
return;
}
file.flush();
}
StorageMetadata StorageBackend<ResourceDataSource>::loadMetadata(const std::string& location) {
Path path = Path("Resources") / (location + ".meta");
StorageMetadata metadata;
if (!std::filesystem::exists(path)) {
return metadata;
}
std::ifstream file(path);
if (!file.is_open()) {
DEER_CORE_TRACE("Failed to open metadata file '{}' for reading", path.string().c_str());
return metadata;
}
std::string line;
while (std::getline(file, line)) {
// Skip empty lines or comments
if (line.empty() || line[0] == '#')
continue;
auto pos = line.find(" : ");
if (pos == std::string::npos)
continue;
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 3); // skip " : "
// Trim whitespace if needed
auto trim = [](std::string& s) {
s.erase(0, s.find_first_not_of(" \t\r\n"));
s.erase(s.find_last_not_of(" \t\r\n") + 1);
};
trim(key);
trim(value);
metadata[key] = value;
}
return metadata;
}
void StorageBackend<ResourceDataSource>::saveMetadata(const StorageMetadata& metadata, const std::string& location) {
Path path = Path("Resources") / (location + ".meta");
std::stringstream metadataBuilder;
metadataBuilder << "#Metadata file for resource " << location << "\n";
for (const auto& part : metadata) {
metadataBuilder << part.first << " : " << part.second << "\n";
}
std::ofstream file(path, std::ios::out | std::ios::trunc);
if (!file.is_open()) {
DEER_CORE_TRACE("Failed to open metadata file '{}' for writing", path.string().c_str());
return;
}
file << metadataBuilder.str();
}
} // namespace Deer

View File

@ -4,21 +4,12 @@
#include "DeerRender/Shader.h" #include "DeerRender/Shader.h"
#include "DeerRender/Texture.h" #include "DeerRender/Texture.h"
#include "DeerStudio/EditorDataImporter.h"
#include "DeerStudio/EditorDataSource.h"
#include "DeerStudio/ResourceDataSource.h"
#include "angelscript.h" #include "angelscript.h"
#include "scriptany.h" #include "scriptany.h"
#include "scriptarray.h" #include "scriptarray.h"
#include "scriptdictionary.h" #include "scriptdictionary.h"
namespace Deer { namespace Deer {
Resource<Texture> StudioAPI::getIcon(std::string& icon) {
Path iconPath = Path("Icons") / icon;
return ResourceManager<Texture>::loadResource<EditorDataSource>(iconPath);
}
ResourceType StudioAPI::getResourceType(std::string& dir) { ResourceType StudioAPI::getResourceType(std::string& dir) {
Path path(dir); Path path(dir);
std::string extension = path.extension().string(); std::string extension = path.extension().string();

View File

@ -1,32 +1,30 @@
#include "DeerStudio/StudioScripting.h" #include "DeerStudio/StudioScripting.h"
#include "DeerRender/Scripting.h" #include "DeerRender/Scripting.h"
#include "DeerStudio/ResourceDataSource.h"
#include "DeerStudio/StudioAPI.h" #include "DeerStudio/StudioAPI.h"
#include "DeerStudio/StudioResources.h"
#include "DeerRender/Mesh.h" #include "DeerRender/Mesh.h"
#include "DeerRender/Shader.h" #include "DeerRender/Shader.h"
#include "DeerRender/Texture.h" #include "DeerRender/Texture.h"
#include "angelscript.h" #include "angelscript.h"
namespace Deer { namespace Deer {
void StudioScripting::registerStudioScripting() { void StudioScripting::registerStudioScripting() {
asIScriptEngine* scriptEngine = Scripting::getScriptEngine(); asIScriptEngine* scriptEngine = Scripting::getScriptEngine();
scriptEngine->RegisterEnum("ResourceType"); scriptEngine->RegisterEnum("Resources");
scriptEngine->RegisterEnumValue("ResourceType", "None", (int)ResourceType::NONE); scriptEngine->RegisterEnumValue("ResourceType", "None", (int)ResourceType::NONE);
scriptEngine->RegisterEnumValue("ResourceType", "Mesh", (int)ResourceType::MESH); scriptEngine->RegisterEnumValue("ResourceType", "Mesh", (int)ResourceType::MESH);
scriptEngine->RegisterEnumValue("ResourceType", "Shader", (int)ResourceType::SHADER); scriptEngine->RegisterEnumValue("ResourceType", "Shader", (int)ResourceType::SHADER);
scriptEngine->RegisterEnumValue("ResourceType", "Texture", (int)ResourceType::TEXTURE); scriptEngine->RegisterEnumValue("ResourceType", "Texture", (int)ResourceType::TEXTURE);
scriptEngine->SetDefaultNamespace("");
scriptEngine->SetDefaultNamespace("StudioAPI"); scriptEngine->SetDefaultNamespace("StudioResources");
scriptEngine->RegisterGlobalFunction("Texture loadIcon(string&in)", asFUNCTION(StudioAPI::getIcon), asCALL_CDECL); scriptEngine->RegisterGlobalFunction("GPUMesh loadGPUMesh(StorageId)", asFUNCTION(ResourceManager<GPUMesh>::loadResource<EditorDataSource>), asCALL_CDECL);
scriptEngine->RegisterGlobalFunction("GPUMesh loadGPUMesh(string&in path)", asFUNCTION(ResourceManager<GPUMesh>::loadResource<ResourceDataSource>), asCALL_CDECL); scriptEngine->RegisterGlobalFunction("Shader loadShader(StorageId)", asFUNCTION(ResourceManager<Shader>::loadResource<EditorDataSource>), asCALL_CDECL);
scriptEngine->RegisterGlobalFunction("Shader loadShader(string&in path)", asFUNCTION(ResourceManager<Shader>::loadResource<ResourceDataSource>), asCALL_CDECL); scriptEngine->RegisterGlobalFunction("Texture loadTexture(StorageId)", asFUNCTION(ResourceManager<Texture>::loadResource<EditorDataSource>), asCALL_CDECL);
scriptEngine->RegisterGlobalFunction("Texture loadTexture(string&in path)", asFUNCTION(ResourceManager<Texture>::loadResource<ResourceDataSource>), asCALL_CDECL);
scriptEngine->RegisterGlobalFunction("array<string>@ getResourceFolders(string&in path)", asFUNCTION(StudioAPI::getResourceFolders), asCALL_CDECL);
scriptEngine->RegisterGlobalFunction("array<string>@ getResourceFiles(string&in path)", asFUNCTION(StudioAPI::getResourceFiles), asCALL_CDECL);
scriptEngine->RegisterGlobalFunction("ResourceType getResourceType(string&in path)", asFUNCTION(StudioAPI::getResourceType), asCALL_CDECL);
scriptEngine->SetDefaultNamespace(""); scriptEngine->SetDefaultNamespace("");
} }
} // namespace Deer } // namespace Deer

View File

@ -2,8 +2,7 @@
#include "DeerCore/Tools/Memory.h" #include "DeerCore/Tools/Memory.h"
#include "DeerCore/Universe.h" #include "DeerCore/Universe.h"
#include "DeerStudio/EditorDataImporter.h" #include "DeerStudio/StudioResources.h"
#include "DeerStudio/EditorDataSource.h"
#include "DeerStudio/StudioPanel.h" #include "DeerStudio/StudioPanel.h"
#include "DeerCore/World.h" #include "DeerCore/World.h"
@ -11,12 +10,6 @@
#include "imgui.h" #include "imgui.h"
namespace Deer { namespace Deer {
template <typename T>
Scope<T> loadResourceData(const Path& storageId) {
StorageData storageData = StorageBackend<EditorDataSource>::loadData(storageId);
return storageData.deserialize<EditorDataImporter, T>();
}
void DeerStudio::worldManagerMenu() { void DeerStudio::worldManagerMenu() {
if (ImGui::MenuItem("Save world")) { if (ImGui::MenuItem("Save world")) {
WorldSerializationSettings serializationSettings{ WorldSerializationSettings serializationSettings{
@ -37,8 +30,9 @@ namespace Deer {
}; };
WorldSerializationSettings serializationSettings{ WorldSerializationSettings serializationSettings{
.meshLoadingFunction = loadResourceData<MeshData>, .meshLoadingFunction = ResourceManager<GPUMesh>::loadResource<EditorDataSource>,
.shaderLoadingFunction = loadResourceData<ShaderData>}; .shaderLoadingFunction = ResourceManager<Shader>::loadResource<EditorDataSource>
};
World* world_new = Universe::loadWorldFromJson(worldSettings, serializationSettings, "Worlds/world.json"); World* world_new = Universe::loadWorldFromJson(worldSettings, serializationSettings, "Worlds/world.json");
world = world_new; world = world_new;

View File

@ -1,6 +1,6 @@
[Window][DockSpace Demo] [Window][DockSpace Demo]
Pos=0,0 Pos=0,0
Size=2560,1371 Size=1440,749
Collapsed=0 Collapsed=0
[Window][Debug##Default] [Window][Debug##Default]
@ -69,7 +69,7 @@ Collapsed=0
DockId=0x00000009,2 DockId=0x00000009,2
[Docking][Data] [Docking][Data]
DockSpace ID=0x0AC2E849 Window=0xD0388BC8 Pos=0,28 Size=2560,1343 Split=Y DockSpace ID=0x0AC2E849 Window=0xD0388BC8 Pos=0,26 Size=1440,723 Split=Y
DockNode ID=0x00000003 Parent=0x0AC2E849 SizeRef=1920,662 Split=X DockNode ID=0x00000003 Parent=0x0AC2E849 SizeRef=1920,662 Split=X
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=399,985 Selected=0x16E3C1E7 DockNode ID=0x00000001 Parent=0x00000003 SizeRef=399,985 Selected=0x16E3C1E7
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1519,985 Split=X DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1519,985 Split=X