Loading and unloading working
This commit is contained in:
parent
6ee3cc146f
commit
946c9e0027
@ -1,83 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "DeerCore/Tools/Memory.h"
|
|
||||||
#include "DeerCore/Tools/TypeDefs.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace Deer {
|
|
||||||
/*
|
|
||||||
class DataSource {
|
|
||||||
public:
|
|
||||||
using DataImporter = [ClassOfTheDataImporter]
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
using StorageMetadata = std::unordered_map<std::string, std::string>;
|
|
||||||
template <typename T>
|
|
||||||
concept HasMetadata = requires(const std::string& location) {
|
|
||||||
{ T::loadMetadata(location) } -> std::same_as<StorageMetadata>;
|
|
||||||
{ T::saveMetadata(StorageMetadata{}, location) };
|
|
||||||
};
|
|
||||||
|
|
||||||
class StorageData {
|
|
||||||
public:
|
|
||||||
StorageData() = default;
|
|
||||||
StorageData(uint32_t dataSize) : size(dataSize), data(MakeScope<uint8_t[]>(dataSize)) {}
|
|
||||||
|
|
||||||
inline uint8_t* getData() { return data.get(); }
|
|
||||||
inline const uint8_t* getData() const { return data.get(); }
|
|
||||||
inline uint32_t getSize() const { return size; }
|
|
||||||
inline StorageMetadata& getMetadata() { return metadata; }
|
|
||||||
|
|
||||||
template <typename DataImporter, typename T>
|
|
||||||
Scope<T> deserialize();
|
|
||||||
|
|
||||||
template <typename DataImporter, typename T>
|
|
||||||
static StorageData serialize(const T&);
|
|
||||||
|
|
||||||
inline explicit operator bool() const { return size != 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
StorageMetadata metadata;
|
|
||||||
Scope<uint8_t[]> data = nullptr;
|
|
||||||
uint32_t size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename DataSource>
|
|
||||||
class StorageBackend {
|
|
||||||
public:
|
|
||||||
static StorageData loadData(const std::string& location);
|
|
||||||
static void saveData(const std::string& location, const StorageData& data);
|
|
||||||
|
|
||||||
static StorageMetadata loadMetadata(const std::string& location);
|
|
||||||
static void saveMetadata(const StorageMetadata& metadata, const std::string& location);
|
|
||||||
|
|
||||||
static std::vector<std::string> indexResources(const std::string& location);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename DataSource>
|
|
||||||
class DataManager {
|
|
||||||
public:
|
|
||||||
template <typename T>
|
|
||||||
static Scope<T> load(const std::string& dataId) {
|
|
||||||
StorageData data = StorageBackend<DataSource>::loadData(dataId);
|
|
||||||
|
|
||||||
if constexpr (HasMetadata<StorageBackend<DataSource>>) {
|
|
||||||
data.getMetadata() = StorageBackend<DataSource>::loadMetadata(dataId);
|
|
||||||
data.getMetadata()["dataId"] = dataId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.deserialize<typename DataSource::DataImporter, T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static void store(const std::string& dataId, T& value) {
|
|
||||||
StorageData data = StorageData::serialize<typename DataSource::DataImporter, T>(value);
|
|
||||||
StorageBackend<DataSource>::saveData(dataId, data);
|
|
||||||
if constexpr (HasMetadata<StorageBackend<DataSource>>) {
|
|
||||||
StorageBackend<DataSource>::saveMetadata(data.getMetadata(), dataId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace Deer
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <filesystem>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "DeerCore/Tools/Path.h"
|
|
||||||
|
|
||||||
#define DEER_RESOURCE_PATH "Assets"
|
|
||||||
|
|
||||||
#define DEER_VOXEL_PATH "Voxels"
|
|
||||||
#define DEER_VOXEL_DATA_PATH "Voxels/Data"
|
|
||||||
#define DEER_VOXEL_ASPECT_PATH "Voxels/Visuals"
|
|
||||||
#define DEER_VOXEL_TEXTURE_PATH "Voxels/Textures"
|
|
||||||
#define DEER_VOXEL_SHADER_PATH "Voxels/Shaders"
|
|
||||||
|
|
||||||
#define DEER_EDITOR_PATH "Editor"
|
|
||||||
#define DEER_EDITOR_PANEL_PATH "Editor/Panels"
|
|
||||||
#define DEER_EDITOR_SERVICE_PATH "Editor/Services"
|
|
||||||
|
|
||||||
#define DEER_MESH_EXTENSION ".dmesh"
|
|
||||||
#define DEER_SHADER_EXTENSION ".glsl"
|
|
||||||
#define DEER_SCRIPT_EXTENSION ".as"
|
|
||||||
|
|
||||||
#define DEER_BIN_PATH "bin"
|
|
||||||
#define DEER_TEMP_PATH "tmp"
|
|
||||||
#define DEER_NULL_PATH "null"
|
|
||||||
|
|
||||||
namespace Deer {
|
|
||||||
|
|
||||||
struct DirectoryData {
|
|
||||||
std::vector<Path> dirs;
|
|
||||||
std::vector<Path> elements;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Namespace to manage memory interactions
|
|
||||||
namespace DataStore {
|
|
||||||
// Clears the cache of dir data
|
|
||||||
void clearCache();
|
|
||||||
|
|
||||||
// Rerturns a directory data with the elements relative to the id
|
|
||||||
const DirectoryData& getDirData(const Path& id, const Path& dir, const char* extension);
|
|
||||||
|
|
||||||
// TODO: Add safety
|
|
||||||
// Returns the data of the specified file path
|
|
||||||
bool loadFileData(const Path& id, const Path& name, uint8_t** data, uint32_t* size);
|
|
||||||
// Returns the data of the specified file path avoiding extension
|
|
||||||
bool loadGlobalFileData(const Path& id, const Path& name, uint8_t** data, uint32_t* size);
|
|
||||||
void freeFileData(uint8_t*);
|
|
||||||
|
|
||||||
void createFolder(const Path& path);
|
|
||||||
|
|
||||||
void saveFile(const Path&, uint8_t* data, uint32_t size);
|
|
||||||
uint8_t* readFile(const Path&, uint32_t* size);
|
|
||||||
void deleteFile(const Path&);
|
|
||||||
|
|
||||||
// Refactor----
|
|
||||||
void compressFiles(std::vector<Path> files, const Path& path);
|
|
||||||
std::vector<Path> getFiles(const Path& path,
|
|
||||||
const std::string& extension);
|
|
||||||
// Refactor----
|
|
||||||
} // namespace DataStore
|
|
||||||
} // namespace Deer
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "DeerCore/Components.h"
|
#include "DeerCore/Components.h"
|
||||||
#include "DeerCore/Log.h"
|
#include "DeerCore/Log.h"
|
||||||
#include "DeerCore/Resource.h"
|
|
||||||
#include "DeerCore/Tools/Memory.h"
|
#include "DeerCore/Tools/Memory.h"
|
||||||
|
|
||||||
#include "entt/entt.hpp"
|
#include "entt/entt.hpp"
|
||||||
|
|||||||
@ -1,140 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "DeerCore/DataManagment.h"
|
|
||||||
#include "DeerCore/Log.h"
|
|
||||||
#include "DeerCore/Tools/Memory.h"
|
|
||||||
#include "DeerCore/Tools/Path.h"
|
|
||||||
#include "DeerCore/Tools/TypeDefs.h"
|
|
||||||
|
|
||||||
#include <cxxabi.h>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace Deer {
|
|
||||||
template <typename T>
|
|
||||||
class ResourceManager;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class Resource {
|
|
||||||
public:
|
|
||||||
int32_t getResourceId() const { return resourceId; }
|
|
||||||
|
|
||||||
bool isValid() const { return ResourceManager<T>::isValid(*this); }
|
|
||||||
T& getData() { return ResourceManager<T>::getResourceData(*this); }
|
|
||||||
|
|
||||||
const std::string& getStorageId() const { return ResourceManager<T>::getStorageId(*this); }
|
|
||||||
|
|
||||||
inline explicit operator bool() const { return resourceId >= 0; }
|
|
||||||
|
|
||||||
static Resource<T> unsafeFromId(int32_t id) {
|
|
||||||
Resource<T> res;
|
|
||||||
res.resourceId = id;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// -1 = no resource loaded
|
|
||||||
int32_t resourceId = -1;
|
|
||||||
friend ResourceManager<T>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class ResourceBuilder {
|
|
||||||
public:
|
|
||||||
using BaseDataType = char;
|
|
||||||
static Scope<T> buildResource(const BaseDataType& baseData) {
|
|
||||||
static_assert(sizeof(T) == 0, "ResourceBuilder must be specialized for this type T");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class ResourceManager {
|
|
||||||
private:
|
|
||||||
struct ResourceData {
|
|
||||||
public:
|
|
||||||
ResourceData(const std::string& _resourceId, Scope<T>&& _data)
|
|
||||||
: storageId(_resourceId), data(std::move(_data)) {}
|
|
||||||
|
|
||||||
Scope<T> data;
|
|
||||||
const std::string storageId;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::vector<ResourceData> resources;
|
|
||||||
static std::unordered_map<std::string, Resource<T>> resourceCache;
|
|
||||||
|
|
||||||
public:
|
|
||||||
template <typename DataSource>
|
|
||||||
static Resource<T> loadResource(const std::string& storageId) {
|
|
||||||
if (resourceCache.contains(storageId))
|
|
||||||
return resourceCache[storageId];
|
|
||||||
|
|
||||||
using ResourceBuilderBaseDataType = typename ResourceBuilder<T>::BaseDataType;
|
|
||||||
Scope<T> data;
|
|
||||||
|
|
||||||
if constexpr (!std::is_void_v<ResourceBuilderBaseDataType>) {
|
|
||||||
Scope<ResourceBuilderBaseDataType> baseData = DataManager<DataSource>::template load<ResourceBuilderBaseDataType>(storageId);
|
|
||||||
if (!baseData) {
|
|
||||||
const char* baseDataType = abi::__cxa_demangle(typeid(ResourceBuilderBaseDataType).name(), 0, 0, nullptr);
|
|
||||||
const char* dataType = abi::__cxa_demangle(typeid(T).name(), 0, 0, nullptr);
|
|
||||||
DEER_CORE_ERROR("Error loading base resource {} for resource {} with id {}", baseDataType, dataType, storageId.c_str());
|
|
||||||
return Resource<T>();
|
|
||||||
}
|
|
||||||
data = ResourceBuilder<T>::buildResource(*baseData.get());
|
|
||||||
} else {
|
|
||||||
data = ResourceBuilder<T>::buildResource(); // No base data
|
|
||||||
}
|
|
||||||
|
|
||||||
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());
|
|
||||||
resources.push_back({storageId, std::move(data)});
|
|
||||||
resourceCache[storageId] = resource;
|
|
||||||
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Resource<T> getResource(const std::string& storageId) {
|
|
||||||
if (resourceCache.contains(storageId))
|
|
||||||
return resourceCache[storageId];
|
|
||||||
|
|
||||||
return Resource<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static Resource<T> loadResourceFromData(const typename ResourceBuilder<T>::BaseDataType& resourceData, const std::string& storageId) {
|
|
||||||
if (resourceCache.contains(storageId))
|
|
||||||
return resourceCache[storageId];
|
|
||||||
|
|
||||||
Scope<T> data = ResourceBuilder<T>::buildResource(resourceData);
|
|
||||||
|
|
||||||
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());
|
|
||||||
resources.push_back({storageId, std::move(data)});
|
|
||||||
resourceCache[storageId] = resource;
|
|
||||||
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unloadResources() {
|
|
||||||
resourceCache.clear();
|
|
||||||
resources.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool isValid(Resource<T> res) {
|
|
||||||
return res.resourceId >= 0 && res.resourceId < static_cast<int32_t>(resources.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline const std::string& getStorageId(Resource<T> res) {
|
|
||||||
const static std::string invalid("NULL");
|
|
||||||
if (!isValid(res))
|
|
||||||
return invalid;
|
|
||||||
|
|
||||||
return resources[res.resourceId].storageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
static T& getResourceData(Resource<T> res) {
|
|
||||||
return *resources[res.resourceId].data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
std::vector<typename ResourceManager<T>::ResourceData> ResourceManager<T>::resources;
|
|
||||||
template <typename T>
|
|
||||||
std::unordered_map<std::string, Resource<T>> ResourceManager<T>::resourceCache;
|
|
||||||
} // namespace Deer
|
|
||||||
@ -35,7 +35,7 @@ namespace Deer {
|
|||||||
std::string baseTypeName;
|
std::string baseTypeName;
|
||||||
std::string moduleName;
|
std::string moduleName;
|
||||||
std::vector<SystemEvent> events;
|
std::vector<SystemEvent> events;
|
||||||
SystemDescription(const std::string& _baseTypeName, const std::string& _moduleName, const std::vector<SystemEvent>& _events = {}) : baseTypeName(_baseTypeName), moduleName(_moduleName), events(_events) {}
|
SystemDescription(const std::string& _baseTypeName = "", const std::string& _moduleName = "", const std::vector<SystemEvent>& _events = {}) : baseTypeName(_baseTypeName), moduleName(_moduleName), events(_events) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Functions called by Engine
|
// Functions called by Engine
|
||||||
|
|||||||
31
Deer/Include/DeerCore/Serialization/WorldSettings.h
Normal file
31
Deer/Include/DeerCore/Serialization/WorldSettings.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "cereal/cereal.hpp"
|
||||||
|
|
||||||
|
#ifdef DEER_RENDER
|
||||||
|
#include "DeerRender/Mesh.h"
|
||||||
|
#include "DeerRender/Shader.h"
|
||||||
|
|
||||||
|
#include "DeerRender/Tools/Memory.h"
|
||||||
|
#include <functional>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Deer {
|
||||||
|
struct WorldSerializationSettings {
|
||||||
|
#ifdef DEER_RENDER
|
||||||
|
bool includeServer = false;
|
||||||
|
bool includeClient = true;
|
||||||
|
|
||||||
|
std::function<Scope<MeshData>(const Path&)> meshLoadingFunction = nullptr;
|
||||||
|
std::function<Scope<ShaderData>(const Path&)> shaderLoadingFunction = nullptr;
|
||||||
|
#else
|
||||||
|
bool includeServer = true;
|
||||||
|
bool includeClient = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& archive) {
|
||||||
|
archive(CEREAL_NVP(includeServer));
|
||||||
|
archive(CEREAL_NVP(includeClient));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Deer
|
||||||
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "DeerCore/Serialization/WorldSettings.h"
|
||||||
#include "DeerCore/Tools/Path.h"
|
#include "DeerCore/Tools/Path.h"
|
||||||
|
|
||||||
namespace Deer {
|
namespace Deer {
|
||||||
@ -7,8 +8,9 @@ namespace Deer {
|
|||||||
|
|
||||||
namespace Universe {
|
namespace Universe {
|
||||||
World* createWorld(const WorldSettings&);
|
World* createWorld(const WorldSettings&);
|
||||||
|
World* loadWorldFromJson(const WorldSettings&, WorldSerializationSettings&, const Path&);
|
||||||
|
|
||||||
void saveWorldInJson(World*, const Path& path);
|
void saveWorldInJson(World*, WorldSerializationSettings& serializationSettings, const Path& path);
|
||||||
|
|
||||||
void destroyAllWorlds();
|
void destroyAllWorlds();
|
||||||
void flushDestroyedWorlds();
|
void flushDestroyedWorlds();
|
||||||
|
|||||||
@ -1,2 +1,78 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "DeerCore/DataManagment.h"
|
#include "DeerCore/Tools/Memory.h"
|
||||||
|
#include "DeerCore/Tools/TypeDefs.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Deer {
|
||||||
|
|
||||||
|
using StorageMetadata = std::unordered_map<std::string, std::string>;
|
||||||
|
template <typename T>
|
||||||
|
concept HasMetadata = requires(const std::string& location) {
|
||||||
|
{ T::loadMetadata(location) } -> std::same_as<StorageMetadata>;
|
||||||
|
{ T::saveMetadata(StorageMetadata{}, location) };
|
||||||
|
};
|
||||||
|
|
||||||
|
class StorageData {
|
||||||
|
public:
|
||||||
|
StorageData() = default;
|
||||||
|
StorageData(uint32_t dataSize) : size(dataSize), data(MakeScope<uint8_t[]>(dataSize)) {}
|
||||||
|
|
||||||
|
inline uint8_t* getData() { return data.get(); }
|
||||||
|
inline const uint8_t* getData() const { return data.get(); }
|
||||||
|
inline uint32_t getSize() const { return size; }
|
||||||
|
inline StorageMetadata& getMetadata() { return metadata; }
|
||||||
|
|
||||||
|
template <typename DataImporter, typename T>
|
||||||
|
Scope<T> deserialize();
|
||||||
|
|
||||||
|
template <typename DataImporter, typename T>
|
||||||
|
static StorageData serialize(const T&);
|
||||||
|
|
||||||
|
inline explicit operator bool() const { return size != 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
StorageMetadata metadata;
|
||||||
|
Scope<uint8_t[]> data = nullptr;
|
||||||
|
uint32_t size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename DataSource>
|
||||||
|
class StorageBackend {
|
||||||
|
public:
|
||||||
|
static StorageData loadData(const std::string& location);
|
||||||
|
static void saveData(const std::string& location, const StorageData& data);
|
||||||
|
|
||||||
|
static StorageMetadata loadMetadata(const std::string& location);
|
||||||
|
static void saveMetadata(const StorageMetadata& metadata, const std::string& location);
|
||||||
|
|
||||||
|
static std::vector<std::string> indexResources(const std::string& location);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename DataSource>
|
||||||
|
class DataManager {
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
static Scope<T> load(const std::string& dataId) {
|
||||||
|
StorageData data = StorageBackend<DataSource>::loadData(dataId);
|
||||||
|
|
||||||
|
if constexpr (HasMetadata<StorageBackend<DataSource>>) {
|
||||||
|
data.getMetadata() = StorageBackend<DataSource>::loadMetadata(dataId);
|
||||||
|
data.getMetadata()["dataId"] = dataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.deserialize<typename DataSource::DataImporter, T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void store(const std::string& dataId, T& value) {
|
||||||
|
StorageData data = StorageData::serialize<typename DataSource::DataImporter, T>(value);
|
||||||
|
StorageBackend<DataSource>::saveData(dataId, data);
|
||||||
|
if constexpr (HasMetadata<StorageBackend<DataSource>>) {
|
||||||
|
StorageBackend<DataSource>::saveMetadata(data.getMetadata(), dataId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Deer
|
||||||
@ -1,2 +1,140 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "DeerCore/Resource.h"
|
#include "DeerRender/DataManagment.h"
|
||||||
|
#include "DeerRender/Log.h"
|
||||||
|
#include "DeerRender/Tools/Memory.h"
|
||||||
|
#include "DeerRender/Tools/Path.h"
|
||||||
|
#include "DeerRender/Tools/TypeDefs.h"
|
||||||
|
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Deer {
|
||||||
|
template <typename T>
|
||||||
|
class ResourceManager;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Resource {
|
||||||
|
public:
|
||||||
|
int32_t getResourceId() const { return resourceId; }
|
||||||
|
|
||||||
|
bool isValid() const { return ResourceManager<T>::isValid(*this); }
|
||||||
|
T& getData() { return ResourceManager<T>::getResourceData(*this); }
|
||||||
|
|
||||||
|
const std::string& getStorageId() const { return ResourceManager<T>::getStorageId(*this); }
|
||||||
|
|
||||||
|
inline explicit operator bool() const { return resourceId >= 0; }
|
||||||
|
|
||||||
|
static Resource<T> unsafeFromId(int32_t id) {
|
||||||
|
Resource<T> res;
|
||||||
|
res.resourceId = id;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// -1 = no resource loaded
|
||||||
|
int32_t resourceId = -1;
|
||||||
|
friend ResourceManager<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ResourceBuilder {
|
||||||
|
public:
|
||||||
|
using BaseDataType = char;
|
||||||
|
static Scope<T> buildResource(const BaseDataType& baseData) {
|
||||||
|
static_assert(sizeof(T) == 0, "ResourceBuilder must be specialized for this type T");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ResourceManager {
|
||||||
|
private:
|
||||||
|
struct ResourceData {
|
||||||
|
public:
|
||||||
|
ResourceData(const std::string& _resourceId, Scope<T>&& _data)
|
||||||
|
: storageId(_resourceId), data(std::move(_data)) {}
|
||||||
|
|
||||||
|
Scope<T> data;
|
||||||
|
const std::string storageId;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<ResourceData> resources;
|
||||||
|
static std::unordered_map<std::string, Resource<T>> resourceCache;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename DataSource>
|
||||||
|
static Resource<T> loadResource(const std::string& storageId) {
|
||||||
|
if (resourceCache.contains(storageId))
|
||||||
|
return resourceCache[storageId];
|
||||||
|
|
||||||
|
using ResourceBuilderBaseDataType = typename ResourceBuilder<T>::BaseDataType;
|
||||||
|
Scope<T> data;
|
||||||
|
|
||||||
|
if constexpr (!std::is_void_v<ResourceBuilderBaseDataType>) {
|
||||||
|
Scope<ResourceBuilderBaseDataType> baseData = DataManager<DataSource>::template load<ResourceBuilderBaseDataType>(storageId);
|
||||||
|
if (!baseData) {
|
||||||
|
const char* baseDataType = abi::__cxa_demangle(typeid(ResourceBuilderBaseDataType).name(), 0, 0, nullptr);
|
||||||
|
const char* dataType = abi::__cxa_demangle(typeid(T).name(), 0, 0, nullptr);
|
||||||
|
DEER_CORE_ERROR("Error loading base resource {} for resource {} with id {}", baseDataType, dataType, storageId.c_str());
|
||||||
|
return Resource<T>();
|
||||||
|
}
|
||||||
|
data = ResourceBuilder<T>::buildResource(*baseData.get());
|
||||||
|
} else {
|
||||||
|
data = ResourceBuilder<T>::buildResource(); // No base data
|
||||||
|
}
|
||||||
|
|
||||||
|
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());
|
||||||
|
resources.push_back({storageId, std::move(data)});
|
||||||
|
resourceCache[storageId] = resource;
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Resource<T> getResource(const std::string& storageId) {
|
||||||
|
if (resourceCache.contains(storageId))
|
||||||
|
return resourceCache[storageId];
|
||||||
|
|
||||||
|
return Resource<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Resource<T> loadResourceFromData(const typename ResourceBuilder<T>::BaseDataType& resourceData, const std::string& storageId) {
|
||||||
|
if (resourceCache.contains(storageId))
|
||||||
|
return resourceCache[storageId];
|
||||||
|
|
||||||
|
Scope<T> data = ResourceBuilder<T>::buildResource(resourceData);
|
||||||
|
|
||||||
|
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());
|
||||||
|
resources.push_back({storageId, std::move(data)});
|
||||||
|
resourceCache[storageId] = resource;
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unloadResources() {
|
||||||
|
resourceCache.clear();
|
||||||
|
resources.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isValid(Resource<T> res) {
|
||||||
|
return res.resourceId >= 0 && res.resourceId < static_cast<int32_t>(resources.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const std::string& getStorageId(Resource<T> res) {
|
||||||
|
const static std::string invalid("NULL");
|
||||||
|
if (!isValid(res))
|
||||||
|
return invalid;
|
||||||
|
|
||||||
|
return resources[res.resourceId].storageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
static T& getResourceData(Resource<T> res) {
|
||||||
|
return *resources[res.resourceId].data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::vector<typename ResourceManager<T>::ResourceData> ResourceManager<T>::resources;
|
||||||
|
template <typename T>
|
||||||
|
std::unordered_map<std::string, Resource<T>> ResourceManager<T>::resourceCache;
|
||||||
|
} // namespace Deer
|
||||||
|
|||||||
@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
#include "DeerCore/Serialization/Components/TransformComponent.h"
|
#include "DeerCore/Serialization/Components/TransformComponent.h"
|
||||||
|
|
||||||
|
#ifdef DEER_RENDER
|
||||||
|
#include "DeerRender/Serialization/Components/MeshComponentSerialization.h"
|
||||||
|
#include "DeerRender/Serialization/Components/ShaderComponentSerialization.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "cereal/cereal.hpp"
|
#include "cereal/cereal.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -16,18 +21,34 @@ namespace Deer {
|
|||||||
uint32_t entityId;
|
uint32_t entityId;
|
||||||
|
|
||||||
template <class Archive, class T, class S>
|
template <class Archive, class T, class S>
|
||||||
void saveComponent(Archive& archive, Entity& entity) {
|
void saveComponent(Archive& archive, Entity& entity, const char* name) const {
|
||||||
std::string containsComponentString = "Contains_";
|
std::string containsComponentString = "Contains_";
|
||||||
containsComponentString += typeid(T).name();
|
containsComponentString += name;
|
||||||
|
|
||||||
bool hasComponent = entity.hasComponent<T>();
|
bool hasComponent = entity.hasComponent<T>();
|
||||||
archive(cereal::make_nvp(containsComponentString.c_str(), hasComponent));
|
archive(cereal::make_nvp(containsComponentString.c_str(), hasComponent));
|
||||||
if (hasComponent) {
|
if (hasComponent) {
|
||||||
S serialization;
|
S serialization{
|
||||||
serialization.component = entity.getComponent<T>();
|
.component = entity.getComponent<T>(),
|
||||||
serialization.settings = settings;
|
.settings = settings};
|
||||||
|
|
||||||
archive(cereal::make_nvp(typeid(T).name(), serialization));
|
archive(cereal::make_nvp(name, serialization));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Archive, class T, class S>
|
||||||
|
void loadComponent(Archive& archive, Entity& entity, const char* name) {
|
||||||
|
std::string containsComponentString = "Contains_";
|
||||||
|
containsComponentString += name;
|
||||||
|
|
||||||
|
bool hasComponent;
|
||||||
|
archive(cereal::make_nvp(containsComponentString.c_str(), hasComponent));
|
||||||
|
if (hasComponent) {
|
||||||
|
S serialization{
|
||||||
|
.component = entity.addComponent<T>(),
|
||||||
|
.settings = settings};
|
||||||
|
|
||||||
|
archive(cereal::make_nvp(name, serialization));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,14 +64,46 @@ namespace Deer {
|
|||||||
archive(cereal::make_nvp("NetworkBehaviour", tag.networkBehaviour));
|
archive(cereal::make_nvp("NetworkBehaviour", tag.networkBehaviour));
|
||||||
archive(cereal::make_nvp("Parent", relation.parent_id));
|
archive(cereal::make_nvp("Parent", relation.parent_id));
|
||||||
|
|
||||||
TransformComponentSerialization serialization;
|
TransformComponentSerialization transformSerialization{
|
||||||
serialization.settings = settings;
|
.settings = settings,
|
||||||
serialization.component = entity.getComponent<T>();
|
.component = entity.getComponent<TransformComponent>()};
|
||||||
archive(cereal::make_nvp(typeid(TransformComponent).name(), serialization));
|
archive(cereal::make_nvp("TransformComponent", transformSerialization));
|
||||||
|
|
||||||
|
if (settings.includeClient) {
|
||||||
|
#ifdef DEER_RENDER
|
||||||
|
saveComponent<Archive, MeshComponent, MeshComponentSerialization>(archive, entity, "MeshComponent");
|
||||||
|
saveComponent<Archive, ShaderComponent, ShaderComponentSerialization>(archive, entity, "ShaderComponent");
|
||||||
|
#else
|
||||||
|
DEER_CORE_ERROR("Can not include client on Deer Core Headless Compile");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
void load(Archive& archive) {
|
void load(Archive& archive) {
|
||||||
|
archive(cereal::make_nvp("Id", entityId));
|
||||||
|
Entity& entity = entityEnvironment->createEntityWithId(entityId);
|
||||||
|
|
||||||
|
TagComponent& tag = entity.getComponent<TagComponent>();
|
||||||
|
RelationshipComponent& relation = entity.getComponent<RelationshipComponent>();
|
||||||
|
|
||||||
|
archive(cereal::make_nvp("Tag", tag.tag));
|
||||||
|
archive(cereal::make_nvp("NetworkBehaviour", tag.networkBehaviour));
|
||||||
|
archive(cereal::make_nvp("Parent", tag.networkBehaviour));
|
||||||
|
|
||||||
|
TransformComponentSerialization transformSerialization{
|
||||||
|
.settings = settings,
|
||||||
|
.component = entity.getComponent<TransformComponent>()};
|
||||||
|
archive(cereal::make_nvp("TransformComponent", transformSerialization));
|
||||||
|
|
||||||
|
if (settings.includeClient) {
|
||||||
|
#ifdef DEER_RENDER
|
||||||
|
loadComponent<Archive, MeshComponent, MeshComponentSerialization>(archive, entity, "MeshComponent");
|
||||||
|
loadComponent<Archive, ShaderComponent, ShaderComponentSerialization>(archive, entity, "ShaderComponent");
|
||||||
|
#else
|
||||||
|
DEER_CORE_ERROR("Can not include client on Deer Core Headless Compile");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace Deer
|
} // namespace Deer
|
||||||
@ -18,7 +18,7 @@ namespace Deer {
|
|||||||
void save(Archive& archive) const {
|
void save(Archive& archive) const {
|
||||||
std::vector<EntitySerialization> entities;
|
std::vector<EntitySerialization> entities;
|
||||||
|
|
||||||
size_t entityIndex = 0;
|
uint32_t entityIndex = 0;
|
||||||
size_t remainingEntities = entityEnvironment->getEntityCount();
|
size_t remainingEntities = entityEnvironment->getEntityCount();
|
||||||
while (remainingEntities > 0) {
|
while (remainingEntities > 0) {
|
||||||
if (!entityEnvironment->entityExists(entityIndex)) {
|
if (!entityEnvironment->entityExists(entityIndex)) {
|
||||||
@ -43,13 +43,12 @@ namespace Deer {
|
|||||||
entityIndex++;
|
entityIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
entities.push_back({});
|
EntitySerialization entityS{
|
||||||
|
.settings = settings,
|
||||||
|
.entityEnvironment = entityEnvironment,
|
||||||
|
.entityId = entityIndex};
|
||||||
|
|
||||||
EntitySerialization& entityS = entities.push_back();
|
entities.push_back(entityS);
|
||||||
|
|
||||||
entityS.settings = settings;
|
|
||||||
entityS.entityId = entityEnvironment;
|
|
||||||
entityS.entityId = entityIndex;
|
|
||||||
|
|
||||||
remainingEntities--;
|
remainingEntities--;
|
||||||
entityIndex++;
|
entityIndex++;
|
||||||
@ -63,14 +62,20 @@ namespace Deer {
|
|||||||
template <class Archive>
|
template <class Archive>
|
||||||
void load(Archive& archive) {
|
void load(Archive& archive) {
|
||||||
size_t entitySize;
|
size_t entitySize;
|
||||||
archive(cereal::make_nvp("Entities", entitySize));
|
archive(cereal::make_size_tag(entitySize));
|
||||||
|
|
||||||
|
std::vector<uint32_t> entities;
|
||||||
for (size_t i = 0; i < entitySize; i++) {
|
for (size_t i = 0; i < entitySize; i++) {
|
||||||
EntitySerialization entityS;
|
EntitySerialization entityS{.settings = settings, .entityEnvironment = entityEnvironment};
|
||||||
entityS.entityEnvironment = entityEnvironment;
|
|
||||||
entityS.settings = settings;
|
|
||||||
|
|
||||||
archive(entityS);
|
archive(entityS);
|
||||||
|
|
||||||
|
entities.push_back(entityS.entityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t entity_id : entities) {
|
||||||
|
Entity& entity = entityEnvironment->getEntity(entity_id);
|
||||||
|
RelationshipComponent& tag = entity.getComponent<RelationshipComponent>();
|
||||||
|
entity.setParent(entityEnvironment->getEntity(tag.parent_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,18 +8,15 @@ namespace Deer {
|
|||||||
class World;
|
class World;
|
||||||
|
|
||||||
struct WorldSerialization {
|
struct WorldSerialization {
|
||||||
WorldSerializationSettings settings;
|
WorldSerializationSettings& settings;
|
||||||
EntityEnvironment* entityEnv;
|
|
||||||
uint32_t entityId;
|
|
||||||
World* world;
|
World* world;
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
void serialize(Archive& archive) {
|
void serialize(Archive& archive) {
|
||||||
EntityEnvironmentSerialization entityEnvironment;
|
EntityEnvironmentSerialization entityEnvironment{
|
||||||
entityEnvironment.settings = settings;
|
.settings = settings,
|
||||||
entityEnvironment.entityEnvironment = world->entityEnvironment.get();
|
.entityEnvironment = world->entityEnvironment.get()};
|
||||||
|
|
||||||
archive(cereal::make_nvp("SerializationSettings", settings));
|
|
||||||
archive(cereal::make_nvp("EntityEnvironment", entityEnvironment));
|
archive(cereal::make_nvp("EntityEnvironment", entityEnvironment));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "cereal/cereal.hpp"
|
|
||||||
|
|
||||||
namespace Deer {
|
|
||||||
struct WorldSerializationSettings {
|
|
||||||
bool includeServer;
|
|
||||||
bool includeClient;
|
|
||||||
|
|
||||||
WorldSerializationSettings() {
|
|
||||||
#ifdef DEER_RENDER
|
|
||||||
includeServer = false;
|
|
||||||
includeClient = true;
|
|
||||||
#else
|
|
||||||
includeServer = true;
|
|
||||||
includeClient = false;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Archive>
|
|
||||||
void serialize(Archive& archive) {
|
|
||||||
archive(CEREAL_NVP(includeServer));
|
|
||||||
archive(CEREAL_NVP(includeClient));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace Deer
|
|
||||||
@ -1,6 +1,35 @@
|
|||||||
#include "DeerCore/Universe.h"
|
#include "DeerCore/Universe.h"
|
||||||
|
|
||||||
|
#include "DeerCore/Serialization/World.h"
|
||||||
|
#include "cereal/archives/json.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
namespace Deer {
|
namespace Deer {
|
||||||
void Universe::saveWorldInJson(World* world, const Path& path) {
|
void Universe::saveWorldInJson(World* world, WorldSerializationSettings& serializationSettings, const Path& path) {
|
||||||
|
std::ofstream file(path);
|
||||||
|
cereal::JSONOutputArchive archive(file);
|
||||||
|
|
||||||
|
WorldSerialization worldSerialization{
|
||||||
|
.settings = serializationSettings,
|
||||||
|
.world = world};
|
||||||
|
|
||||||
|
archive(cereal::make_nvp("SerializationSettings", serializationSettings));
|
||||||
|
archive(cereal::make_nvp("World", worldSerialization));
|
||||||
|
}
|
||||||
|
|
||||||
|
World* Universe::loadWorldFromJson(const WorldSettings& worldSettings, WorldSerializationSettings& serializationSettings, const Path& path) {
|
||||||
|
std::ifstream file(path);
|
||||||
|
cereal::JSONInputArchive archive(file);
|
||||||
|
|
||||||
|
World* world = Universe::createWorld(worldSettings);
|
||||||
|
WorldSerialization worldSerialization{
|
||||||
|
.settings = serializationSettings,
|
||||||
|
.world = world};
|
||||||
|
|
||||||
|
archive(cereal::make_nvp("SerializationSettings", serializationSettings));
|
||||||
|
archive(cereal::make_nvp("World", worldSerialization));
|
||||||
|
|
||||||
|
return world;
|
||||||
}
|
}
|
||||||
} // namespace Deer
|
} // namespace Deer
|
||||||
@ -20,7 +20,7 @@ namespace Deer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
World::~World() {
|
World::~World() {
|
||||||
DEER_CORE_ASSERT(executingState == WorldState::Stopped, "Invalid executing state while destroying world");
|
DEER_CORE_ASSERT(executingState == WorldState::ReadyToDestroy, "Invalid executing state while destroying world");
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::stopExecution() {
|
void World::stopExecution() {
|
||||||
|
|||||||
@ -65,6 +65,10 @@ namespace Deer {
|
|||||||
RenderCommand::init();
|
RenderCommand::init();
|
||||||
RenderUtils::initializeRenderUtils();
|
RenderUtils::initializeRenderUtils();
|
||||||
|
|
||||||
|
Builtin::cube();
|
||||||
|
Builtin::simpleShader();
|
||||||
|
Builtin::sphere();
|
||||||
|
|
||||||
ImGuiLayer::init(*window);
|
ImGuiLayer::init(*window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "DeerCore/Serialization/WorldSettings.h"
|
||||||
|
|
||||||
|
#include "DeerRender/Components.h"
|
||||||
|
|
||||||
|
#include "cereal/cereal.hpp"
|
||||||
|
|
||||||
|
namespace Deer {
|
||||||
|
struct MeshComponentSerialization {
|
||||||
|
WorldSerializationSettings& settings;
|
||||||
|
MeshComponent& component;
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void save(Archive& archive) const {
|
||||||
|
archive(cereal::make_nvp("IsActive", component.active));
|
||||||
|
archive(cereal::make_nvp("Mesh", component.mesh.getStorageId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void load(Archive& archive) {
|
||||||
|
std::string storageId;
|
||||||
|
|
||||||
|
archive(cereal::make_nvp("IsActive", component.active));
|
||||||
|
archive(cereal::make_nvp("Mesh", storageId));
|
||||||
|
|
||||||
|
Scope<MeshData> meshData = settings.meshLoadingFunction(storageId);
|
||||||
|
|
||||||
|
Resource<GPUMesh> mesh = ResourceManager<GPUMesh>::loadResourceFromData(*meshData.get(), storageId);
|
||||||
|
component.mesh = mesh;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Deer
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "DeerCore/Serialization/WorldSettings.h"
|
||||||
|
|
||||||
|
#include "DeerRender/Components.h"
|
||||||
|
|
||||||
|
#include "cereal/cereal.hpp"
|
||||||
|
|
||||||
|
namespace Deer {
|
||||||
|
struct ShaderComponentSerialization {
|
||||||
|
WorldSerializationSettings& settings;
|
||||||
|
ShaderComponent& component;
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void save(Archive& archive) const {
|
||||||
|
archive(cereal::make_nvp("Shader", component.shader.getStorageId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void load(Archive& archive) {
|
||||||
|
std::string storageId;
|
||||||
|
|
||||||
|
archive(cereal::make_nvp("Shader", storageId));
|
||||||
|
|
||||||
|
Scope<ShaderData> shaderData = settings.shaderLoadingFunction(storageId);
|
||||||
|
|
||||||
|
Resource<Shader> shader = ResourceManager<Shader>::loadResourceFromData(*shaderData.get(), storageId);
|
||||||
|
component.shader = shader;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Deer
|
||||||
@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "DeerCore/Serialization/WorldSettings.h"
|
|
||||||
|
|
||||||
#include "DeerRender/Components.h"
|
|
||||||
|
|
||||||
#include "cereal/cereal.hpp"
|
|
||||||
|
|
||||||
namespace Deer {
|
|
||||||
struct MeshComponentSerialization {
|
|
||||||
WorldSerializationSettings& settings;
|
|
||||||
TransformComponent& component;
|
|
||||||
|
|
||||||
template <class Archive>
|
|
||||||
void serialize(Archive& archive) {
|
|
||||||
archive(cereal::make_nvp("Position", component.position));
|
|
||||||
archive(cereal::make_nvp("Scale", component.scale));
|
|
||||||
archive(cereal::make_nvp("Rotation", component.rotation));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace Deer
|
|
||||||
@ -5,9 +5,13 @@
|
|||||||
int main(int, char**);
|
int main(int, char**);
|
||||||
|
|
||||||
namespace Deer {
|
namespace Deer {
|
||||||
|
class World;
|
||||||
|
|
||||||
namespace DeerStudio {
|
namespace DeerStudio {
|
||||||
void onRender();
|
extern World* world;
|
||||||
void onUpdate();
|
|
||||||
|
void worldUpdate(World&);
|
||||||
|
void worldRender(World&);
|
||||||
|
|
||||||
void onEvent(Event& e);
|
void onEvent(Event& e);
|
||||||
void main();
|
void main();
|
||||||
@ -16,5 +20,6 @@ namespace Deer {
|
|||||||
|
|
||||||
// Other
|
// Other
|
||||||
void onPanelMenuBar();
|
void onPanelMenuBar();
|
||||||
|
void worldManagerMenu();
|
||||||
} // namespace DeerStudio
|
} // namespace DeerStudio
|
||||||
} // namespace Deer
|
} // namespace Deer
|
||||||
|
|||||||
@ -24,6 +24,5 @@ namespace Deer {
|
|||||||
CScriptDictionary* setResourceMetadata(std::string& resource);
|
CScriptDictionary* setResourceMetadata(std::string& resource);
|
||||||
|
|
||||||
ResourceType getResourceType(std::string&);
|
ResourceType getResourceType(std::string&);
|
||||||
|
|
||||||
} // namespace StudioAPI
|
} // namespace StudioAPI
|
||||||
} // namespace Deer
|
} // namespace Deer
|
||||||
@ -4,7 +4,8 @@ namespace Deer {
|
|||||||
class World;
|
class World;
|
||||||
|
|
||||||
namespace StudioPanel {
|
namespace StudioPanel {
|
||||||
void init(World*);
|
void init();
|
||||||
|
void setWorld(World*);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
void render();
|
void render();
|
||||||
|
|||||||
@ -16,7 +16,7 @@ namespace Deer {
|
|||||||
class FrameBuffer;
|
class FrameBuffer;
|
||||||
|
|
||||||
namespace DeerStudio {
|
namespace DeerStudio {
|
||||||
Universe::WorldHandle mainWorld;
|
World* world;
|
||||||
|
|
||||||
void onUpdate();
|
void onUpdate();
|
||||||
void onRender();
|
void onRender();
|
||||||
@ -29,6 +29,7 @@ namespace Deer {
|
|||||||
void main() {
|
void main() {
|
||||||
Engine::init();
|
Engine::init();
|
||||||
Engine::setEventCallback(DeerStudio::onEvent);
|
Engine::setEventCallback(DeerStudio::onEvent);
|
||||||
|
StudioPanel::init();
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20, 20));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20, 20));
|
||||||
initializeFonts();
|
initializeFonts();
|
||||||
@ -41,10 +42,12 @@ namespace Deer {
|
|||||||
.renderFrequency = 166,
|
.renderFrequency = 166,
|
||||||
};
|
};
|
||||||
|
|
||||||
mainWorld = Universe::createWorld(worldSettings);
|
world = Universe::createWorld(worldSettings);
|
||||||
StudioPanel::init(&Universe::getWorld(mainWorld));
|
|
||||||
|
|
||||||
Universe::getWorld(mainWorld).execute();
|
while (world) {
|
||||||
|
StudioPanel::setWorld(world);
|
||||||
|
world->execute();
|
||||||
|
}
|
||||||
|
|
||||||
Engine::shutdown();
|
Engine::shutdown();
|
||||||
} // namespace DeerStudio
|
} // namespace DeerStudio
|
||||||
@ -80,8 +83,7 @@ namespace Deer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool p_open = true;
|
static bool p_open = true;
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||||
ImVec2(0.0f, 0.0f));
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||||
ImGui::Begin("DockSpace Demo", &p_open, window_flags);
|
ImGui::Begin("DockSpace Demo", &p_open, window_flags);
|
||||||
@ -93,17 +95,17 @@ namespace Deer {
|
|||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
|
||||||
if (ImGui::BeginMenuBar()) {
|
if (ImGui::BeginMenuBar()) {
|
||||||
if (ImGui::BeginMenu("Panel")) {
|
if (ImGui::BeginMenu("World")) {
|
||||||
onPanelMenuBar();
|
DeerStudio::worldManagerMenu();
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
if (ImGui::MenuItem("Reload Editor")) {
|
|
||||||
}
|
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
StudioPanel::render();
|
if (world.getExecutionState() == Deer::WorldState::Executing)
|
||||||
|
StudioPanel::render();
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
@ -117,10 +119,11 @@ namespace Deer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool onWindowCloseEvent(WindowCloseEvent&) {
|
bool onWindowCloseEvent(WindowCloseEvent&) {
|
||||||
Universe::getWorld(mainWorld).stopExecution();
|
world->stopExecution();
|
||||||
|
world = nullptr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // namespace DeerStudio
|
} // namespace DeerStudio
|
||||||
} // namespace Deer
|
} // namespace Deer
|
||||||
|
|
||||||
int main(int argc, char** args) { Deer::DeerStudio::main(); }
|
int main(int argc, char** args) { Deer::DeerStudio::main(); }
|
||||||
@ -13,12 +13,15 @@ namespace Deer {
|
|||||||
void renderSystem(ScriptSystem* system);
|
void renderSystem(ScriptSystem* system);
|
||||||
} // namespace StudioPanel
|
} // namespace StudioPanel
|
||||||
|
|
||||||
void StudioPanel::init(World* world) {
|
void StudioPanel::init() {
|
||||||
StudioScripting::registerStudioScripting();
|
StudioScripting::registerStudioScripting();
|
||||||
Scripting::registerInterface("Panel");
|
Scripting::registerInterface("Panel");
|
||||||
Scripting::registerInterfaceFunction("Panel", "onImGui", Scripting::EventType::void_event);
|
Scripting::registerInterfaceFunction("Panel", "onImGui", Scripting::EventType::void_event);
|
||||||
|
|
||||||
Scripting::compileFiles("Editor/Scripts", "Editor");
|
Scripting::compileFiles("Editor/Scripts", "Editor");
|
||||||
|
}
|
||||||
|
|
||||||
|
void StudioPanel::setWorld(World* world) {
|
||||||
Scripting::SystemDescription systemDescription("Panel", "Editor");
|
Scripting::SystemDescription systemDescription("Panel", "Editor");
|
||||||
systemDescription.events.push_back(Scripting::SystemEvent("onInit", Scripting::EventType::void_event));
|
systemDescription.events.push_back(Scripting::SystemEvent("onInit", Scripting::EventType::void_event));
|
||||||
systemDescription.events.push_back(Scripting::SystemEvent("onShutdown", Scripting::EventType::void_event));
|
systemDescription.events.push_back(Scripting::SystemEvent("onShutdown", Scripting::EventType::void_event));
|
||||||
@ -67,5 +70,6 @@ namespace Deer {
|
|||||||
|
|
||||||
void StudioPanel::shutdown() {
|
void StudioPanel::shutdown() {
|
||||||
editorInstance->executeOnGroup_voidEvent(1);
|
editorInstance->executeOnGroup_voidEvent(1);
|
||||||
|
studioPanelEnvironment.release();
|
||||||
}
|
}
|
||||||
} // namespace Deer
|
} // namespace Deer
|
||||||
47
DeerStudio/src/DeerStudio/WorldManager.cpp
Normal file
47
DeerStudio/src/DeerStudio/WorldManager.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "DeerCore/Serialization/WorldSettings.h"
|
||||||
|
#include "DeerCore/Tools/Memory.h"
|
||||||
|
#include "DeerCore/Universe.h"
|
||||||
|
|
||||||
|
#include "DeerStudio/EditorDataImporter.h"
|
||||||
|
#include "DeerStudio/EditorDataSource.h"
|
||||||
|
#include "DeerStudio/StudioPanel.h"
|
||||||
|
|
||||||
|
#include "DeerCore/World.h"
|
||||||
|
#include "DeerStudio/DeerStudio.h"
|
||||||
|
#include "imgui.h"
|
||||||
|
|
||||||
|
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() {
|
||||||
|
if (ImGui::MenuItem("Save world")) {
|
||||||
|
WorldSerializationSettings serializationSettings{
|
||||||
|
.includeServer = true,
|
||||||
|
.includeClient = true};
|
||||||
|
Universe::saveWorldInJson(world, serializationSettings, "Worlds/world.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Load world")) {
|
||||||
|
StudioPanel::shutdown();
|
||||||
|
world->destroy();
|
||||||
|
|
||||||
|
WorldSettings worldSettings = {
|
||||||
|
.updateCallback = worldUpdate,
|
||||||
|
.updateFrequency = 60,
|
||||||
|
.renderCallback = worldRender,
|
||||||
|
.renderFrequency = 166,
|
||||||
|
};
|
||||||
|
|
||||||
|
WorldSerializationSettings serializationSettings{
|
||||||
|
.meshLoadingFunction = loadResourceData<MeshData>,
|
||||||
|
.shaderLoadingFunction = loadResourceData<ShaderData>};
|
||||||
|
|
||||||
|
World* world_new = Universe::loadWorldFromJson(worldSettings, serializationSettings, "Worlds/world.json");
|
||||||
|
world = world_new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Deer
|
||||||
135
Worlds/world.json
Normal file
135
Worlds/world.json
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
{
|
||||||
|
"SerializationSettings": {
|
||||||
|
"includeServer": true,
|
||||||
|
"includeClient": true
|
||||||
|
},
|
||||||
|
"World": {
|
||||||
|
"EntityEnvironment": [
|
||||||
|
{
|
||||||
|
"Id": 0,
|
||||||
|
"Tag": "root",
|
||||||
|
"NetworkBehaviour": 0,
|
||||||
|
"Parent": 0,
|
||||||
|
"TransformComponent": {
|
||||||
|
"Position": {
|
||||||
|
"x": 0.0,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": 0.0
|
||||||
|
},
|
||||||
|
"Scale": {
|
||||||
|
"x": 1.0,
|
||||||
|
"y": 1.0,
|
||||||
|
"z": 1.0
|
||||||
|
},
|
||||||
|
"Rotation": {
|
||||||
|
"x": 0.0,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": 0.0,
|
||||||
|
"w": 1.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Contains_MeshComponent": false,
|
||||||
|
"Contains_ShaderComponent": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 1,
|
||||||
|
"Tag": "node",
|
||||||
|
"NetworkBehaviour": 0,
|
||||||
|
"Parent": 0,
|
||||||
|
"TransformComponent": {
|
||||||
|
"Position": {
|
||||||
|
"x": 0.0,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": 0.0
|
||||||
|
},
|
||||||
|
"Scale": {
|
||||||
|
"x": 1.0,
|
||||||
|
"y": 1.0,
|
||||||
|
"z": 1.0
|
||||||
|
},
|
||||||
|
"Rotation": {
|
||||||
|
"x": 0.0,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": 0.0,
|
||||||
|
"w": 1.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Contains_MeshComponent": true,
|
||||||
|
"MeshComponent": {
|
||||||
|
"IsActive": true,
|
||||||
|
"Mesh": "Builtin:Cube"
|
||||||
|
},
|
||||||
|
"Contains_ShaderComponent": true,
|
||||||
|
"ShaderComponent": {
|
||||||
|
"Shader": "Builtin:SimpleShader"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 2,
|
||||||
|
"Tag": "node",
|
||||||
|
"NetworkBehaviour": 0,
|
||||||
|
"Parent": 0,
|
||||||
|
"TransformComponent": {
|
||||||
|
"Position": {
|
||||||
|
"x": 2.299999952316284,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": 0.0
|
||||||
|
},
|
||||||
|
"Scale": {
|
||||||
|
"x": 1.0,
|
||||||
|
"y": 1.0,
|
||||||
|
"z": 1.0
|
||||||
|
},
|
||||||
|
"Rotation": {
|
||||||
|
"x": 0.0,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": 0.0,
|
||||||
|
"w": 1.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Contains_MeshComponent": true,
|
||||||
|
"MeshComponent": {
|
||||||
|
"IsActive": true,
|
||||||
|
"Mesh": "Builtin:Sphere"
|
||||||
|
},
|
||||||
|
"Contains_ShaderComponent": true,
|
||||||
|
"ShaderComponent": {
|
||||||
|
"Shader": "Builtin:SimpleShader"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 3,
|
||||||
|
"Tag": "node",
|
||||||
|
"NetworkBehaviour": 0,
|
||||||
|
"Parent": 0,
|
||||||
|
"TransformComponent": {
|
||||||
|
"Position": {
|
||||||
|
"x": -3.700000047683716,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": 0.0
|
||||||
|
},
|
||||||
|
"Scale": {
|
||||||
|
"x": 1.0,
|
||||||
|
"y": 1.0,
|
||||||
|
"z": 1.0
|
||||||
|
},
|
||||||
|
"Rotation": {
|
||||||
|
"x": 0.0,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": 0.0,
|
||||||
|
"w": 1.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Contains_MeshComponent": true,
|
||||||
|
"MeshComponent": {
|
||||||
|
"IsActive": true,
|
||||||
|
"Mesh": "train-locomotive-a.obj"
|
||||||
|
},
|
||||||
|
"Contains_ShaderComponent": true,
|
||||||
|
"ShaderComponent": {
|
||||||
|
"Shader": "shader_darkBlue.glsl"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
16
imgui.ini
16
imgui.ini
@ -1,6 +1,6 @@
|
|||||||
[Window][DockSpace Demo]
|
[Window][DockSpace Demo]
|
||||||
Pos=0,0
|
Pos=0,0
|
||||||
Size=1920,1011
|
Size=2560,1371
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Debug##Default]
|
[Window][Debug##Default]
|
||||||
@ -10,30 +10,30 @@ Collapsed=0
|
|||||||
|
|
||||||
[Window][ViewportPanel]
|
[Window][ViewportPanel]
|
||||||
Pos=561,26
|
Pos=561,26
|
||||||
Size=934,493
|
Size=1574,853
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000005,0
|
DockId=0x00000005,0
|
||||||
|
|
||||||
[Window][PropertiesPanel]
|
[Window][PropertiesPanel]
|
||||||
Pos=1497,26
|
Pos=2137,26
|
||||||
Size=423,493
|
Size=423,853
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000006,0
|
DockId=0x00000006,0
|
||||||
|
|
||||||
[Window][ResourceExplorer]
|
[Window][ResourceExplorer]
|
||||||
Pos=0,521
|
Pos=0,881
|
||||||
Size=1920,490
|
Size=2560,490
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000004,0
|
DockId=0x00000004,0
|
||||||
|
|
||||||
[Window][TreePanel]
|
[Window][TreePanel]
|
||||||
Pos=0,26
|
Pos=0,26
|
||||||
Size=559,493
|
Size=559,853
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,0
|
DockId=0x00000001,0
|
||||||
|
|
||||||
[Docking][Data]
|
[Docking][Data]
|
||||||
DockSpace ID=0x0AC2E849 Window=0xD0388BC8 Pos=0,26 Size=1920,985 Split=Y
|
DockSpace ID=0x0AC2E849 Window=0xD0388BC8 Pos=0,26 Size=2560,1345 Split=Y
|
||||||
DockNode ID=0x00000003 Parent=0x0AC2E849 SizeRef=1920,493 Split=X
|
DockNode ID=0x00000003 Parent=0x0AC2E849 SizeRef=1920,493 Split=X
|
||||||
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=559,985 Selected=0x16E3C1E7
|
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=559,985 Selected=0x16E3C1E7
|
||||||
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1359,985 Split=X
|
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1359,985 Split=X
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user